如果簡(jiǎn)單的使用USART的話(huà)配置相當(dāng)簡(jiǎn)單,只要配置一下波特率,數(shù)據(jù)長(zhǎng)度,停止位長(zhǎng)度,校驗(yàn)位。然后再設(shè)置一下串口的引腳,輸入為上后輸入,輸出為利用推挽輸出。這樣一來(lái)串口就配置好了,如果使用庫(kù)則一目了然,如果使用寄存器操作會(huì)繁瑣一點(diǎn)找各個(gè)寄存器,因?yàn)樵O(shè)置波特率和設(shè)置數(shù)據(jù)長(zhǎng)度等這些并不在一個(gè)寄存器中設(shè)置完成,還有可能忘記個(gè)別設(shè)置而無(wú)法找其原因。但寄存器操作的效率會(huì)很高。如下配置:
void USART_Initial(uint32_t Baud)
{
USART_InitTypeDef USART_InitStruct;
USART_GPIO(); //配置串口引腳
USART_InitStruct.USART_BaudRate=Baud; //波特率
USART_InitStruct.USART_WordLength=USART_WordLength_8b;//數(shù)據(jù)長(zhǎng)度
USART_InitStruct.USART_StopBits=USART_StopBits_1;//停止位
USART_InitStruct.USART_Parity=USART_Parity_No;//奇偶校驗(yàn)
USART_InitStruct.USART_HardwareFlowControl=USART_HardwareFlowControl_None;//硬件流失能
USART_InitStruct.USART_Mode=USART_Mode_Tx|USART_Mode_Rx;//使能接收和發(fā)送
USART_Init(USART1,&USART_InitStruct);
USART_Cmd(USART1,ENABLE);//打開(kāi)串口
USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);//開(kāi)中斷,本代碼只在接收時(shí)用到
}
void USART_GPIO(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_9;
GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;
GPIO_Init(GPIOA,&GPIO_InitStruct);
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_10;
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IPU;
GPIO_Init(GPIOA,&GPIO_InitStruct);
GPIO_SetBits(GPIOA,GPIO_Pin_9|GPIO_Pin_10);
}
我使能的USART1為PA9和PA10兩個(gè)串口線(xiàn)。
如果使能到串口中斷則在NVIC中設(shè)置好中斷向量斷并設(shè)置好優(yōu)先級(jí),并在串口寄存器中使能該中斷。
void NVIC_USART_Initial(void)
{
NVIC_InitTypeDef NVIC_InitStruct;
NVIC_InitStruct.NVIC_IRQChannel=USART1_IRQn;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=2;
NVIC_InitStruct.NVIC_IRQChannelSubPriority=1;
NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE;
NVIC_Init(&NVIC_InitStruct);
}
(中斷優(yōu)先級(jí)分組為2)
此時(shí)你可以在串口的中斷服務(wù)代碼中寫(xiě)入你想處理的代碼。至于你想是接收中斷還是發(fā)送中斷或者傳送錯(cuò)誤中斷還是奇偶校驗(yàn),偵錯(cuò)誤等中斷你可以設(shè)置USART_ITConfig中設(shè)置,在void USART_Initial(uint32_t Baud)函數(shù)中最后一句第二個(gè)參數(shù)進(jìn)行設(shè)置。
如果你想使能printf或者scanf來(lái)串口傳輸請(qǐng)看我的另一篇博文。http://blog.sina.com.cn/s/blog_79fbaced01011tpj.html
而串口的其它功能則沒(méi)有用到,至于智能卡個(gè)人覺(jué)得應(yīng)該挺有意思的,以后興許會(huì)搞搞。而串口的同步模式不知道他和SPI比是不是速度更快,它的傳輸則由發(fā)送數(shù)據(jù)時(shí)產(chǎn)生CLK時(shí)鐘和些時(shí)鐘進(jìn)行同步,接收數(shù)據(jù)也只有在此時(shí)才可以接收,也就是不可以獨(dú)立的接收數(shù)據(jù)。
博主也試了串口DMA不中斷是可以傳輸?shù)?,但是?dāng)我打開(kāi)DMA傳輸完成中斷時(shí),發(fā)現(xiàn)串口沒(méi)有數(shù)據(jù),以為串口速度根不上DMA就提高了波特率發(fā)現(xiàn)還是不行。但當(dāng)我使能DMA半傳輸中斷時(shí)能夠中斷也能傳輸?shù)侵袛喑绦驘o(wú)法執(zhí)行。。等高手回答。
下面則是ADC。因?yàn)閷?shí)驗(yàn)儀上的ADC引腳引出來(lái)有限,所以很多功能未實(shí)現(xiàn),首先就是ADCON這個(gè)東西一直有點(diǎn)混。一直以為使能此位這前校驗(yàn)ADC(手冊(cè)上說(shuō)校驗(yàn)ADC是ADCON=0必須在兩個(gè)周期以上,但手冊(cè)上又說(shuō)ADCON=0時(shí)ADC消耗基本為0)后試過(guò)只有打開(kāi)此位才可以校驗(yàn)。但是ADCON再次設(shè)置時(shí)可以啟動(dòng)ADC轉(zhuǎn)換,手冊(cè)上好像講是啟動(dòng)規(guī)則轉(zhuǎn)換,因?yàn)闆](méi)有度過(guò)注入轉(zhuǎn)換所以規(guī)則轉(zhuǎn)換可以設(shè)置些位,也可以設(shè)置ADCx_CR2寄存器器中的外部觸發(fā)來(lái)啟動(dòng),規(guī)則通道則是先設(shè)置EXTSEL[2:0]位,如果設(shè)置成111即軟件觸發(fā),后設(shè)置位20EXTTRIG位允許外部事件觸發(fā),最后設(shè)置位22SWSART來(lái)啟動(dòng)規(guī)則軟件觸發(fā),而注入觸發(fā)則同樣設(shè)置CR2寄存器中的某些對(duì)應(yīng)位來(lái)啟動(dòng)。
ADC有很多模式,而雙ADC模式個(gè)人認(rèn)為比較經(jīng)典,或許見(jiàn)識(shí)有點(diǎn)少了。哈哈。這里不多說(shuō),為什么?沒(méi)有經(jīng)驗(yàn),實(shí)驗(yàn)儀提供的資源多,但是隨心的少。
SCAN模式,即掃描整個(gè)通道。如果規(guī)則通道組中有3個(gè)通道,則啟動(dòng)通道時(shí)轉(zhuǎn)換完第一個(gè)自動(dòng)轉(zhuǎn)換第二個(gè)再然后第三個(gè)后停止并產(chǎn)生一個(gè)EOC事件,如果使能了中斷則產(chǎn)生中斷。(以前對(duì)中斷頭疼,現(xiàn)在覺(jué)得就是個(gè)紙老虎)
CONT即單詞continue(本來(lái)看成count)當(dāng)設(shè)置了SCAN又設(shè)置了CONT時(shí)將循環(huán)的轉(zhuǎn)換通道,即上面轉(zhuǎn)換完三后繼續(xù)生第一個(gè)轉(zhuǎn)換。同樣的地方產(chǎn)生EOC。(應(yīng)該是的,沒(méi)有實(shí)踐不敢斷定)。
注入模式:一種是外部觸發(fā),優(yōu)先于規(guī)則,如果有外部觸發(fā)將打斷正在轉(zhuǎn)換的規(guī)則通道。直至完成。
自動(dòng)注入模式:即轉(zhuǎn)換完成規(guī)則通道后自動(dòng)的切換到注入通道執(zhí)行轉(zhuǎn)換。
當(dāng)然ADC還有很多,比如常常配合ADC的DMA。ADC時(shí)鐘,外部觸發(fā)的事件啊,等等細(xì)節(jié)。
配置ADC,這里不將時(shí)鐘的打開(kāi),以上串口也未講。
void ADC_Initial(void)
{
ADC_InitTypeDef ADC_InitStruct;
ADC_Cmd(ADC1,ENABLE); //啟動(dòng)ADC
System_Delay_us(100); //延時(shí)幾個(gè)ADC周期
ADC_ResetCalibration(ADC1); //重置ADC校驗(yàn)
while(ADC_GetResetCalibrationStatus(ADC1)); //等待重置完成
ADC_StartCalibration(ADC1); //校驗(yàn)ADC
while(ADC_GetCalibrationStatus(ADC1)); //等待校驗(yàn)完成
ADC_InitStruct.ADC_Mode=ADC_Mode_Independent; //獨(dú)立模式
ADC_InitStruct.ADC_ScanConvMode=DISABLE; //非掃描模式,當(dāng)有多個(gè)ADC通道須要轉(zhuǎn)換時(shí)可以使能此位
ADC_InitStruct.ADC_ContinuousConvMode=ENABLE; //連續(xù)轉(zhuǎn)換使能
ADC_InitStruct.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None; //外部觸發(fā)條件,這里為軟件觸發(fā)
ADC_InitStruct.ADC_DataAlign=ADC_DataAlign_Right; //右對(duì)齊模式
ADC_InitStruct.ADC_NbrOfChannel=1; //規(guī)則通道的個(gè)數(shù),放在SQR寄存器的L[3:0]中
ADC_Init(ADC1,&ADC_InitStruct);
ADC_RegularChannelConfig(ADC1,ADC_Channel_10,1,ADC_SampleTime_239Cycles5); //開(kāi)啟通道10寫(xiě)入規(guī)則通道中,并設(shè)置第幾個(gè)轉(zhuǎn)換,轉(zhuǎn)換周期為239
}
以上函數(shù)可以參考庫(kù)手冊(cè)。
再執(zhí)行完ADC_Cmd(ADC1,ENABLE);這條語(yǔ)句就可以讀通道10的AD轉(zhuǎn)換值了。12位AD值在0~4096之間。然后將這些值打印到串口看其變化。你會(huì)發(fā)現(xiàn)變化波動(dòng)還是較大的??赡軜O差并不會(huì)太大。你可以自己進(jìn)行濾波。
昨天洗完澡回來(lái)后并無(wú)睡意,所以寫(xiě)了個(gè)濾波,但沒(méi)什么新意,只是不厭其煩的取平均值。最后可以使AD值變化最大的情況下只有一個(gè)值的變化,一般情況下采樣值都會(huì)是同一個(gè)值。但這樣就大大(很大)犧牲了采樣靈敏度。
不過(guò)這樣的采樣濾波不科學(xué)。有興趣的同學(xué)可以上網(wǎng)搜下常見(jiàn)的AD的10大軟件濾波程序。比較經(jīng)典。
以下是一個(gè)簡(jiǎn)單的濾波代碼。犧牲了速度。
#define GetValueTimes 30
#define DeleteValue 10
uint16_t ADC_GetValue(void)
{
uint8_t i,j;
uint16_t DigitalValue[GetValueTimes],SwapTreg;
uint32_t CalValue=0;
for(i=0;i
{
DigitalValue[i]=ADC_GetConversionValue(ADC1);
}
for(i=0;i
{
for(j=i+1;j
{
if(DigitalValue[i]>DigitalValue[j])
{
SwapTreg=DigitalValue[i];
DigitalValue[i]=DigitalValue[j];
DigitalValue[j]=SwapTreg;
}
}
}
for(i=DeleteValue,j=0;i
{
DigitalValue[j]=DigitalValue[i];
}
for(i=0;i
{
CalValue+=DigitalValue[i];
}
CalValue=CalValue/i;
return (uint16_t)CalValue;
}
#define SampleTimes 10
uint16_t MoveMix(void)
{
uint16_t SampleBuffer[SampleTimes];
uint8_t i,j;
uint32_t CalValue=0;
Lable: for(i=0;i
{
SampleBuffer[i]=ADC_GetValue();
}
for(i=0;i
{
for(j=i;j
{
if(abs(SampleBuffer[i]-SampleBuffer[j])>=20)goto Lable;
}
}
for(i=0;i
{
CalValue+=SampleBuffer[i];
}
CalValue/=i;
return (uint16_t)CalValue;
}
#define SampleTimes2 10
uint16_t MoreMix(void)
{
uint8_t i;
uint32_t CalValue=0;
for(i=0;i
{
CalValue+=MoveMix();
}
CalValue/=i;
return (uint16_t)CalValue;
}
#define SampleOver 5
uint16_t OverMix(void)
{
uint8_t i;
uint16_t OverValue[SampleOver];
Lable2: for(i=0;i
{
OverValue[i]=MoreMix();
}
for(i=0;i
{
if(OverValue[i]!=OverValue[i+1])goto Lable2;
}
return OverValue[0];
}