一、STM32 的 USART 简介
STM32 芯片具有多个 USART 外设用于串口通讯,它是 Universal SynchronousAsynchronous Receiver and Transmitter 的缩写,即通用同步异步收发器可以灵活地与外部设备进行全双工数据交换。有别于 USART,它还有具有 UART 外设(UniversalAsynchronousReceiver and Transmitter),它是在 USART 基础上裁剪掉了同步通信功能,只有异步通信。简单区分同步和异步就是看通信时需不需要对外提供时钟输出,我们平时用的串口通信基本都是 UART。
USART 满足外部设备对工业标准 NRZ 异步串行数据格式的要求,并且使用了小数波特率发生器,可以提供多种波特率,使得它的应用更加广泛。 USART 支持同步单向通信和半双工单线通信;还支持局域互连网络 LIN、智能卡(SmartCard)协议与 lrDA(红外线数据协会) SIR ENDEC 规范。
USART 支持使用 DMA,可实现高速数据通信。
USART 在 STM32 应用最多莫过于“打印”程序信息,一般在硬件设计时都会预留一个 USART 通信接口连接电脑,用于在调试程序是可以把一些调试信息“打印”在电脑端的串口调试助手工具上,从而了解程序运行是否正确、指出运行出错位置等等。STM32 的 USART 输出的是 TTL 电平信号,若需要 RS-232 标准的信号可使用MAX232 芯片进行转换。
二、协议层
1、数据包的组成:
2、波特率:
主要使用的是串口异步通讯,异步通讯中由于没有时钟信号,所以两个通讯设备之间需要约定好波特率,即每个码元的长度,以便对信号进行解码,常见的波特率为4800、 9600、 115200 等。
3、 通讯的起始和停止信号:
串口通讯的一个数据包从起始信号开始,直到停止信号结束。数据包的起始信号由一个逻辑 0 的数据位表示,而数据包的停止信号可由 0.5、 1、 1.5 或 2 个逻辑 1 的数据位表示,只要双方约定一致即可。
4、有效数据:
在数据包的起始位之后紧接着的就是要传输的主体数据内容,也称为有效数据,有效数据的长度常被约定为 5、 6、 7 或 8 位长。
5、数据校验:
在有效数据之后,有一个可选的数据校验位。由于数据通信相对更容易受到外部干扰导致传输数据出现偏差,可以在传输过程加上校验位来解决这个问题。校验方法有奇校验(odd)、偶校验(even)、 0 校验(space)、 1 校验(mark)以及无校验(noparity)。
三、编程要点
1-初始化串口需要用到的GPIO, GPIO_InitTypeDef,GPIO_PinAFConfig();
2-初始化串口, USART_InitTypeDef
3-中断配置
4-使能串口
5-编写发送和接收函数
6-编写中断服务函数
四、编程时需要用到的固件库函数
1-配置GPIO为具体的第二功能
void GPIO_PinAFConfig(GPIO_TypeDef* GPIOx, uint16_t GPIO_PinSource, uint8_t GPIO_AF)
2-中断配置函数
void USART_ITConfig(USART_TypeDef* USARTx, uint16_t USART_IT,FunctionalState NewState)
3-串口使能函数
void USART_Cmd(USART_TypeDef* USARTx,FunctionalState NewState)
4-数据发送函数
void USART_SendData(USART_TypeDef* USARTx, uint16_t Data)
5-数据接收函数
uint16_t USART_ReceiveData(USART_TypeDef* USARTx)
6-中断状态位获取函数
ITStatus USART_GetITStatus(USART_TypeDef* USARTx, uint16_t USART_IT)
五、一些结构体
USART初始化结构体
typedef struct
{undefined
uint32_t USART_BaudRate; //波特率 BRR
uint16_t USART_WordLength; //字长 CR1_M
uint16_t USART_StopBits; //停止位 CR2_STOP
uint16_t USART_Parity; //校验控制 CR1_PCE、 CR1_PS
uint16_t USART_Mode; //模式选择CR1_TE、 CR1_RE
// 硬件流选择 CR3_CTSE、 CR3_RTSE
uint16_t USART_HardwareFlowControl;
} USART_InitTypeDef;
同步时钟初始化结构体
typedef struct
{undefined
uint16_t USART_Clock; // 同步时钟 CR2_CLKEN
uint16_t USART_CPOL; // 极性 CR2_CPOL
uint16_t USART_CPHA; // 相位 CR2_CPHA
uint16_t USART_LastBit; //最后一个位的时钟脉冲 CR2_LBC
} USART_ClockInitTypeDef;
六、代码片段
#ifndef __BSP_USART_H
#define __BSP_USART_H
/**
******************************************************************************
* @file bsp.usart.c
* @author Sumjess
* @version V1.0
* @date 2019-09-10
* @brief MDK5.27
******************************************************************************
* @attention
*
* 实验平台 :STM32 F429
* CSDN Blog :https://blog.csdn.net/qq_38351824
* 微信公众号 :Tech云
*
******************************************************************************
*/
#include "stm32f4xx.h"
#include <stdio.h>
//---------------------------------------------------------------------------------------------//
// STM32F429IGT6 芯片的 USART 引脚
// APB2(最高 90MHz) APB1(最高 45MHz)
// USART1 USART6 USART2 USART3 UART4 UART5 UART7 UART8
//TX PA9/PB6 PC6/PG14 PA2/PD5 PB10/PD8/PC10 PA0/PC10 PC12 PF7/PE8 PE1
//RX PA10/PB7 PC7/PG9 PA3/PD6 PB11/PD9/PC11 PA1/PC11 PD2 PF6/PE7 PE0
//SCLK PA8 PG7/PC8 PA4/PD7 PB12/PD10/PC12
//nCTS PA11 PG13/PG15 PA0/PD3 PB13/PD11
//nRTS PA12 PG8/PG12 PA1/PD4 PB14/PD12
/
//------------------------------------------------------//
//串口1中断开关
/*******************************************************/
#define EXTI_KEY 0
/
//串口开关
/*******************************************************/
#define USART1_Switch 1
#define USART2_Switch 1
#define USART3_Switch 1
#define UART4_Switch 1
#define UART5_Switch 1
#define USART6_Switch 1
#define UART7_Switch 1
#define UART8_Switch 1
//!!!USART和UART区别:USART即可以同步通信,又可以异步通信;
// UART 只能异步通信;
// SCLK、nCTS、nRTS这些引脚UART没有。
//
//① 重定向c库函数printf到串口,重定向后可使用printf等函数
//② 重定向c库函数scanf到串口,重写向后可使用scanf、getchar等函数
//选择使用串口被允许使用 ① ②
#define DEBUG_USART_printf_choose DEBUG_USART1
//
//------------------------------------------------------//
//引脚定义
/*******************************************************/
#if USART1_Switch
#define DEBUG_USART1 USART1
#define DEBUG_USART1_CLK RCC_APB2Periph_USART1 //注意!只有串口1和6是APB2为90M,其他均为APB1为45M
#define DEBUG_USART1_BAUDRATE 115200 //串口波特率
#define DEBUG_USART1_RX_GPIO_PORT GPIOA
#define DEBUG_USART1_RX_GPIO_CLK RCC_AHB1Periph_GPIOA
#define DEBUG_USART1_RX_PIN GPIO_Pin_10
#define DEBUG_USART1_RX_AF GPIO_AF_USART1 //映射
#define DEBUG_USART1_RX_SOURCE GPIO_PinSource10
//!!!一个引脚有许多功能,通过映射将引脚与你要选的功能连接起来。
#define DEBUG_USART1_TX_GPIO_PORT GPIOA
#define DEBUG_USART1_TX_GPIO_CLK RCC_AHB1Periph_GPIOA
#define DEBUG_USART1_TX_PIN GPIO_Pin_9
#define DEBUG_USART1_TX_AF GPIO_AF_USART1 //映射
#define DEBUG_USART1_TX_SOURCE GPIO_PinSource9
//中断部分配置//
#define DEBUG_USART_IRQHandler USART1_IRQHandler
#define DEBUG_USART_IRQ USART1_IRQn //串口1中断
#endif
#if USART2_Switch
/************************************************************/
//串口2引脚定义
/*******************************************************/
#define DEBUG_USART2 USART2
#define DEBUG_USART2_CLK RCC_APB1Periph_USART2
#define DEBUG_USART2_BAUDRATE 115200 //串口波特率
#define DEBUG_USART2_RX_GPIO_PORT GPIOD
#define DEBUG_USART2_RX_GPIO_CLK RCC_AHB1Periph_GPIOD
#define DEBUG_USART2_RX_PIN GPIO_Pin_6
#define DEBUG_USART2_RX_AF GPIO_AF_USART2 //映射
#define DEBUG_USART2_RX_SOURCE GPIO_PinSource6
//!!!一个引脚有许多功能,通过映射将引脚与你要选的功能连接起来。
#define DEBUG_USART2_TX_GPIO_PORT GPIOD
#define DEBUG_USART2_TX_GPIO_CLK RCC_AHB1Periph_GPIOD
#define DEBUG_USART2_TX_PIN GPIO_Pin_5
#define DEBUG_USART2_TX_AF GPIO_AF_USART2 //映射
#define DEBUG_USART2_TX_SOURCE GPIO_PinSource5
#endif
#if USART3_Switch
/************************************************************/
//串口3引脚定义
/*******************************************************/
#define DEBUG_USART3 USART3
#define DEBUG_USART3_CLK RCC_APB1Periph_USART3
#define DEBUG_USART3_BAUDRATE 115200 //串口波特率
#define DEBUG_USART3_RX_GPIO_PORT GPIOB
#define DEBUG_USART3_RX_GPIO_CLK RCC_AHB1Periph_GPIOB
#define DEBUG_USART3_RX_PIN GPIO_Pin_11
#define DEBUG_USART3_RX_AF GPIO_AF_USART3 //映射
#define DEBUG_USART3_RX_SOURCE GPIO_PinSource11
//!!!一个引脚有许多功能,通过映射将引脚与你要选的功能连接起来。
#define DEBUG_USART3_TX_GPIO_PORT GPIOB
#define DEBUG_USART3_TX_GPIO_CLK RCC_AHB1Periph_GPIOB
#define DEBUG_USART3_TX_PIN GPIO_Pin_10
#define DEBUG_USART3_TX_AF GPIO_AF_USART3 //映射
#define DEBUG_USART3_TX_SOURCE GPIO_PinSource10
#endif
#if UART4_Switch
/************************************************************/
//串口4引脚定义
/*******************************************************/
#define DEBUG_UART4 UART4
#define DEBUG_UART4_CLK RCC_APB1Periph_UART4
#define DEBUG_UART4_BAUDRATE 115200 //串口波特率
#define DEBUG_UART4_RX_GPIO_PORT GPIOC
#define DEBUG_UART4_RX_GPIO_CLK RCC_AHB1Periph_GPIOC
#define DEBUG_UART4_RX_PIN GPIO_Pin_11
#define DEBUG_UART4_RX_AF GPIO_AF_UART4 //映射
#define DEBUG_UART4_RX_SOURCE GPIO_PinSource11
//!!!一个引脚有许多功能,通过映射将引脚与你要选的功能连接起来。
#define DEBUG_UART4_TX_GPIO_PORT GPIOC
#define DEBUG_UART4_TX_GPIO_CLK RCC_AHB1Periph_GPIOC
#define DEBUG_UART4_TX_PIN GPIO_Pin_10
#define DEBUG_UART4_TX_AF GPIO_AF_UART4 //映射
#define DEBUG_UART4_TX_SOURCE GPIO_PinSource10
#endif
#if UART5_Switch
/************************************************************/
//串口5引脚定义
/*******************************************************/
#define DEBUG_UART5 UART5
#define DEBUG_UART5_CLK RCC_APB1Periph_UART5
#define DEBUG_UART5_BAUDRATE 115200 //串口波特率
#define DEBUG_UART5_RX_GPIO_PORT GPIOD
#define DEBUG_UART5_RX_GPIO_CLK RCC_AHB1Periph_GPIOD
#define DEBUG_UART5_RX_PIN GPIO_Pin_2
#define DEBUG_UART5_RX_AF GPIO_AF_UART5 //映射
#define DEBUG_UART5_RX_SOURCE GPIO_PinSource2
//!!!一个引脚有许多功能,通过映射将引脚与你要选的功能连接起来。
#define DEBUG_UART5_TX_GPIO_PORT GPIOC
#define DEBUG_UART5_TX_GPIO_CLK RCC_AHB1Periph_GPIOC
#define DEBUG_UART5_TX_PIN GPIO_Pin_12
#define DEBUG_UART5_TX_AF GPIO_AF_UART5 //映射
#define DEBUG_UART5_TX_SOURCE GPIO_PinSource12
#endif
#if USART6_Switch
/************************************************************/
//串口6引脚定义
/*******************************************************/
#define DEBUG_USART6 USART6
#define DEBUG_USART6_CLK RCC_APB2Periph_USART6 //注意!只有串口1和6是APB2为90M,其他均为APB1为45M
#define DEBUG_USART6_BAUDRATE 115200 //串口波特率
#define DEBUG_USART6_RX_GPIO_PORT GPIOC
#define DEBUG_USART6_RX_GPIO_CLK RCC_AHB1Periph_GPIOC
#define DEBUG_USART6_RX_PIN GPIO_Pin_7
#define DEBUG_USART6_RX_AF GPIO_AF_USART6 //映射
#define DEBUG_USART6_RX_SOURCE GPIO_PinSource7
//!!!一个引脚有许多功能,通过映射将引脚与你要选的功能连接起来。
#define DEBUG_USART6_TX_GPIO_PORT GPIOC
#define DEBUG_USART6_TX_GPIO_CLK RCC_AHB1Periph_GPIOC
#define DEBUG_USART6_TX_PIN GPIO_Pin_6
#define DEBUG_USART6_TX_AF GPIO_AF_USART6 //映射
#define DEBUG_USART6_TX_SOURCE GPIO_PinSource6
#endif
#if UART7_Switch
/************************************************************/
//串口7引脚定义
/*******************************************************/
#define DEBUG_UART7 UART7
#define DEBUG_UART7_CLK RCC_APB1Periph_UART7
#define DEBUG_UART7_BAUDRATE 115200 //串口波特率
#define DEBUG_UART7_RX_GPIO_PORT GPIOF
#define DEBUG_UART7_RX_GPIO_CLK RCC_AHB1Periph_GPIOF
#define DEBUG_UART7_RX_PIN GPIO_Pin_6
#define DEBUG_UART7_RX_AF GPIO_AF_UART7 //映射
#define DEBUG_UART7_RX_SOURCE GPIO_PinSource6
//!!!一个引脚有许多功能,通过映射将引脚与你要选的功能连接起来。
#define DEBUG_UART7_TX_GPIO_PORT GPIOF
#define DEBUG_UART7_TX_GPIO_CLK RCC_AHB1Periph_GPIOF
#define DEBUG_UART7_TX_PIN GPIO_Pin_7
#define DEBUG_UART7_TX_AF GPIO_AF_UART7 //映射
#define DEBUG_UART7_TX_SOURCE GPIO_PinSource7
#endif
#if UART8_Switch
/************************************************************/
//串口8引脚定义
/*******************************************************/
#define DEBUG_UART8 UART8
#define DEBUG_UART8_CLK RCC_APB1Periph_UART8
#define DEBUG_UART8_BAUDRATE 115200 //串口波特率
#define DEBUG_UART8_RX_GPIO_PORT GPIOE
#define DEBUG_UART8_RX_GPIO_CLK RCC_AHB1Periph_GPIOE
#define DEBUG_UART8_RX_PIN GPIO_Pin_0
#define DEBUG_UART8_RX_AF GPIO_AF_UART8 //映射
#define DEBUG_UART8_RX_SOURCE GPIO_PinSource0
//!!!一个引脚有许多功能,通过映射将引脚与你要选的功能连接起来。
#define DEBUG_UART8_TX_GPIO_PORT GPIOE
#define DEBUG_UART8_TX_GPIO_CLK RCC_AHB1Periph_GPIOE
#define DEBUG_UART8_TX_PIN GPIO_Pin_1
#define DEBUG_UART8_TX_AF GPIO_AF_UART8 //映射
#define DEBUG_UART8_TX_SOURCE GPIO_PinSource1
#endif
/*****************************************串口相关函数***************************************/
void Debug_USART_Config(void); //串口初始化
void Usart_SendByte( USART_TypeDef * pUSARTx, uint8_t ch); //发送一个字符
void Usart_SendHalfWord( USART_TypeDef * pUSARTx, uint16_t ch);//发送一个16位数
void Usart_SendString( USART_TypeDef * pUSARTx, char *str); //发送字符串
int fputc(int ch, FILE *f); //重定向c库函数printf到串口,重定向后可使用printf函数
int fgetc(FILE *f); //重定向c库函数scanf到串口,重写向后可使用scanf、getchar等函数
#endif /* __BSP_DEBUG_USART_H */
七、USART 中断请求
中断事件 | 事件标志 | 使能控制位 |
发送数据寄存器为空 | TXE | TXEIE |
CTS 标志 | CTS | CTSIE |
发送完成 | TC | TCIE |
准备好读取接收到的数据 | RXNE | RXNEIE |
检测到上溢错误 | ORE | |
检测到空闲线路 | IDLE | IDLEIE |
奇偶校验错误 | PE | PEIE |
断路标志 | LBD | LBDIE |
多缓冲区通信中的噪声标志、上溢错误和帧错误 | NF 或 ORE 或 FE | EIE |
八、常用函数总结
(1)发送字符串
/***************** 发送字符串 **********************/
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)
{}
}
(2)发送一个字符
/***************** 发送一个字符 **********************/
void Usart_SendByte( USART_TypeDef * pUSARTx, uint8_t ch)
{
/* 发送一个字节数据到USART */
USART_SendData(pUSARTx,ch);
/* 等待发送数据寄存器为空 */
while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);
}
(3)发送一个16位数
/***************** 发送一个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);
}
(4)字符接收函数
//字符接收函数:
//uint8_t Usart_Sum_rec( USART_TypeDef * pUSARTx, uint8_t * rev)
//返回值:1为获取数据成功 0为获取数据失败
//USART_TypeDef * pUSARTx 选择串口输出,注意必须先初始化、使能该串口
//uint8_t * rev 利用指针获取数据
uint8_t Usart_Sum_rec( USART_TypeDef * pUSARTx, uint8_t * rev)
{
if(USART_GetFlagStatus(pUSARTx,USART_FLAG_RXNE)!=RESET)
{
*rev = USART_ReceiveData(pUSARTx);
Delay_ms(1);
return 1;
}
return 0;
}
评论(0)
您还未登录,请登录后发表或查看评论