STM32f103 串口接收不定长数据

发布者:huanxin最新更新时间:2021-11-02 来源: eefocus关键字:STM32f103  串口  不定长数据 手机看文章 扫描二维码
随时随地手机看文章

方法1:串口接受数据,定时器来判断超时是否接受数据完成。 


方法2:DMA接受+IDLE中断 


实现思路:采用STM32F103的串口1,并配置成空闲中断IDLE模式且使能DMA接收,并同时设置接收缓冲区和初始化DMA。那么初始化完成之后,当外部给单片机发送数据的时候,假设这帧数据长度是200个字节,那么在单片机接收到一个字节的时候并不会产生串口中断,而是DMA在后台把数据默默地搬运到你指定的缓冲区里面。当整帧数据发送完毕之后串口才会产生一次中断,此时可以利用DMA_GetCurrDataCounter();函数计算出本次的数据接受长度,从而进行数据处理。


应用对象:适用于各种串口相关的通信协议,如:MODBUS,PPI ;还有类似于GPS数据接收解析,串口WIFI的数据接收等,都是很好的应用对象。


关键代码分析:


void uart_init(u32 bound);

void MYDMA_Enable(DMA_Channel_TypeDef*DMA_CHx);

 

#endif

usart.C

//初始化IO 串口1 

//bound:波特率

void uart_init(u32 bound)

{

    //GPIO端口设置

    GPIO_InitTypeDef GPIO_InitStructure;

    USART_InitTypeDef USART_InitStructure;

    NVIC_InitTypeDef NVIC_InitStructure;

    DMA_InitTypeDef DMA_InitStructure;

 

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA,ENABLE); //使能          USART1,GPIOA时钟

    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); //使能DMA传输

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE);//使能USART2时钟

 

    USART_DeInit(USART1);  //复位串口1

    //USART1_TX   PA.9

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9

    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出

    GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化PA9

 

    //USART1_RX  PA.10

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入

    GPIO_Init(GPIOA, &GPIO_InitStructure);  //初始化PA10

 

    //Usart1 NVIC 配置

    NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;

    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//抢占优先级3

    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //子优先级3

    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能

    NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器

 

    //USART 初始化设置

    USART_InitStructure.USART_BaudRate = bound;

    USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式

    USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位

    USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位

    USART_InitStructure.USART_HardwareFlowControl =USART_HardwareFlowControl_None;//无硬件数据流控制

    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收发模式

 

    USART_Init(USART1, &USART_InitStructure); //初始化串口

    USART_ITConfig(USART1, USART_IT_IDLE, ENABLE);//开启空闲中断

    USART_DMACmd(USART1,USART_DMAReq_Rx,ENABLE);   //使能串口1 DMA接收

    USART_Cmd(USART1, ENABLE);                   //使能串口 

 

    //相应的DMA配置

    DMA_DeInit(DMA1_Channel5);   //将DMA的通道5寄存器重设为缺省值  串口1对应的是DMA通道5

    DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&USART1->DR; //DMA外设usart基地址

    DMA_InitStructure.DMA_MemoryBaseAddr = (u32)DMA_Rece_Buf;  //DMA内存基地址

    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;  //数据传输方向,从外设读取发送到内存

    DMA_InitStructure.DMA_BufferSize = DMA_Rec_Len;  //DMA通道的DMA缓存的大小

    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设地址寄存器不变

    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;  //内存地址寄存器递增

    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; //数据宽度为8位

    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; //数据宽度为8位

    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;  //工作在正常缓存模式

    DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; //DMA通道 x拥有中优先级 

    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;  //DMA通道x没有设置为内存到内存传输

    DMA_Init(DMA1_Channel5, &DMA_InitStructure);  //根据DMA_InitStruct中指定的参数初始化DMA的通道

 

    DMA_Cmd(DMA1_Channel5, ENABLE);  //正式驱动DMA传输

}

 

//重新恢复DMA指针

