0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

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

RXL111 来源:RXL111 作者:RXL111 2022-09-23 14:06 次阅读

缺点:有些情况下会导致数据丢失(可能返回数据中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
    +关注

    关注

    2265

    文章

    10870

    浏览量

    354682
  • 串口
    +关注

    关注

    14

    文章

    1543

    浏览量

    76156
收藏 人收藏

    评论

    相关推荐

    Labview读取二进制文件(有的时候会自动添加0X0D0x0A前面)

    我是利用Labview开发TCP/IP通信的,需要把接收的网络数据保存为二进制文件。用UltraEdit查看保存的文件里面有好多二进制值,0x00~0xFF,里面会有
    发表于 05-02 14:48

    stm32串口怎么用DMA接收不定长数据?

    stm32串口怎么用DMA接收不定长数据,求大神点播1. 网上查到,空闲中断+DMA可以接收
    发表于 08-21 09:21

    串口接收0x0a0x0d表示的什么?

    void USART1_IRQHandler(void){ u8 res; if(USART1->SR&(163)USART_RX_STA=0;//接收数据错误,重新开始接收 }}}
    发表于 08-19 03:09

    stm32识别TC35短信有两个“0x0d 0x0a”怎么解决?

    原子哥的串口代码里,遇到0x0d 0x0a就停止接收,但是从TC35模块读取短信时,前面的短信息说明,会有两个“0x0d
    发表于 08-28 08:00

    Labview串口时候数据中的0x0A与换行符冲突怎么解决?

    串口数据传输时候,含有0x0A与换行符冲突,如果关闭终止符,那样就无法识别串口数据结束,无法识别
    发表于 12-06 21:33

    STM32串口接收不定长数据原理是什么

    STM32串口接收不定长数据原理是什么
    发表于 12-08 07:29

    STM32串口接收不定长数据的实现方法

    STM32串口接收不定长数据的实现方法
    发表于 12-09 06:17

    针对接收一帧含有多个字节的不定长数据接收方式进行讨论

    (比如0X0D,0X0A)结束 非常常见的一种接收方式,正点原子的例程便是
    发表于 12-09 07:16

    如何利用STM32串口去解析json命令呢

    STM32串口解析json命令(使用HAL库)串口接收中断处理(0x0D 0x0A作为结尾)测试
    发表于 01-21 10:07

    STM32串口接收不定长数据的程序免费下载

    本文档的主要内容详细介绍的是STM32串口接收不定长数据的程序免费下载。
    发表于 08-26 08:00 62次下载
    <b class='flag-5'>STM32</b><b class='flag-5'>串口</b><b class='flag-5'>接收</b><b class='flag-5'>不定长</b><b class='flag-5'>数据</b>的程序免费下载

    STM32串口通信 (采用链表接收不定长数据帧)

    STM32串口接收不定长数据帧->链表数据帧说明二级目录三级目录
    发表于 11-23 18:07 30次下载
    <b class='flag-5'>STM32</b><b class='flag-5'>串口</b>通信 (<b class='flag-5'>采用</b>链表<b class='flag-5'>接收</b><b class='flag-5'>不定长</b><b class='flag-5'>数据</b>帧)

    STM32串口接收不定长数据的几种方法

    (比如0X0D,0X0A)结束 非常常见的一种接收方式,正点原子的例程便是
    发表于 11-26 13:21 17次下载
    <b class='flag-5'>STM32</b><b class='flag-5'>串口</b><b class='flag-5'>接收</b><b class='flag-5'>不定长</b><b class='flag-5'>数据</b>的几种方法

    stm32 串口接收不定长度数据及黏包处理 + 串口DMA接收

    ,那么stm32串口是如何实现接收不定长度数据的呢? 串口接收
    发表于 12-23 19:09 27次下载
    <b class='flag-5'>stm32</b> <b class='flag-5'>串口</b><b class='flag-5'>接收</b><b class='flag-5'>不定长度数据</b>及黏包处理 + <b class='flag-5'>串口</b>DMA<b class='flag-5'>接收</b>

    STM32 DMA串口接收不定长数据

    STM32 DMA串口接收不定长数据
    发表于 12-24 18:50 40次下载
    <b class='flag-5'>STM32</b>  DMA<b class='flag-5'>串口</b><b class='flag-5'>接收</b><b class='flag-5'>不定长</b><b class='flag-5'>数据</b>

    RM0451_超低功耗 STM32L0x0 先进的基于 Arm® 的 32 MCU

    RM0451_超低功耗 STM32L0x0 先进的基于 Arm® 的 32 MCU
    发表于 11-23 08:20 1次下载
    RM0451_超低功耗 <b class='flag-5'>STM32L0x0</b> 先进的基于 Arm® 的 32 <b class='flag-5'>位</b> MCU