精华内容
下载资源
问答
  • STM32】5分钟了解STM32串口通信

    万次阅读 多人点赞 2020-08-21 10:18:28
    串口通信(Serial Communications)的概念非常简单,串口按位(bit)发送和接收字节的通信方式。文章主要是串口通信简介和STM32串口通信

    Author:AXYZdong 自动化专业 工科男
    有一点思考,有一点想法,有一点理性!
    定个小小目标,努力成为习惯!在最美的年华遇见更好的自己!
    CSDN@AXYZdong,CSDN首发,AXYZdong原创
    唯一博客更新的地址为: 👉 AXYZdong的博客 👈

    在这里插入图片描述


    一、串口通信简介


    1.1 百度百科解释

    • 来源百度百科


    串行接口是一种可以将接收来自CPU的并行数据字符转换为连续的串行数据流发送出去,同时可将接收的串行数据流转换为并行的数据字符供给CPU的器件。一般完成这种功能的电路,我们称为串行接口电路。

    串口通信(Serial Communications)的概念非常简单,串口按位(bit)发送和接收字节的通信方式。

    1.2 通信接口

    种类特点
    并行通信数据各个位同时传输,速度快,但占用资源多
    串行通信数据按位的顺序传输,速度慢,但占用资源少

    1.3 串口通信分类

    通信方式特点
    单工在任何时刻都只能进行一个方向的通讯,即一个固定为发送设备,另一个 固定为接收设备
    半双工两个设备之间可以收发数据,但不能在同一时刻进行
    全双工在同一时刻,两个设备之间可以同时收发数据

    在这里插入图片描述

    ▲ 全双工、半双工和单工


    1.4 STM32串行通信的通信方式


    通信标准引脚说明 通信方式通信方向
    UART
    (通用异步收发器)
    TXD:发送端
    RXD:接收端
    GND:公共地
    异步通信全双工
    单总线DQ:发送/接收端异步通信半双工
    SPISCK:同步时钟
    MISO:主机输入,从机输出
    MOSI:主机输出,从机输入
    同步通信全双工
    半双工
    I2CSCL:同步时钟
    SDA:数据输入/输出端
    同步通信

    插播一条反爬虫信息,读者可以忽略:


    在这里插入图片描述

    二、STM32的串口通信


    在这里插入图片描述

    ▲ USART 功能框图


    2.1 功能引脚

    TX: 发送数据输出引脚。

    RX: 接收数据输入引脚。

    SW_RX: 数据接收引脚,只用于单线和智能卡模式,属于内部引脚,没有具体外部引 脚。

    nRTS: 请求以发送(Request To Send),n表示低电平有效。如果使能 RTS流控制,当 USART 接收器准备好接收新数据时就会将 nRTS变成低电平;当接收寄存器已满时, nRTS将被设置为高电平。该引脚只适用于硬件流控制。

    nCTS: 清除以发送(Clear To Send),n 表示低电平有效。如果使能 CTS流控制,发送 器在发送下一帧数据之前会检测 nCTS引脚,如果为低电平,表示可以发送数据,如果为 高电平则在发送完当前数据帧之后停止发送。该引脚只适用于硬件流控制。 SCLK:发送器时钟输出引脚。这个引脚仅适用于同步模式。


    2.2 数据寄存器

    USART 数据寄存器(USART_DR)只有低 9位有效

    USART 控制寄存器 1(USART_CR1)
    M 位
    字长
    08位数据字长
    19位数据字长

    一般使用 8位数据字长。

    USART_DR 包含了已发送的数据或者接收到的数据。

    USART_DR功能
    可写 TDR用于发送,当进行发送操作时,往 USART_DR 写入数据会自动存储在 TDR 内
    可读 RDR用于接收,当进行读取操作时,向 USART_DR 读取数据会自动提取 RDR 数据

    TDR 和 RDR 都是介于系统总线和移位寄存器之间。串行通信是一个位一个位传输的, 发送时把 TDR内容转移到发送移位寄存器,然后把移位寄存器数据每一位发送出去,接收时把接收到的每一位顺序保存在接收移位寄存器内然后才转移到 RDR。


    2.3 控制器

    USART 有专门控制发送的发送器、控制接收的接收器,还有唤醒单元、中断控制等等。 使用 USART 之前需要向 USART_CR1寄存器的 UE 位置 1 使能 USART。发送或者接收数据字长可选 8位或 9位,由 USART_CR1的 M 位控制。


    2.4 小数波特率生成

    波特率指数据信号对载波的调制速率,它用单位时间内载波调制状态改变次数来表示, 单位为波特

    比特率指单位时间内传输的比特数,单位 bit/s(bps)。

    对于 USART 波特率与 比特率相等,以后不区分这两个概念。波特率越大,传输速率越快。 USART 的发送器和接收器使用相同的波特率。计算公式如下:


    波 特 率 = f P L C K 8 ⋅ ( 2 − O V E R 8 ) ⋅ U S A R T D I V 波特率=\frac{f_{PLCK}}{8\cdot(2-OVER8)\cdot USARTDIV} =8(2OVER8)USARTDIVfPLCK


    参数含义
    f P L C K f_{PLCK} fPLCKUSART 时钟
    O V E R 8 OVER8 OVER8USART_CR1 寄存器的 OVER8 位对应的值
    U S A R T D I V USARTDIV USARTDIV存放在波特率寄存器 (USART_BRR) 的一个无符号定点数

    三、总结

    • 串口通信是 STM32 的一个重要组成部分,对于项目程序调试具有重要意义。

    • 利用串口调试助手,实现了人机的交互,提高了调试的效率。

    • 利用串口通信可以实现人与芯片的对话。



    【参考文献】

    [1] 《零死角玩转 STM32—基于野火 F407[霸天虎]开发板 》

    [2]   屈微 , 王志良. STM32单片机应用基础与项目实践 [M]. 北京:清华大学出版社. 2019.



    「你可能还想看」系列文章:
    【STM32】点亮LED
    【STM32】GPIO输入—按键检测
    【STM32】0.96寸OLED显示屏(7针SPI协议)软件模拟SPI
    【STM32】1.44寸TFT液晶屏显示字符、汉字和图片
    【STM32】stm32f407 + DS18B20 碰出不一样的火花
    【STM32】串口通信—用代码与芯片对话
    【STM32】串口通信出现乱码(使用官方标准库)
    【STM32】EXTI—外部中断/事件控制器
    【STM32】TIM—基本定时器
    【STM32】PWM 输出 (标准库)

    【STM32】CubeMX+HAL 点亮LED
    【STM32】CubeMX+HAL 输出PWM

    【STM32】ST-LINK下载器下载后需复位,程序才运行的问题

    其他相关文章:
    【信号与系统】笔记合集,你确定不收藏吗?我已经收藏了
    我用50行代码居然「让天猫精灵把客厅灯开了」
    流程图在线绘制,快速、便捷、高效!

      本次的分享就到这里


    11

    好书不厌百回读,熟读自知其中意。将学习成为习惯,用知识改变命运,用博客见证成长,用行动证明努力。
    如果我的博客对你有帮助、如果你喜欢我的博客内容,请 “点赞” “评论” “收藏” 一键三连哦!
    听说 👉 点赞 👈 的人运气不会太差,每一天都会元气满满呦!^ _ ^ ❤️ ❤️ ❤️
    码字不易,大家的支持就是我坚持下去的动力。点赞后不要忘了👉关注👈我哦!
    更多精彩内容请前往 AXYZdong的博客


    如果以上内容有任何错误或者不准确的地方,欢迎在下面 👇 留个言。或者你有更好的想法,欢迎一起交流学习~~~

    展开全文
  • STM32 串口通信实验

    2018-12-10 14:30:30
    STM32开发板上的串口通信实验代码,移植时请注意修改相应的引脚
  • STM32串口通信基本原理

    千次阅读 多人点赞 2021-05-22 18:41:36
    通信方式 并行通信 传输原理:数据各个位同时传输 优点:速度快(一个引脚传输一个位) 缺点:占用引脚资源多 串行通信 传输原理:数据按位顺序传输 优点:占用引脚资源少(一个引脚都可以) 缺点:速度相对较慢 ...

    参考正点原子视频

    通信方式

    并行通信

    • 传输原理:数据各个位同时传输
    • 优点:速度快(一个引脚传输一个位)
    • 缺点:占用引脚资源多

    串行通信

    • 传输原理:数据按位顺序传输
    • 优点:占用引脚资源少(一个引脚都可以)
    • 缺点:速度相对较慢

    串行通信

    按照数据传送方向,分为

    • 单工:数据传输只支持数据在一个方向上传输
    • 半双工:允许数据在两个方向上传输,但是,在某一时刻,只允许数据在一个方向上传输,它实际上是一种切换方向的单工通信
    • 全双工:允许数据同时在两个方向上传输,因此,全双工通信是两个单工通信方式的结合,它要求发送设备和接收设备都有独立的接收和发送能力

    串口通信三种传送方式

    在这里插入图片描述

    串行通信的通信方式

    • 同步通信:带时钟同步信号传输。 -SPI,IIC通信接口
    • 异步通信:不带时钟同步信号。 -UART(通用异步收发器),单总线

    在同步通信中,收发设备上方会使用一根信号线传输信号,在时钟信号的驱动下双方进行协调,同步数据。例如,通讯中通常双方会统一规定在时钟信号的上升沿或者下降沿对数据线进行采样。

    在异步通信中不使用时钟信号进行数据同步,它们直接在数据信号中穿插一些用于同步的信号位,或者将主题数据进行打包,以数据帧的格式传输数据。通讯中还需要双方规约好数据的传输速率(也就是波特率)等,以便更好地同步。常用的波特率有4800bps、9600bps、115200bps等。

    在同步通讯中,数据信号所传输的内容绝大部分是有效数据,而异步通讯中会则会包含数据帧的各种标识符,所以同步通讯效率高,但是同步通讯双方的时钟允许误差小,稍稍时钟出错就可能导致数据错乱,异步通讯双方的时钟允许误差较大。

    常见的串行通信接口

    在这里插入图片描述

    STM32的串口通信接口

    • UART:通用异步收发器
    • USART:通用同步异步收发器

    UART异步通信方式引脚连接方式

    • RXD:数据输入引脚。数据接收
    • TXD:数据发送引脚。数据发送

    在这里插入图片描述
    在这里插入图片描述

    UART异步通信方式特点

    • 全双工异步通信
    • 分数波特率发生器系统,提供精确的波特率。发送和接受共用的可编程波特率,最高可达4.5Mbits/s
    • 可编程的数据子长度(8位或者9位)
    • 可配置的停止位(支持1或者2位停止位)
    • 可配置的使用DMA多缓冲器通信
    • 单独的发送器和接收器使能位
    • 检测标志:1接受缓冲器 2发送缓冲器空 3传输结束标志
    • 多个带标志的中断源。触发中断
    • 其他:检验控制,四个错误检测标志

    串口通信过程

    在这里插入图片描述

    STM32串口异步通信需要定义的参数

    1. 起始位
    2. 数据位(8位或者9位)
    3. 奇偶校验位(第9位)
    4. 停止位(4,15,2位)
    5. 波特率设置

    在这里插入图片描述

    USART框图

    在这里插入图片描述

    常用的串口相关寄存器

    • USART_SR状态寄存器
    • USART_DR数据寄存器
    • USART_BRR波特率寄存器

    波特率计算方法

    在这里插入图片描述

    串口操作相关库函数

    void USART_Init();//串口初始化:波特率,数据字长,奇偶检验位,硬件流控以及收发使能
    void USART_Cmd();//使能串口
    void USART_ITConfig();//使能相关中断
    
    void USART_SendData();//发送数据到串口,DR
    uint16_ USART_ReceiveData();//接受数据,从DR读取接受到的数据
    
    FlagStatus USART_GetFlagStatus();//获取状态标志位
    void USART_ClearFlag();//清除状态标志位
    ITStatus USART_GetITStatus();//获取中断状态标志位
    void USART_ClearTPendingBit();//清除中断状态标志位
    

    USART_InitTypeDef

    typedef struct
    {
      //设置波特率
      uint32_t USART_BaudRate;            /*!< This member configures the USART communication baud rate.
                                               The baud rate is computed using the following formula:
                                                - IntegerDivider = ((PCLKx) / (16 * (USART_InitStruct->USART_BaudRate)))
                                                - FractionalDivider = ((IntegerDivider - ((u32) IntegerDivider)) * 16) + 0.5 */
      //设置字长度
      uint16_t USART_WordLength;          /*!< Specifies the number of data bits transmitted or received in a frame.
                                               This parameter can be a value of @ref USART_Word_Length */
      //设置停止位
      uint16_t USART_StopBits;            /*!< Specifies the number of stop bits transmitted.
                                               This parameter can be a value of @ref USART_Stop_Bits */
      //设置奇偶校验
      uint16_t USART_Parity;              /*!< Specifies the parity mode.
                                               This parameter can be a value of @ref USART_Parity
                                               @note When parity is enabled, the computed parity is inserted
                                                     at the MSB position of the transmitted data (9th bit when
                                                     the word length is set to 9 data bits; 8th bit when the
                                                     word length is set to 8 data bits). */
      //设置通信模式
      uint16_t USART_Mode;                /*!< Specifies wether the Receive or Transmit mode is enabled or disabled.
                                               This parameter can be a value of @ref USART_Mode */
      //设置硬件流
      uint16_t USART_HardwareFlowControl; /*!< Specifies wether the hardware flow control mode is enabled
                                               or disabled.
                                               This parameter can be a value of @ref USART_Hardware_Flow_Control */
    } USART_InitTypeDef;
    

    串口配置的一般步骤

    STM32串口配置的一般步骤(库函数)

    1. 串口时钟使能:RCC_APBxPeriphClockCmd();
      GPIO时钟使能:RCC_AHBxPeriphClockCmd();
    2. 引脚复用映射:GPIO_PinAFConfig();
    3. GPIO端口模式配置:GPIO_Init(); 模式配置为GPIO_Mode_AF_PP
    4. 串口参数初始化:USART_Init();
    5. 开启中断并且初始化NVIC(如果需要开启中断才需要这个步骤)
      NVIC_Init();
      USART_ITConfig();
    6. 使能串口:USART_Cmd();
    7. 编写中断处理函数:USARTx_IRQHandler();
    8. 串口数据收发:
      void USART_SendData();//发送数据到串口,DR
      uint16_t USART_ReceiveData();//接收数据,从DR读取接收的数据
    9. 串口传输状态获取:
      FlagStatus USART_GetFlagStatus();
      void USART_ClearITPendingBit();

    例子配置

    void uart_init(u32 bound){
      GPIO_InitTypeDef GPIO_InitStructure;//GPIO端口设置
    	USART_InitTypeDef USART_InitStructure;//USART端口设置
    	NVIC_InitTypeDef NVIC_InitStructure;//NVIC中断设置
    	 
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE);	//开启USART1和GPIOA的时钟,使能
      
    	//USART1_TX   GPIOA.9
      GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9
      GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//速度50MHz
      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//复用推挽输出
      GPIO_Init(GPIOA, &GPIO_InitStructure);//根据指定参数初始化GPIOA
       
      //USART1_RX	 GPIOA.10
      GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//PA10
      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
      GPIO_Init(GPIOA, &GPIO_InitStructure);//根据指定参数初始化GPIOA.10  
    
      //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);	//根据指定的参数初始化NVIC
      
       //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); //根据指定参数初始化串口1
      USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启串口接受中断(USART1_IRQHandler)
      USART_Cmd(USART1, ENABLE);//使能串口1
    
    }
    
    void USART1_IRQHandler(void)//串口1中断服务程序
    	{
    	u8 Res;//8位无标志字符
    #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)//接收未完成
    			{
    			if(USART_RX_STA&0x4000)//接收到了0x0d
    				{
    				if(Res!=0x0a)USART_RX_STA=0;//接收错误,重新开始
    				else USART_RX_STA|=0x8000;	//接收完成了
    				}
    			else //还没收到0x0d
    				{	
    				if(Res==0x0d)USART_RX_STA|=0x4000;
    				else
    					{
    					USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ;
    					USART_RX_STA++;
    					if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;//接收数据错误,重新开始接收  
    					}		 
    				}
    			}   		 
         } 
    #if SYSTEM_SUPPORT_OS //如果SYSTEM_SUPPORT_OS为真,则需要支持OS
    	OSIntExit();  											 
    #endif
    }
    
    展开全文
  • 2021-01-12 学习日志STM32f1库函数开发学习实战二 · 串口通信1. 背景知识2. usart文件夹介绍 STM32f1库函数开发学习 实战二 · 串口通信 1. 背景知识 DMA 通信方式 LIN总线 DMA,Direct Memory Access,...




    STM32f1库函数开发学习

    实战二 · 串口通信

    1. 背景知识

    • DMA
    • 通信方式
    • LIN总线

    • DMA,Direct Memory Access,存储器直接访问,一种高速数据传输操作,允许外设与存储器、外设与外设之间直接交换数据。

      CPU 和 DMA 控制器的传输过程处于并行操作状态,大大提高整个计算机系统效率。

      适用于一些高速的I/O设备(kBps),例如磁盘存取、图像处理、高速数据采集、同步通信中的收/发信号。

      DMAC,DMA控制器,负责DMA传送全过程控制的硬件电路。

      DMA

      参考文章:DMA总结


    • 通信方式
      数据传输,按照数据流方向可分为三种传输方式:

      • 单工通信
      • 半双工通信
      • 全双工通信

      单工通信只支持单方向传输数据,任何时候不能改变传输方向。为了保证数据不失真,需要校验位,校验出错时通过监控信道发送请求重发信号。

      适用于数据收集系统,例如计算机和打印机,只有计算机向打印机传输数据。

      半双工通信,支持两个方向传输,但同一时刻只能存在一个方向上的传输,是一种可调换方向的单工通信,例如对讲机。

      全双工通信,允许数据同时在两个方向上传输,有两个传输道路,是两个单工通信结合。

      全双工通信效率高,控制简单,造价高,例如手机、计算机。


    • LIN总线

      Local Interconnect Network,本地互联网络总线。

      LIN主要功能是为CAN总线网络提供辅助功能:

      • 单主多从组网方式,最多16节点,1主15从
      • 硬件要求低,只需要UART/SCI接口,几乎所有的MCU都支持LIN
      • 不需要单独的晶振
      • 只需要一根信号线,单总线设备
      • 传输速率20Kbps
      • 新节点不影响原有节点的硬件

      LIN网络节点任务分为主机任务和从机任务,从机任务在主机节点和从机节点都可以运行。

      LIN通信可以用作“主从通信”、“基于时间表的通信”,后期可以做个多机通信处理系统?

      参考文章:





    2. usart文件夹介绍

    usart文件夹包括 .c 文件和 .h 文件,针对串口1进行了初始化和中断接收,用其他串口时需要更改。主要包括两个函数:

    1. uart_init 函数,串口初始化
    2. USART1_IRQHandler 函数 ,中断响应函数


    下面来解剖这两个函数


    1.uart_init 函数

    1. 引入32位参数 波特率(bound)
    void uart_init(u32 bound)
    

    1. 定义结构体
    GPIO_InitTypeDef GPIO_InitStructure;
    USART_InitTypeDef USART_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;
    

    1. 开启时钟使能
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA
    |RCC_APB2Periph_AFIO, ENABLE);
    //使能 USART1,GPIOA 时钟
    //以及复用功能时钟
    

    使用一个内置外设的时候,要首先使能相应的GPIO时钟,然后使能复用功能时钟内置外设时钟

    不知道内置外设应该开启哪个时钟使能的时候,在参考手册搜索“系统架构/系统结构”:
    系统结构图


    1. 初始化GPIO端口为特定状态
    //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); 
     //初始化 GPIOA.9 发送端
     
     //USART1_RX PA.10 
     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
     //PA.10
     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
     //浮空输入
     GPIO_Init(GPIOA, &GPIO_InitStructure); 
     //初始化 GPIOA.10 接收端
    

    GPIO配置步骤:

    • 时钟使能 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    • 引脚号 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_x;
    • 端口翻转速度 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    • 引脚模式 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    • 端口初始化 GPIO_Init(GPIOA, &GPIO_InitStructure);

    如何查找GPIO端口应该配置为什么模式


    在《STM32中文参考手册》中搜索“外设的GPIO配置”,得到以下几个表格(以下不全):
    GPIO配置1
    GPIO配置2GPIO配置3


    1. Usart_1 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); 
    //中断优先级配置
    

    NVIC_IRQChannel:

    定义初始化的是哪个中断,这个我们可以在 stm32f10x.h 中找到每个中断对应的名字。

    例如 USART1_IRQn。


    1. 串口1初始化参数以及使能
    //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_RXNE, ENABLE);
     //开启中断
     USART_Cmd(USART1, ENABLE); 
     //使能串口
    
    



    串口配置的一般步骤

    1. 串口时钟使能,GPIO时钟使能
    2. 串口复位
    3. GPIO端口模式设置
    4. 串口参数初始化
    5. 开启中断,初始化NVIC
    6. 使能串口
    7. 中断处理函数

    几个配置需要的库函数:

    1. 串口时钟使能

    查询系统架构图可知,USART1挂在APB2下,需要开启时钟:

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1);

    2. 串口复位
    复位用于设备异常时重新配置,系统刚开始工作时也需要复位。
    USART_DeInit(USART1); //复位串口 1


    3. 串口参数初始化

    需要初始化的参数是:波特率、字长、停止位、奇偶校验位、硬件数据流控制、收发模式

    通过初始化函数完成:
    USART_Init(USART1, &USART_InitStructure);
    结构体的成员变量配置示例如下

    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); 
    //初始化串口
    

    4. 数据发送与接收

    STM32的发送接收通过寄存器USART_DR实现,这是一个双寄存器,包含了TDR和RDR,写数据时串口就自动发送,收到数据时存储在内

    发数据:
    void USART_SendData(USART_TypeDef* USARTx, uint16_t Data);

    读数据:
    uint16_t USART_ReceiveData(USART_TypeDef* USARTx);


    5. 串口状态

    通过寄存器USART_SR读取串口状态,一共有32位只取前10位,一般我们只关注第5、6位RXNE和TC:

    USART_SR
    RXNE(读数据寄存器非空):该位为1的时候,说明有数据被接收到,并且可读。此时需要尽快读取USART_DR,然后将RXNE清零或者直接置0清除

    TC(发送完成):该位被置位时,USART_DR数据已经发送完成,可以设置中断。也有两种清零方式:读USART_SR,写USART_DR;直接将TC写0

    读取串口状态的库函数:

    USART_GetFlagStatus(USART1, USART_FLAG_RXNE);

    USART_GetFlagStatus(USART1, USART_FLAG_TC);

    串口的状态是通过宏定义实现的:

    #define USART_IT_PE ((uint16_t)0x0028)
    #define USART_IT_TXE ((uint16_t)0x0727)
    #define USART_IT_TC ((uint16_t)0x0626)
    #define USART_IT_RXNE ((uint16_t)0x0525)
    #define USART_IT_IDLE ((uint16_t)0x0424)
    #define USART_IT_LBD ((uint16_t)0x0846)
    #define USART_IT_CTS ((uint16_t)0x096A)
    #define USART_IT_ERR ((uint16_t)0x0060)
    #define USART_IT_ORE ((uint16_t)0x0360)
    #define USART_IT_NE ((uint16_t)0x0260)
    #define USART_IT_FE ((uint16_t)0x0160)
    

    6. 串口使能

    通过函数USART_Cmd()实现:

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

    7. 开启串口响应中断

    当我们需要开启串口中断的时候,需要使能,例如:

    USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
    //开启中断,接收到数据中断
    

    此函数的第二个入口参数是使能串口的类型,例如此例中我们需要在接收到数据的时候产生中断,就需要开启RXNE的中断USART_IT_RXNE

    如果需要在发送数据结束的时候产生中断,则:

    USART_ITConfig(USART1,USART_IT_TC,ENABLE);
    //数据发送结束产生串口中断
    

    8. 获取中断状态

    比如我们使能了某个串口发生中断,当中断发生了,可以调用函数判断是否完成中断:

    USART_GetITStatus(USART1, USART_IT_TC)
    

    返回值是SET,则串口发送完成中断






    2. USART1_IRQHandler

    USART1_IRQHandler函数是串口1的中断响应函数,串口1发生中断时会跳转到其中去执行

    1. if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)

    用上面列举的常用库函数中第八句(获取中断状态),判断是否接受中断,如果接收了中断则读取串口接收到的数据:

    1. Res = USART_ReceiveData(USART1);//(USART1->DR); //读取接收到的数据

    数据赋给变量Res。读到数据之后就对数据进行分析。

    这里有一个接收协议,利用数组USART_RX_BUF[],接收状态“寄存器”USART_RX_STA (实为一个全局变量,但是起到类似寄存器的作用),实现对串口数据的接收管理。

    • USART_RX_BUF[] 的长度由USART_REC_LEN定义:
      u8 USART_RX_BUF[USART_REC_LEN];

      USART_REC_LEN是位于 usart.h中定义的一个全局参数,定义最大接收的字节数

    • USART_RX_STA 是一个接收状态寄存器,定义表如下:

    USART_SR
    当接收到数据时,把数据保存在USART_RX_BUF[]中,同时在接收状态寄存器(USART_RX_STA)中计数接收到的有效数据个数。

    当接收到回车( 回车由0X0D和0X0A组成 ) 的第一个字节0X0D (0x0D,asc码是13,指的是回车\r,把光标置于本行行首) 时,停止计数;

    等待0X0A (0x0A,asc码是10,指的是换行 \n,把光标置于下一行的同一列) ,标记USART_RX_STA的第15位接收完成标志,完成一次接收,等待第15位被清除后完成一次接收。

    如果0X0D回车来迟,而数据超过USART_REC_LEN时,会丢弃前面的数据重新接收


    配置示例

    void USART1_IRQHandler(void) //串口 1 中断服务程序
    {
    	u8 Res;
    	#if SYSTEM_SUPPORT_OS //如果 SYSTEM_SUPPORT_OS 为真,则需要支持 OS
    	OSIntEnter(); 
    	#endif
    
    	if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) 
    	//接收中断(接收到的数据必须是 0x0d 0x0a 结尾) 		
    	{
    		Res =USART_ReceiveData(USART1);//(USART1->DR); //读取接收到的数据
    		if((USART_RX_STA&0x8000)==0)//接收未完成
    		{
    			if(USART_RX_STA&0x4000)//接收到了 0x0d
    			{
    				if(Res!=0x0a)USART_RX_STA=0;//接收错误,重新开始
    				else USART_RX_STA|=0x8000; //接收完成了
    			}
    		else //还没收到 0X0D
    			{
    				if(Res==0x0d)USART_RX_STA|=0x4000;
    				else
    				{
    					USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ;
    					USART_RX_STA++;
    					if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;
    					//接收数据错误,重新开始接收 
    				} 
    			}
    		} 
    	} 
    	
    #if SYSTEM_SUPPORT_OS //如果 SYSTEM_SUPPORT_OS 为真,则需要支持 OS
    OSIntExit(); 
    #endif
    }
    
    
    
    
    

    关于OS操作系统的研究日后再进行






    3. 硬件电路

    查看原理图:
    U1
    USART1的RXD和TXD位于PA10和PA9,再次查找得到电气连接方式:

    电气连接

    这里发现串口1的TXD和RXD需要用跳线帽跟PA9、PA10连接在一起






    4. 主函数的一些说明

    usart.h文件中可以引入"stdio.h"头文件,并且加入一段代码,即可提供printf()函数支持,直接利用printf函数向串口发送我们需要的内容。原理及操作见下文:

    STM32使用printf打印串口

    我们来看一下主函数设计的几个示例及要点:

    1. 接收数据部分

    if(USART_RX_STA & 0x8000)
    { 
    	len = USART_RX_STA&0x3fff;//得到此次接收到的数据长度
    	printf("\r\n 您发送的消息为:\r\n");
    	for(t=0;t<len;t++){
    		USART1->DR = USART_RX_BUF[t];
    		while((USART1->SR & 0X40) == 0);}//等待发送结束
    	printf("\r\n\r\n");//插入换行
    	USART_RX_STA = 0;
    }
    

    USART_RX_STA的bit15表示接收完成标志,bit14表示接收到0X0D


    USART_RX_STA&0x8000,即bit15位比较,若为1则接受完成,之后再接收判断长度。


    判断长度就是剩余14位比较,USART_RX_STA&0x3fff,0x3fff即0011 1111 1111 1111,bit相同则为1否则为0,便可得到USART_RX_STA的低14位的值,便得到其长度


    2. 发送数据部分

    else{
    		times ++;
    		if(times % 5000 == 0){
    			printf("\r\n123456789\r\n");
    			printf("asdfghjkl\r\n\r\n\r\n");}
    		if(times % 200 == 0)printf("hello world\r\n");  
    		if(times % 30 == 0)LED0 =! LED0;
    		//LED闪烁指示系统还在运行
    		delay_ms(10);   
    	}
    
    展开全文
  • STM32串口通信详解以及通信异常或者卡死常见问题分析 目录 STM32串口通信详解以及通信异常或者卡死常见问题分析 一、常见的异常问题 二、STM32的串口简介 1.串口的通讯方式 ①按数据传输方向 ②串行通讯的通信方式 ...

    STM32串口通信详解以及通信异常或者卡死常见问题分析


    一、常见的异常问题

    ◉异常一:数据传输中会出现乱码
    ◉异常二:程序卡在中断函数里面无法跳出执行主函数的逻辑
    ◉异常三:数据传输中间歇性数据异常
    ◉异常四:数据发送时会出现漏发的现象

    这些问题对小编带了了巨大的困扰,本文也因这些问题应时而生。小编将自己的见解分享大家,也希望各路大神指导改正。欢迎交流


    二、STM32的串口简介

    1.串口的通讯方式

    ◉并行通讯
    -传输原理:数据各个同时传输
    -优点:速度快
    -缺点:占用引脚资源多

    ◉串行通讯
    -传输原理:数据安位顺序传输
    -优点:占用引脚资源少
    -缺点:传输速度较慢

    ①按数据传输方向

    ◉单工:
    -数据传输只支持数据一个方向传输

    ◉半双工
    -允许数据在两个方向上传输,但是,在某一时刻,只允许数据在一个方向上传输,他是实际是一种切换方向的单工通讯。
    ◉全双工
    -允许数据同时在两个方向上传输,因此,全双工通讯是两单工通讯方式的结合,它要求发送设备和接收设备都有独立的接收和发送能力。

    串行三种通讯方式如图所示:
    在这里插入图片描述

    ②串行通讯的通信方式

    ◉同步通信
    -带时钟同步信号传输(接口:SPI,IIC,USART(通用同步异步首发器)

    ◉异步通信

    -不带时钟同步信号(接口:UART(通用异步收发器),单总线

    -常见的串口通信接口如图:在这里插入图片描述

    ③UART异步通信方式引脚连接方法

    ◉RXD: 数据输入引脚,数据接收。

    ◉TXD: 数据发送引脚,数据接收。

    接线如图:
    在这里插入图片描述

    ④STM32F103系列串口对应引脚

    串口号TXDRXD重定义TXD重定义RXD
    USART1PA9PA10PA6PA7
    USART2PA2PA3PD5PD6
    USART3PB10PB11PD8/PC10PD9 /PC11
    USART4PC10PC11//
    USART5PC12PD3//

    ⑤串口通讯过程

    在这里插入图片描述

    2.串口的部分寄存器以及库函数的应用

    ①USART_SR状态寄存器

    作用:状态寄存器USART_SR,描述串口寄存器的一些状态

    获取状态标志位函数-操作USART_SR寄存器

    // 获取状态标志位
    FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, uint16_t USART_FLAG);
    // 清除状态标志位
    void USART_ClearFlag(USART_TypeDef* USARTx, uint16_t USART_FLAG);
    // 获取中断状态标志位
    ITStatus USART_GetITStatus(USART_TypeDef* USARTx, uint16_t USART_IT);
    // 清除中断状态标志位
    void USART_ClearITPendingBit(USART_TypeDef* USARTx, uint16_t USART_IT);
    

    ②USART_DR数据寄存器

    USART_DR实际是包含了两个寄存器,一个专门用于发送的TDR,一个专门用于接收的RDR。进行发送数据操作时,往USART_DR写入数据会自动存储在TDR内;当进行读取数据操作时,向USART_DR读取数据会自动提取RDR数据。

    接收发送数据函数-操作USART_DR寄存器

    // 发送数据到串口(通过写USART_DR寄存器发送数据)
    void USART_SendData(USART_TypeDef* USARTx, uint16_t Data);
    // 接收数据(从USART_DR寄存器读取接收到的数据)
    uint16_t USART_ReceiveData(USART_TypeDef* USARTx);
    

    ③重要的标志位

    1、USART_FLAG_RXNE 串口信号接收完成

    2、USART_FLAG_TXE 数据预发送准备

    3、USART_FLAG_TC数据发送完成

    在这里插入图片描述在这里插入图片描述

    常用的代码应用:

    
    USART_ITConfig(USART1, USART_IT_TXE, ENABLE); //清除溢出中断
    
    USART_ClearFlag(USART1, USART_FLAG_TC);//清除传输完成标志位
    
    USART_ClearFlag(USART1,USART_FLAG_RXNE); //清空中断标志位
    

    三、实用的代码讲解分析

    1.发送功能函数应用详解

    ①字符发送

    u8 Uart1_PutChar(u8 ch) //发送一个字符,输入参数为发送的字符
    {
    	USART_SendData(USART1, (u8) ch);//向串口1,发送一个字符
        while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET){}//等待发送完成
        return ch;//返回字符
    }
    

    ②字符串发送

    表达①

    void Uart1_PutString(u8* buf , u8 len)//发送一个字符串,输入参数为要发送的数组,发送的字符串个数
    { 
        u8 i;
    	for(i=0;i<len;i++)
    	{
    		Uart1_PutChar(*buf++);//发送一个字符
    	}
    }
    

    表达②

    void Uart1_SendStr(u8 *SendBuf)//串口1打印数据
    {
    	while(*SendBuf)
    	{
    	   while((USART1->SR&0X40)==0){};//等待发送完成 
           USART1->DR = (u8) *SendBuf; 
    	   SendBuf++;
    	}
    }
    

    ③C语言printf应用

    #if 1
    #pragma import(__use_no_semihosting)             
    //标准库需要的支持函数                 
    struct __FILE 
    { 
    	int handle; 
    }; 
    
    FILE __stdout;       
    //定义_sys_exit()以避免使用半主机模式    
    _sys_exit(int x) 
    { 
    	x = x; 
    } 
    //重定义fputc函数 ,重定义到串口1
    int fputc(int ch, FILE *f)
    {      
    	while((USART1->SR&0X40)==0);//循环发送,直到发送完毕   
        USART1->DR = (u8) ch;      
    	return ch;
    }
    #endif 
    

    2.接收功能函数应用详解

    ①解析数据帧头的通讯接收方式

    -说明:通过分析帧头来确定一包数据的到来,还需要确认数据的长度。
    -例如:如果帧头确定第一个字符是0X5A,第二个字符是0X5A。串口1接收到的数据从串口2发送出去
    -代码函数如下:

    u8 old_ch;
    u8 oold_ch;
    u8 send_distant = 0; //发送字符的指针
    void USART2_IRQHandler(void)                	//串口2中断服务程序
    {
    	u8 ch;
    	if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)  //是否发送中断事件
    		{
    			ch =USART_ReceiveData(USART2);//将接收到的数据存在数组Usart1RecBuf[RxCounter]里
    			if(oold_ch == 0x5A && old_ch == 0x5A)
    			{
    				send_distant = 2;
    			}
    			if(send_distant)
    			{
    				if(send_distant == 1)
    				{
    					ch = JuLi_L;//改变第二个字符
    				}else if(send_distant == 2)
    				{
    					ch = JuLi_H;//改变第二个字符
    				}
    				send_distant--;
    			}
    			oold_ch = old_ch;
    			old_ch = ch;
    			USART_SendData(USART1,ch);//将接收到的数据从串口1发送出去
        } 
    
    

    ②解析数据帧尾的通讯接收方式

    -说明:通过分析帧尾来确定一包数据的结束,不需要确认数据的长度。
    -例如:如果帧尾确定倒数第一个字符是0X0A,倒数第二个字符是0X0D。串口1接收到的数据从串口2发送出去
    -代码函数如下:

    	 
    void USART1_IRQHandler(void)                	//串口1中断服务程序
    {
      u8 Res;
    	if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)//接收中断(接收到的数据必须是0x0d 0x0a结尾)
    		{
    			Res =USART_ReceiveData(USART1);	//读取接收到的数据
    			if((USART_RX_STA&0x8000)==0)//接收未完成
    			{
    			  if(USART_RX_STA&0x4000)//接收到了0x0d
    				{
    					if(Res!=0x0a)USART_RX_STA=0;//接收错误,重新开始
    				  else USART_RX_STA|=0x8000;	//接收完成了 
    				}
    				else //还没收到0X0D
    				{	
    					if(Res==0x0d)USART_RX_STA|=0x4000;
    					else
    					{
    						USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ;
    						USART_RX_STA++;
    						if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;//接收数据错误,重新开始接收	  
    					}		 
    				}
    			}   		 
    		} 
    } 
    
    

    ③解析接收超时的通讯接收方式

    -说明:该方法不需要判断帧头帧尾,也不需要确认好数据的长度。是通过判断接收数据帧的时间间隔来判断一包数据是否接收完成。

    -该方法需要开启定时器来计算时间,接收超时的时间需要计算出数据帧的接收时间间隔来判定,不同的波特率数据帧的接收时间间隔不一样,比如:波特率为115200,时间间隔为:10/115200=0.08ms。

    串口中断函数代码如下:

    extern unsigned char star_time_led ;  //计时开始变量
    unsigned char recv_flag = 0;//定义接受标志位
    unsigned long recv_cnt = 0;//串口1接收数据缓存
    unsigned char recv_buf[MAX_REV_NUM];//串口1接收数据缓存
    extern unsigned char star_time;
    extern unsigned char recv_time_cnt;
    
    void USART1_IRQHandler(void)                	//串口1中断服务程序
    {
    	static char ch;
    	if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  //是否发送中断事件
    		{
    			ch = USART_ReceiveData(USART1);//将接收到的数据存在数组Usart1RecBuf[RxCounter]里
    			star_time = 1;         //接受到一帧数据的时候,打开软件定时器,去计数
    			if(recv_cnt < MAX_REV_NUM)//数组长度是否超过缓存区
    			{
    				recv_buf[recv_cnt] =ch;//将接收到的数据存在数组Usart1RecBuf[RxCounter]里
    				recv_cnt++;
    			}
    			else
    			{
    				recv_cnt = MAX_REV_NUM
    				;	//限制数组长度,超过缓存区则不再接收
    			}
    			recv_time_cnt = 0; //每接收到一帧数据,把定时计数器清零,相当于喂狗
    			                   //但是在定时器中断里面会不断的累加
    			USART_ClearFlag(USART1,USART_FLAG_RXNE); //清空中断标志位
    		}
    } 
    
    

    定时器中断函数代码如下:

    unsigned char star_time = 0 ;  //计时开始变量
    unsigned char recv_time_cnt;  //定时计数器
    extern unsigned long recv_cnt;
    extern unsigned char recv_flag;
    unsigned char star_time_led = 0 ;  //计时开始变量
    void TIM4_IRQHandler(void)   //TIM1中断函数
    {
    	if (TIM_GetITStatus(TIM4, TIM_IT_Update) != RESET) //检查指定的TIM1中断发生与否:TIM1中断源 
    		{	
         star_time_led++;
    		if(star_time == 1)
    		{ 
    			recv_time_cnt++; //1、累加定时时间计数器
          if(recv_time_cnt>MAX_REV_TIME)//2、判断时间是否超过了设定的最大的时间阈值,
    				                            //   超过则说明等待一段时间后没有新的数据到来
    			                              //   则判断一包数据接收完毕
    			{
    				recv_time_cnt = 0;//3、清除定时计数器,处理数据 清楚nuffer(放在数据处理之后)
    				recv_cnt = 0;
    				recv_flag = 1; //接收完成标志位置1
    			}
    		}
      		TIM_ClearITPendingBit(TIM4, TIM_IT_Update  );  //清除TIM1的中断待处理位:TIM1中断源 
    		}	
    }
    
    

    四、对第一章的问题分析

    ◉异常一:数据传输中会出现乱码
    数据传输中会出现乱码,很有可能是数组溢出,或者定义的数组长度不够。或者中断被打断。

    ◉异常二:程序卡在中断函数里面无法跳出执行主函数的逻辑
    中断标志位没有被清除,在这里要注意一点,串口中断标志位自动清空的前提是软件需要先读USART_SR寄存器,然后读USART_DR寄存器来自动清除。即串口中断事件发生后,如果使能的接收中断,而中断函数里面什么都不执行的话,接收中断标志位是无法自动清空的,故而,函数会一直卡在中断函数里面。

    比如一下这个函数,该函数没有逻辑问题,但会引发以上问题,代码如下

    extern unsigned char star_time_led ;  //计时开始变量
    unsigned char recv_flag = 0;//定义接受标志位
    unsigned long recv_cnt = 0;//串口1接收数据缓存
    unsigned char recv_buf[MAX_REV_NUM];//串口1接收数据缓存
    extern unsigned char star_time;
    extern unsigned char recv_time_cnt;
    /*
    以下写法有严重问题
    如果没有这句函数→USART_ClearFlag(USART1,USART_FLAG_RXNE); //清空中断标志位
    串口接收中断标志位将文法被清空,会导致函数卡在中断函数里面一直循环,无法正常运行主函数
    
    原因分析:
    中断条件成立后,中断标志位将会标记,程序将会进入中断函数运行,软件自动轻触中断标志位的条件是
    先读USART_SR寄存器,再读USART_DR寄存器。
    void USART1_IRQHandler(void)                	//串口1中断服务程序
    {
    	if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  //是否发送中断事件
    		{
    			star_time = 1;         //接受到一帧数据的时候,打开软件定时器,去计数
    			if(recv_cnt < MAX_REV_NUM)//数组长度是否超过缓存区
    			{
    				recv_buf[recv_cnt] =USART_ReceiveData(USART1);//将接收到的数据存在数组Usart1RecBuf[RxCounter]里
    				recv_cnt++;
    			}
    			else
    			{
    				recv_cnt = MAX_REV_NUM
    				;	//限制数组长度,超过缓存区则不再接收
    			}
    			recv_time_cnt = 0; //每接收到一帧数据,把定时计数器清零,相当于喂狗
    			                   //但是在定时器中断里面会不断的累加
    			USART_ClearFlag(USART1,USART_FLAG_RXNE); //清空中断标志位
    		}
    } 
    */
    

    上述代码优化后如下

    void USART1_IRQHandler(void)                	//串口1中断服务程序
    {
    	static char ch;
    	if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  //是否发送中断事件
    		{
    			ch = USART_ReceiveData(USART1);//将接收到的数据存在数组Usart1RecBuf[RxCounter]里
    			star_time = 1;         //接受到一帧数据的时候,打开软件定时器,去计数
    			if(recv_cnt < MAX_REV_NUM)//数组长度是否超过缓存区
    			{
    				recv_buf[recv_cnt] =ch;//将接收到的数据存在数组Usart1RecBuf[RxCounter]里
    				recv_cnt++;
    			}
    			else
    			{
    				recv_cnt = MAX_REV_NUM
    				;	//限制数组长度,超过缓存区则不再接收
    			}
    			recv_time_cnt = 0; //每接收到一帧数据,把定时计数器清零,相当于喂狗
    			                   //但是在定时器中断里面会不断的累加
    			USART_ClearFlag(USART1,USART_FLAG_RXNE); //清空中断标志位
    		}
    } 
    

    ◉异常三:数据发送中间歇性数据异常漏发乱发等

    对于这些奇奇怪怪的问题,首先要了解一下发送函数是怎么发送的

    USART_DR 包含了已发送的数据或者接收到的数据。 USART_DR 实际是包含了两个寄存器,一个专门用于发送的可写 TDR,一个专门用于接收的可读 RDR。当进行发送操作时,往 USART_DR 写入数据会自动存储在 TDR 内;当进行读取操作时,向 USART_DR读取数据会自动提取 RDR 数据。

    TDR 和 RDR 都是介于系统总线和移位寄存器之间。串行通信是一个位一个位传输的,发送时把 TDR 内容转移到发送移位寄存器,然后把移位寄存器数据每一位发送出去,接收时把接收到的每一位顺序保存在接收移位寄存器内然后才转移到 RDR。

    当 TDR 内容转移到发送移位寄存器,还没有发送出去的,就再次把TDR 内容转移到发送移位寄存器里,就会出现少发的现象。

    什么时候会有这种情况呢?错误操作代码如下:

    void USART2_IRQHandler(void)                	//串口2中断服务程序
    {
    	if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)  //是否发送中断事件
    		{
    			Usart1RecBuf[RxCounter] =USART_ReceiveData(USART2);//将接收到的数据存在数组Usart1RecBuf[RxCounter]里
    			RxCounter++;//指向数组地址自加
    			if(RxCounter==2) 
    			{	
    				USART_SendData(USART1, Usart1RecBuf[0]);//发送Usart1RecBuf[0]
                    USART_SendData(USART1, Usart1RecBuf[1]);//发送Usart1RecBuf[1]
    				USART_SendData(USART1, Usart1RecBuf[2]);//发送Usart1RecBuf[2]
    			}
    		}
    }
    

    上述代码连续运行了3次USART_SendData(USART1, Usart1RecBuf);这个函数,这种情况一般都会出现只有最后一个数据发送成功出去。原因可能就是数据还没有发送出去,发送移位寄存器就更新了。

    四、总结

    ◉上述内用的一些程序源码连接如下,包括解析数据帧头的通讯接收方式,解析数据帧尾的通讯接收方式,解析接收超时的通讯接收方式。创作实属不易

    链接:
    https://download.csdn.net/download/weixin_43281206/19342432

    在这里插入图片描述
    具体源码工程压缩包可在本博客上传资料下载。或者下面QQ群下载,“星云视界”资料共享群:626051465
    “星云视界”资料共享群资料二维码如下:

    请添加图片描述

    非常感谢大家的观看,希望对大家有所帮助。小编常接外包设计定单哦!非常乐意为大家提供毕设技术指导以及产品设计等服务。

    如需要可直接联系小编(添加请备注博客添加哈)

    QQ : 3778615131

    微信号 : a13428153731

    展开全文
  • 1.1 串口通信协议概念 1.2 RS-232标准 1.3TTL标准 二. 安装 stm32CubeMX,配合Keil,使用寄存器方式(汇编或C,不限) 或HAL库这两种方式,完成下列任务: 2.1 安装Java 2.2安装stm32CubeMX 2.3安装固件库 三...
  • STM32串口通信(USART)

    2020-04-17 15:14:22
    USART是通用同步异步串口通信的简称,以STM32为例,它不仅支持最基本的通用串口同步、异步通信,还具有LIN总线功能(局域互联网)、IRDA功能(红外通信)、SmartCard功能。 异步串口通信协议 最基本、最常用的方法:全...
  • 2个STM32串口之间的串口通信(RX,TX)

    千次阅读 2021-07-11 01:40:53
    2个STM32串口之间的串口通信(RX,TX) 链接:https://pan.baidu.com/s/1HKGYOi58lC9GUnCSVoRyLQ 提取码:qdzy 历程是根据正点和普中的程序结合改写的。 实现的功能: 串口调试助手1通过单片机1的USART3发送数据,...
  • STM32串口通信简介

    2021-10-23 22:27:52
    目录 前言 一、串口协议是什么?...STM32串口通信,发送Hello Windows示例_噗噗的罐子博客-CSDN博客https://blog.csdn.net/qq_46467126/article/details/120841504参考资料: 零死角玩转STM32-F103指南者
  • 该代码实现了STM32与FPGA的串口通信,调试可用。并且串口的波特率可调整,默认工作频率50M
  • STM32串口通信学习总结

    千次阅读 2020-09-09 17:30:42
    STM32串口通信学习总结 1.概述 1.1学习目的 通过基于AWA5812平台,学习STM32F767芯片的串口通信程序开发。本人学习串口通信比较曲折,一开始使用的芯片时STM32新开发出来的一块STM32L496ZG的板子,这块板子的优点...
  • STM32串口通讯详解

    万次阅读 多人点赞 2019-07-30 22:26:34
    串口通讯(Serial Communication)是一种设备间非常常用的串行通讯方式,因为它简单便捷,因此大部分电子设备都支持该通讯方式,其通讯协议可分层为协议层和物理层。物理层规定通信协议中具有机械、电子功能的特性,...
  • 串口发送调用HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout)函数即可。 定义一个存放串口数据发送的缓冲区: /* USER CODE BEGIN 0 */ uint8...
  • STM32串口通信(针对stm32f10x)

    千次阅读 2020-01-12 15:30:44
    处理器与外部通信的两种方式 并行通信 数据各个位同时传输,速度快,占用引脚资源多 串行通信 数据按位顺序传输,占用引脚资源少,速度相对比较慢 1.按照数据传送方向可以分为: 单工:数据传输只支持在一个方向上...
  • STM32串口通信实验

    2020-10-27 17:35:14
    DB9接口指9针的接口(串口连接器) USART_InitTypeDef.USART_BaudRate //波特率 USART_InitTypeDef.USART_WordLength //字长 USART_InitTypeDef.USART_StopBits //停止位 USART_InitTypeDef.USART_Parity //奇偶校验位...
  • stm32 串口接收引脚配置为浮空输入问题 最近做一个多串口的项目,共用到三个串口,一个串口是485,一个是4G模块,另外一个是蓝牙。其中4G模块和蓝牙都是通过串口直接连接的。在测试过程中发现有时隔几个小时或者两三...
  • STM32串口通信

    2021-01-26 22:23:20
    STM32串口通信串口通信简介编程代码 注意:本文参考STM32F10XXX数据手册 串口通信简介 USART为通用同步异步接收/发送器,我们常用的是异步通信,下面也重点讲解异步通信 问:同步异步有什么区别呢? 答:具体区别...
  • STM32串口通信基本原理(超基础、详细版)

    万次阅读 多人点赞 2018-04-12 13:26:02
    STM32F1xx官方资料: 《STM32中文参考手册V10》-第25章通用同步异步收发器(USART) 通信接口背景知识 设备之间通信的方式 一般情况下,设备之间的通信方式可以分成并行通信和串行通信两种。它们的区别是: 并...
  • stm32串口通信实验

    千次阅读 2019-05-21 11:13:10
    STM32F1 串口简介 串口作为 MCU 的重要外部接口,同时也是软件开发重要的调试手段,其重要性不言而喻。...的 STM32F103ZET6 最多可提供 5 路串口,有分数波特率发生器、支持同步单线通信和半双工 单线通讯、支持 ...
  • STM32串口通信

    千次阅读 2018-08-13 16:34:11
    串口通信原理  串口通信的概念非常简单,串口按位(bit)发送和接收字节。尽管比按字节(byte)的并行通信慢,但是串口可以在使用一根线发送数据的同时用另一根线接收数据。它很简单并且能够实现远距离通信。比如...
  • STM32串口通信、串口调试助手

    万次阅读 多人点赞 2018-12-05 14:09:23
    STM32学习之旅④ USART串口和上位机通信 STM32学习之旅⑤ SPI控制TFT,从底层到底层的设计 目录: 一、认识其本质 (一)串口 (二)协议 (三)时序 (四)上位机 二、所需材料 三、USART的介绍 四、USART串口的...
  • STM32串口通信控制pwm

    千次阅读 2020-10-29 16:23:10
    STM32F103RC串口通信控制PWM
  • stm32串口(3)

    2021-05-08 17:34:59
    stm32 串口工程串口简介二级目录三级目录函数介绍完整代码usart.husart.cmain.c实验现象 工程 将01 跑马灯工程复制一份,并改名为03 串口。 打开文件夹中Hrd文件,并新建USART文件夹。 在Keil中新建两个文件并保存在...
  • stm32串口通信调试总结

    万次阅读 多人点赞 2017-05-10 22:31:30
    本调试记录分为两部分,即”以USART1为例的串口初始化”和“调试中遇到的问题”。
  • STM32串口通信 通信方式 一、同步通信、异步通信 同步通信 通信中双方使用频率一致的时钟 异步通信 通信中的接收方并不知道数据什么时候会到达,收发双方可以有各自自己的时钟 异同点: 1.同步通信效率高;异步...
  • 串口收发共需要三根线 其中,TX脚为发送引脚, RX脚为发送引脚, GND为地, 作为电平的参考. 如果A发B收, 只需要连接两条线: A的TX连接B的RX, 以及GND相连即可 1 传输一个字节 1.1 发送一个字节 首先, 从传输一个字节...
  • STM32下的USART串口通信程序

    千次阅读 2020-12-01 14:33:20
    STM32的USART串口通信实践
  • STM32串口通信(基于缓冲区)

    千次阅读 2020-05-08 19:11:54
    一、串口的初始化和中断设置 1、初始化GPIO: ...当然啦,在使用STM32外设的时候不要忘记打开外设时钟(GPIO和USART的RCC)。 GPIO_InitTypeDef GPIO_InitStructure; //开启串口和GPIO的时钟 RCC_APB2P...
  • 二、完成一个STM32的USART串口通讯程序 (1)创建新工程并编写代码 (2)生成hex文件 (3)结果演示 三、使用Keil的软件仿真逻辑分析仪功能观察管脚的时序波形 (1)观察3个GPIO端口的输出波形 (2)串口输出...
  • STM32】HAL库 STM32CubeMX教程四---UART串口通信详解

    万次阅读 多人点赞 2019-08-11 08:57:51
    今天我们学习STM32CubeMX串口的操作,以及HAL库串口的配置,我们会详细的讲解各个模块的使用和具体功能,并且基于HAL库实现Printf函数功能重定向,UART中断接收,本系列教程将HAL库与STM32CubeMX结合在一起讲解,使...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 7,160
精华内容 2,864
关键字:

stm32串口通信引脚