void MYDMA_Enable(DMA_Channel_TypeDef*DMA_CHx)

    DMA_Cmd(DMA_CHx, DISABLE );  //关闭USART1 TX DMA1所指示的通道    

    DMA_SetCurrDataCounter(DMA_CHx,DMA_Rec_Len);//DMA通道的DMA缓存的大小

    DMA_Cmd(DMA_CHx, ENABLE);  //打开USART1 TX DMA1所指示的通道  

}   

 

//发送len个字节

//buf:发送区首地址

//len:发送的字节数

void Usart1_Send(u8 *buf,u8 len)

{

    u8 t;

    for(t=0;t    {          

        while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);   

        USART_SendData(USART1,buf[t]);

    }    

    while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);     

}

 

//串口中断函数

void USART1_IRQHandler(void)                //串口1中断服务程序

{

 

     if(USART_GetITStatus(USART1, USART_IT_IDLE) != RESET) //接收中断(接收到的数据必须是0x0d 0x0a结尾)

      {

          USART_ReceiveData(USART1);//读取数据注意:这句必须要,否则不能够清除中断标志位。

          Usart1_Rec_Cnt =DMA_Rec_Len-DMA_GetCurrDataCounter(DMA1_Channel5); //算出接本帧数据长度

 

         //***********帧数据处理函数************//

          printf ("Thelenght:%drn",Usart1_Rec_Cnt);

          printf ("The data:rn");

          Usart1_Send(DMA_Rece_Buf,Usart1_Rec_Cnt);

         printf ("rnOver! rn");

        //*************************************//

         USART_ClearITPendingBit(USART1,USART_IT_IDLE);         //清除中断标志

         MYDMA_Enable(DMA1_Channel5);                  //恢复DMA指针,等待下一次的接收

     } 

 

}


方法3:实现思路:直接利用stm32的RXNE和IDLE中断进行接收不定字节数据。 


基本知识: 

IDLE中断什么时候发生? 

IDLE就是串口收到一帧数据后,发生的中断。什么是一帧数据呢?比如说给单片机一次发来1个字节,或者一次发来8个字节,这些一次发来的数据,就称为一帧数据,也可以叫做一包数据。 


如何判断一帧数据结束,就是我们今天讨论的问题。因为很多项目中都要用到这个,因为只有接收到一帧数据以后,你才可以判断这次收了几个字节和每个字节的内容是否符合协议要求。 


看了前面IDLE中断的定义,你就会明白了,一帧数据结束后,就会产生IDLE中断。


如何配置好IDLE中断? 


下面我们就配置好串口IDLE中断吧。 

 这里写图片描述 

这是串口CR1寄存器,其中,对bit4写1开启IDLE中断,对bit5写1开启接收数据中断。(注意:不同系列的STM32,对应的寄存器位可能不同)


RXNE中断和IDLE中断的区别? 

当接收到1个字节,就会产生RXNE中断,当接收到一帧数据,就会产生IDLE中断。比如给单片机一次性发送了8个字节,就会产生8次RXNE中断,1次IDLE中断。 

 这里写图片描述 

这是状态寄存器,当串口接收到数据时,bit5就会自动变成1,当接收完一帧数据后,bit4就会变成1. 


需要注意的是,在中断函数里面,需要把对应的位清0,否则会影响下一次数据的接收。比如RXNE接收数据中断,只要把接收到的一个字节读出来,就会清除这个中断。IDLE中断,如何是F0系列的单片机,需要用ICR寄存器来清除,如果是F1系列的单片机,清除方法是“先读SR寄存器,再读DR寄存器”。(我怎么知道?手册上写的)


下面以STM32F103为例给出源程序。 


我们先来看程序中的主要部分。 

串口初始化函数片段 


/****************************************************************************

* 名    称:void USART1_Configuration(void)

* 功    能:配置USART1参数

* 入口参数:

* 出口参数:无

* 说    明:

* 调用方法:无 

****************************************************************************/

void USART1_Configuration(void)

