STM32F1与STM32CubeIDE快速入门-USART/UART串口通信 USART/UART串口通信 1、USART介绍 通用同步异步收发器(Universal Synchronous Asynchronous Receiver and Transmitter)是一个串行通信设备,可以灵活地与外部设备进行全双工数据交换。
USART提供了一种灵活的方式,可以与需要行业标准 NRZ 异步串行数据格式的外部设备进行全双工数据交换。 USART使用小数波特率发生器提供非常广泛的波特率范围。
支持同步单向通信和半双工单线通信。 它还支持 LIN(本地互连网络)、智能卡协议和 IrDA(红外数据协会)SIR ENDEC 规范以及调制解调器操作 (CTS/RTS)。 它允许多处理器通信。
在STM32中,还可以通过将DMA用于多缓冲区配置,从而实现高速数据通信。
STM32F103VET6微控制器有三个 USART 和两个 UART,其中 USART1 和时钟来源于 APB2 总线时钟,其最大频率为 72MHz,其他四个的时钟来源于 APB1 总线时钟,其最大频率为 36MHz。UART 只是异步传输功能,所以没有 SCLK、nCTS 和 nRTS 功能引脚。USART的框图如下:
STM32F103VE中UART的引脚如下:
中断控制寄存器如下:
2、HAL的USART/UART使用步骤介绍 1)USART使用步骤
第一步:声明一个 USART_HandleTypeDef 句柄结构(例如 USART_HandleTypeDef husart)
第二步:通过实现 HAL_USART_MspInit() API 来初始化 USART 底层资源:
a)使能 USARTx 接口时钟
b)USART 引脚配置:
启用 USART GPIO 的时钟
将 USART 引脚配置为复用功能上拉
c)如果需要使用中断处理,则需要配置NVIC,通过函数HAL_USART_Transmit_IT和HAL_USART_TransmitReceive_IT实现
配置 USARTx 中断优先级
启用 NVIC USART IRQ 句柄
d)如果需要使用DMA,则通过HAL_USART_Transmit_DMA、HAL_USART_Receive_DMA() 和 HAL_USART_TransmitReceive_DMA()实现:
为 Tx/Rx 通道声明一个 DMA 句柄结构
使能 DMAx 接口时钟
使用所需的 Tx/Rx 参数配置声明的 DMA 句柄结构
配置 DMA Tx/Rx 通道
将初始化的 DMA 句柄关联到 USART DMA Tx/Rx 句柄
为 DMA Tx/Rx 通道上的传输完成中断配置优先级并启用 NVIC
配置 USARTx 中断优先级并启用 NVIC USART IRQ 句柄(用于 DMA 非循环模式下的最后一个字节发送完成检测)
第三步:在 USART_HandleTypeDef实例结构中对波特率、字长、停止位、奇偶校验、硬件流控制和模式(接收器/发送器)进行设置
第四步:通过调用 HAL_USART_Init() 函数初始化 USART 寄存器,
这些 API 还通过调用自定义的 HAL_USART_MspInit(&husart) API 来配置低级硬件 GPIO、时钟、CORTEX 等)
UART与USART的使用步骤类似,在这里就不展开介绍了,请参考HAL参考手册。
3、USART配置 第一步:创建工程 :
第二步:选择芯片
第三步:配置系统时钟
第四步:配置USART
1)配置USART模式
2)配置USART引脚
3)配置USART中断
保存配置并生成代码。
4、USART代码生成与功能实现 配置工程生成的关键代码如下:
1)USART引脚初始化
在main.c文件中:
1 2 3 4 5 6 7 8 9 10 11 12 13 /\*\* \* @brief GPIO Initialization Function \* @param None \* @retval None \*/ static void MX\_GPIO\_Init(void) { /\* GPIO Ports Clock Enable \*/ \_\_HAL\_RCC\_GPIOA\_CLK\_ENABLE(); }
在stm32f10x_hal_msp.c文件中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 /\*\* \* @brief UART MSP Initialization \* This function configures the hardware resources used in this example \* @param huart: UART handle pointer \* @retval None \*/ void HAL\_UART\_MspInit(UART_HandleTypeDef\* huart) { GPIO_InitTypeDef GPIO_InitStruct = {0}; if(huart->Instance==USART1) { /\* USER CODE BEGIN USART1\_MspInit 0 \*/ /\* USER CODE END USART1\_MspInit 0 \*/ /\* Peripheral clock enable \*/ \_\_HAL\_RCC\_USART1\_CLK\_ENABLE(); \_\_HAL\_RCC\_GPIOA\_CLK\_ENABLE(); /\*\*USART1 GPIO Configuration PA9 ------> USART1\_TX PA10 ------> USART1\_RX \*/ GPIO_InitStruct.Pin = GPIO_PIN_9; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; HAL\_GPIO\_Init(GPIOA, &GPIO_InitStruct); GPIO_InitStruct.Pin = GPIO_PIN_10; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull = GPIO_NOPULL; HAL\_GPIO\_Init(GPIOA, &GPIO_InitStruct); /\* USER CODE BEGIN USART1\_MspInit 1 \*/ /\* USER CODE END USART1\_MspInit 1 \*/ } }
2)USART配置初始化
在main.c文件中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 /\*\* \* @brief USART1 Initialization Function \* @param None \* @retval None \*/ static void MX\_USART1\_UART\_Init(void) { /\* USER CODE BEGIN USART1\_Init 0 \*/ /\* USER CODE END USART1\_Init 0 \*/ /\* USER CODE BEGIN USART1\_Init 1 \*/ /\* USER CODE END USART1\_Init 1 \*/ 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; if (HAL\_UART\_Init(&huart1) != HAL_OK) { Error\_Handler(); } /\* USER CODE BEGIN USART1\_Init 2 \*/ /\* USER CODE END USART1\_Init 2 \*/
3)USART中断初始化及中断处理
在main.c文件中:
1 2 3 4 5 6 7 8 9 10 11 /\*\* \* @brief NVIC Configuration. \* @retval None \*/ static void MX\_NVIC\_Init(void) { /\* USART1\_IRQn interrupt configuration \*/ HAL\_NVIC\_SetPriority(USART1_IRQn, 0, 0); HAL\_NVIC\_EnableIRQ(USART1_IRQn); }
在stm32f10x_it.c文件中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 /\*\* \* @brief This function handles USART1 global interrupt. \*/ 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 \*/ }
函数HAL_UART_IRQHandler处理USARTx的中断请求。HAL_UART_IRQHandler完成后,有调用了如下函数:
HAL_UART_TxHalfCpltCallback:半双工发送完成回调
HAL_UART_TxCpltCallback:全双工发送完成回调
HAL_UART_RxHalfCpltCallback:半双工接收完成回调
HAL_UART_RxCpltCallback:全双工接收完成回调
HAL_UART_ErrorCallback:错误回调
HAL_UART_TxRxCpltCallback:接收发送完成回调
注意:这些函数运行于非阻塞模式。
在本次实例中,通过HAL_UART_RxCpltCallback函数实现一个串口回显功能。在stm32f10x_it.c文件中添加代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 /\* USER CODE BEGIN 1 \*/ void HAL\_UART\_RxCpltCallback(UART_HandleTypeDef \*huart) { if (huart->Instance == USART1) { // 发送数据,实现Echo HAL\_UART\_Transmit(&huart1, (uint8_t\*) RX_Buffer, 1, 0xffff); // 重新启动接收中断 HAL\_UART\_Receive\_IT(&huart1, (uint8_t\*) RX_Buffer, 1); } } /\* USER CODE END 1 \*/
4)重定向
有时,为了方便调用stdio.h标准C库中的printf函数,就需要进行输出重定向。由于STM32Cube IDE使用的编译器是arm-noneabi-gcc,所以需要重写int _write(int fd, char *ptr, int len)函数。在main.c文件中添加如下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 /\* USER CODE BEGIN 4 \*/ // 重定向 /\* \* To implement the STDIO functions you need to create \* the \_read and \_write functions and hook them to the \* USART you are using. This example also has a buffered \* read function for basic line editing. \*/ int \_write(int fd, char \*ptr, int len); /\* \* Called by libc stdio fwrite functions \*/ int \_write(int fd, char \*ptr, int len) { int i = 0; /\* \* write "len" of char from "ptr" to file id "fd" \* Return number of char written. \* \* Only work for STDOUT, STDIN, and STDERR \*/ if (fd > 2) { return -1; } while (\*ptr && (i < len)) { HAL\_UART\_Transmit(&huart1, (uint8_t\*) ptr, 1, 100); if (\*ptr == '\n') { HAL\_UART\_Transmit(&huart1, (uint8_t\*) __r_chr, 1, 100); } // 重启接收中断 HAL\_UART\_Receive\_IT(&huart1, (uint8_t\*) RX_Buffer, 1); i++; ptr++; } return i; } /\* USER CODE END 4 \*/
5)调用实现
在main.c文件中,程序调用实现如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 /\*\* \* @brief The application entry point. \* @retval int \*/ int main(void) { /\* USER CODE BEGIN 1 \*/ /\* USER CODE END 1 \*/ /\* MCU Configuration--------------------------------------------------------\*/ /\* Reset of all peripherals, Initializes the Flash interface and the Systick. \*/ HAL\_Init(); /\* USER CODE BEGIN Init \*/ /\* USER CODE END Init \*/ /\* Configure the system clock \*/ SystemClock\_Config(); /\* USER CODE BEGIN SysInit \*/ /\* USER CODE END SysInit \*/ /\* Initialize all configured peripherals \*/ MX\_GPIO\_Init(); MX\_USART1\_UART\_Init(); /\* Initialize interrupts \*/ MX\_NVIC\_Init(); /\* USER CODE BEGIN 2 \*/ // 开启接收中断 HAL\_UART\_Receive\_IT(&huart1, (uint8_t \*)RX_Buffer, 1); /\* USER CODE END 2 \*/ /\* Infinite loop \*/ /\* USER CODE BEGIN WHILE \*/ printf("STM32F103VET6 UART Demo\n"); while (1) { /\* USER CODE END WHILE \*/ HAL\_Delay(1); /\* USER CODE BEGIN 3 \*/ } /\* USER CODE END 3 \*/ }
5、运行结果
文章来源: https://iotsmart.blog.csdn.net/article/details/123263120
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!