飞道的博客

STM32的UART复用问题

370人阅读  评论(0)

 网上一搜关于STM32的串口复用帖子挺多的,但是都是讲的GPIO复用成为UART的IO,怎么去设置不同的IO复用在UART上,很少又帖子设计,可能是我基础太差了,不知道这个到底怎么搞得,用CubeMX生成的工程实际查了一下,希望能有帮助

1. 在配置串口的时候,大概是这样的


   
  1. void HAL_UART_MspInit(UART_HandleTypeDef* huart)
  2. {
  3. GPIO_InitTypeDef GPIO_InitStruct = { 0};
  4. if(huart->Instance==USART1)
  5. {
  6. /* USER CODE BEGIN USART1_MspInit 0 */
  7. /* USER CODE END USART1_MspInit 0 */
  8. /* Peripheral clock enable */
  9. __HAL_RCC_USART1_CLK_ENABLE();
  10. __HAL_RCC_GPIOA_CLK_ENABLE();
  11. /**USART1 GPIO Configuration
  12. PA9 ------> USART1_TX
  13. PA10 ------> USART1_RX
  14. */
  15. GPIO_InitStruct.Pin = GPIO_PIN_9|GPIO_PIN_10;
  16. GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
  17. GPIO_InitStruct.Pull = GPIO_NOPULL;
  18. GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
  19. GPIO_InitStruct.Alternate = GPIO_AF7_USART1;
  20. HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
  21. /* USER CODE BEGIN USART1_MspInit 1 */
  22. /* USER CODE END USART1_MspInit 1 */
  23. }
  24. else if(huart->Instance==USART2)
  25. {
  26. /* USER CODE BEGIN USART2_MspInit 0 */
  27. /* USER CODE END USART2_MspInit 0 */
  28. /* Peripheral clock enable */
  29. __HAL_RCC_USART2_CLK_ENABLE();
  30. __HAL_RCC_GPIOA_CLK_ENABLE();
  31. /**USART2 GPIO Configuration
  32. PA2 ------> USART2_TX
  33. PA3 ------> USART2_RX
  34. */
  35. GPIO_InitStruct.Pin = GPIO_PIN_2|GPIO_PIN_3;
  36. GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
  37. GPIO_InitStruct.Pull = GPIO_NOPULL;
  38. GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
  39. GPIO_InitStruct.Alternate = GPIO_AF7_USART2;
  40. HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
  41. /* USER CODE BEGIN USART2_MspInit 1 */
  42. /* USER CODE END USART3_MspInit 1 */
  43. } else if(huart->Instance==UART4)
  44. {
  45. /* USER CODE BEGIN UART4_MspInit 0 */
  46. /* USER CODE END USART3_MspInit 0 */
  47. /* Peripheral clock enable */
  48. __HAL_RCC_UART4_CLK_ENABLE();
  49. __HAL_RCC_GPIOA_CLK_ENABLE();
  50. /**UART4 GPIO Configuration
  51. PA11 ------> UART4_RX
  52. PA12 ------> UART4_TX
  53. */
  54. GPIO_InitStruct.Pin = GPIO_PIN_11|GPIO_PIN_12;
  55. GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
  56. GPIO_InitStruct.Pull = GPIO_NOPULL;
  57. GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
  58. GPIO_InitStruct.Alternate = GPIO_AF6_UART4;
  59. HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
  60. /* USER CODE BEGIN UART4_MspInit 1 */
  61. /* USER CODE END UART4_MspInit 1 */
  62. }
  63. }

流程1 就是初始化uart外设的设置中,这个在HAL库中做了封装,直接调用__HAL_RCC_U(S)ARTx_CLK_ENABLE();函数打开对应时钟,不需要像标准库中使用函数打开,查看外设所在总线再使能。2 设置打开IO所在端口时钟  __HAL_RCC_GPIOA_CLK_ENABLE();这个也封装成了宏定义。3 配置IO模式,调用HAL_GPIO_Init函数

 2. 问题在于,我们知道,串口不只可以复用在固定的两个引脚,例如UART4可以复用在PI9做RX,PA0做TX;还可以复用在PA11做RX,PA12做TX;并且我们在stm32f7xx_hal_gpio_ex.h发现了例如


   
  1. #define GPIO_AF7_USART1 ((uint8_t)0x07U)
  2. #define GPIO_AF4_USART1 ((uint8_t)0x04)
  3. #define GPIO_AF8_UART4 ((uint8_t)0x08U)
  4. #define GPIO_AF6_UART4 ((uint8_t)0x06U)

