特别注意:两个设备之间的TXD和RXD,必须交差连接,方可正常通信
实现串口通信的外设:Universal Synchronous asynchronous receiver transmitter,通用同步异步收发器。
Universal asynchronous receiver transmitter,通用异步收发器。
USART/UART都可以与外设进行全双工(同时接收或发送数据)异步(无时钟信号)通信。
1,全双工异步通信
2,单线半双工通信
3,单独的发送器和接收器使能位
4,可配置使用DMA的多缓冲器通信
5, 多个带标志的中断源
波特率计算公式:
其中fck是串口的时钟,如:USART1的时钟是PCLK2,其他串口都是PCLK1
波特比率寄存器BRR
把USARTDIV的整数部分写入位[15:4], USARTDIV的小数部分写入[3:0]
uint16_t mantissa;
uint16_t fraction;
mantissa=39;
fraction=0.0625*16+0.5=0x01; /* USARTDIV = DIV_Mantissa + (DIV_Fraction/16) +0.5是四舍五入*/
USART1->BRR = (mantissa << 4) + fraction;
控制寄存器1(CR1)
该寄存器需要完成的配置:
位13:使能USART
位12:配置8个数据位
位10:禁止检验控制
位5:使能接收缓冲区非空中断
位3:使能发送
位2:使能接收
控制寄存器2(CR2)
控制寄存器3(CR3)
数据寄存器(DR)
设置好控制寄存器和波特率寄存器后,往该寄存器写入数据即可发送,接收数据则读该寄存器。
HAL_StatusTypeDef HAL_UART_Init(UART_HandleTypeDef *huart)
typedef struct
{ uint32_t BaudRate; /* 波特率 */
uint32_t WordLength; /* 字长 */
uint32_t StopBits; /* 停止位 */
uint32_t Parity; /* 奇偶校验位 */
uint32_t Mode; /* UART 模式 */
uint32_t HwFlowCtl; /* 硬件流设置 */
uint32_t OverSampling; /* 过采样设置 */
}UART_InitTypeDef
typedef enum
{
HAL_OK = 0x00U,
HAL_ERROR = 0x01U,
HAL_BUSY = 0x02U,
HAL_TIMEOUT = 0x03U
} HAL_StatusTypeDef;
typedef struct
{
__IO uint32_t SR; /*!< USART Status register, Address offset: 0x00 */
__IO uint32_t DR; /*!< USART Data register, Address offset: 0x04 */
__IO uint32_t BRR; /*!< USART Baud rate register, Address offset: 0x08 */
__IO uint32_t CR1; /*!< USART Control register 1, Address offset: 0x0C */
__IO uint32_t CR2; /*!< USART Control register 2, Address offset: 0x10 */
__IO uint32_t CR3; /*!< USART Control register 3, Address offset: 0x14 */
__IO uint32_t GTPR; /*!< USART Guard time and prescaler register, Address offset: 0x18 */
} USART_TypeDef;
HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart,
uint8_t *pData, uint16_t Size)
HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart,
uint8_t *pData, uint16_t Size, uint32_t Timeout)
同一时间IO只能用作一种复用功能,否则会发生冲突,遇到IO复用功能冲突,可考虑重映射功能。
为了解决F1系列存在的IO复用功能冲突问题,F4往后的系列都加入了复用器。
复用器特点:
PA9对应的是TXD,连接的是RXD。
PA10对应的是RXD,连接的是TXD。
输出不用设置上下拉,输入不用设置速度。
因为空闲的时候是高电平,所以输入设置为上拉。
usart.h
#ifndef __USART_H_
#define __USART_H_
//当有一个变量需要在多个文件中用到时,不能定义在头文件中,会导致重复定义,要把该变量定义在某个.c文件中,另一个需要用到该变量的.c文件在该变量的声明前加extern
extern UART_HandleTypeDef UART1_Handler;
extern u16 USART_RX_STA;
#define RXBUFFERSIZE 1
extern u8 aRxBuffer[RXBUFFERSIZE];
usart.c
u16 USART_RX_STA=0;//接收状态标记
UART_HandleTypeDef UART1_Handler;/*UART串口句柄*/
u8 aRxBuffer[RXBUFFERSIZE];//HAL库使用的串口接收缓冲区
void usart_init(uint32_t baudrate)
{
UART1_Handler.Instance = USART1; //寄存器基地址
UART1_Handler.Init.BaudRate = baudrate;
UART1_Handler.Init.WordLength = UART_WORDLENGTH_8B;
UART1_Handler.Init.StopBits = UART_STOPBITS_1;
UART1_Handler.Init.Parity = UART_PARITY_NONE;
UART1_Handler.Init.Mode = UART_MODE_TX_RX;
HAL_UART_Init(&UART1_Handler);
//开启串口接收中断
HAL_UART_Receive_IT(&UART1_Handler,(u8 *)aRxBuffer,RXBUFFERSIZE)
}
//串口初始化MSP回调函数
void HAL_UART_MspInit(UART_HandleTypeDef *huart)
{
//GPIO端口设置
GPIO_InitTypeDef GPIO_Initure;
if(huart->Instance == USART1)
{
//使能USART和对应IO时钟
__HAL_RCC_USART1_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_AFIO_CLK_ENABLE();
//初始化IO
GPIO_Initure.Pin = GPIO_PIN_9;
GPIO_Initure.Mode = GPIO_MODE_AF_PP;//不能使用开漏式,因为不能使用高电平,除非有外部上拉,输出不需要上下拉
GPIO_Initure.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOA,&GPIO_Initure);
GPIO_Initure.Pin = GPIO_PIN_10;
GPIO_Initure.Mode = GPIO_MODE_AF_INPUT;
GPIO_Initure.Pull = GPIO_NOPULL;//默认状态是高电平,所以要上拉
HAL_GPIO_Init(GPIOA,&GPIO_Initure);
//使能USART1中断,设置优先级
HAL_NVIC_EnableIRQ(USART1_IRQn);
HAL_NVIC_SetPriority(USART1_IRQn,3,3);
}
}
/*串口1中断服务函数*/
void USART1_IRQHandler(void)
{
HAL_UART_IRQHandler(&UART1_Handler);//失能中断,并且会调用Callback函数
HAL_UART_Receive_IT(&UART1_Handler,(u8 *)aRxBuffer,RXBUFFERSIZE);
}
//串口数据接收完成回调函数
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
}