STM32串口接收不定长数据:采用标志位(比如0X0D,0X0A)结束法

缺点:有些情况下会导致数据丢失(可能返回数据中0x0d、0a本身为有效数据)
适用:约定协议的数据帧(发送数据的设备必须以相应的约定字节作为一次数据结束)
void usart1_irqhandler(void) //串口中断服务程序(函数) { u8 res; //定义res,用于res =usart_receivedata(usart1);中存储串口1发送的数据(这里的数据按位发送)#if system_support_os //如果system_support_os为真,则需要支持os osintenter(); #endif if(usart_getitstatus(usart1, usart_it_rxne) != reset) //接收中断(接收到的数据必须是0x0d 0x0a结尾) { res =usart_receivedata(usart1); //读取接收到的数据 if((usart_rx_sta&0x8000)==0)//接收未完成 1000 0000 0000 0000//判断usart_rx_sta的第一位是否为0,这时因为usart_rx_sta的初始值为0,所以我们进入if(usart_rx_sta&0x4000)。 { if(usart_rx_sta&0x4000)//接收到了0x0d 0100 0000 0000 0000//判断usart_rx_sta的第二位是否为1,所以我们进入else //还没收到0x0d。 { if(res!=0x0a)usart_rx_sta=0;//接收错误,重新开始 else usart_rx_sta|=0x8000; //接收完成了 } else //还没收到0x0d { if(res==0x0d)usart_rx_sta|=0x4000;//再次判断这次接收到的是不是0x0d,判断了res是否0x0d, 即res是否为回车,这里如果串口有输入数据的话明显可以判断的,所以我们进入下面的else. else { usart_rx_buf[usart_rx_sta&0x3fff]=res ; // 0011 1111 1111 1111 usart_rx_sta++; if(usart_rx_sta>(usart_rec_len-1))usart_rx_sta=0;//接收数据错误,重新开始接收 } } } } #if system_support_os osintexit(); #endif} osintenter()和osintexit()两者必须成对出现。
进入中断时调用osintenter(),退出中断时调用osintexit()。
osintenter 是进⼊中断服务函数,⽤来记录中断嵌套层数(osintnesting增加 1);
osintenter()应该在中断关闭后调用,所以函数里面没有使用os_enter_critical() and os_exit_critical(),如此在调用osintenter()前需关闭中断。
osintexit():所有中断结束后进行任务调度,使系统更加实时。
osintexit 是退出中断服务函数,该函数可能触发⼀次任务切换(当 osintnesting==0&&调度器未上锁&&就绪表最⾼优先级任务 != 被中断的任务优先级时),否则继续返回原来的任务执⾏代码(如果 osintnesting 不为 0,则减 1)。
os_sched():ucos进行任务调度,不在中断调用。
osintnesting:统计中断嵌套数,最多255。在osintexit()和os_sched()中都有判别。
os_enter_critical():保存中断状态,关中断。ucos将无法再执行任务调度,硬件中断也被屏蔽。
void osintenter (void){if (osrunning == os_true) {if (osintnesting 0u) { /* prevent osintnesting from wrapping */osintnesting--;}if (osintnesting == 0u) { /* reschedule only if all isrs complete ... */if (oslocknesting == 0u) { /* ... and not locked. */os_schednew();ostcbhighrdy = ostcbpriotbl[ospriohighrdy];if (ospriohighrdy != ospriocur) { /* no ctx sw if current task is highest rdy */#if os_task_profile_en > 0uostcbhighrdy->ostcbctxswctr++; /* inc. # of context switches to this task */#endifosctxswctr++; /* keep track of the number of ctx switches */osintctxsw(); /* perform interrupt level ctx switch */}}}os_exit_critical();}}函数的前面部分对osintnesting减1,刚好与osintenter() 相对应;后面部分则进行任务调度。 总结:任何中断服务函数,我们都应该加上 osintenter 和 osintexit 函数,ucosii 是⼀个可剥夺型的内核,中断服务⼦程序运⾏之后,系统会根据情况进⾏⼀次任务调度去运⾏优先级别最⾼的就绪任务,⽽并不⼀定接着运⾏被中断的任务!
#if...#endif是c++中的条件编译预处理命令 有两种格式:
1:#ifdef  标示符      
 程序段1      
#else        
 程序段2    
#endif
表示:如果标示符已经被#define命令定义过,则编译程序段1,否则编译程序段2。期中else部分可以没有。
2:#if 表达式      
  程序段1    
#else        
 程序段2    
#endif
表示:如果表达式为真,则编译程序段1,否则编译程序段2.
if((usart_rx_sta&0x8000)==0)  //0x8000,即二进制1000 0000 0000 0000,与变量usart_rx_sta,按位与(&),并与0比较,作用是判断usart_rx_sta数值第16位是否为0。
usart_rx_sta&0x8000有两种可能:
第一种1××× ×××× ×××× ××××&1000 0000 0000 0000=1000 0000 0000 0000
第二种0××× ×××× ×××× ××××&1000 0000 0000 0000=0000 0000 0000 0000
由此可以判断usart_rx_sta第16位是否为0
usart_rx_sta的作用,usart_rx_sta一共有16位,前两位为标记位,后14位记录了串口发送的数的位数。第一位标记位标记了res是否为0x0a,第二位标记位标记了res是否为0x0d。
知识点:0x0d是回车的ascll码,0x0a是换行的ascll码
usart_rx_buf这个是用来保存接收到的数据的可以看到每次结束判断会有
usart_rx_buf[usart_rx_sta&0x3fff]=res ;
usart_rx_sta=0; //接收状态标记
 usart_rx_sta的作用就是在全部函数之间实现一个消息传递,自己设置,自己管理,自己识别。
bit15     bit14    bit13~0
接收完成标志0x0a 接收到0x0d标志 接收到的有效数据个数
usart_rx_sta|=0x4000;将第二位状态标志位置为1;在倒数第1次循环中使用usart_rx_sta|=0x8000;将第一位状态标志位也置为1,;而后串口数据接收结束,所有从串口接收的数据保存在usart_rx_buf[ ]数组中,串口所发送的数据长度保存在usart_rx_sta的后14位中。


什么是六参数空气自动站
为什么SMT贴片加工应用广泛,它的优势是什么
人工智能的概念是什么
PLC网段转换器(IP耦合器)是什么?有什么功能?
技术微课堂丨科普篇:电力电子无处不在
STM32串口接收不定长数据:采用标志位(比如0X0D,0X0A)结束法
国外研发出可穿戴电子皮肤 能实时反映身体器官健康状况
超能健康服务机器人:智慧养老新选择,“读懂”老人的真实需求
英特尔将人工智能嵌入英特尔IT 创造超过10亿美元的业务价值
选用玻璃转子流量计时需要注意什么
iPhone 8这些新功能已确定 想想都激动!
创维发布两款全新产品,电视功能转型成为智慧家电
GE 荣获两项海上风电研发奖项 空客实现2021年商用飞机交付目标
华为P30系列国外售价曝光,新U麒麟985或在研发
viss透明屏,在商业广告中,广告展示效果有什么不同?
鸿蒙内核源码之线程环境下的任务切换
从硬件和软件入手的UPS抗干扰技术
并联有源电力滤波器交流侧滤波电感的优化设计
功率MOSFET零电压软开关ZVS的基础认识
ARM Cortex-M3 处理器的主要特性分析