在嵌入式开发的奇妙旅程中,GPIO(通用输入输出接口)作为芯片与外部世界交互的重要桥梁,扮演着不可或缺的角色。从简单的 LED 灯控制,到复杂的外设通信,GPIO 的灵活运用为开发者打开了无限可能的大门。自本章开始,正式开始用代码控制AS32x601各外设完成功能配置。
需要注意的是,AS32X601提供了8组GPIO,其中GPIOA~GPIOG寄存器操作完全一致,但在使用GPIOH的时候,寄存器列表中间少了一个32位寄存器,因此在使用过程中容易造成误操作,我们在驱动库中已经做了映射,若想要自行操作寄存器进行控制,需要格外注意这一点。
另外,在芯片的IO复用表中,其默认功能并非全部都是GPIO,还包含了MUL类型,使用此类型IO时,需要先将复用配置为GPIO功能,在完成接下来的操作。

硬件设计
AS32x601评估板板载3颗LED灯用于IO输出评估,原理图如下:

根据上图可以知道,LED"正极"接电源,"负极"接GPIOG三个引脚,当IO拉低时,LED亮,IO输出高时,LED灭,据此设计控制逻辑。
程序设计
操作流程
-
开led对应IO时钟
-
检查对应引脚默认配置,是否需要复用调整
-
初始化gpio结构体
-
控制gpio输出
主要代码分析
复制上一小节的工程模板,在工程目录下新建Bsp文件夹用于存放led相关控制代码,在IAR工程界面添加led.c和led.h文件。
在led.c文件中添加相应头文件,之后编写led初始化代码。
- /*
- * Function: User_LED_Init
- * Description: Configure LED GPIO.
- * Param: None.
- * Return: None.
- */
- void User_LED_Init()
- {
- GPIO_InitTypeDef GPIO_InitStructure;
- GPIOG_CLK_ENABLE();
- /* GPIOB Configure */
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_14 | GPIO_Pin_15;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
- GPIO_InitStructure.GPIO_OType = GPIO_Out_PP;
- GPIO_InitStructure.GPIO_OStrength = GPIO_OStrength_9mA;
- GPIO_Init(GPIOG, &GPIO_InitStructure);
- }
在上述代码清单中,根据电路原理图,led与mcu的PG10、14、15引脚相连,因此我们首先打开GPIOG的时钟使能;
之后初始化gpio结构体,通过或操作同时对三个引脚进行初始化,配置推挽输出,同时配置io输出能力位9mA。
接下来,我们用宏定义的形式编写LED的控制函数。
- #define LED1_ON() GPIO_WriteBits(GPIOG, GPIO_Pin_15, GPIO_OCtrl_Vol)
- #define LED1_OFF() GPIO_WriteBits(GPIOG, GPIO_Pin_15, GPIO_OCtrl_Voh)
- #define LED1_TOGGLE() GPIO_ToggleBits(GPIOG, GPIO_Pin_15)
- #define LED2_ON() GPIO_WriteBits(GPIOG, GPIO_Pin_14, GPIO_OCtrl_Vol)
- #define LED2_OFF() GPIO_WriteBits(GPIOG, GPIO_Pin_14, GPIO_OCtrl_Voh)
- #define LED2_TOGGLE() GPIO_ToggleBits(GPIOG, GPIO_Pin_14)
- #define LED3_ON() GPIO_WriteBits(GPIOG, GPIO_Pin_10, GPIO_OCtrl_Vol)
- #define LED3_OFF() GPIO_WriteBits(GPIOG, GPIO_Pin_10, GPIO_OCtrl_Voh)
- #define LED3_TOGGLE() GPIO_ToggleBits(GPIOG, GPIO_Pin_10)
在led.h文件中添加如上代码,AS32驱动库中包含了引脚控制输出函数以及引脚翻转控制函数,通过宏的形式完成led控制名称的转换,便于理解。
此时,代码并不算完成,之后我们需要查询芯片设计手册中,GPIOG所在的总线,在系统时钟配置函数中需要打开对应总线时钟,具体方式参考上一小节。
最后,编写主函数代码,控制三个led灯流水闪烁。
-
void main()
-
{
-
Systemclock_Init();
-
delay_init(SMU_ClocksStruct.AXIBus0_Frequency/1000000);
-
/* Initialize LED */
-
User_LED_Init();
-
while(1)
-
{
-
LED1_ON();LED2_OFF();LED3_OFF();
-
delay_ms(100);
-
LED1_OFF();LED2_ON();LED3_OFF();
-
delay_ms(100);
-
LED1_OFF();LED2_OFF();LED3_ON();
-
delay_ms(100);
-
}
-
}
补充
在这个代码中调用了一个延时函数,该函数位于库文件System目录下,利用RISCV的CSR定时器,可以理解为系统定时器编写的精确延时函数,因此需要对此函数进行初始化,并传入当前系统时钟。
- delay_init(SMU_ClocksStruct.AXIBus0_Frequency/1000000);
SMU_ClocksStruct.AXIBus0_Frequency就是在系统时钟初始化函数中最后一个函数调用所读回来的所有总线时钟,由于Core时钟与AXIBus0同频,所以在此处就利用该参数进行延时初始化,除1000000的作用是,延时计算的时候单位为MHz,所以把后边的数量级给除掉。