有一次做一个东西,为了尽量不占用CPU的处理数据时间,所以就使用DMA接收串口的数据,但是呢问题来了.,,,,,怎么样才能确定接收到了一条完整的数据了,,我们都知道只要打开DMA
那家伙就不停的把接收的数据放到我们指定的地方.
只要接收到一条完整的数据我就该去处理了
关于空闲中断,,,就是说每接收到一条完整的数据就会置位空闲标志位,我们只需要判断空闲标志位是否置一,,就能知道是不是接收到了一条完整的数据
用空闲中断的好处就是,,对于以前我写程序通信都会在数据的后面加上尾,,然后另一个接收的单片机通过判断数据的尾来确定是不是一条完整的数据,,,有了空闲中断就不需要在给数据加上尾了,,,,,
直接程序吧
u8 Usart1_RX_Cop[]={}; //串口2备用接收缓冲,最大 1024 个字节. u8 Usart1_RX_BUF[]={}; //串口1接收缓冲,最大 1024 个字节. u16 Usart1_REC_Cnt = ; //串口1接收的数据个数 u16 Usart1_Current_Cnt = ; //串口1当前接收的数据个数 u16 Usart1_Current_cnt = ; //串口1当前接收的数据个数 u8 Usart1_AT_flage = ; //串口1接收完成标志位 u8 Usart2_RX_Cop[]={}; //串口2备用接收缓冲,最大 1024 个字节. u8 Usart2_RX_BUF[]={}; //串口2接收缓冲,最大 1024 个字节. u16 Usart2_REC_Cnt = ; //串口2接收的数据个数 u16 Usart2_Current_Cnt = ; //串口2当前接收的数据个数 u16 Usart2_Current_cnt = ; //串口2当前接收的数据个数 u8 Usart2_AT_flage = ; //串口2接收完成标志位 u8 Usart3_RX_BUF[]={}; //串口3接收缓冲,最大 1024 个字节. u16 Usart3_REC_Cnt = ; //串口3接收的数据个数 u8 Usart3_AT_flage = ; //串口3接收完成标志位 u8 Free_Read_Rst = ;//读DR清除空闲中断
void USART123_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时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB|RCC_APB2Periph_USART1|RCC_APB2Periph_AFIO , ENABLE); //USART1_TX PA9 GPIO_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 PA10 GPIO_InitStructure.GPIO_Mode =GPIO_Mode_IN_FLOATING ; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; GPIO_Init(GPIOA, &GPIO_InitStructure); //USART2_TX GPIOA.2 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; //PA.2 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出 GPIO_Init(GPIOA, &GPIO_InitStructure); //USART2_RX GPIOA.3初始化 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;//PA3 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入 GPIO_Init(GPIOA, &GPIO_InitStructure); //USART3_TX GPIOB.10 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; //PB10 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出 GPIO_Init(GPIOB, &GPIO_InitStructure); //USART3_RX GPIOB.11初始化 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;//PB11 GPIO_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 中断服务程序**********************/ void USART1_IRQHandler(void) { if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //正常情况下进入这个接收 { USART_ClearITPendingBit(USART1, USART_FLAG_ORE); USART_ClearITPendingBit(USART1,USART_IT_ORE); //清除中断标志 Usart1_RX_BUF[Usart1_REC_Cnt] =USART_ReceiveData(USART1); //读取接收到的数据 Usart1_REC_Cnt++; } else if(USART_GetITStatus(USART1,USART_IT_IDLE) == SET)//传输完一条完整的数据就会进入这个 { Free_Read_Rst = USART1->DR; //清USART_IT_IDLE标志 Usart1_AT_flage = ;//接收到一条完整的数据 Usart1_Current_Cnt = Usart1_REC_Cnt;//复制接收到的数据个数 Usart1_REC_Cnt = ;//清零接收的个数 } }
主函数循环里只需要......
先说一点:单片机的串口可以接收任意波特率的数据,你所写的9600意思是以这个波特率发送....
其实昨天才发现这家伙真的太准确了,,准确到如果碰见通信中速率如果不是设置的波特率,就是说通信的速率慢了不是(我上面设置的波特率是9600)1/9600(S)发过来一位数据了,低于了这个值假设是2400吧!接受到一位数据后如果1/9600(s)后没有接收到数据,那么这家伙也会进空闲中断.......因为你是设置的9600,,,,那么在1/9600(s)后理应接收到下一位数据....而其实是在1/2400(S)后才会接收到另一位数据.....如果能把空闲中断的检测时间降到满足的要求就好了....
所以嘛,,,,,自己写个别这么苛刻的,昨天写好了,不过呢今天主要是把自己遇到的问题说一下
其实思路都知道
串口接收的时候打开一个定时器,并且只要接收到数据就清零一个变量,这个变量是在定时器里面执行自加一操作,,
如果串口一段时间(空闲中断的检测时间)不接收数据了这个变量就能自加到我们设置的数,然后关掉定时器,置位接收完成标志位,...
直接上程序
/********************串口 1 中断服务程序**********************/ void USART1_IRQHandler(void) { if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) { USART_ClearITPendingBit(USART1, USART_FLAG_ORE); USART_ClearITPendingBit(USART1,USART_IT_ORE); //清除中断标志 Usart1_RX_BUF[Usart1_REC_Cnt] =USART_ReceiveData(USART1); //读取接收到的数据 Usart1_REC_Cnt++; TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE );//打开定时器开始计时 Time2_cnt = ;//清零计数 }
}
void timer_config(void) { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); /* Resets the TIM2 */ TIM_DeInit(TIM2); //设置了时钟分割。 TIM_TimeBaseStructure.TIM_ClockDivision = ; // 选择了计数器模式。 TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //初值 TIM_TimeBaseStructure.TIM_Period = ;//定时时间1ms进一次 //设置了用来作为 TIMx 时钟频率除数的预分频值。72M / 7099+1 = 0.01M TIM_TimeBaseStructure.TIM_Prescaler = ; //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 ); }
void TIM2_IRQHandler(void) { if(TIM_GetITStatus(TIM2, TIM_IT_Update) == SET) { TIM_ClearITPendingBit(TIM2, TIM_IT_Update); )//防止累加循环过去 { Time2_cnt ++ ; } )//空闲时间大于约3毫秒 { TIM_ITConfig(TIM2, TIM_IT_Update, DISABLE );//关闭定时器---注意千万不要放到主函数里面关,,,,大家可以试一试会出现什么问题..... Usart1_AT_flage = ;//接收完成标志位置一 Usart1_Current_Cnt = Usart1_REC_Cnt;//赋值接收的数据个数 Usart1_REC_Cnt = ;//清零接收的数据个数 }
}
然后昨天又写了一个两个串口的,因为用了两个串口做数据转换(用的串口1和串口3),,,,其实其中一个也可以用空闲中断,,但是担心数据传输过程中万一速率有所变化,,,,,,,,完蛋啦
uint8_t Usart1_TimeFlage = ;//串口1空闲变量允许累加标志 uint16_t Usart1_IdealTime = ;//串口1空闲累加变量 uint8_t Usart3_TimeFlage = ;//串口3空闲变量允许累加标志 uint16_t Usart3_IdealTime = ;//串口3空闲累加变量 u8 Usart1_RX_Cop[]={}; //串口2备用接收缓冲,最大 1024 个字节. u8 Usart1_RX_BUF[]={}; //串口1接收缓冲,最大 1024 个字节. u16 Usart1_REC_Cnt = ; //串口1接收的数据个数 u16 Usart1_Current_Cnt = ; //串口2当前接收的数据个数 u16 Usart1_Current_cnt = ; //串口2当前接收的数据个数 u8 Usart1_AT_flage = ; //串口1接收完成标志位 u8 Usart2_RX_Cop[]={}; //串口2备用接收缓冲,最大 1024 个字节. u8 Usart2_RX_BUF[]={}; //串口2接收缓冲,最大 1024 个字节. u16 Usart2_REC_Cnt = ; //串口2接收的数据个数 u16 Usart2_Current_Cnt = ; //串口2当前接收的数据个数 u16 Usart2_Current_cnt = ; //串口2当前接收的数据个数 u8 Usart2_AT_flage = ; //串口2接收完成标志位 u8 Usart3_RX_Cop[]={}; //串口2备用接收缓冲,最大 1024 个字节. u8 Usart3_RX_BUF[]={}; //串口2接收缓冲,最大 1024 个字节. u16 Usart3_REC_Cnt = ; //串口2接收的数据个数 u16 Usart3_Current_Cnt = ; //串口2当前接收的数据个数 u16 Usart3_Current_cnt = ; //串口2当前接收的数据个数 u8 Usart3_AT_flage = ; //串口2接收完成标志位
void timer3_config(void) { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); /* Resets the TIM2 */ TIM_DeInit(TIM3); //设置了时钟分割。 TIM_TimeBaseStructure.TIM_ClockDivision = ; // 选择了计数器模式。 TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //初值 TIM_TimeBaseStructure.TIM_Period = ;//定时时间1Ms进一次 //设置了用来作为 TIMx 时钟频率除数的预分频值。72M / 7099+1 = 0.01M TIM_TimeBaseStructure.TIM_Prescaler = ; //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 ); }
void TIM3_IRQHandler(void) { if(TIM_GetITStatus(TIM3, TIM_IT_Update) == SET) { TIM_ClearITPendingBit(TIM3, TIM_IT_Update); )//开始累加空闲变量 { )//防止累加过去,造成循环 { Usart1_IdealTime++;//空闲变量累加 } } )//调节这个值以适应不同的接收速率 { Usart1_TimeFlage = ;//停止空闲变量累加 Usart1_IdealTime = ;//清零空闲累加变量 Usart1_AT_flage = ; //接收标志位置一 Usart1_Current_Cnt = Usart1_REC_Cnt;//拷贝接收的数据个数 Usart1_REC_Cnt =;//清零接收的数据个数 } )//开始累加空闲变量 { )//防止累加过去,造成循环 { Usart3_IdealTime++;//空闲变量累加 } } )//调节这个值以适应不停的接收速率 { Usart3_TimeFlage = ;//停止空闲变量累加 Usart3_IdealTime = ;//清零空闲累加变量 Usart3_AT_flage = ; //接收标志位置一 Usart3_Current_Cnt = Usart3_REC_Cnt;//拷贝接收的数据个数 Usart3_REC_Cnt =;//清零接收的数据个数 } } }
那么主循环里---具体的处理函数,改为自己的就行
源码,,这个是用的板子的空闲中断,,,,板子的其余文件删掉便可,,,,
链接:http://pan.baidu.com/s/1c228q6c 密码:pl3k