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

发布者:AngelicGrace最新更新时间:2024-06-14 来源: elecfans关键字: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  串口接收  不定长数据  标志位 引用地址:STM32串口接收不定长数据:采用标志位(比如0X0D,0X0A)结束法

上一篇:STM32CUBEMX(13)--SPI,W25Q128外部Flash移植
下一篇:总结STM32控制中常见的PID算法 理解万能的PID算法

推荐阅读最新更新时间:2024-11-16 19:56

DSP进行浮点快速傅立叶变换剖析
前言 本文目的是演示如何使用STM32F30x 内部的DSP 进行浮点快速傅立叶变换(FFT),为联系实际应用,使用ADC 对波形发生器进行ADC 采样,然后对ADC 采样结果进行FFT, 与 Matlab 仿真结果进行比较察看最终结果的准确性。会使用到ARMDSP 库文件,以及STM32F30x 的浮点运算单元以及DSP指令等。 模拟ADC采样数据实现FFT 使用Matlab生成AM调制波形 波形公式为:AM_50= sin(2πfc)*(1+50%*sin(2πfm)), 其中fc 为载波频率,fm 为调制波频率,调制比50%。为了使用ADC 采样,将波形进行偏移处理,叠加1.5V 电压,最终波形展开公式如下: AM_50
[单片机]
DSP进行浮点快速傅立叶变换剖析
STM32的IIC应用详解3
这两天将STM32的IIC按照原子哥的程序,大致走了一遍,多少对IIC不是那么地陌生了,也多少有了自己的一些感悟,在这里,将这两天的学习的一个大致步骤总结下,一来可以让自己形成一个清晰地思路,二来,希望能给一些新手一点启发。 首先IIC是一种通信协议,通信方式相对比较简单,主要有两条线,SDA,SCL。SDA是串行数据线,上面走命令和数据,而SCL只是一条时钟线,其保证数据是按照时钟节拍来进行传输。IIC上面可以外挂很多的IIC芯片,每一个芯片对应着不同的地址,通过地址来将不同的芯片进行分开,保证不同芯片之间的数据传输,由于每一个芯片都是可以独立地收发,故,每一个芯片都是主机/从机。接下来,就是数据的传输过程了, 大致的一个数
[单片机]
<font color='red'>STM32</font>的IIC应用详解3
STM32输入捕获实验示例详解
STM32输入捕获实验 寄存器部分讲解(以TIM5_CH1为例) TIMx_CCMR1.ICF 的作用 滤波器的作用就是“采集取样以便于确定准确的电平状态”。我们以ICIF = 0010为例: 实例应用:假设输入信号在最多5个内部时钟周期的时间内抖动,我们须配置滤波器的带宽长于5个时钟周期。因此我们可以(以fDTS频率)连续采样8次,以确认在TI1上一次真实的边沿变换,即在TIMx_CCMR1寄存器中写入IC1F=0011。 TIMx_CCER.CC1P的作用 这个寄存器很重要,它决定了“上升沿/下降沿触发输入捕获 “,而且最重要的是,它是用来配置极性的唯一寄存器,这说明输入极性与输出极性都要经过它进行配置,因此
[单片机]
<font color='red'>STM32</font>输入捕获实验示例详解
STM32外部中断大问题
问题:一直进入中断,没有触发信号,也一直进入。 描述:开PA0为外部中断,刚刚很好,一个触发信号一个中断,中断函数没有丢,也没有抢跑,开PA1为外部中断也是,都很好,只要能开到3个外部中断以上,就会出现这种情况,明明没有触发外部中断,可是中断服务函数还是不断的++。 问题一:电气噪声和抖动 电气噪声和抖动是常见的问题,可能会导致STM32的外部中断不断触发,即使没有明显的触发信号。以下是一些处理电气噪声和抖动的方法: 1.添加电容滤波器:在外部中断引脚上添加适当大小的电容,以平滑信号并抑制高频噪声。电容的值应根据信号频率和噪声特性进行选择。 2.使用滤波器电路:在外部信号引脚前添加滤波器电路,如低通滤波器,以滤除高频噪
[单片机]
STM32的USART发送数据时如何使用TXE和TC标志
在USART的发送端有2个寄存器,一个是程序可以看到的USART_DR寄存器(下图中阴影部分的TDR),另一个是程序看不到的移位寄存器(下图中阴影部分Transmit Shift Register)。 对应USART数据发送有两个标志,一个是TXE=发送数据寄存器空,另一个是TC=发送结束;对照下图,当TDR中的数据传送到移位寄存器后,TXE被设置,此时移位寄存器开始向TX信号线按位传输数据,但因为TDR已经变空,程序可以把下一个要发送的字节(操作USART_DR)写入TDR中,而不必等到移位寄存器中所有位发送结束,所有位发送结束时(送出停止位后)硬件会设置TC标志。 另一方面,在刚刚初始化好USART还没有发送任何数据时,也会
[单片机]
<font color='red'>STM32</font>的USART发送<font color='red'>数据</font>时如何使用TXE和TC<font color='red'>标志</font>
stm32之GPIO_Remap_SWJ_Disable之后无法使用swd下载
说明:库文件版本:3.5.0 软件环境:iar for arm 在系统复位的时候默认是开启JTAG与swd的, 在点击下载后的2秒内按下复位键即可将程序下载进stm32 注意:在程序里边加入GPIO_PinRemapConfig(GPIO_Remap_SWJ_NoJTRST,ENABLE); 来彻底解除限制,或用写寄存器的方式,SWG_CFG 写入000
[单片机]
STM32学习笔记之RTC实时时钟2
5. 程序实现 5.1 初始化 u8 RTC_Init(void){ u8 temp=0; RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE); //使能PWR和BKP外设时钟 PWR_BackupAccessCmd(ENABLE); //使能后备寄存器访问 if (BKP_ReadBackupRegister(BKP_DR1) != 0x5050) //从指定的后备寄存器中读出数据:读出了与写入的指定数据不相乎 { BKP_DeInit(); //复位备份区域
[单片机]
<font color='red'>STM32</font>学习笔记之RTC实时时钟2
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved