嵌入式ARM芯片GPIO复用功能总结

666 阅读4分钟

1 STM32 MP157复用功能表

image.png

1.1 芯片引脚视图

image.png image.png image.png image.png

2 STM32H7端口复用功能表

  • 对于STM32H7,数据手册里面的Table 9. Port A alternate functions开始就是所有端口的 AF 映射表 image.png image.png

2.1 芯片引脚视图

image.png

2.1 STM32H7端口复用案例

  • 以串口 1 为例来讲解配置 GPOPA.9和GPIOA.10口为串口 1 复用功能的一般步骤:
  • 首先,我们要使用 IO 复用功能,必须先打开对应的 IO 时钟和复用功能外设时钟,这里我们使用了 GPIOA 以及 USART1,所以我们需要使能 GPIOA 和 USART1 时钟。方法如下:
__HAL_RCC_GPIOA_CLK_ENABLE(); //使能 GPIOA 时钟
__HAL_RCC_USART1_CLK_ENABLE(); //使能 USART1 时钟
  • 其次,我们在 GIPOx_MODER 寄存器中将所需 IO(对于串口 1 是 PA9,PA10)配置为复用功能。
  • 再次,我们还需要对 IO 口的其他参数,例如上拉/下拉以及输出速度等进行配置。
  • 最后,我们需要配置 GPIOx_AFRL 或者 GPIOx_AFRH 寄存器,将 IO 连接到所需的 AFx。对于PA9,PA10 复用为 USART1 的发送接收引脚,根据表 4.4.4 可知都需要连接 AF7。
  • 和其他外设一样,HAL 库为串口的使用开放了 MSP 函数。在串口初始化函数HAL_UART_Init内部,会调用串口MSP函数HAL_UART_MspInit来设置与MCU相关的配置。根据前面的讲解,函数 HAL_UART_Init 主要用来初始化与串口相关的参数(这些参数与 MCU无关),包括波特率,停止位等。而串口 MSP 函数 HAL_UART_MspInit 用来设置 GPIO 初始化,NVIC 配置等于 MCU 相关的配置。
HAL 库一共提供了 5 个中断处理回调函数:
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart);//发送完成回调函数
void HAL_UART_TxHalfCpltCallback(UART_HandleTypeDef *huart);//发送完成过半
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart);//接收完成回调函数
void HAL_UART_RxHalfCpltCallback(UART_HandleTypeDef *huart);//接收完成过半
void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart);//错误处理回调函数

uart.c:

u8 aRxBuffer[RXBUFFERSIZE];//HAL库使用的串口接收缓冲
UART_HandleTypeDef UART1_Handler; //UART句柄
//初始化IO 串口1 
//bound:波特率
void uart_init(u32 bound)
{	
    //UART 初始化设置
    UART1_Handler.Instance=USART1;					    
    UART1_Handler.Init.BaudRate=bound;			//波特率
    UART1_Handler.Init.WordLength=UART_WORDLENGTH_8B;   //字长为8位数据格式
    UART1_Handler.Init.StopBits=UART_STOPBITS_1;	//一个停止位
    UART1_Handler.Init.Parity=UART_PARITY_NONE;	        //无奇偶校验位
    UART1_Handler.Init.HwFlowCtl=UART_HWCONTROL_NONE;   //无硬件流控
    UART1_Handler.Init.Mode=UART_MODE_TX_RX;		//收发模式
    HAL_UART_Init(&UART1_Handler);					    
    HAL_UART_Receive_IT(&UART1_Handler, (u8 *)aRxBuffer, RXBUFFERSIZE);//该函数会开启接收中断:标志位UART_IT_RXNE,并且设置接收缓冲以及接收缓冲接收最大数据量  
}

//UART底层初始化,时钟使能,引脚配置,中断配置
//此函数会被HAL_UART_Init()调用
//huart:串口句柄

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_FREQ_HIGH;//高速

        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	
    }

}

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
    if(huart->Instance==USART1)//如果是串口1
    {
        if((USART_RX_STA&0x8000)==0)//接收未完成
        {
            if(USART_RX_STA&0x4000)//接收到了0x0d
            {
                if(aRxBuffer[0]!=0x0a)USART_RX_STA=0;//接收错误,重新开始
                else USART_RX_STA|=0x8000;	//接收完成了 
            }
            else //还没收到0X0D
            {	
                if(aRxBuffer[0]==0x0d)USART_RX_STA|=0x4000;
                else
                {
                    USART_RX_BUF[USART_RX_STA&0X3FFF]=aRxBuffer[0] ;
                    USART_RX_STA++;
                    if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;//接收数据错误,重新开始接收	  
                }		 
            }
        }

    }
}

//标准串口1中断处理函数
void USART1_IRQHandler(void)                	
{ 
    u32 timeout=0;
    u32 maxDelay=0x1FFFF;
    
    HAL_UART_IRQHandler(&UART1_Handler);	//调用HAL库中断处理公用函数
   
    timeout=0;
    while (HAL_UART_GetState(&UART1_Handler)!=HAL_UART_STATE_READY)//等待就绪
    {
        timeout++;////超时处理
        if(timeout>maxDelay) break;		
    }

    timeout=0;
    while(HAL_UART_Receive_IT(&UART1_Handler,(u8 *)aRxBuffer, RXBUFFERSIZE)!=HAL_OK)//一次处理完成之后,重新开启中断并设置RxXferCount为1
    {
        timeout++; //超时处理
        if(timeout>maxDelay) break;	
    }
} 


  • 主函数
int main(void)
{	
    u8 len;	
    u16 times=0; 

    Cache_Enable();                 //打开L1-Cache
    HAL_Init();			    //初始化HAL库
    Stm32_Clock_Init(160,5,2,4);    //设置时钟,400Mhz 
    delay_init(400);		    //延时初始化
    uart_init(115200);	            //串口初始化
    LED_Init();			    //初始化LED
    while(1)
    {
       if(USART_RX_STA&0x8000)
        {					   
            len=USART_RX_STA&0x3fff;//得到此次接收到的数据长度
            printf("\r\n您发送的消息为:\r\n");
            HAL_UART_Transmit(&UART1_Handler,(uint8_t*)USART_RX_BUF,len,1000);	//发送接收到的数据
            while(__HAL_UART_GET_FLAG(&UART1_Handler,UART_FLAG_TC)!=SET);		//等待发送结束
            printf("\r\n\r\n");//插入换行
            USART_RX_STA=0;
        }else
        {
            times++;
            if(times%5000==0)
            {
                    printf("\r\nALIENTEK STM32H7开发板 串口实验\r\n");
                    printf("正点原子@ALIENTEK\r\n\r\n\r\n");
            }
            if(times%200==0)printf("请输入数据,以回车键结束\r\n");  
            if(times%30==0)LED0_Toggle;//闪烁LED,提示系统正在运行.
            delay_ms(10);   
        }
	}
}