14 STM32F429 USART

cc14 STM32F429 USART

1.USART功能框图

image-20221003020143368

常用:

TX:发送数据输出引脚。
RX:接收数据输入引脚。

不常用:

SW_RX:数据接收引脚,只用于单线和智能卡模式,属于内部引脚,没有具体外部引脚。
nRTS:请求以发送 (Request To Send),n 表示低电平有效。如果使能 RTS 流控制,当 USART 接
收器准备好接收新数据时就会将 nRTS 变成低电平;当接收寄存器已满时,nRTS 将被设置为高
电平。该引脚只适用于硬件流控制。
nCTS:清除以发送 (Clear To Send),n 表示低电平有效。如果使能 CTS 流控制,发送器在发送下
一帧数据之前会检测 nCTS 引脚,如果为低电平,表示可以发送数据,如果为高电平则在发送完
当前数据帧之后停止发送。该引脚只适用于硬件流控制。
SCLK:发送器时钟输出引脚。这个引脚仅适用于同步模式。

引脚分布图

image-20221003020346363

2.USART寄存器

1.数据寄存器

USART 数据寄存器 (USART_DR) 只有低 9 位有效,并且第 9 位数据是否有效要取决于 USART
控制寄存器 1(USART_CR1) 的 M 位设置,当 M 位为 0 时表示 8 位数据字长,当 M 位为 1 表示 9
位数据字长,我们一般使用 8 位数据字长。
USART_DR 包含了已发送的数据或者接收到的数据。USART_DR 实际是包含了两个寄存器,一
个专门用于发送的可写 TDR,一个专门用于接收的可读 RDR。当进行发送操作时,往 USART_DR
写入数据会自动存储在 TDR 内;当进行读取操作时,向 USART_DR 读取数据会自动提取 RDR
数据。
TDR 和 RDR 都是介于系统总线和移位寄存器之间。串行通信是一个位一个位传输的,发送时把
TDR 内容转移到发送移位寄存器,然后把移位寄存器数据每一位发送出去,接收时把接收到的
每一位顺序保存在接收移位寄存器内然后才转移到 RDR。

image-20221003020529208

2.控制寄存器

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

image-20221003020713812

