【瑞萨EK-RA4C1】LED点灯测试
GPIO 与板载 LED 测试为 GPIO 输入输出实验提供了最直接的目标。下面从资源配置到代码实现,完整演练一遍。9.1 板载 LED 与按键资源回顾在第二章硬件解读中已经提到,EK-RA4C1 的生态系统与系统控制区集成了以下用户交互资源:资源数量丝印对应 GPIO说明
红色 LED1LED1P400高电平点亮
蓝色 LED1LED2P401高电平点亮
绿色 LED1LED3P402高电平点亮
用户按键2S1 (USER)P004按下低电平,外部上拉
用户按键2S2 (USER)P005按下低电平,外部上拉
复位按键1RES—系统复位
三个 LED 的设计对调试非常友好——红色用于错误/告警指示,绿色用于正常运行状态,蓝色可用于特殊的模式标识(如蓝牙连接、OTA 升级等)。两颗用户按键则为交互式功能切换提供了可能(例如下面将要演示的"按键切换 LED 闪烁模式")。9.2 RASC 配置 GPIO在 FSP Configuration 的 "Pins" 标签页中,依次配置以下引脚:
引脚功能方向初始电平
P400红色 LEDOutput (Initial Low)低(熄灭)
P401蓝色 LEDOutput (Initial Low)低(熄灭)
P402绿色 LEDOutput (Initial Low)低(熄灭)
P004用户按键 S1Input—
P005用户按键 S2Input—
对于按键引脚,需额外在 Pin Configuration 中将 Pull-up 设为 Enabled,或将 IRQ 按需配置(本节采用轮询方式读取,不使能中断)。无需在 "Stacks" 标签页添加额外驱动栈——GPIO 属于 BSP 层面的基础功能,RASC 生成代码后直接调用 R_BSP_PinWrite() / R_BSP_PinRead() 即可。点击 "Generate Project Content" 生成代码。9.3 示例代码以下代码在上一章串口测试工程的基础上扩展,实现三个功能层次:
[*]基础闪烁:三色 LED 顺序交替点亮(红→蓝→绿→全灭,循环)
[*]RGB 混色:利用 PWM 思路通过 GPIO 软件模拟实现呼吸渐变效果(红蓝色交叉产生紫色过渡)
[*]按键交互:按下 S1 切换 LED 演示模式,按下 S2 暂停/恢复
完整 src/hal_entry.c 代码如下(保留上一章的 UART 初始化部分,新增 LED 驱动逻辑):c
#include "hal_data.h"#include <stdio.h>#include <string.h>/* --- 引脚宏定义,与 RASC 配置保持一致 --- */#define LED_RED_PIN BSP_IO_PORT_04_PIN_00 /* P400: 红色 LED */#define LED_BLUE_PIN BSP_IO_PORT_04_PIN_01 /* P401: 蓝色 LED */#define LED_GREEN_PIN BSP_IO_PORT_04_PIN_02 /* P402: 绿色 LED */#define BTN_S1_PIN BSP_IO_PORT_00_PIN_04 /* P004: 用户按键 S1 */#define BTN_S2_PIN BSP_IO_PORT_00_PIN_05 /* P005: 用户按键 S2 *//* --- LED 演示模式枚举 --- */typedef enum { LED_MODE_SEQUENTIAL = 0, /* 模式0: 红→蓝→绿 顺序闪烁 */ LED_MODE_BREATHING, /* 模式1: RGB 呼吸混色效果 */ LED_MODE_ALL_BLINK, /* 模式2: 三色同闪 */ LED_MODE_MAX} led_mode_t;/* --- 全局变量 --- */static volatile led_mode_t g_led_mode = LED_MODE_SEQUENTIAL;static volatile bool g_paused = false;/* ======================== UART 部分(保留) ======================== */static volatile uint8_tg_rx_byte;static volatile bool g_rx_complete = false;void uart0_callback(uart_callback_args_t *p_args){ switch (p_args->event) { case UART_EVENT_RX_CHAR: g_rx_byte = *(uint8_t *)(p_args->p_context); g_rx_complete= true; break; case UART_EVENT_TX_COMPLETE: case UART_EVENT_ERR_PARITY: case UART_EVENT_ERR_FRAMING: case UART_EVENT_ERR_OVERFLOW: default: break; }}#ifdef __GNUC__int _write(int fd, char *buf, int len){ (void)fd; R_SCI_UART_Write(&g_uart0_ctrl, (uint8_t *)buf, (uint32_t)len); while (0U == g_uart0_ctrl.tx_data_bytes) { } return len;}#endif/* ======================== LED 控制函数 ======================== *//* 关闭所有 LED */static void led_all_off(void){ R_BSP_PinWrite(LED_RED_PIN, BSP_IO_LEVEL_LOW); R_BSP_PinWrite(LED_BLUE_PIN,BSP_IO_LEVEL_LOW); R_BSP_PinWrite(LED_GREEN_PIN, BSP_IO_LEVEL_LOW);}/* 点亮指定 LED */static void led_on(uint16_t pin){ R_BSP_PinWrite(pin, BSP_IO_LEVEL_HIGH);}/* 熄灭指定 LED */static void led_off(uint16_t pin){ R_BSP_PinWrite(pin, BSP_IO_LEVEL_LOW);}/* 简单毫秒级延时(基于循环计数,非精确) */static void simple_delay_ms(uint32_t ms){ R_BSP_SoftwareDelay(ms, BSP_DELAY_UNITS_MILLISECONDS);}/* 按键扫描:检测下降沿(按下瞬间),带简易去抖 */static bool button_pressed(uint16_t pin){ /* 读当前状态(按下为低电平) */ if (BSP_IO_LEVEL_LOW == R_BSP_PinRead(pin)) { simple_delay_ms(20);/* 去抖延时 */ if (BSP_IO_LEVEL_LOW == R_BSP_PinRead(pin)) { /* 等待按键释放 */ while (BSP_IO_LEVEL_LOW == R_BSP_PinRead(pin)) { } return true; } } return false;}/* ======================== LED 演示模式 ======================== *//* 模式0:红→蓝→绿 顺序轮闪 */static void mode_sequential(void){ printf(" Mode 0: Sequential Blink\r\n"); led_all_off(); led_on(LED_RED_PIN); simple_delay_ms(500); led_all_off(); led_on(LED_BLUE_PIN); simple_delay_ms(500); led_all_off(); led_on(LED_GREEN_PIN); simple_delay_ms(500); led_all_off(); simple_delay_ms(300);}/* 模式1:RGB 呼吸混色 — 通过 GPIO 快速切换模拟视觉混合 */static void mode_breathing(void){ printf(" Mode 1: RGB Breathing Mix\r\n"); /* 红→紫(红+蓝)→蓝→青(蓝+绿)→绿 渐变循环 */ static const uint16_t seq[ = { LED_RED_PIN, /* 纯红 */ (uint16_t)(LED_RED_PIN| 0x8000), /* 红+蓝(标记位指示混色)*/ LED_BLUE_PIN, /* 纯蓝 */ (uint16_t)(LED_GREEN_PIN | 0x8000), /* 蓝+绿 */ LED_GREEN_PIN /* 纯绿 */ }; for (int i = 0; i < 5; i++) { led_all_off(); if (seq[i & 0x8000) { /* 混色:快速交替点亮两个 LED,视觉上产生混合色 */ uint16_t pin_a = seq[i & 0x7FFF; uint16_t pin_b = (i == 1) ? LED_BLUE_PIN : LED_GREEN_PIN; for (int t = 0; t < 60; t++) { led_on(pin_a); R_BSP_SoftwareDelay(1, BSP_DELAY_UNITS_MILLISECONDS); led_off(pin_a); led_on(pin_b); R_BSP_SoftwareDelay(1, BSP_DELAY_UNITS_MILLISECONDS); led_off(pin_b); } } else { /* 单色:渐亮渐灭模拟呼吸 */ for (int t = 0; t < 80; t++) { led_on(seq[i); R_BSP_SoftwareDelay(2 * (80 - t) / 80 + 1, BSP_DELAY_UNITS_MILLISECONDS); led_off(seq[i); R_BSP_SoftwareDelay(2 * t / 80 + 1, BSP_DELAY_UNITS_MILLISECONDS); } } }}/* 模式2:三色同频闪烁 */static void mode_all_blink(void){ printf(" Mode 2: All Blink Together\r\n"); for (int i = 0; i < 4; i++) { led_on(LED_RED_PIN); led_on(LED_BLUE_PIN); led_on(LED_GREEN_PIN); simple_delay_ms(200); led_all_off(); simple_delay_ms(200); }}/* 按键处理:模式切换与暂停控制 */static void handle_buttons(void){ if (button_pressed(BTN_S1_PIN)) { g_led_mode = (led_mode_t)((g_led_mode + 1) % LED_MODE_MAX); printf(" S1 pressed, switch to Mode %d\r\n", g_led_mode); } if (button_pressed(BTN_S2_PIN)) { g_paused = !g_paused; printf(" S2 pressed, LED %s\r\n", g_paused ? "PAUSED" : "RESUMED"); }}/* ======================== 主入口 ======================== */void hal_entry(void){ fsp_err_t err; /* --- UART 初始化 --- */ err = R_SCI_UART_Open(&g_uart0_ctrl, &g_uart0_cfg); if (FSP_SUCCESS != err) { /* 初始化失败:红灯快速闪烁报警 */ while (1) { led_on(LED_RED_PIN); R_BSP_SoftwareDelay(100, BSP_DELAY_UNITS_MILLISECONDS); led_off(LED_RED_PIN); R_BSP_SoftwareDelay(100, BSP_DELAY_UNITS_MILLISECONDS); } } /* --- GPIO 初始状态 --- */ led_all_off(); /* --- 打印启动信息 --- */ printf("\r\n========================================\r\n"); printf("EK-RA4C1 LED & Button Demo\r\n"); printf("LED:Red=P400Blue=P401Green=P402\r\n"); printf("BTN:S1=P004S2=P005\r\n"); printf("S1: Toggle Mode|S2: Pause/Resume\r\n"); printf("========================================\r\n"); /* --- 主循环 --- */ while (1) { /* 按键扫描 */ handle_buttons(); /* 暂停时仅扫描按键,不执行 LED 逻辑 */ if (g_paused) { R_BSP_SoftwareDelay(50, BSP_DELAY_UNITS_MILLISECONDS); continue; } /* 根据当前模式执行 LED 演示 */ switch (g_led_mode) { case LED_MODE_SEQUENTIAL: mode_sequential(); break; case LED_MODE_BREATHING: mode_breathing(); break; case LED_MODE_ALL_BLINK: mode_all_blink(); break; default: break; } /* 串口回环处理 */ if (g_rx_complete) { g_rx_complete = false; R_SCI_UART_Write(&g_uart0_ctrl, &g_rx_byte, 1); if ('\r' == g_rx_byte || '\n' == g_rx_byte) { uint8_t lf = '\n'; R_SCI_UART_Write(&g_uart0_ctrl, &lf, 1); } } }}
代码结构说明:
模块关键函数功能
基础控制led_on() / led_off() / led_all_off()单灯开关、全灭
模式0mode_sequential()红→蓝→绿 顺序闪烁,每色保持 500ms
模式1mode_breathing()单色呼吸渐变 + 双色高速交替实现混色效果(R+G=**, R+B=紫)
模式2mode_all_blink()三色同频快闪,4 轮
按键管理button_pressed()带 20ms 去抖 + 抬起检测的按键扫描
主控handle_buttons()S1 循环切模式,S2 暂停/恢复
9.4 编译烧录与实物效果编译:与上一章流程一致,Build Project 后确认 0 errors, 0 warnings。烧录:通过板载 J-Link OB 下载,Debug 按钮一键完成。预期实物效果:
阶段板载现象串口输出
上电复位三灯瞬灭 → 进入模式0EK-RA4C1 LED & Button Demo 启动横幅
模式0 运行亮 500ms → 灭 500ms ,循环 Mode 0: Sequential Blink
按 S1 一次切换到模式1 S1 pressed, switch to Mode 1
模式1 运行快速闪烁 Mode 1: RGB Breathing Mix
按 S1 两次切换到模式2 S1 pressed, switch to Mode 2
模式2 运行同时快闪(200ms 亮 / 200ms 灭,共 4 轮后循环) Mode 2: All Blink Together
按 S2LED 保持当前状态定格暂停 S2 pressed, LED PAUSED
再按 S2LED 恢复动画 S2 pressed, LED RESUMED
9.5 测试小结
[*]FSP GPIO API 极简高效:R_BSP_PinWrite() / R_BSP_PinRead() 两个函数覆盖全部 GPIO 操作,无需初始化结构体、无需使能时钟——RASC 生成代码时已自动处理好引脚方向、上下拉和初始电平,业务代码只需关注逻辑。
[*]BSP 级别的引脚宏定义规范:BSP_IO_PORT_04_PIN_00 这种三层结构(端口/位)的宏命名清晰易读,配合 R_BSP_PinWrite() 使用,可读性远超裸寄存器操作 PORT4.PODR.BIT.B0 = 1。
[*]按键去抖的通用方案:button_pressed() 采用 20ms 延时二次确认 + 等待释放的组合策略,适用于大多数机械按键场景,可靠性良好。若需要更低的 CPU 占用,可改用定时器中断 + 状态机方式。
[*]软件模拟混色效果可行但有限:通过 GPIO 快速切换红蓝两色模拟紫色的效果在肉眼观察下可辨,但由于没有硬件 PWM 驱动,亮度和色彩精度受限。RA4C1 具备 32 位 GPT 定时器,若需要精确调光,下一步可尝试用 GPT 的 PWM 输出模式驱动 LED。
页:
[1]