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