您可以捐助,支持我们的公益事业。

1元 10元 50元





认证码:  验证码,看不清楚?请点击刷新验证码 必填



  求知 文章 文库 Lib 视频 iPerson 课程 认证 咨询 工具 讲座 Model Center   Code  
会员   
   
 
     
   
 
 订阅
STM32—串口通信(串口的接收和发送)
作者: 藕粉
   次浏览      
 2023-7-25
 
编辑推荐:
本文主要对串口通信做一个简要的总结,各种情况下串口通信在STM32的实际使用方面占有很大的比重。希望对您的学习有所帮助。
本文来自于微信公众号古月居,由火龙果软件Alice编辑、推荐。

STM32的串口通信

本文在于记录自己的学习过程中遇到的问题和总结,各种情况下串口通信在STM32的实际使用方面占有很大的比重,本文主要对串口通信做一个简要的总结。

一、STM32里的串口通信

在STM32里,串口通信是USART,STM32可以通过串口和其他设备进行传输并行数据,是全双工,异步时钟控制,设备之间是点对点的传输。

对应的STM32引脚分别是RX和TX端。STM32的串口资源有USART1、USART2、USART3.

串口的几个重要的参数:

波特率,串口通信的速率

空闲,一般为高电平

起始位,标志一个数据帧的开始,固定为低电平。当数据开始发送时,产生一个下降沿。(空闲–>起始位)

数据位,发送数据帧,1为高电平,0为低电平。低位先行。

比如 发送数据帧0x0F 在数据帧里就是低位线性 即 1111 0000

校验位,用于数据验证,根据数据位的计算得来。有奇校验,偶校验和无校验。

停止位,用于数据的间隔,固定为高电平。数据帧发送完成后,产生一个上升沿。(数据传输–>停止位)

下方就是一个字节数据的传输过程,从图中可以看出,串口发送的数据一般都是以数据帧的形式进行传输,每个数据帧都由起始位,数据位,停止位组成, 且停止位可变。

二、串口的发送和接收

USART是STM32内部集成的硬件外设,可以根据数据寄存器的一个字节数据自动生成数据帧时序,从TX引脚发送出去,也可以自动接收RX引脚的数据帧时序,拼接成一个字节数据,存放在数据寄存器里。

当配置好USART的电路之后,直接读取数据寄存器,就可以自动发送数据和接收数据了。在发送和接收的模块有4个重要的寄存器

发送数据寄存器TDR

发送移位寄存器,把一个字节的数据一位一位的移出去

接收数据寄存器RDR

接收移位寄存器,把一个字节的数据

下方为串口的发送和接收图解:

串口发送

在配置串口的各个参数时,可以选择发送数据帧的数据位的大小,可选8位或9位。

串口发送数据实际上就是对发送数据寄存器TDR进行写操作。

1. 当串口发送数据时,会检测发送移位寄存器是不是有数据正在移位,如果没有移位,那么这个数据就会立刻转移到发送移位寄存器里。准备发送。

2. 当数据移动到移位寄存器时,会产生一个TXE发送寄存器空标志位,该位描述如下。当TXE被置1,那么就可以在TDR写入下一个数据了。即发送下一个数据。

3. 发送移位寄存器在发送器控制的控制下,向右移位,一位一位的把数据传输到TX引脚。

4. 数据移位完成后,新的数据就会再次从TDR转移到发送移位寄存器里来,依次重复1-3的过程。通过读取TXE标志位来判断是否发送下一个数据。

串口接收

数据从RX引脚通向接收移位寄存器,在接收控制的控制下,一位一位的读取RX的电平,把第一位放在最高位,然后右移,移位八次之后就可以接收一个字节了。

当一个字节数据移位完成之后,这一个字节的数据就会整体的移到接收数据寄存器RDR里来。

在转移时会置RXNE接收标志位,即RDR寄存器非空,下方为该位的描述。当被置1后,就说明数据可以被读出。

下图即为串口接收的工作流程

三、串口在STM32中的配置

首先要明确几点:使用STM32串口外设中的哪一个?串口发送或者接收数据?串口相关的参数配置?发送或接收是否使用到中断?

下方为串口发送的配置。

1. RCC开启USART、串口TX/RX所对应的GPIO口

RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE); //开启USART2的时钟

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); //开启GPIOA的时钟

 

2. 初始化GPIO口

这里注意哈,根据自己的需求来配置GPIO口,发送和接收是都需要还是只需要其中一个。然后对应的根据引脚定义表来初始化对应的GPIO口。

USART2对应的引脚

USART1对应的引脚

这里根据手册来看,RX引脚模式配置成浮空输入或者上拉输入。TX引脚模式配置成复用推挽输出。

**比如我这里只初始化TX发送端**

 

//TX端

GPIO_InitTypeDef GPIO_InitStructure;

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

GPIO_InitStructure.GPIO_Pin=GPIO_Pin_2; //USART2对应的TX端为GPIOA2

GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; //50MhZ

GPIO_Init(GPIOA,&GPIO_InitStructure);

 

3. 串口初始化

注意哈,USART_Init()这个函数,是用来配置串口的相关参数的。

USART_BaudRate 串口通信使用的波特率 一般是9600或者是115200,这里我们给9600

USART_HardwareFlowControl 是否选择硬件流触发,一般这个我们也不选,所以选择无硬件流触发。

USART_Mode 这个参数要注意了哈,串口的模式,发送模式还是接收模式,还是两者都有

USART_Parity 校验位,可以选择奇偶校验和不校验。没有需求就直接无校验

USART_StopBits 停止位 有1、0.5、2位,我们这里选1位停止位

USART_WordLength 数据位 有8位和9位可以选择

//串口初始化

USART_InitTypeDef USART_InitStruct;

USART_StructInit(&USART_InitStruct); //初始默认值

USART_InitStruct.USART_BaudRate=9600;

USART_InitStruct.USART_HardwareFlowControl=USART_HardwareFlowControl_None; //不使用硬件流触发

USART_InitStruct.USART_Mode=USART_Mode_Tx; //TX 发送模式

USART_InitStruct.USART_Parity=USART_Parity_No; //不选择校验

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

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

USART_Init(USART2,&USART_InitStruct);

 

4. 串口使能

//串口使能

USART_Cmd(USART2,ENABLE);

5. 串口发送数据

注意哈,我们要判断TXE标志位的状态。0,数据还没有被转移到移位寄存器;1,数据已经被转移到移位寄存器。

当TXE标志位为1时,就说明可以发送下一个数据了。详细过程可看上面串口发送的解释。

void Serial_SendByte(uint16_t Byte)

{

USART_SendData(USART2,Byte);

//0 表示数据还未转移到移位寄存器 循环等待 1 数据已经被转移到了移位寄存器可以发送数据

while(USART_GetFlagStatus(USART2,USART_FLAG_TXE)==RESET); //不需要手动清零 再次写入TDR时会自动清零

}

 

经过上述五步的配置,单片机就可以通过串口发送数据了。

下方为发送数据图例,STM32向串口发送0x16数据

四、串口接收的两种实现方式

上方是发送数据的例子,那么串口接收又该如何配置,又要在串口发送的例子上做哪些更改呢?

这里我们可以通过查询或者中断的方式来进行接收数据的两种方式。

查询方式就是通过不断的查询RXNE标志位,通过判断RXNE位的状态来确定数据是否接收。

中断方式就是通过配置接收输出控制通道,配置NVIC,在中断服务子函数里进行数据的接收。

1. 需要更改的地方

既然我们要实现串口的接收,那么就要配置串口RX引脚,在串口模式中添加USART_Mode_RX模式。

初始化RX引脚

//RX端

GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU; //上拉输入

GPIO_InitStructure.GPIO_Pin=GPIO_Pin_3;

GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; //50MhZ

GPIO_Init(GPIOA,&GPIO_InitStructure);

添加串口模式

USART_InitStruct.USART_Mode=USART_Mode_Tx|USART_Mode_Rx; //TX 发送模式 RX 接收模式

2. 查询RXNE标志位

这里我们还是来看一看RXNE标志位的描述

上图描述,为0时数据没有收到,为1时收到了数据,数据可以从RDR里读出

所以在主程序里不断读取RXNE标志位,如果为1,表示数据可以读出

uint8_t RX_Data;

int main()

{

Serial_Init();

Serial_SendByte(0x16);

while(1)

{

if(USART_GetFlagStatus(USART2,USART_FLAG_RXNE)==SET) //0 循环等待 1 可以接收数据

{

RX_Data=USART_ReceiveData(USART2);

Serial_SendByte(RX_Data);

}

}

}

 

下图为程序现象:pc向单片机发送数据0x15,单片机接收数据0x15,并且把接收到的数据作为数据发送到pc,在pc上显示0x15。

3. 使用中断

通过配置串口的接收作为中断源,开启中断输出控制,配置NVIC。开启中断通道。

//开启中断输出控制

USART_ITConfig(USART2,USART_IT_RXNE,ENABLE);

//配置NVIC

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);

NVIC_InitTypeDef NVIC_InitStruct;

NVIC_InitStruct.NVIC_IRQChannel=USART2_IRQn; //选择USART2的中断通道

NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE; //中断使能

NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=1;

NVIC_InitStruct.NVIC_IRQChannelSubPriority=1;

NVIC_Init(&NVIC_InitStruct);

 

中断服务子函数

中断服务子函数写好后,就可以在中断里读取接收到的数据了。

当接收到数据后,触发接收中断,主程序暂停执行。接收完数据后主程序回复执行。当接收到数据时,就触发中断。

void USART2_IRQHandler(void)

{

if(USART_GetITStatus(USART2,USART_IT_RXNE)==SET) //RXNE 标志位为1 表示可以接收数据

{

RX_Data=USART_ReceiveData(USART2);

Flag=1;

USART_ClearITPendingBit(USART2,USART_IT_RXNE); //清除RXNE标志位

}

}

 

主程序测试

uint8_t RX_Data;

uint8_t Flag;

int main()

{

Serial_Init();

Serial_SendByte(0x16);

while(1)

{

if(Flag==1)

{

Serial_SendByte(RX_Data);

}

}

}

void USART2_IRQHandler(void)

{

if(USART_GetITStatus(USART2,USART_IT_RXNE)==SET) //RXNE 标志位为1 表示可以接收数据

{

RX_Data=USART_ReceiveData(USART2);

Flag=1;

USART_ClearITPendingBit(USART2,USART_IT_RXNE); //清除RXNE标志位

}

}

 

下图为程序现象:可以看到,串口确实收到了数据,只是我把接收到的数据0xFE放在了while循环里,这说明数据接收是成功的,使用中断是可行的。

总结

到这里,就大致总结了串口的发送和接收。

串口的配置,使用查询或者中断来接收数据。

串口的使用会很常用到,所以在这里对串口做一个总结,也算是对之前知识的一个回顾和总结,加强印象。

 

   
次浏览       
相关文章

一文了解汽车嵌入式AUTOSAR架构
嵌入式Linux系统移植的四大步骤
嵌入式中设计模式的艺术
嵌入式软件架构设计 模块化 & 分层设计
相关文档

企点嵌入式PHP的探索实践
ARM与STM简介
ARM架构详解
华为鸿蒙深度研究
相关课程

嵌入式C高质量编程
嵌入式操作系统组件及BSP裁剪与测试
基于VxWorks的嵌入式开发、调试与测试
嵌入式单元测试最佳实践

最新活动计划
C++高级编程 12-25 [线上]
白盒测试技术与工具实践 12-24[线上]
LLM大模型应用与项目构建 12-26[特惠]
需求分析最佳实践与沙盘演练 1-6[线上]
SysML建模专家 1-16[北京]
UAF架构体系与实践 1-22[北京]
 
 
最新文章
基于FPGA的异构计算在多媒体中的应用
深入Linux内核架构——简介与概述
Linux内核系统架构介绍
浅析嵌入式C优化技巧
进程间通信(IPC)介绍
最新课程
嵌入式Linux驱动开发
代码整洁之道-态度、技艺与习惯
嵌入式软件测试
嵌入式C高质量编程
嵌入式软件可靠性设计
成功案例
某军工所 嵌入式软件架构
中航工业某研究所 嵌入式软件开发指南
某轨道交通 嵌入式软件高级设计实践
深圳 嵌入式软件架构设计—高级实践
某企业 基于IPD的嵌入式软件开发
更多...