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

缺点:有些情况下会导致数据丢失(可能返回数据中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 < 255u) { OSIntNesting++; /* Increment ISR nesting level */ } } } 这个函数的作用是对全局变量OSIntNesting增1,OSIntNesting为中断嵌套深度。 void OSIntExit (void) { #if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */ OS_CPU_SR cpu_sr = 0u; #endif if (OSRunning == OS_TRUE) { OS_ENTER_CRITICAL(); 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 > 0u OSTCBHighRdy->OSTCBCtxSwCtr++; /* Inc. # of context switches to this task */ #endif OSCtxSwCtr++; /* 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位中。

审核编辑:汤梓红

免责声明:文章内容来自互联网,本站不对其真实性负责,也不承担任何法律责任,如有侵权等情况,请与本站联系删除。
转载请注明出处:STM32串口接收不定长数据:采用标志位(比如0X0D,0X0A)结束法-stm32串口发送不定长数据 https://www.yhzz.com.cn/a/7374.html

上一篇 2023-04-17
下一篇 2023-04-17

相关推荐

联系云恒

在线留言: 我要留言
客服热线:400-600-0310
工作时间:周一至周六,08:30-17:30,节假日休息。