3.状态寄存器

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mYNYsdve-1664941974894)(https://picture-1309470925.cos.ap-chengdu.myqcloud.com/pic/image-20221003021432354.png)]

发送器
当 USART_CR1 寄存器的发送使能位 TE 置 1 时,启动数据发送,发送移位寄存器的数据会在 TX
引脚输出,如果是同步模式 SCLK 也输出时钟信号。
一个字符帧发送需要三个部分:起始位 + 数据帧 + 停止位。起始位是一个位周期的低电平,位周
期就是每一位占用的时间;数据帧就是我们要发送的 8 位或 9 位数据,数据是从最低位开始传输
的;停止位是一定时间周期的高电平。

停止位时间长短是可以通过 USART 控制寄存器 2(USART_CR2) 的 STOP[1:0] 位控制,可选 0.5
个、1 个、1.5 个和 2 个停止位。默认使用 1 个停止位。2 个停止位适用于正常 USART 模式、单
线模式和调制解调器模式。0.5 个和 1.5 个停止位用于智能卡模式。

当发送使能位 TE 置 1 之后,发送器开始会先发送一个空闲帧 (一个数据帧长度的高电平),接下
来就可以往 USART_DR 寄存器写入要发送的数据。在写入最后一个数据后,需要等待 USART 状
态寄存器 (USART_SR) 的 TC 位为 1,表示数据传输完成,如果 USART_CR1 寄存器的 TCIE 位置
1,将产生中断。

image-20221003021518315

接收器
如果将 USART_CR1 寄存器的 RE 位置 1,使能 USART 接收,使得接收器在 RX 线开始搜索
起始位。在确定到起始位后就根据 RX 线电平状态把数据存放在接收移位寄存器内。接收完成
后就把接收移位寄存器数据移到 RDR 内,并把 USART_SR 寄存器的 RXNE 位置 1,同时如果
USART_CR2 寄存器的 RXNEIE 置 1 的话可以产生中断

image-20221003021853426

3.波特率

image-20221003022341209

image-20221003022402230

波特率的常用值有 2400、9600、19200、115200。下面以实例讲解如何设定寄存器值得到波特率
的值。
由表 STM32F429IGT6 芯片的 USART 引脚 可知 USART1 和 USART6 使用 APB2 总线时钟,最高可
达 90MHz,其他 USART 的最高频率为 45MHz。我们选取 USART1 作为实例讲解,即 fPLCK=90MHz。
当我们使用 16 倍过采样时即 OVER8=0,为得到 115200bps 的波特率,此时:
image-20221003022437484
8 ∗ 2 ∗ USARTDIV
解得 USARTDIV=48.825125,可算得 DIV_Fraction=0xD,DIV_Mantissa=0x30,即应该设置 US-
ART_BRR 的值为 0x30D。
在计算 DIV_Fraction 时经常出现小数情况,经过我们取舍得到整数,这样会导致最终输出的波特
率较目标值略有偏差。下面我们从 USART_BRR 的值为 0x30D 开始计算得出实际输出的波特率
大小。
由 USART_BRR 的 值 为 0x30D, 可 得 DIV_Fraction=13,DIV_Mantissa=48, 所 以 USART-
DIV=48+16*0.13=48.8125,所以实际波特率为:115237;这个值跟我们的目标波特率误差为 0.03%,
这么小的误差在正常通信的允许范围内。
8 倍过采样时计算情况原理是一样的。

4.校验控制

STM32F4xx 系列控制器 USART 支持奇偶校验。当使用校验位时,串口传输的长度将是 8 位的数
据帧加上 1 位的校验位总共 9 位,此时 USART_CR1 寄存器的 M 位需要设置为 1,即 9 数据位。
将 USART_CR1 寄存器的 PCE 位置 1 就可以启动奇偶校验控制,奇偶校验由硬件自动完成。启
动了奇偶校验控制之后,在发送数据帧时会自动添加校验位,接收数据时自动验证校验位。接收
数据时如果出现奇偶校验位验证失败,会见 USART_SR 寄存器的 PE 位置 1,并可以产生奇偶校
验中断。
使能了奇偶校验控制后,每个字符帧的格式将变成:起始位 + 数据帧 + 校验位 + 停止位。

5.中断控制

image-20221003022535380

6.实验代码分析

image-20221003022855995


  
#include "./usart/bsp_debug_usart.h"


 /**
  * @brief  配置嵌套向量中断控制器NVIC
  * @param  无
  * @retval 无
  */
static void NVIC_Configuration(void)
{
  NVIC_InitTypeDef NVIC_InitStructure;
  
  /* 嵌套向量中断控制器组选择 */
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
  
  /* 配置USART为中断源 */
  NVIC_InitStructure.NVIC_IRQChannel = DEBUG_USART_IRQ;
  /* 抢断优先级为1 */
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
  /* 子优先级为1 */
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
  /* 使能中断 */
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  /* 初始化配置NVIC */
  NVIC_Init(&NVIC_InitStructure);
}


 /**
  * @brief  DEBUG_USART GPIO 配置,工作模式配置。115200 8-N-1 ,中断接收模式
  * @param  无
  * @retval 无
  */
void Debug_USART_Config(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;
  USART_InitTypeDef USART_InitStructure;
		
  RCC_AHB1PeriphClockCmd(DEBUG_USART_RX_GPIO_CLK|DEBUG_USART_TX_GPIO_CLK,ENABLE);

  /* 使能 USART 时钟 */
  RCC_APB2PeriphClockCmd(DEBUG_USART_CLK, ENABLE);
  
  /* GPIO初始化 */
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;  
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  
  /* 配置Tx引脚为复用功能  */
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  GPIO_InitStructure.GPIO_Pin = DEBUG_USART_TX_PIN  ;  
  GPIO_Init(DEBUG_USART_TX_GPIO_PORT, &GPIO_InitStructure);

  /* 配置Rx引脚为复用功能 */
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  GPIO_InitStructure.GPIO_Pin = DEBUG_USART_RX_PIN;
  GPIO_Init(DEBUG_USART_RX_GPIO_PORT, &GPIO_InitStructure);
  
 /* 连接 PXx 到 USARTx_Tx*/
  GPIO_PinAFConfig(DEBUG_USART_RX_GPIO_PORT,DEBUG_USART_RX_SOURCE,DEBUG_USART_RX_AF);

  /*  连接 PXx 到 USARTx__Rx*/
  GPIO_PinAFConfig(DEBUG_USART_TX_GPIO_PORT,DEBUG_USART_TX_SOURCE,DEBUG_USART_TX_AF);
  
  /* 配置串DEBUG_USART 模式 */
  /* 波特率设置:DEBUG_USART_BAUDRATE */
  USART_InitStructure.USART_BaudRate = DEBUG_USART_BAUDRATE;
  /* 字长(数据位+校验位):8 */
  USART_InitStructure.USART_WordLength = USART_WordLength_8b;
  /* 停止位:1个停止位 */
  USART_InitStructure.USART_StopBits = USART_StopBits_1;
  /* 校验位选择:不使用校验 */
  USART_InitStructure.USART_Parity = USART_Parity_No;
  /* 硬件流控制:不使用硬件流 */
  USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
  /* USART模式控制:同时使能接收和发送 */
  USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
  /* 完成USART初始化配置 */
  USART_Init(DEBUG_USART, &USART_InitStructure); 
	
  /* 嵌套向量中断控制器NVIC配置 */
	NVIC_Configuration();
  
	/* 使能串口接收中断 */
	USART_ITConfig(DEBUG_USART, USART_IT_RXNE, ENABLE);
	
  /* 使能串口 */
  USART_Cmd(DEBUG_USART, ENABLE);
}

/*****************  发送一个字符 **********************/
void Usart_SendByte( USART_TypeDef * pUSARTx, uint8_t ch)
{
	/* 发送一个字节数据到USART */
	USART_SendData(pUSARTx,ch);
		
	/* 等待发送数据寄存器为空 */
	while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);	
}

