STM32 USART串口通信


一、介绍

通用同步异步收发器(USART)提供了一种灵活的方法与使用工业标准NRZ异步串行数据格式的外部设备之间进行全双工数据交换。USART利用分数波特率发生器提供宽范围的波特率选择。它支持同步单向通信和半双工单线通信,也支持LIN(局部互连网),智能卡协议和IrDA(红外数据组织)SIR ENDEC规范,以及调制解调器(CTS/RTS)操作。它还允许多处理器通信。使用多缓冲器配置的DMA方式,可以实现高速数据通信。

二、硬件连接

  1. 串口之间的接线方式
  2. TTL与RS232的电平标准
  3. STM32 USART框图

三、通信协议

  1. 数据包
    串口通讯的数据包由发送设备通过自身的TXD接口传输到接收设备得RXD接口,在协议层中规定了数据包的内容,具体包括起始位、主体数据(8位或9位)、校验位以及停止位,通讯的双方必须将数据包的格式约定一致才能正常收发数据。

  2. 波特率
    由于异步通信中没有时钟信号,所以接收双方要约定好波特率,常见的波特率有4800、9600、115200等。

  3. 起始和停止信号
    数据包的首尾分别是起始位和停止位,数据包的起始信号由一个逻辑0的数据位表示,停止位信号可由0.5、1、1.5、2个逻辑1的数据位表示,双方需约定一致。

  4. 有效数据
    有效数据规定了主题数据的长度,一般为8或9位。

  5. 数据校验
    在有效数据之后,有一个可选的数据校验位。由于数据通信相对更容易受到外部干扰导致传输数据出现偏差,可以在传输过程加上校验位来解决这个问题。校验方法有奇校验(odd)、偶校验(even)、 0 校验(space)、 1 校验(mark)以及无(noparity)。

4、STM32 USART的寄存器

  1. STM32 USART的配置的寄存器,库函数中的结构体积是基于寄存器进行封装的,还没学会怎么看寄存器的小伙伴可以看我之前的笔记
寄存器 偏移 复位值 描述
USART_SR 0x00 0x00C0 状态寄存器
USART_DR 0x04 不确定 数据寄存器
USART_BRR 0x08 0x0000 波特比率寄存器
USART_CR1 0x0C 0x0000 控制寄存器1
USART_CR2 0x10 0x0000 控制寄存器2
USART_CR3 0x14 0x0000 控制寄存器3
USART_GTPR 0x18 0x0000 保护时间和预分频寄存器
  1. 寄存器的地址映象

四、代码分析

  1. 配置串口的结构体
typedef struct
{
    uint32_t USART_BaudRate;  // 波特率设置
    uint16_t USART_WordLength;    //数据位数设置
    uint16_t USART_StopBits;    //停止位设置
    uint16_t USART_Parity;    //是否奇偶校验
    uint16_t USART_Mode;    //接收与发送都使能
    uint16_t USART_HardwareFlowControl;      //硬件流控制模式设置
} USART_InitTypeDef;

  1. 中断配置结构体
typedef struct
{
    uint8_t NVIC_IRQChannel;    // 配置USART为中断源
    uint8_t NVIC_IRQChannelPreemptionPriority;    // 抢断优先级
    uint8_t NVIC_IRQChannelSubPriority;    // 子优先级
    FunctionalState NVIC_IRQChannelCmd;    // 使能中断
} NVIC_InitTypeDef;

  1. 配置USART 的 IO引脚
    将Tx配置为复用推挽输出,将Rx配置为浮空输入
    /* USART1 使用IO端口配置 */    
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);    
  
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;	//浮空输入
    GPIO_Init(GPIOA, &GPIO_InitStructure);   //初始化GPIOA

  1. 配置USART 的工作模式配置
    /* USART1 工作模式配置 */
    USART_InitStructure.USART_BaudRate = 115200;	//波特率设置:115200
    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;//接收与发送都使能

  1. 将Rx读取配置为中断读取模式
void NVIC_Configuration(void)
{
    NVIC_InitTypeDef NVIC_InitStructure;
	
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);		// 设置NVIC中断分组2:2位抢占优先级,2位响应优先级
  
    NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;		// 配置USART为中断源
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;		// 抢断优先级
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;		// 子优先级
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;		// 使能中断
    NVIC_Init(&NVIC_InitStructure);		// 初始化配置NVIC
}

  1. 中断函数使用
    当串口接收到数据后此中断函数会被调用,调用次函数后,会将接收到的信息有通过串口发送获取。这里的中断函数名已经在启动文件中已经定义好了的,建议不做更改。

    注意:有的小伙伴编写好程序后,发现串口无法收到发送的信息,可能是这里的中断函数名写错了。
void USART1_IRQHandler(void)
{
	uint16_t  res;
	/* 判断是否收到中断信号 */
	if(USART_GetITStatus(USART1, USART_IT_RXNE) == SET)
	{
		res = USART_ReceiveData(USART1);
		USART_SendData(USART1, res);
	}
	//USART_SendData(USART1,(uint16_t)0xAC);	

}

五、程序源码

  1. usart1.c文件
/***************************************
 * 文件名  :usart1.c
 * 描述    :配置USART1         
 * 实验平台:MINI STM32开发板 基于STM32F103C8T6
 * 硬件连接:------------------------
 *          | PA9  - USART1(Tx)      |
 *          | PA10 - USART1(Rx)      |
 *           ------------------------


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

#include "usart1.h"
#include <stdarg.h>
#include "misc.h"


void NVIC_Configuration(void)
{
	NVIC_InitTypeDef NVIC_InitStructure;
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);		// 设置NVIC中断分组2:2位抢占优先级,2位响应优先级
  
	NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;		// 配置USART为中断源
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;		// 抢断优先级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;		// 子优先级
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;		// 使能中断
	NVIC_Init(&NVIC_InitStructure);		// 初始化配置NVIC
}


void USART1_Config(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;

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

	/* USART1 使用IO端口配置 */    
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);    
  
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;	//浮空输入
	GPIO_Init(GPIOA, &GPIO_InitStructure);   //初始化GPIOA
	  
	/* USART1 工作模式配置 */
	USART_InitStructure.USART_BaudRate = 115200;	//波特率设置:115200
	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);  //初始化USART1
	USART_Cmd(USART1, ENABLE);// USART1使能
	
	
	USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);	// 开启串口接受中断	
	NVIC_Configuration();// 串口中断优先级配置
	
	
}

void USART1_IRQHandler(void)
{
	uint16_t  res;
	/* 判断是否收到中断信号 */
	if(USART_GetITStatus(USART1, USART_IT_RXNE) == SET)
	{
		res = USART_ReceiveData(USART1);
		USART_SendData(USART1, res);
	}
	//USART_SendData(USART1,(uint16_t)0xAC);	

}

  1. main.c文件
#include "stm32f10x.h"
#include "usart1.h"



int main(void)
{  
	     
    SystemInit();	//配置系统时钟为 72M 
   
	USART1_Config(); //USART1 配置 		

	while (1)
	{	 

	}
}

五、编译运行

  1. 编译

  2. 运行

六、常见问题

程序下载后运行后发送数据无反馈。
解决办法:

  1. 检查中断函数名是否正确。
  2. 将STM32的引脚设置为运行模式,有不知道的怎么设置为运行模式的小伙伴可以参考STM32零基础入门教程


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM