STM32F103串口简单化处理
用过串口的人,是不是觉得用串口时,都有种不是很爽的感觉,因为串口接受数据时,时间是不确定的,有可能随时都会发送过来,这样就必须要用到中断来读取数据,但是读取过来的数据长度也经常并不是确定的,使用DMA也不是很合适,那就要在每接受一个数据,进行一次处理,这样中断函数就变大,并且不能做到统一处理。
想想如果有这么一个串口,接受数据时,它自动接收,不用主线程来做任何干预,直到串口接收完整条贞(5ms间隔算一条贞)时,通知主线程此时接受到一条贞,主线程就可以一次性将整条数据贞读取出来,一次处理完整条贞,而不是像上面一样分散处理。(蓝牙、以太网...就是这样做的,它们是因为有很多层协议组成的,但是串口没有)
想想还是分享出来这个思路吧:
1、在跑裸机时代,我是这样处理的:串口接收到一个数据,将数据存入到缓存区,就开启一个定时器,又接到时,定时器重新定时,当这个定时器到了定时时间,也就是进入了中断程序,说明这个消息贞结束了。然后调用回调通知主线程接受完成一贞,主线程再去读串口缓存区。
问题:(1)消耗了硬件定时器
(2)调用回调函数的地方,就要放在中断函数里面,这样就会出现万一回调函数里面出现了很占时间的程序,就会导致中断时间占用过长(这个学过单片机的人都知道,这是不理想的)
2、现在使用ucos操作系统,可以开辟一个小线程,来单独处理串口接受事件:
先讲解一个小知识:等待信号量,可以设置为无限等待(只要不设置这个信号量,就会一直等待),也可以设置为超时等待(有个超时时间,如果超过了这个时间,还没有信号量,会跳过,如果超时时间内有信号量,也会跳过)。
串口初始化函数:
- USART_Init(); /* 串口各种初始化,配置接收中断模式 */
- ......
- OSSemCreate /* 创建信号量 */
- OSTaskCreate /* 创建小线程 */
复制代码
线程函数:
- while(1){
- /* 等待贞的第一个数据 */
- OSSemPend (&sem,0,OS_OPT_PEND_BLOCKING,&ts,&err); /* 等待信号量(无限等待,阻塞方式) */
- /* 有第一个数据后,就要开始判断整条贞的结尾,既5ms没有数据来*/
- while(1){
- OSSemPend (&__modrecive_sem,5,OS_OPT_PEND_BLOCKING,&ts,&err); /* 5ms 的延时等待 */
- if(OS_ERR_TIMEOUT == err){ /* 超时,既5ms内还没有信号 */
- Mb_recive_callback(); /* 调用回调函数,通知主线程数据接收完全 */
- break;
- }
- }
- }
串口接收中断函数:
- recive_buffer[recive_buffer_count++] = USART_ReceiveData(); /* 将接收到的数据存入缓存区 */
- OSSemPost (&__modrecive_sem, OS_OPT_POST_1, &err); /* 发送消息,既通知上面的线程的等待消息 */
至此,就如果我们将这个思路封装成一个库,也就是只要调用串口初始化函数,并且传入回调函数,我们就可以相当方便的使用串口了,不需要查询,不需要判断,不需要一直处理,只要在回调函数里面,将数据一次性提取出来,统一处理就OK了,这样是不是很爽呢?呵呵
可能有的人会这样想,就是ucos里面还有软件定时器,可以接收到一个数据,马上开启定时器,或者重新启动定时器,这样当定时时间到,就会调用回调函数通知主线程。这种想法是对的,但是开启定时器这个功能是要在中断函数里面开启,但是,ucos的开启定时器函数是不能在中断函数里面调用的。
|