代码改变世界

STM32-IO引脚复用-原理和使用

2022-01-12 00:59  jym蒟蒻  阅读(2421)  评论(0编辑  收藏  举报

1.什么是端口复用?

STM32有很多的内置外设(把一些功能ADC\看门狗…集中到芯片里面),这些外设的外部引脚都是与GPIO复用的。也就是说,一个GPIO如果可以复用为内置外设的功能引脚,那么当这个GPIO作为内置外设使用的时候,就叫做复用。

例如串口1 的发送接收引脚是PA9,PA10,当我们把PA9,PA10不用作GPIO,而用做复用功能串口1的发送接收引脚的时候,叫端口复用。

2.STM32引脚可以复用为哪些功能?

可在芯片STM32767IGT6资料中的pin and ball definitions中找到:

在这里插入图片描述

STM32(M4内核以上)的端口复用映射原理

STM32系列微控制器IO引脚通过一个复用器连接到内置外设或模块。该复用器一次只允许一个外设的复用功能(AF)连接到对应的IO口。这样可以确保共用同一个IO引脚的外设之间不会发生冲突。

每个IO引脚都有一个复用器,该复用器采用16路复用功能输入(AF0到AF15),可通过GPIOx_AFRL(针对引脚0-7)和GPIOx_AFRH(针对引脚8-15)寄存器对这些输入进行配置,每四位控制一路复用。

在这里插入图片描述

对于每一组GPIO都有GPIO 复用功能低位寄存器 (GPIOx_AFRL) (x = A…K):比如GPIOA有16个IO口,GPIOx_AFRL是32位,可以配置引脚0-7。

GPIOx_AFRL寄存器:

在这里插入图片描述

GPIO 复用功能高位寄存器 (GPIOx_AFRH) (x = A…J):

在这里插入图片描述

在这里插入图片描述

比如配置PA9连接到AF7,那么就是配置GPIOA_AFRH的AFR9,配置成0111 。

3.复用功能配置:

1.系统功能:将I/O连接到AF0,然后根据所用功能进行配置:

  • JTAG/SWD:在各器件复位之后,会将这些引脚指定为专用引脚,可供片上调试模块立即使用 (不受GPIO控制器控制)
  • RTC_REFIN:此引脚应配置为输入浮空模式。
  • MCO1和MCO2:这些引脚必须配置为复用功能模式。

2.GPIO:在GPIOx_MODER寄存器中将所需I/O配置为输出或输入。

3.外设复用功能:

对于ADC和DAC,在GPIOx_MODER寄存器中将所需I/O配置为模拟通道。对于其它外设:

  • 在GPIOx_MODER寄存器中将所需I/O配置为复用功能
  • 通过GPIOx_OTYPER、GPIOx_PUPDR和GPIOx_OSPEEDER寄存器,分别选择类型、上拉/下拉以及输出速度。
  • 在GPIOx_AFRL或GPIOx_AFRH寄存器中,将I/O连接到所需AFx

4.端口复用功能配置过程

以PA9、PA10配置为串口1为例:

1.GPIO端口时钟使能。
__HAL_RCC_GPIOA_CLK_ENABLE(); //使能GPIO时钟

2.复用外设时钟使能。
比如你要将端口PA9,PA10复用为串口,所以要使能串口时钟。
__HAL_RCC_USART1_CLK_ENABLE(); //使能串口1时钟

3.端口模式配置为复用功能。 HAL_GPIO_Init函数。
GPIO_Initure.Mode=GPIO_MODE_AF_PP; //复用推挽输出

4.配置GPIOx_AFRL或者GPIOx_AFRH寄存器,将IO连接到所需的AFx。HAL_GPIO_Init函数。

GPIO_Initure.Alternate=GPIO_AF7_USART1;//复用为USART1

在文件system-usart.c中可以找到:HAL_UART_MspInit

void HAL_UART_MspInit(UART_HandleTypeDef *huart)
{
    //GPIO端口设置
	GPIO_InitTypeDef GPIO_Initure;
	
	if(huart->Instance==USART1)//如果是串口1,进行串口1 MSP初始化
	{
		__HAL_RCC_GPIOA_CLK_ENABLE();			//使能GPIOA时钟
		__HAL_RCC_USART1_CLK_ENABLE();			//使能USART1时钟
	
		GPIO_Initure.Pin=GPIO_PIN_9;			//PA9
		GPIO_Initure.Mode=GPIO_MODE_AF_PP;		//复用推挽输出
		GPIO_Initure.Pull=GPIO_PULLUP;			//上拉
		GPIO_Initure.Speed=GPIO_SPEED_FAST;		//高速
		GPIO_Initure.Alternate=GPIO_AF7_USART1;	//复用为USART1
		HAL_GPIO_Init(GPIOA,&GPIO_Initure);	   	//初始化PA9

		GPIO_Initure.Pin=GPIO_PIN_10;			//PA10
		HAL_GPIO_Init(GPIOA,&GPIO_Initure);	   	//初始化PA10
		
#if EN_USART1_RX
		HAL_NVIC_EnableIRQ(USART1_IRQn);				//使能USART1中断通道
		HAL_NVIC_SetPriority(USART1_IRQn,3,3);			//抢占优先级3,子优先级3
#endif	
	}

}