/*****************  发送字符串 **********************/
void Usart_SendString( USART_TypeDef * pUSARTx, char *str)
{
	unsigned int k=0;
  do 
  {
      Usart_SendByte( pUSARTx, *(str + k) );
      k++;
  } while(*(str + k)!='\0');
  
  /* 等待发送完成 */
  while(USART_GetFlagStatus(pUSARTx,USART_FLAG_TC)==RESET)
  {}
}

/*****************  发送一个16位数 **********************/
void Usart_SendHalfWord( USART_TypeDef * pUSARTx, uint16_t ch)
{
	uint8_t temp_h, temp_l;
	
	/* 取出高八位 */
	temp_h = (ch&0XFF00)>>8;
	/* 取出低八位 */
	temp_l = ch&0XFF;
	
	/* 发送高八位 */
	USART_SendData(pUSARTx,temp_h);	
	while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);
	
	/* 发送低八位 */
	USART_SendData(pUSARTx,temp_l);	
	while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);	
}

///重定向c库函数printf到串口,重定向后可使用printf函数
int fputc(int ch, FILE *f)
{
		/* 发送一个字节数据到串口 */
		USART_SendData(DEBUG_USART, (uint8_t) ch);
		
		/* 等待发送完毕 */
		while (USART_GetFlagStatus(DEBUG_USART, USART_FLAG_TXE) == RESET);		
	
		return (ch);
}

///重定向c库函数scanf到串口,重写向后可使用scanf、getchar等函数
int fgetc(FILE *f)
{
		/* 等待串口输入数据 */
		while (USART_GetFlagStatus(DEBUG_USART, USART_FLAG_RXNE) == RESET);

		return (int)USART_ReceiveData(DEBUG_USART);
}
/*********************************************END OF FILE**********************/

USART结构体与宏定义
USART_InitTypeDef USART_InitStructure;

typedef struct {
uint32_t USART_BaudRate;
// 波特率
uint16_t USART_WordLength;
// 字长
uint16_t USART_StopBits;
// 停止位
uint16_t USART_Parity;
// 校验位
uint16_t USART_Mode;
// USART 模式
uint16_t USART_HardwareFlowControl; // 硬件流控制
} USART_InitTypeDef;

//宏定义
#define DEBUG_USART                             USART1
#define DEBUG_USART_CLK                         RCC_APB2Periph_USART1
#define DEBUG_USART_BAUDRATE                    115200  //串口波特率

#define DEBUG_USART_RX_GPIO_PORT                GPIOA
#define DEBUG_USART_RX_GPIO_CLK                 RCC_AHB1Periph_GPIOA
#define DEBUG_USART_RX_PIN                      GPIO_Pin_10
#define DEBUG_USART_RX_AF                       GPIO_AF_USART1
#define DEBUG_USART_RX_SOURCE                   GPIO_PinSource10

#define DEBUG_USART_TX_GPIO_PORT                GPIOA
#define DEBUG_USART_TX_GPIO_CLK                 RCC_AHB1Periph_GPIOA
#define DEBUG_USART_TX_PIN                      GPIO_Pin_9
#define DEBUG_USART_TX_AF                       GPIO_AF_USART1
#define DEBUG_USART_TX_SOURCE                   GPIO_PinSource9