这样的定义,我们在初始化的时候 GPIO_InitStruct.Alternate = GPIO_AF7_USART1;GPIO_InitStruct.Alternate = GPIO_AF6_UART4;为什么这样设置,为什么没有设置成为另外的两个宏呢,不用查看手册我们可以直接猜想到这和复用的引脚有关系,不同的IO对用不同的AFx,这样就可以设置成不同的引脚复用。

 3. 在CubeMX中生成一个实例,我们以UART4为例,设置UART4模式为Asynchronous,在Pinout查看可以看到默认设置在了PI9做RX,PA0做TX,查看IO时发现也可以设置在PA11做RX,PA12TX,点击PA11 PA12这样设置

相对应不同的IO我们分别生成工程,打开其中的stm32f7xx_hal_msp.c文件

在UART4复用在PI9 PA0上的工程中UART4的初始化为


   
  1. void HAL_UART_MspInit(UART_HandleTypeDef* huart)
  2. {
  3. GPIO_InitTypeDef GPIO_InitStruct = { 0};
  4. if(huart->Instance==UART4)
  5. {
  6. /* USER CODE BEGIN UART4_MspInit 0 */
  7. /* USER CODE END UART4_MspInit 0 */
  8. /* Peripheral clock enable */
  9. __HAL_RCC_UART4_CLK_ENABLE();
  10. __HAL_RCC_GPIOI_CLK_ENABLE();
  11. __HAL_RCC_GPIOA_CLK_ENABLE();
  12. /**UART4 GPIO Configuration
  13. PI9 ------> UART4_RX
  14. PA0/WKUP ------> UART4_TX
  15. */
  16. GPIO_InitStruct.Pin = GPIO_PIN_9;
  17. GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
  18. GPIO_InitStruct.Pull = GPIO_NOPULL;
  19. GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
  20. GPIO_InitStruct.Alternate = GPIO_AF8_UART4;
  21. HAL_GPIO_Init(GPIOI, &GPIO_InitStruct);
  22. GPIO_InitStruct.Pin = GPIO_PIN_0;
  23. GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
  24. GPIO_InitStruct.Pull = GPIO_NOPULL;
  25. GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
  26. GPIO_InitStruct.Alternate = GPIO_AF8_UART4;
  27. HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
  28. /* USER CODE BEGIN UART4_MspInit 1 */
  29. /* USER CODE END UART4_MspInit 1 */
  30. }
  31. }

在UART4复用在PA11 PA12上的工程中UART4的初始化为


   
  1. void HAL_UART_MspInit(UART_HandleTypeDef* huart)
  2. {
  3. GPIO_InitTypeDef GPIO_InitStruct = { 0};
  4. if(huart->Instance==UART4)
  5. {
  6. /* USER CODE BEGIN UART4_MspInit 0 */
  7. /* USER CODE END UART4_MspInit 0 */
  8. /* Peripheral clock enable */
  9. __HAL_RCC_UART4_CLK_ENABLE();
  10. __HAL_RCC_GPIOA_CLK_ENABLE();
  11. /**UART4 GPIO Configuration
  12. PA11 ------> UART4_RX
  13. PA12 ------> UART4_TX
  14. */
  15. GPIO_InitStruct.Pin = GPIO_PIN_11|GPIO_PIN_12;
  16. GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
  17. GPIO_InitStruct.Pull = GPIO_NOPULL;
  18. GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
  19. GPIO_InitStruct.Alternate = GPIO_AF6_UART4;
  20. HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
  21. /* USER CODE BEGIN UART4_MspInit 1 */
  22. /* USER CODE END UART4_MspInit 1 */
  23. }
  24. }

可以看出,不同的IO配置对应的AFx值,这里区分就是GPIO_AF6_UART4和GPIO_AF8_UART4

5. 如果配置时设置的IO与GPIO_AFx_UART4值不同,我们可以设想一下,例如UART4IO设置为PA11和PA12,Alternate 的值设置为GPIO_AF8_UART4,那么我们将UART4连接在了PI6和PA0上,但是GPIO时钟使能和IO引脚配置都是PA11和PA12,就会造成UART4不能发送和接受, 如果运气好,恰巧GPIOI的时钟打开了,PI6和PA0有恰巧设置成复用推挽输出,那么还可能正常工作,一旦你写的"bug"被修改来了(没错,我不是针对你,我是针对所有人,写的不是code是bug),那么又不能用了,会造成玄学结果


转载:https://blog.csdn.net/qq_38784061/article/details/105586745
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场