串口简介
串口最基本的设置,就是波特率的设置。首先要开启时钟,并设置相应的IO口模式,然后配置一下波特率,数据位长度,奇偶校验位等信息就可以用了。
1.串口时钟使能
串口作为STM32的一个外设,其时钟由外设时钟使能寄存器控制,在stm32f103中串口1是在APB2ENR寄存器的第14位,除了串口 1 的时钟使能在 APB2ENR 寄存器,其他串口的时钟使能位都在 APB1ENR 寄存器,而 APB2(72M)的频率一般是 APB1(36M)的一倍。
2.串口复位
当外设出现异常的时候可以通过复位寄存器里面的相应位设置,实现外设的复位。然后重新配置这个外设达到重新工作的目的。串口的复位是通过APB2RSTR寄存器的第14位来实现的,该寄存器的各位描述如下图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RivCI9DO-1628243635775)(C:\Users\zkhy\AppData\Roaming\Typora\typora-user-images\image-20210805112946240.png)]
3.波特率设置,每个串口都有一个自己独立的波特率寄存器USART_BRR,通过该寄存器就可以达到配置不同波特率的目的。
4.串口控制。STM32的每个串口都有3个控制寄存器USART_CR 1~3,串口的很多配置都是通过这3个寄存器来设置的。
串口的设置一般步骤如下:
1)串口时钟使能,GPIO时钟使能。
2)设置引脚复用器映射:调用GPIO_PinAFConfig函数
3)GPIO初始化设置:设置模式为复用功能
4)串口参数初始化:设置波特率,字长,奇偶校验等参数
5)开启中断并且初始化NVIC,使能中断(如果需要开启中断才需要这样设置)
6)使能串口。
7)编写中断处理函数:函数名格式为USARTxIRQHandler(x,对应串口号)
1.串口参数初始化
我使用的MCU为STM32L073Rz
串口是STM32的一个外设,HAL库有配置有完整的初始化函数,我使用的是STM32cubemx自动配置生成的代码。初始化函数如下:
HAL_StatusTypeDef HAL_UART_Init(UART_HandleTypeDef *huart)
入口参数为huart1,为UART_HandleTypeDef结构体指针类型,也就是串口句柄,结构体成员变量如下:
typedef struct __UART_HandleTypeDef
{
USART_TypeDef *Instance; /*!< UART registers base address */
UART_InitTypeDef Init; /*!< UART communication parameters */
UART_AdvFeatureInitTypeDef AdvancedInit; /*!< UART Advanced Features initialization parameters */
uint8_t *pTxBuffPtr; /*!< Pointer to UART Tx transfer Buffer */
uint16_t TxXferSize; /*!< UART Tx Transfer size */
__IO uint16_t TxXferCount; /*!< UART Tx Transfer Counter */
uint8_t *pRxBuffPtr; /*!< Pointer to UART Rx transfer Buffer */
uint16_t RxXferSize; /*!< UART Rx Transfer size */
__IO uint16_t RxXferCount; /*!< UART Rx Transfer Counter */
uint16_t Mask; /*!< UART Rx RDR register mask */
__IO HAL_UART_RxTypeTypeDef ReceptionType; /*!< Type of ongoing reception */
void (*RxISR)(struct __UART_HandleTypeDef *huart); /*!< Function pointer on Rx IRQ handler */
void (*TxISR)(struct __UART_HandleTypeDef *huart); /*!< Function pointer on Tx IRQ handler */
DMA_HandleTypeDef *hdmatx; /*!< UART Tx DMA Handle parameters */
DMA_HandleTypeDef *hdmarx; /*!< UART Rx DMA Handle parameters */
HAL_LockTypeDef Lock; /*!< Locking object */
__IO HAL_UART_StateTypeDef gState; /*!< UART state information related to global Handle management
and also related to Tx operations. This parameter
can be a value of @ref HAL_UART_StateTypeDef */
__IO HAL_UART_StateTypeDef RxState; /*!< UART state information related to Rx operations. This
parameter can be a value of @ref HAL_UART_StateTypeDef */
__IO uint32_t ErrorCode; /*!< UART Error code */
} UART_HandleTypeDef;
这些结构体成员变量非常多,一般配置的时候采用定义一个结构体变量来进行初始化,代码如下:
UART_HandleTypeDef huart1;
/* USART1 init function */
void MX_USART1_UART_Init(void)
{
huart1.Instance = USART1;
huart1.Init.BaudRate = 115200;
huart1.Init.WordLength = UART_WORDLENGTH_8B;
huart1.Init.StopBits = UART_STOPBITS_1;
huart1.Init.Parity = UART_PARITY_NONE;
huart1.Init.Mode = UART_MODE_TX_RX;
huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart1.Init.OverSampling = UART_OVERSAMPLING_16;
huart1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
huart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
if (HAL_UART_Init(&huart1) != HAL_OK)
{
Error_Handler();
}
}
2.使能串口和GPIO时钟
要使用串口,一定要使能串口和GPIO的时钟,不然不会工作。
__HAL_RCC_USART1_CLK_ENABLE();//使能USART1时钟
__HAL_RCC_GPIOB_CLK_ENABLE();//使能GPIOB时钟
3.GPIO口的初始化设置
我这里的是PB6和PB7分别为RX和TX口。
void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
if(uartHandle->Instance==USART1)
{
/* USART1 clock enable */
__HAL_RCC_USART1_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
GPIO_InitStruct.Pin = GPIO_PIN_6|GPIO_PIN_7;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF0_USART1;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/* USART1 interrupt Init */
HAL_NVIC_SetPriority(USART1_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(USART1_IRQn);
}
}
3.开启串口相关中断,配置串口中断优先级
这个我的是在cubemx里面配置好自动生成的,也就是上面函数的最后两行,中断优先级为0,设置的最高
4.编写中断服务函数
void USART1_IRQHandler(void)
{
/* USER CODE BEGIN USART1_IRQn 0 */
/* USER CODE END USART1_IRQn 0 */
HAL_UART_IRQHandler(&huart1);
/* USER CODE BEGIN USART1_IRQn 1 */
/* USER CODE END USART1_IRQn 1 */
}
未完待续。。。。。。