{

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;           //USART1 TX

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; 

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;    //复用推挽输出

GPIO_Init(GPIOA, &GPIO_InitStructure);     //A端口 

 

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;           //USART1 RX

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; 

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;    //复用开漏输入

GPIO_Init(GPIOA, &GPIO_InitStructure);           //A端口 

 

USART_InitStructure.USART_BaudRate = USART_BAUDRATE; //波特率250000bps

USART_InitStructure.USART_WordLength = USART_WordLength_8b; //数据位8位

USART_InitStructure.USART_StopBits = USART_StopBits_1; //停止位1位

USART_InitStructure.USART_Parity = USART_Parity_No; //无校验位

USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;    //无硬件流控

USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收发模式 

 

USART_Init(USART1, &USART_InitStructure); //配置串口参数函数    

 

USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);                  //使能接收中断

USART_ITConfig(USART1, USART_IT_IDLE, ENABLE); //空闲中断

 

USART_Cmd(USART1, ENABLE); //使能 USART1

}


 

串口中断函数 


void USART1_IRQHandler(void)      //串口1 中断服务程序

{

uint8_t Clear = 0;

/*如果接收到一字节数据*/

if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)     //判断读寄存器是否非空

{

USART_ClearITPendingBit(USART1, USART_IT_RXNE);         //清除中断标志

printf("#");                                            //接收到一字节数据

    /*如果接收到一帧数据*/

}else if(USART_GetITStatus(USART1,USART_IT_IDLE) != RESET){

Clear = USART1->SR;

Clear = USART1->DR;                                 //清除IDLE标志

printf("@");                                         //接收一帧数据

}

if(USART_GetITStatus(USART1, USART_IT_TXE) != RESET)        //这段是为了避免STM32 USART 第一个字节发不出去的BUG 

USART_ITConfig(USART1, USART_IT_TXE, DISABLE); //禁止发缓冲器空中断, 

}

}

 

串口中断函数里面,最重要的两条语句。第一条语句用来判断是否接收到1个字节,第二条语句用来判断是否接收到1帧数据。


主函数 就不要了 中断之后设置标志位进主函数判断就OK了  如下图 发送一帧数据  #意思是收到一字节  @意思是收到一帧数据 完全没问题

关键字:STM32f103  串口  不定长数据 引用地址:STM32f103 串口接收不定长数据

上一篇:STM32 f103 实现命令终端
下一篇:STM32 易阅读的代码风格

推荐阅读最新更新时间:2024-11-17 05:20

