4. GPIO与引脚复用配置实战
在RA FSP平台中,GPIO并不是一个简单的“置高置低”外设,而是由IOPORT模块统一管理引脚方向、电平、复用功能与中断输入。理解IOPORT的API结构,是完成按键输入与LED输出交互程序的基础。本节以RA4M2(Cortex-M33,100引脚LQFP)为例,围绕“LED输出 + 按键输入 + 外部中断”这一典型任务,讲解从引脚规划到代码落地的完整过程。
一、IOPORT模块的API层次
FSP的IOPORT模块对外提供三层能力:引脚控制层(方向、电平、上下拉)、复用功能层(PSEL/PMR/PODR等寄存器映射)、中断输入层(IRQ与ICU联动)。常用API如下:
R_IOPORT_PinCfg():按ioport_pin_cfg_t结构一次性配置方向、上下拉、驱动能力、初始电平。R_IOPORT_PinWrite()/R_IOPORT_PinRead():写/读单个引脚电平,返回fsp_err_t。R_IOPORT_PortWrite()/R_IOPORT_PortRead():按端口(如PORT1、PORT4)批量操作,适合并口LED或矩阵按键。R_IOPORT_PinsCfg():批量配置多个引脚,常用于初始化阶段。R_IOPORT_Open():打开IOPORT实例,通常在hal_entry()中由FSP自动调用。
需要特别注意的是:引脚复用功能(Peripheral Function)的切换并不通过IOPORT API完成,而是在FSP Configurator的“Pins”视图中配置,生成代码写入PmnPFS寄存器(PSEL、PMR、PODR、PCR等)。IOPORT API只负责“通用IO”语义下的读写与方向控制。若某引脚已被配置为SCI、SPI或AGT等外设功能,再调用R_IOPORT_PinWrite()不会改变其复用输出,必须先在FSP中把该引脚改回GPIO模式。
二、引脚规划与FSP配置
假设硬件连接如下(示例参数,实际以原理图为准):
| 功能 | 引脚 | 端口/位 | 方向 | 上下拉 | 初始电平 |
|---|---|---|---|---|---|
| LED1(红) | P405 | PORT4.5 | 输出 | 无 | 高(灭) |
| LED2(绿) | P404 | PORT4.4 | 输出 | 无 | 高(灭) |
| KEY1 | P105 | PORT1.5 | 输入 | 上拉 | — |
| KEY2(中断) | P106 | PORT1.6 | 输入 | 上拉 | — |
在FSP Configurator中依次完成:Stacks → New Stack → Input → External IRQ,选择IRQ通道(如IRQ6对应P106);在Pins视图中把P405、P404设为GPIO Output,P105、P106设为GPIO Input并勾选Pull-up。生成代码后,hal_data.c中会出现g_ioport实例与g_external_irq6实例。
三、LED输出:从寄存器到API
LED接在P405、P404,低电平点亮。初始化时通过R_IOPORT_PinCfg()把两脚设为输出、初始高电平:
ioport_pin_cfg_t led_cfg = {
.pin = BSP_IO_PORT_04_PIN_05,
.dir = IOPORT_DIRECTION_OUTPUT,
.pull = IOPORT_CFG_PULL_UP_OFF,
.drive = IOPORT_CFG_DRIVE_MID,
.level = IOPORT_LEVEL_HIGH
};
R_IOPORT_PinCfg(&g_ioport_ctrl, BSP_IO_PORT_04_PIN_05, &led_cfg);
R_IOPORT_PinCfg(&g_ioport_ctrl, BSP_IO_PORT_04_PIN_04, &led_cfg);
点亮LED1只需R_IOPORT_PinWrite(&g_ioport_ctrl, BSP_IO_PORT_04_PIN_05, BSP_IO_LEVEL_LOW);。若使用R_IOPORT_PortWrite(),可一次写整个PORT4,但要注意不要覆盖同端口其他已配置引脚的状态,通常配合读-改-写或使用位掩码。
四、按键输入与消抖
KEY1接P105,上拉输入,按下为低。查询方式读取:
bsp_io_level_t level;
R_IOPORT_PinRead(&g_ioport_ctrl, BSP_IO_PORT_01_PIN_05, &level);
if (BSP_IO_LEVEL_LOW == level) { /* 按键按下 */ }
机械按键存在5~20 ms抖动,直接在主循环判断会误触发。推荐做法是:检测到低电平后延时10 ms再读一次,两次一致才确认;或者用AGT定时器每5 ms采样一次,连续3次为低才判定按下。示例中采用R_BSP_SoftwareDelay(10, BSP_DELAY_UNITS_MILLISECONDS)做简单消抖,实际产品建议用定时器状态机。
五、外部中断配置
KEY2接P106并复用为IRQ6。FSP中配置External IRQ属性:Trigger选择Falling(下降沿,按下瞬间触发),Callback填入key2_isr,优先级设为12(低于系统节拍)。生成代码后,中断服务函数中应尽量短小,只置标志位,主循环再处理:
volatile bool g_key2_pressed = false;
void key2_isr(external_irq_callback_args_t *p_args) {
(void)p_args;
g_key2_pressed = true;
}
/* 主循环 */
if (g_key2_pressed) {
g_key2_pressed = false;
R_IOPORT_PinWrite(&g_ioport_ctrl, BSP_IO_PORT_04_PIN_04, BSP_IO_LEVEL_LOW);
R_BSP_SoftwareDelay(200, BSP_DELAY_UNITS_MILLISECONDS);
R_IOPORT_PinWrite(&g_ioport_ctrl, BSP_IO_PORT_04_PIN_04, BSP_IO_LEVEL_HIGH);
}
R_ICU_ExternalIrqEnable()重新使能,或确认FSP中IRQ的“Digital Filter”是否开启。RA的ICU支持数字滤波,可有效抑制按键毛刺。六、交互程序闭环
把上述片段组合:上电后LED1、LED2灭;按下KEY1,LED1点亮并保持;按下KEY2,LED2闪烁一次。判断依据是:用万用表或示波器观察P405/P404电平翻转,或在调试器中查看g_key2_pressed变量与IRQ6计数。若LED不亮,先确认P405是否被其他外设复用(PSEL≠0),再检查R_IOPORT_Open()是否成功返回FSP_SUCCESS。