有一次做一個(gè)東西,為了盡量不占用CPU的處理數(shù)據(jù)時(shí)間,所以就使用DMA接收串口的數(shù)據(jù),但是呢問題來了.,,,,,怎么樣才能確定接收到了一條完整的數(shù)據(jù)了,,我們都知道只要打開DMA
那家伙就不停的把接收的數(shù)據(jù)放到我們指定的地方.
只要接收到一條完整的數(shù)據(jù)我就該去處理了
關(guān)于空閑中斷,,,就是說每接收到一條完整的數(shù)據(jù)就會置位空閑標(biāo)志位,我們只需要判斷空閑標(biāo)志位是否置一,,就能知道是不是接收到了一條完整的數(shù)據(jù)
用空閑中斷的好處就是,,對于以前我寫程序通信都會在數(shù)據(jù)的后面加上尾,,然后另一個(gè)接收的單片機(jī)通過判斷數(shù)據(jù)的尾來確定是不是一條完整的數(shù)據(jù),,,有了空閑中斷就不需要在給數(shù)據(jù)加上尾了,,,,,
直接程序吧
u8? Usart1_RX_Cop[1024]={0};//串口2備用接收緩沖,最大 1024 個(gè)字節(jié).u8? Usart1_RX_BUF[1024]={0};//串口1接收緩沖,最大 1024 個(gè)字節(jié).u16 Usart1_REC_Cnt =0;//串口1接收的數(shù)據(jù)個(gè)數(shù)u16 Usart1_Current_Cnt =0;//串口1當(dāng)前接收的數(shù)據(jù)個(gè)數(shù)u16 Usart1_Current_cnt =0;//串口1當(dāng)前接收的數(shù)據(jù)個(gè)數(shù)u8? Usart1_AT_flage =0;//串口1接收完成標(biāo)志位u8? Usart2_RX_Cop[1024]={0};//串口2備用接收緩沖,最大 1024 個(gè)字節(jié).u8? Usart2_RX_BUF[1024]={0};//串口2接收緩沖,最大 1024 個(gè)字節(jié).u16 Usart2_REC_Cnt =0;//串口2接收的數(shù)據(jù)個(gè)數(shù)u16 Usart2_Current_Cnt =0;//串口2當(dāng)前接收的數(shù)據(jù)個(gè)數(shù)u16 Usart2_Current_cnt =0;//串口2當(dāng)前接收的數(shù)據(jù)個(gè)數(shù)u8? Usart2_AT_flage =0;//串口2接收完成標(biāo)志位u8? Usart3_RX_BUF[1024]={0};//串口3接收緩沖,最大 1024 個(gè)字節(jié).u16 Usart3_REC_Cnt =0;//串口3接收的數(shù)據(jù)個(gè)數(shù)u8? Usart3_AT_flage =0;//串口3接收完成標(biāo)志位u8 Free_Read_Rst=0;//讀DR清除空閑中斷
voidUSART123_Init(uint32_t bound_1,uint32_t bound_2,uint32_t bound_3)
{
USART_InitTypeDef USART_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2|RCC_APB1Periph_USART3, ENABLE);//使能USART2,USART3時(shí)鐘RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB|RCC_APB2Periph_USART1|RCC_APB2Periph_AFIO , ENABLE);//USART1_TX? PA9GPIO_InitStructure.GPIO_Mode =GPIO_Mode_AF_PP;;
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);//USART1_RX? PA10GPIO_InitStructure.GPIO_Mode =GPIO_Mode_IN_FLOATING ;
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10;
GPIO_Init(GPIOA,&GPIO_InitStructure);//USART2_TX? GPIOA.2GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;//PA.2GPIO_InitStructure.GPIO_Speed =GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode= GPIO_Mode_AF_PP;//復(fù)用推挽輸出GPIO_Init(GPIOA, &GPIO_InitStructure);//USART2_RX? ? ? GPIOA.3初始化GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;//PA3GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空輸入GPIO_Init(GPIOA, &GPIO_InitStructure);//USART3_TX? GPIOB.10GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//PB10GPIO_InitStructure.GPIO_Speed =GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode= GPIO_Mode_AF_PP;//復(fù)用推挽輸出GPIO_Init(GPIOB, &GPIO_InitStructure);//USART3_RX? ? ? GPIOB.11初始化GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;//PB11GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空輸入GPIO_Init(GPIOB, &GPIO_InitStructure);
USART_InitStructure.USART_BaudRate=bound_1;
USART_InitStructure.USART_WordLength=USART_WordLength_8b;
USART_InitStructure.USART_StopBits=USART_StopBits_1;
USART_InitStructure.USART_Parity=USART_Parity_No ;
USART_InitStructure.USART_HardwareFlowControl=USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode= USART_Mode_Rx |USART_Mode_Tx;
USART_Init(USART1,&USART_InitStructure);
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//開啟串口接受中斷USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);//開啟串口接受中斷USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);//開啟串口接受中斷USART_ITConfig(USART1, USART_IT_IDLE, ENABLE);//開啟串口1總線空閑中斷USART_ITConfig(USART2, USART_IT_IDLE, ENABLE);//開啟串口2總線空閑中斷USART_InitStructure.USART_BaudRate=bound_2;
USART_Init(USART2,&USART_InitStructure);
USART_InitStructure.USART_BaudRate=bound_3;
USART_Init(USART3,&USART_InitStructure);
USART_Cmd(USART1, ENABLE);
USART_Cmd(USART2, ENABLE);
USART_Cmd(USART3, ENABLE);
}
/********************串口 1 中斷服務(wù)程序**********************/voidUSART1_IRQHandler(void)
{if(USART_GetITStatus(USART1, USART_IT_RXNE) !=RESET) //正常情況下進(jìn)入這個(gè)接收
{
USART_ClearITPendingBit(USART1, USART_FLAG_ORE);
USART_ClearITPendingBit(USART1,USART_IT_ORE);//清除中斷標(biāo)志Usart1_RX_BUF[Usart1_REC_Cnt] =USART_ReceiveData(USART1);//讀取接收到的數(shù)據(jù)Usart1_REC_Cnt++;
}elseif(USART_GetITStatus(USART1,USART_IT_IDLE) ==SET)//傳輸完一條完整的數(shù)據(jù)就會進(jìn)入這個(gè)
{
Free_Read_Rst= USART1->DR;//清USART_IT_IDLE標(biāo)志Usart1_AT_flage =1;//接收到一條完整的數(shù)據(jù)Usart1_Current_Cnt = Usart1_REC_Cnt;//復(fù)制接收到的數(shù)據(jù)個(gè)數(shù)Usart1_REC_Cnt =0;//清零接收的個(gè)數(shù)}
}
主函數(shù)循環(huán)里只需要......
先說一點(diǎn):單片機(jī)的串口可以接收任意波特率的數(shù)據(jù),你所寫的9600意思是以這個(gè)波特率發(fā)送....
其實(shí)昨天才發(fā)現(xiàn)這家伙真的太準(zhǔn)確了,,準(zhǔn)確到如果碰見通信中速率如果不是設(shè)置的波特率,就是說通信的速率慢了不是(我上面設(shè)置的波特率是9600)1/9600(S)發(fā)過來一位數(shù)據(jù)了,低于了這個(gè)值假設(shè)是2400吧!接受到一位數(shù)據(jù)后如果1/9600(s)后沒有接收到數(shù)據(jù),那么這家伙也會進(jìn)空閑中斷.......因?yàn)槟闶窃O(shè)置的9600,,,,那么在1/9600(s)后理應(yīng)接收到下一位數(shù)據(jù)....而其實(shí)是在1/2400(S)后才會接收到另一位數(shù)據(jù).....如果能把空閑中斷的檢測時(shí)間降到滿足的要求就好了....
所以嘛,,,,,自己寫個(gè)別這么苛刻的,昨天寫好了,不過呢今天主要是把自己遇到的問題說一下
其實(shí)思路都知道
串口接收的時(shí)候打開一個(gè)定時(shí)器,并且只要接收到數(shù)據(jù)就清零一個(gè)變量,這個(gè)變量是在定時(shí)器里面執(zhí)行自加一操作,,
如果串口一段時(shí)間(空閑中斷的檢測時(shí)間)不接收數(shù)據(jù)了這個(gè)變量就能自加到我們設(shè)置的數(shù),然后關(guān)掉定時(shí)器,置位接收完成標(biāo)志位,...
直接上程序
/********************串口 1 中斷服務(wù)程序**********************/voidUSART1_IRQHandler(void)
{if(USART_GetITStatus(USART1, USART_IT_RXNE) !=RESET)
{
USART_ClearITPendingBit(USART1, USART_FLAG_ORE);
USART_ClearITPendingBit(USART1,USART_IT_ORE);//清除中斷標(biāo)志Usart1_RX_BUF[Usart1_REC_Cnt] =USART_ReceiveData(USART1);//讀取接收到的數(shù)據(jù)Usart1_REC_Cnt++;
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE );//打開定時(shí)器開始計(jì)時(shí)Time2_cnt =0;//清零計(jì)數(shù)}
}
voidtimer_config(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);/*Resets the TIM2*/TIM_DeInit(TIM2);//設(shè)置了時(shí)鐘分割。TIM_TimeBaseStructure.TIM_ClockDivision =0;//選擇了計(jì)數(shù)器模式。TIM_TimeBaseStructure.TIM_CounterMode =TIM_CounterMode_Up;//初值TIM_TimeBaseStructure.TIM_Period =10;//定時(shí)時(shí)間1ms進(jìn)一次//設(shè)置了用來作為 TIMx 時(shí)鐘頻率除數(shù)的預(yù)分頻值。72M / 7099+1 = 0.01MTIM_TimeBaseStructure.TIM_Prescaler =7199;//TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;TIM_TimeBaseInit(TIM2,&TIM_TimeBaseStructure);
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);/*Enables the TIM2 counter*/TIM_Cmd(TIM2, ENABLE);/*Enables the TIM2 Capture Compare channel 1 Interrupt source*/TIM_ITConfig(TIM2, TIM_IT_Update, DISABLE );
}
voidTIM2_IRQHandler(void)
{if(TIM_GetITStatus(TIM2, TIM_IT_Update) ==SET)
{
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);if(Time2_cnt<100)//防止累加循環(huán)過去
{
Time2_cnt++;
}if(Time2_cnt>3)//空閑時(shí)間大于約3毫秒
{
TIM_ITConfig(TIM2, TIM_IT_Update, DISABLE );//關(guān)閉定時(shí)器---注意千萬不要放到主函數(shù)里面關(guān),,,,大家可以試一試會出現(xiàn)什么問題.....Usart1_AT_flage =1;//接收完成標(biāo)志位置一
Usart1_Current_Cnt=Usart1_REC_Cnt;//賦值接收的數(shù)據(jù)個(gè)數(shù)
Usart1_REC_Cnt=0;//清零接收的數(shù)據(jù)個(gè)數(shù)? ? ? }
}
然后昨天又寫了一個(gè)兩個(gè)串口的,因?yàn)橛昧藘蓚€(gè)串口做數(shù)據(jù)轉(zhuǎn)換(用的串口1和串口3),,,,其實(shí)其中一個(gè)也可以用空閑中斷,,但是擔(dān)心數(shù)據(jù)傳輸過程中萬一速率有所變化,,,,,,,,完蛋啦
uint8_t? Usart1_TimeFlage =0;//串口1空閑變量允許累加標(biāo)志uint16_t Usart1_IdealTime =0;//串口1空閑累加變量uint8_t? Usart3_TimeFlage =0;//串口3空閑變量允許累加標(biāo)志uint16_t Usart3_IdealTime =0;//串口3空閑累加變量u8? Usart1_RX_Cop[1024]={0};//串口2備用接收緩沖,最大 1024 個(gè)字節(jié).u8? Usart1_RX_BUF[1024]={0};//串口1接收緩沖,最大 1024 個(gè)字節(jié).u16 Usart1_REC_Cnt =0;//串口1接收的數(shù)據(jù)個(gè)數(shù)u16 Usart1_Current_Cnt =0;//串口2當(dāng)前接收的數(shù)據(jù)個(gè)數(shù)u16 Usart1_Current_cnt =0;//串口2當(dāng)前接收的數(shù)據(jù)個(gè)數(shù)u8? Usart1_AT_flage =0;//串口1接收完成標(biāo)志位u8? Usart2_RX_Cop[1024]={0};//串口2備用接收緩沖,最大 1024 個(gè)字節(jié).u8? Usart2_RX_BUF[1024]={0};//串口2接收緩沖,最大 1024 個(gè)字節(jié).u16 Usart2_REC_Cnt =0;//串口2接收的數(shù)據(jù)個(gè)數(shù)u16 Usart2_Current_Cnt =0;//串口2當(dāng)前接收的數(shù)據(jù)個(gè)數(shù)u16 Usart2_Current_cnt =0;//串口2當(dāng)前接收的數(shù)據(jù)個(gè)數(shù)u8? Usart2_AT_flage =0;//串口2接收完成標(biāo)志位u8? Usart3_RX_Cop[1024]={0};//串口2備用接收緩沖,最大 1024 個(gè)字節(jié).u8? Usart3_RX_BUF[1024]={0};//串口2接收緩沖,最大 1024 個(gè)字節(jié).u16 Usart3_REC_Cnt =0;//串口2接收的數(shù)據(jù)個(gè)數(shù)u16 Usart3_Current_Cnt =0;//串口2當(dāng)前接收的數(shù)據(jù)個(gè)數(shù)u16 Usart3_Current_cnt =0;//串口2當(dāng)前接收的數(shù)據(jù)個(gè)數(shù)u8? Usart3_AT_flage =0;//串口2接收完成標(biāo)志位
voidtimer3_config(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);/*Resets the TIM2*/TIM_DeInit(TIM3);//設(shè)置了時(shí)鐘分割沮焕。TIM_TimeBaseStructure.TIM_ClockDivision =0;//選擇了計(jì)數(shù)器模式吨岭。TIM_TimeBaseStructure.TIM_CounterMode =TIM_CounterMode_Up;//初值TIM_TimeBaseStructure.TIM_Period =10;//定時(shí)時(shí)間1Ms進(jìn)一次//設(shè)置了用來作為 TIMx 時(shí)鐘頻率除數(shù)的預(yù)分頻值拉宗。72M / 7099+1 = 0.01MTIM_TimeBaseStructure.TIM_Prescaler =7199;//TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;TIM_TimeBaseInit(TIM3,&TIM_TimeBaseStructure);
TIM_ClearITPendingBit(TIM3, TIM_IT_Update);/*Enables the TIM2 counter*/TIM_Cmd(TIM3, ENABLE);/*Enables the TIM2 Capture Compare channel 1 Interrupt source*/TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE );
}
voidTIM3_IRQHandler(void)
{if(TIM_GetITStatus(TIM3, TIM_IT_Update) ==SET)
{
TIM_ClearITPendingBit(TIM3, TIM_IT_Update);if(Usart1_TimeFlage ==1)//開始累加空閑變量{if(Usart1_IdealTime<400)//防止累加過去,造成循環(huán){
Usart1_IdealTime++;//空閑變量累加}
}if(Usart1_IdealTime>=100)//調(diào)節(jié)這個(gè)值以適應(yīng)不同的接收速率{
Usart1_TimeFlage=0;//停止空閑變量累加Usart1_IdealTime =0;//清零空閑累加變量Usart1_AT_flage =1;//接收標(biāo)志位置一Usart1_Current_Cnt = Usart1_REC_Cnt;//拷貝接收的數(shù)據(jù)個(gè)數(shù)Usart1_REC_Cnt =0;//清零接收的數(shù)據(jù)個(gè)數(shù)}if(Usart3_TimeFlage ==1)//開始累加空閑變量{if(Usart3_IdealTime<400)//防止累加過去,造成循環(huán){
Usart3_IdealTime++;//空閑變量累加}
}if(Usart3_IdealTime>=100)//調(diào)節(jié)這個(gè)值以適應(yīng)不停的接收速率{
Usart3_TimeFlage=0;//停止空閑變量累加Usart3_IdealTime =0;//清零空閑累加變量Usart3_AT_flage =1;//接收標(biāo)志位置一Usart3_Current_Cnt = Usart3_REC_Cnt;//拷貝接收的數(shù)據(jù)個(gè)數(shù)Usart3_REC_Cnt =0;//清零接收的數(shù)據(jù)個(gè)數(shù)}
}
}
那么主循環(huán)里---具體的處理函數(shù),改為自己的就行
源碼,,這個(gè)是用的板子的空閑中斷,,,,板子的其余文件刪掉便可,,,,
鏈接:http://pan.baidu.com/s/1c228q6c密碼:pl3k