stm32f103+znfat+ch375+vs1003实现简单mp3播放器功能
以前做毕业设计买了VS1003语音解码芯片和CH375优盘模块,现在有时间想做一个mp3播放器出来。参照的znFAT例程&SD卡驱动(STM32F103)第9个例程、振南电子SD卡MP3播放器程序和正点原子的mp3播放器程序。可实现播放优盘或TF卡根目录的所有mp3文件,增加4个独立按键,实现下一曲、上一曲切换,音量+、音量-的功能。显示mp3信息没用显示屏,用的串口直接输出到串口调试助手上。能够显示mp3文件名称,总大小,歌曲码率,歌曲总时长,播放时间等信息。 打开mp3文件后,获取文件总大小,vs1003的缓冲区每次至少要发送32字节,用for循环每次取每簇4096字节送给vs1003解码。按键处理程序要在这个for循环里
[单片机]
<font color='red'>stm32f103</font>+znfat+ch375+vs1003实现简单mp3播放器功能
嵌入式Qt中实现串口读取的事件驱动方法
在嵌入式Linux系统的UI设计中,比较常见的是使用Qt库来实现。而在Qt中进行程序设计时,也经常会用到串口(UART)通信。现在基于Qt5.1以上的版本中,集成有串口模块(如QSerialPort),或者使用第三方开发的串口模块控件(如qextserialport等)。但无论采用哪种方式,在Linux系统下对于串口的数据接收都只能使用查询(Polling)的方式来实现,而在Windows系统下就可以使用效率较高的所谓事件驱动(EventDriven)方式。查询方式需要CPU反复对串口进行读取,看是否有发送来的可读数据,因此会消耗大量的CPU资源,一般的做法是把串口查询放到一个新建的线程中,以获得较高的效率。而对于事件方式则不同,
[单片机]
嵌入式Qt中实现<font color='red'>串口</font>读取的事件驱动方法
STM32串口USART通讯
1. USART和UART USART(Universal Synchronous Asynchronous Receiver and Transmitter)即通用同步异步收发器,它是一个串行通信设备,与外部设备可灵活进行全双工数据交换。在这之前我们常用到的是UART(Universal Asynchronous Receiver and Transmitter),它是在USART基础上裁剪掉了同步通信功能,只有异步通信。区分同步和异步最简单的方法就是看通信时需不需要对外提供时钟输出,我们平时使用的串口通信基本都是UART。关于串口通信其他基本概念,在上一篇文章http://blog.csdn.net/qq_29344757
[单片机]
STM32<font color='red'>串口</font>USART通讯
MC9S12XDP512串口使用笔记(中断方式)
1.相关寄存器: 1.SCIBDH,SCIBDL:波特率寄存器(SCIBDH只有低5位有效) 波特率 = 总线频率 / (16 * SBR ) 2. SCICR2: SCI控制寄存器2 TIE: 发送中断使能位。使能发送数据寄存器空标志(TDRE)来产生中断申请 TCIE: 发送完成中断使能位。使能发送完成标志(TC)来产生中断申请 RIE: 接收器满中断使能位 TE: 发送器使能位 RE: 接收器使能位 3.SCISR1: SCI状态寄存器1 TDRE: 发送数据寄存器空标志 TC: 发送完成标志 RDRF: 接收数据寄存器满标志 4.SCIDRL,(SCIDRH): SCI
[单片机]
MC9S12XDP512<font color='red'>串口</font>使用笔记(中断方式)
一种测量准确的体温数据采集装置的设计
1 引言 随着现代社会的蓬勃发展,科学技术水平的不断提高,医疗机构的现代化和信息化建设也是大势所趋。在医院传统体温测量中,水银温度计操作不便、使用费时,而且不能实现数据的自动检测、数据通信等。随着电子科学的迅猛发展,新型温度传感器的出现以及新型高性能单片机的不断推出,使得温度测量的自动检测和数据通信的实现成为了可能。 2 概述 生活中有一部分人处于“亚健康”状态。亚健康,按中医观点而论是身体已经出现了阴阳、气血、脏腑营卫的不平衡状态。按照西医的观点。这些不平衡状态表现为体温、体重、心率、血压、尿液成份等人体生理信号在一段时间里发生了不正常的变化。分析一段时间的信号变化数据,就可以对一个人的健康状态做出比较客观的判断。体温数据
[应用]
STM8 74hc164串口输出扩为并口输出子程序
软件设计 /********************************************************************* 目 的: 建立74hc164操作库 目标系统: 基于STM8单片机 应用软件: Cosmic CxSTM8 *********************************************************************/ #include stm8s207s8.h #define HC164_OUT_DATA sbi(PC_DDR,3);sbi(PC_CR1,3);sbi(PC_CR2,3); //PB6 数据口 #define HC16
[单片机]
PC/104标准四串口通信板设计
1 引言 PC/104嵌入式控制PC出现于80年代末,并于1992年形成IEEEP966.1标准,它既继承了所有的PC资源,又在结构、体积、功耗、可靠性等方面重新进行了设计,使之与IBM PC完全兼容,并具有了体积小、功耗低、工作温度范围宽、可靠性高等特点。PC/104嵌入式控制PC采用了独特的“自栈式”总线连接,模块化结构,使用起来灵活方便。它所采用的面向对象的硬件设计方法使得在PC/104标准上开发的扩展模块具有更强的通用性和更长的生命期。同台式PC机一样,PC/104嵌入式控制PC也提供两个RS-232串行口。串行通信端口在数据通信中一直扮演极重要的角色,它不仅没有因为时代的进步而被淘汰,反而在规格上愈来愈向其极限挑战。常
[单片机]
PC/104标准四<font color='red'>串口</font>通信板设计
stm32f103 c6t6 CAN总线的配置
KEIl5 环境下 中文显示复制过来有问题又懒得打字
[单片机]
<font color='red'>stm32f103</font> c6t6 CAN总线的配置

