ELF 1开发板GPIO配置与RGB LED按键控制实践 📅 2026/7/17 9:41:18 1. ELF 1开发板GPIO基础配置与验证在开始控制RGB LED和按键之前我们需要先确认ELF 1开发板的GPIO子系统是否正常工作。RK3568芯片的GPIO控制器通过Linux内核的GPIO子系统进行管理每个GPIO引脚都可以通过sysfs接口或直接操作寄存器来访问。1.1 检查GPIO驱动状态首先通过以下命令检查GPIO驱动是否正常加载lsmod | grep gpio dmesg | grep gpio正常情况下应该能看到与RK3568相关的GPIO驱动信息。如果驱动未加载可能需要重新编译内核或加载相应模块。1.2 GPIO编号计算RK3568的GPIO分为5组GPIO0-GPIO4每组有32个引脚。Linux系统中的GPIO编号计算公式为全局GPIO编号 gpiochip基址 组内偏移可以通过以下命令查看各gpiochip的基址cat /sys/class/gpio/gpiochip*/base例如如果gpiochip0的base是0那么GPIO0_C0的编号就是0 (GPIO0基址) 2*32 (C组) 0 641.3 测试GPIO功能我们可以通过sysfs接口手动测试GPIO功能。以GPIO0_C0为例# 导出GPIO echo 64 /sys/class/gpio/export # 设置为输出模式 echo out /sys/class/gpio/gpio64/direction # 输出高电平 echo 1 /sys/class/gpio/gpio64/value # 输出低电平 echo 0 /sys/class/gpio/gpio64/value # 取消导出 echo 64 /sys/class/gpio/unexport2. RGB LED控制实现ELF 1开发板上的RGB LED通常由三个GPIO分别控制红、绿、蓝三个通道。我们需要先确定这三个GPIO对应的引脚编号。2.1 硬件连接确认查阅ELF 1开发板原理图确认RGB LED的连接方式。假设红色LEDGPIO1_A0绿色LEDGPIO1_A1蓝色LEDGPIO1_A2根据GPIO编号计算公式可以计算出对应的Linux GPIO编号# GPIO1基址通常是32 RED32 # GPIO1_A0 GREEN33 # GPIO1_A1 BLUE34 # GPIO1_A22.2 LED控制脚本创建一个控制RGB LED的shell脚本#!/bin/bash # GPIO编号 RED32 GREEN33 BLUE34 # 初始化GPIO init_gpio() { for gpio in $RED $GREEN $BLUE; do echo $gpio /sys/class/gpio/export echo out /sys/class/gpio/gpio$gpio/direction echo 0 /sys/class/gpio/gpio$gpio/value done } # 设置LED颜色 set_color() { echo $1 /sys/class/gpio/gpio$RED/value echo $2 /sys/class/gpio/gpio$GREEN/value echo $3 /sys/class/gpio/gpio$BLUE/value } # 清理GPIO cleanup() { for gpio in $RED $GREEN $BLUE; do echo 0 /sys/class/gpio/gpio$gpio/value echo $gpio /sys/class/gpio/unexport done exit 0 } trap cleanup INT TERM init_gpio # 示例循环显示不同颜色 while true; do set_color 1 0 0 # 红色 sleep 1 set_color 0 1 0 # 绿色 sleep 1 set_color 0 0 1 # 蓝色 sleep 1 set_color 1 1 0 # 黄色 sleep 1 set_color 1 0 1 # 紫色 sleep 1 set_color 0 1 1 # 青色 sleep 1 set_color 1 1 1 # 白色 sleep 1 done2.3 PWM调光控制如果需要实现LED亮度调节可以使用PWM功能。RK3568的PWM控制器可以通过sysfs接口控制# 查找可用的PWM通道 ls /sys/class/pwm/ # 使用PWM0通道0 echo 0 /sys/class/pwm/pwmchip0/export echo 1000000 /sys/class/pwm/pwmchip0/pwm0/period echo 500000 /sys/class/pwm/pwmchip0/pwm0/duty_cycle echo 1 /sys/class/pwm/pwmchip0/pwm0/enable3. 按键控制实现按键通常连接到GPIO作为输入设备我们需要配置GPIO为输入模式并检测电平变化。3.1 按键硬件连接假设开发板上的用户按键连接到GPIO0_B5计算其Linux GPIO编号# GPIO0基址是0 BUTTON0 1*32 5 373.2 按键检测脚本创建一个检测按键状态的脚本#!/bin/bash BUTTON37 # 初始化按键GPIO echo $BUTTON /sys/class/gpio/export echo in /sys/class/gpio/gpio$BUTTON/direction # 检测按键状态 while true; do value$(cat /sys/class/gpio/gpio$BUTTON/value) if [ $value 0 ]; then echo Button pressed # 这里可以添加控制LED的逻辑 else echo Button released fi sleep 0.1 done # 清理 echo $BUTTON /sys/class/gpio/unexport3.3 按键消抖处理机械按键存在抖动问题需要在软件中实现消抖#!/bin/bash BUTTON37 DEBOUNCE_TIME50 # 消抖时间50ms echo $BUTTON /sys/class/gpio/export echo in /sys/class/gpio/gpio$BUTTON/direction last_state$(cat /sys/class/gpio/gpio$BUTTON/value) last_time$(date %s%N | cut -b1-13) while true; do current_state$(cat /sys/class/gpio/gpio$BUTTON/value) current_time$(date %s%N | cut -b1-13) if [ $current_state ! $last_state ]; then if [ $(($current_time - $last_time)) -gt $DEBOUNCE_TIME ]; then if [ $current_state 0 ]; then echo Button pressed (debounced) else echo Button released (debounced) fi last_state$current_state fi last_time$current_time fi sleep 0.01 done4. 综合应用按键控制RGB LED现在我们将按键和RGB LED控制结合起来实现按键控制LED颜色变化的功能。4.1 硬件连接确认假设按键GPIO0_B5 (37)RGB LED红色GPIO1_A0 (32)绿色GPIO1_A1 (33)蓝色GPIO1_A2 (34)4.2 综合控制脚本#!/bin/bash # GPIO编号 BUTTON37 RED32 GREEN33 BLUE34 # 颜色状态 COLORS(1 0 0 0 1 0 0 0 1 1 1 0 1 0 1 0 1 1 1 1 1) current_color0 # 初始化GPIO init_gpio() { # 按键 echo $BUTTON /sys/class/gpio/export echo in /sys/class/gpio/gpio$BUTTON/direction # LED for gpio in $RED $GREEN $BLUE; do echo $gpio /sys/class/gpio/export echo out /sys/class/gpio/gpio$gpio/direction echo 0 /sys/class/gpio/gpio$gpio/value done } # 设置LED颜色 set_color() { echo $1 /sys/class/gpio/gpio$RED/value echo $2 /sys/class/gpio/gpio$GREEN/value echo $3 /sys/class/gpio/gpio$BLUE/value } # 清理GPIO cleanup() { for gpio in $RED $GREEN $BLUE $BUTTON; do echo 0 /sys/class/gpio/gpio$gpio/value echo $gpio /sys/class/gpio/unexport done exit 0 } trap cleanup INT TERM init_gpio # 初始颜色 set_color ${COLORS[$current_color]} # 主循环 last_state$(cat /sys/class/gpio/gpio$BUTTON/value) last_time$(date %s%N | cut -b1-13) while true; do current_state$(cat /sys/class/gpio/gpio$BUTTON/value) current_time$(date %s%N | cut -b1-13) # 按键状态变化检测 if [ $current_state ! $last_state ]; then if [ $(($current_time - $last_time)) -gt 50 ]; then # 按键按下事件 if [ $current_state 0 ]; then current_color$(( (current_color 1) % ${#COLORS[]} )) set_color ${COLORS[$current_color]} echo Changed to color $current_color fi last_state$current_state fi last_time$current_time fi sleep 0.01 done4.3 进阶功能双击检测要实现按键双击功能可以记录按键按下的时间间隔#!/bin/bash BUTTON37 DOUBLE_CLICK_TIME300 # 双击时间间隔300ms echo $BUTTON /sys/class/gpio/export echo in /sys/class/gpio/gpio$BUTTON/direction last_press_time0 click_count0 while true; do current_state$(cat /sys/class/gpio/gpio$BUTTON/value) current_time$(date %s%N | cut -b1-13) if [ $current_state 0 ]; then if [ $(($current_time - $last_press_time)) -gt $DOUBLE_CLICK_TIME ]; then click_count1 else click_count$((click_count 1)) fi last_press_time$current_time # 等待按键释放 while [ $(cat /sys/class/gpio/gpio$BUTTON/value) 0 ]; do sleep 0.01 done # 检测双击 if [ $click_count -eq 2 ]; then echo Double click detected click_count0 # 这里可以添加双击触发的功能 fi fi sleep 0.01 done5. 性能优化与注意事项在实际应用中我们还需要考虑一些优化和注意事项。5.1 使用poll监控GPIO状态频繁读取GPIO值会占用CPU资源可以使用poll监控GPIO状态变化#include stdio.h #include stdlib.h #include fcntl.h #include poll.h #include unistd.h int main() { int fd; struct pollfd pfd; char buf[10]; fd open(/sys/class/gpio/gpio37/value, O_RDONLY); if (fd 0) { perror(open); return 1; } pfd.fd fd; pfd.events POLLPRI | POLLERR; // 初始读取 lseek(fd, 0, SEEK_SET); read(fd, buf, sizeof(buf)); while (1) { int ret poll(pfd, 1, -1); if (ret 0) { lseek(fd, 0, SEEK_SET); read(fd, buf, sizeof(buf)); printf(GPIO value changed: %c\n, buf[0]); } } close(fd); return 0; }5.2 使用libgpiod库对于更复杂的GPIO操作可以使用libgpiod库#include gpiod.h #include stdio.h #include unistd.h int main() { struct gpiod_chip *chip; struct gpiod_line *line; int ret; chip gpiod_chip_open(/dev/gpiochip0); if (!chip) { perror(gpiod_chip_open); return 1; } line gpiod_chip_get_line(chip, 37); // GPIO0_B5 if (!line) { perror(gpiod_chip_get_line); gpiod_chip_close(chip); return 1; } ret gpiod_line_request_input(line, button); if (ret 0) { perror(gpiod_line_request_input); gpiod_line_release(line); gpiod_chip_close(chip); return 1; } while (1) { int val gpiod_line_get_value(line); printf(Button state: %d\n, val); usleep(100000); // 100ms } gpiod_line_release(line); gpiod_chip_close(chip); return 0; }5.3 常见问题排查GPIO无法导出检查GPIO编号是否正确确认GPIO没有被其他驱动占用检查/sys/class/gpio/gpiochip*/base值按键响应不灵敏增加消抖时间检查硬件连接是否可靠使用中断方式代替轮询LED亮度不一致不同颜色的LED可能有不同的正向电压考虑使用PWM调节亮度检查限流电阻是否合适系统资源占用高减少轮询频率使用poll或中断方式考虑使用内核模块实现功能