网上一搜关于STM32的串口复用帖子挺多的,但是都是讲的GPIO复用成为UART的IO,怎么去设置不同的IO复用在UART上,很少又帖子设计,可能是我基础太差了,不知道这个到底怎么搞得,用CubeMX生成的工程实际查了一下,希望能有帮助
1. 在配置串口的时候,大概是这样的
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_PIN_10;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF7_USART1;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/* USER CODE BEGIN USART1_MspInit 1 */
/* USER CODE END USART1_MspInit 1 */
}
else if(huart->Instance==USART2)
{
/* USER CODE BEGIN USART2_MspInit 0 */
/* USER CODE END USART2_MspInit 0 */
/* Peripheral clock enable */
__HAL_RCC_USART2_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
/**USART2 GPIO Configuration
PA2 ------> USART2_TX
PA3 ------> USART2_RX
*/
GPIO_InitStruct.Pin = GPIO_PIN_2|GPIO_PIN_3;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF7_USART2;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/* USER CODE BEGIN USART2_MspInit 1 */
/* USER CODE END USART3_MspInit 1 */
}else if(huart->Instance==UART4)
{
/* USER CODE BEGIN UART4_MspInit 0 */
/* USER CODE END USART3_MspInit 0 */
/* Peripheral clock enable */
__HAL_RCC_UART4_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
/**UART4 GPIO Configuration
PA11 ------> UART4_RX
PA12 ------> UART4_TX
*/
GPIO_InitStruct.Pin = GPIO_PIN_11|GPIO_PIN_12;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF6_UART4;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/* USER CODE BEGIN UART4_MspInit 1 */
/* USER CODE END UART4_MspInit 1 */
}
}
流程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发现了例如
#define GPIO_AF7_USART1 ((uint8_t)0x07U)
#define GPIO_AF4_USART1 ((uint8_t)0x04)
#define GPIO_AF8_UART4 ((uint8_t)0x08U)
#define GPIO_AF6_UART4 ((uint8_t)0x06U)
为什么这样设置,为什么没有设置成为另外的两个宏呢,不用查看手册我们可以直接猜想到这和复用的引脚有关系,不同的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的初始化为
void HAL_UART_MspInit(UART_HandleTypeDef* huart)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
if(huart->Instance==UART4)
{
/* USER CODE BEGIN UART4_MspInit 0 */
/* USER CODE END UART4_MspInit 0 */
/* Peripheral clock enable */
__HAL_RCC_UART4_CLK_ENABLE();
__HAL_RCC_GPIOI_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
/**UART4 GPIO Configuration
PI9 ------> UART4_RX
PA0/WKUP ------> UART4_TX
*/
GPIO_InitStruct.Pin = GPIO_PIN_9;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF8_UART4;
HAL_GPIO_Init(GPIOI, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_0;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF8_UART4;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/* USER CODE BEGIN UART4_MspInit 1 */
/* USER CODE END UART4_MspInit 1 */
}
}
在UART4复用在PA11 PA12上的工程中UART4的初始化为
void HAL_UART_MspInit(UART_HandleTypeDef* huart)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
if(huart->Instance==UART4)
{
/* USER CODE BEGIN UART4_MspInit 0 */
/* USER CODE END UART4_MspInit 0 */
/* Peripheral clock enable */
__HAL_RCC_UART4_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
/**UART4 GPIO Configuration
PA11 ------> UART4_RX
PA12 ------> UART4_TX
*/
GPIO_InitStruct.Pin = GPIO_PIN_11|GPIO_PIN_12;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF6_UART4;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/* USER CODE BEGIN UART4_MspInit 1 */
/* USER CODE END UART4_MspInit 1 */
}
}
可以看出,不同的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),那么又不能用了,会造成玄学结果
|
|
2021-11-25 14:53:35
评论
举报
|
|
|