推荐帖子

关于MSP430f149的RS485通信,高手请进
下面是我编写的MSP430f149的485通信小程序,请各位大侠看看问题出在哪里?程序目的:想用串口精灵发送一个字节数据给单片机,然后单片机再将接受的数据回发给串口精灵。下面是错误的现象描述:1.C:\\Users\\panruifeng\\Desktop\\1.jpg串口精灵中,发送0x56,接收到的是0x002.C:\\Users\\panruifeng\\Desktop\\2.jpg仿真器显示收到的数据是0x56,是正确的3.下面是程序#includemsp430x14x.
451432837 微控制器 MCU
高性能数据采集系统增强数字X射线和MRI的图像
高性能数据采集系统增强数字X射线和MRI的图像数字X射线(DXR)、磁共振成像和其他医疗设备要求数据采集系统具备小型、高性能、低功耗等特性,以满足竞争市场上医生、病人和制造商的需求。本文展示一款高精度、低功耗信号链,可解决多通道应用(如数字X射线,需多路复用多通道的大信号和小信号测量)以及过采样应用(如MRI,要求低噪声、高动态范围和宽带宽)带来的挑战。高吞吐速率、低噪声、高线性度、低功耗以及小尺寸使18位、5MSPSPulSAR差分ADCAD7960成为这些高性能成像应用以及其他精
youluo ADI参考电路
linux开机后自动运行用户的应用程序
开机后自动运行用户的应用程序或启动系统服务的命令保存在开发板根文件系统的/usr/etc/rc.local文件中。有的开发板开机后自动运行图形界面程序,需要按住ctrl+c让开发板进入到linux的SHELL提示符界面。其实可通过注释掉rc.local文件中调用图形界面的命令,增加运行用户应用程序的命令,达到开机自动运行用户应用程序的目的。  下面以我做的实验为例,描述具体的实现步骤。该方法源于网络,我加以验证,稍做修改,此文相当于转载。  1.进入pc机的Linux操作系统,在
jxb01033016 Linux与安卓
家庭电子小制作
中文名称:家庭电子小制作版本:高清晰PDF图片电子图书发行时间:2004年地区:大陆语言:普通话编辑、剪辑:方大千基本信息·出版社:新时代出版社·ISBN:7504208876·条码:9787504208873·版次:1·装帧:平装--------------------------------------------------------------------------------内容简介:本书介绍的家庭电子小制作,适合于业余条件下制作。这些经精选的电子小装置具
yuandayuan6999 DIY/开源硬件专区
【藏书阁】普通示波器及数字示波器基础知识
【藏书阁】普通示波器及数字示波器基础知识好东西谢谢
wzt 测试/测量
CMOS集成电路设计手册(第3版)- 共3册
《CMOS集成电路设计手册》讨论了CMOS电路设计的工艺、设计流程、EDA工具手段以及数字、模拟集成电路设计,并给出了一些相关设计实例,内容介绍由浅入深。该著作涵盖了从模型到器件,从电路到系统的全面内容,是一本权威、综合的CMOS电路设计的工具书及参考书。《CMOS集成电路设计手册》英文原版书是作者近30年教学、科研经验的结晶,是CMOS集成电路设计领域的一本力作。《CMOS集成电路设计手册》已经过两次修订,目前为第3版,内容较第2版有了改进,补充了CMOS电路设计领域的一些新知识,使
arui1999 下载中心专版
小广播
设计资源 培训 开发板 精华推荐

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

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

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

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