#define DEBUG_USART_IRQHandler                  USART1_IRQHandler
#define DEBUG_USART_IRQ                 				USART1_IRQn  

1.使能GPIO口和USART时钟
  RCC_AHB1PeriphClockCmd(DEBUG_USART_RX_GPIO_CLK|DEBUG_USART_TX_GPIO_CLK,ENABLE);

  /* 使能 USART 时钟 */
  RCC_APB2PeriphClockCmd(DEBUG_USART_CLK, ENABLE);
2.将输出和输入引脚配置到对应gpio口
  /* 配置Tx引脚为复用功能  */
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  GPIO_InitStructure.GPIO_Pin = DEBUG_USART_TX_PIN  ;  
  GPIO_Init(DEBUG_USART_TX_GPIO_PORT, &GPIO_InitStructure);

  /* 配置Rx引脚为复用功能 */
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  GPIO_InitStructure.GPIO_Pin = DEBUG_USART_RX_PIN;
  GPIO_Init(DEBUG_USART_RX_GPIO_PORT, &GPIO_InitStructure);
  
 /* 连接 PXx 到 USARTx_Tx*/
  GPIO_PinAFConfig(DEBUG_USART_RX_GPIO_PORT,DEBUG_USART_RX_SOURCE,DEBUG_USART_RX_AF);

  /*  连接 PXx 到 USARTx__Rx*/
  GPIO_PinAFConfig(DEBUG_USART_TX_GPIO_PORT,DEBUG_USART_TX_SOURCE,DEBUG_USART_TX_AF);
3.配置USART
  /* 配置串DEBUG_USART 模式 */
  /* 波特率设置:DEBUG_USART_BAUDRATE */
  USART_InitStructure.USART_BaudRate = DEBUG_USART_BAUDRATE;
  /* 字长(数据位+校验位):8 */
  USART_InitStructure.USART_WordLength = USART_WordLength_8b;
  /* 停止位:1个停止位 */
  USART_InitStructure.USART_StopBits = USART_StopBits_1;
  /* 校验位选择:不使用校验 */
  USART_InitStructure.USART_Parity = USART_Parity_No;
  /* 硬件流控制:不使用硬件流 */
  USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
  /* USART模式控制:同时使能接收和发送 */
  USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
  /* 完成USART初始化配置 */
  USART_Init(DEBUG_USART, &USART_InitStructure); 
4.NVIC嵌套向量中断器配置
 /* 嵌套向量中断控制器NVIC配置 */
NVIC_Configuration();
	
static void NVIC_Configuration(void)
{
  NVIC_InitTypeDef NVIC_InitStructure;
  
  /* 嵌套向量中断控制器组选择 */
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
  
  /* 配置USART为中断源 */
  NVIC_InitStructure.NVIC_IRQChannel = DEBUG_USART_IRQ;
  /* 抢断优先级为1 */
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
  /* 子优先级为1 */
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
  /* 使能中断 */
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  /* 初始化配置NVIC */
  NVIC_Init(&NVIC_InitStructure);
}
5.使能串口与串口接收中断
	/* 使能串口接收中断 */
	USART_ITConfig(DEBUG_USART, USART_IT_RXNE, ENABLE);
	
  /* 使能串口 */
  USART_Cmd(DEBUG_USART, ENABLE);
6.编写中断函数
void DEBUG_USART_IRQHandler(void)
{
  uint8_t ucTemp;
	if(USART_GetITStatus(DEBUG_USART,USART_IT_RXNE)!=RESET)
	{		
		ucTemp = USART_ReceiveData( DEBUG_USART );
    USART_SendData(DEBUG_USART,ucTemp);    
	}	 
}	
7.如果想使用printf()或者getchar()在串口输出/输入数据应该怎么做?
///重定向c库函数printf到串口,重定向后可使用printf函数
int fputc(int ch, FILE *f)
{
		/* 发送一个字节数据到串口 */
		USART_SendData(DEBUG_USART, (uint8_t) ch);
		
		/* 等待发送完毕 */
		while (USART_GetFlagStatus(DEBUG_USART, USART_FLAG_TXE) == RESET);		
	
		return (ch);
}

///重定向c库函数scanf到串口,重写向后可使用scanf、getchar等函数
int fgetc(FILE *f)
{
		/* 等待串口输入数据 */
		while (USART_GetFlagStatus(DEBUG_USART, USART_FLAG_RXNE) == RESET);

		return (int)USART_ReceiveData(DEBUG_USART);
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值