CH582F RISC-V飞控板开发教程(一):硬件架构解析+GPIO控制LED与按键交互完整代码
关键词:CH582F、RISC-V、飞控板、GPIO、嵌入式开发、MounRiver Studio、穿越机
文章目录
- 飞控板硬件架构与核心器件选型
- 开发环境搭建(MounRiver Studio + WCH-Link + ISP)
- GPIO工作原理与CH582F寄存器详解
- LED闪烁程序实现(SDK API + 寄存器两种方式)
- 按键输入与软件消抖
- 综合实验:双按键控制四灯模式切换(完整代码)
一、飞控板硬件架构
1.1 系统框图
本教程所使用的飞控板以沁恒微电子CH582F为主控,集成了姿态感知、无线通信、电机驱动等功能模块。
系统架构如下:
- 主控:CH582F(RISC-V RV32IMAC,60MHz,448KB Flash,32KB SRAM)
- 姿态传感器:MPU-6050(六轴,I2C通信,内置DMP)
- 气压计:SPL06(SPI/I2C,精度±0.06hPa)
- 射频前端:AT2401C(2.4G PA+LNA)
- 电机驱动:4×SI2302 N-MOSFET(Rds=45mΩ,Id=2.8A)
- 电机:4×720/820型空心杯有刷电机
- 指示灯:4×LED(红/绿双色,分布在四角)
- 通信接口:BLE 5.3 + 2.4G私有协议 + USB 2.0
1.2 核心芯片参数
CH582F主要规格:
| 参数 | 规格 |
|---|---|
| CPU内核 | RISC-V RV32IMAC |
| 最高主频 | 60MHz |
| Flash | 448KB |
| SRAM | 32KB |
| GPIO | 2组×16pin (GPIOA/GPIOB) |
| UART | 4个 (UART0~UART3) |
| SPI | 2个 (SPI0/SPI1) |
| I2C | 1个 |
| PWM | 4通道 |
| ADC | 多通道12位 |
| 定时器 | 4个 (TIM0~TIM3) |
| 无线 | BLE 5.3 + 2.4G |
| USB | USB 2.0 Full-Speed |
| 封装 | QFN32 |
MPU-6050技术参数:
| 参数 | 规格 |
|---|---|
| 加速度量程 | ±2g/±4g/±8g/±16g |
| 陀螺仪量程 | ±250°/s~±2000°/s |
| ADC分辨率 | 16位 |
| I2C速率 | 最高400kHz |
| 工作电压 | 2.375V~3.46V |
1.3 GPIO引脚分配表
| 引脚 | 功能 | 方向 | 说明 |
|---|---|---|---|
| PB15 | LED1(前左) | 输出 | 高电平点亮 |
| PA11 | LED2(前右) | 输出 | 高电平点亮 |
| PA14 | LED3(后左) | 输出 | 高电平点亮 |
| PB4 | LED4(后右) | 输出 | 高电平点亮 |
| PB14 | 电机1 PWM | 输出 | 前左电机转速 |
| PA12 | 电机2 PWM | 输出 | 前右电机转速 |
| PA13 | 电机3 PWM | 输出 | 后左电机转速 |
| PB7 | 电机4 PWM | 输出 | 后右电机转速 |
| PB12 | I2C SDA | 双向 | 传感器数据 |
| PB13 | I2C SCL | 输出 | 传感器时钟 |
| PA4 | 2.4G RX EN | 输出 | AT2401接收使能 |
| PA5 | 2.4G TX EN | 输出 | AT2401发送使能 |
| PA15 | ADC | 输入 | 电池电压检测 |
| PA8 | KEY1 | 输入 | 总开关按键 |
| PA9 | KEY2 | 输入 | 模式切换按键 |
| PA9 | UART1_TX | 输出 | 串口输出 |
| PA8 | UART1_RX | 输入 | 串口输入 |
| PB11 | USB_P | 双向 | USB接口 |
| PB10 | USB_N | 双向 | USB接口 |
二、开发环境搭建
2.1 MounRiver Studio安装
- 访问 www.mounriver.com 下载对应操作系统版本
- 运行安装程序,路径避免中文和空格
- 全选组件:IDE + RISC-V GCC + OpenOCD + Device Support
- 首次启动设置Workspace目录
2.2 新建工程
File → New → MounRiver Project → Project name: LED_Blink → Device Family: CH58x → Device: CH582F → Template: Empty Project工程结构:
LED_Blink/ ├── src/main.c // 用户代码 ├── Startup/ // 启动代码 │ ├── startup_CH58x.S │ └── system_CH58x.c ├── StdPeriphDriver/ // 外设驱动库 └── Ld/CH58x.ld // 链接脚本2.3 编译
按Ctrl+B编译,控制台显示 “Build Finished” 且无红色错误即为成功。末尾的 “No rule to make target post-build” 提示可忽略。
2.4 固件下载
方式一:WCH-Link(推荐开发调试用)
连接信号:SWDIO、SWCLK、GND,点击Debug按钮自动编译+下载+进入调试模式。
方式二:ISP串口烧录(适合量产)
接线:TX→RX(交叉),RX→TX,GND→GND。
操作步骤:
- 按住BOOT键
- 按RESET键后松开
- 松开BOOT键(进入ISP Bootloader)
- WCHISPTool选择CH582F → UART → 加载固件 → 烧写
三、GPIO工作原理
3.1 GPIO输出模式
推挽输出(Push-Pull):P-MOS + N-MOS组合,驱动能力强,可直接驱动LED。CH582F最大提供20mA驱动电流。
开漏输出(Open-Drain):仅N-MOS,高电平需外接上拉电阻。常用于I2C总线。
3.2 GPIO输入模式
浮空输入:无内部上下拉,电平由外部决定,易受干扰。
上拉输入:内部弱上拉(50kΩ~100kΩ)至VCC,默认高电平。按键接地场景使用。
下拉输入:内部弱下拉至GND,默认低电平。按键接VCC场景使用。
3.3 CH582F GPIO寄存器
| 寄存器 | 功能 | 操作 |
|---|---|---|
| R32_GPIOx_DIR | 方向 | 0=输入,1=输出 |
| R32_GPIOx_SET | 输出置位 | 写1=高电平 |
| R32_GPIOx_CLR | 输出清零 | 写1=低电平 |
| R32_GPIOx_IN | 输入读取 | 读1=高,读0=低 |
| R32_GPIOx_PU | 上拉使能 | 写1=使能 |
| R32_GPIOx_PD | 下拉使能 | 写1=使能 |
| R32_GPIOx_FUN_MODE | 功能复用 | 00=GPIO |
3.4 SDK API函数速查
// 配置引脚模式GPIOA_ModeCfg(GPIO_Pin_x,GPIO_ModeOut_PP_20mA);// 推挽输出20mAGPIOB_ModeCfg(GPIO_Pin_x,GPIO_ModeIN_PU);// 上拉输入// 输出操作GPIOA_SetBits(GPIO_Pin_x);// 输出高电平GPIOA_ResetBits(GPIO_Pin_x);// 输出低电平GPIOA_InvertBits(GPIO_Pin_x);// 翻转输出// 输入读取val=GPIOA_ReadPortPin(GPIO_Pin_x);// 读取电平GPIO模式常量:
| 常量 | 含义 |
|---|---|
| GPIO_ModeIN_Floating | 浮空输入 |
| GPIO_ModeIN_PU | 上拉输入 |
| GPIO_ModeIN_PD | 下拉输入 |
| GPIO_ModeOut_PP_20mA | 推挽输出20mA |
| GPIO_ModeOut_PP_5mA | 推挽输出5mA |
| GPIO_ModeOut_OD_20mA | 开漏输出20mA |
四、LED闪烁程序
4.1 SDK API方式(推荐)
#include"CH58x_common.h"intmain(void){SetSysClock(CLK_SOURCE_PLL_60MHz);// 配置PA4为推挽输出GPIOA_ModeCfg(GPIO_Pin_4,GPIO_ModeOut_PP_20mA);GPIOA_ResetBits(GPIO_Pin_4);// 初始熄灭while(1){GPIOA_InvertBits(GPIO_Pin_4);// 翻转电平DelayMs(500);// 延时500ms}}4.2 寄存器直接操作方式
#include"CH58x_common.h"#defineLED1_PIN(1<<4)// PA4intmain(void){SetSysClock(CLK_SOURCE_PLL_60MHz);R32_GPIOA_DIR|=LED1_PIN;// PA4输出R32_GPIOA_CLR=LED1_PIN;// 初始低电平while(1){R32_GPIOA_SET=LED1_PIN;DelayMs(500);R32_GPIOA_CLR=LED1_PIN;DelayMs(500);}}4.3 多LED同时控制
// 同时配置4个LED引脚为输出GPIOA_ModeCfg(GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_12|GPIO_Pin_13,GPIO_ModeOut_PP_20mA);// 同时点亮GPIOA_SetBits(GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_12|GPIO_Pin_13);// 同时熄灭GPIOA_ResetBits(GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_12|GPIO_Pin_13);4.4 流水灯效果
#include"CH58x_common.h"#defineLED1GPIO_Pin_4#defineLED2GPIO_Pin_5#defineLED3GPIO_Pin_12#defineLED4GPIO_Pin_13#defineLED_ALL(LED1|LED2|LED3|LED4)constuint32_tled_pins[]={LED1,LED2,LED3,LED4};intmain(void){SetSysClock(CLK_SOURCE_PLL_60MHz);GPIOA_ModeCfg(LED_ALL,GPIO_ModeOut_PP_20mA);GPIOA_ResetBits(LED_ALL);while(1){for(inti=0;i<4;i++){GPIOA_ResetBits(LED_ALL);GPIOA_SetBits(led_pins[i]);DelayMs(200);}}}五、按键输入与软件消抖
5.1 按键电路
按键一端接GPIO(PA8/PA9),另一端接GND。GPIO配置为上拉输入。
- 未按下:内部上拉保持高电平 → 读为1
- 按下:直接接地 → 读为0
5.2 按键消抖原理
机械按键按下瞬间产生5~20ms触点弹跳。软件消抖流程:
- 检测到低电平
- 延时20ms等待抖动消失
- 再次读取确认
- 等待按键释放
5.3 消抖代码实现
uint8_tKey_Scan(void){if(GPIOA_ReadPortPin(GPIO_Pin_9)==0)// 检测到低电平{DelayMs(20);// 消抖延时if(GPIOA_ReadPortPin(GPIO_Pin_9)==0)// 二次确认{while(GPIOA_ReadPortPin(GPIO_Pin_9)==0);// 等待释放return1;}}return0;}注意:实际飞控程序中应使用非阻塞的定时器扫描方式(每10~20ms扫描一次),避免while死等阻塞飞控主循环。
六、综合实验:双按键控制四灯模式切换
6.1 功能需求
- 上电:全灭
- 按KEY1(PA8):四灯全亮
- 按KEY2(PA9):切换跑马灯模式
- 再按KEY2:停止跑马灯,恢复四灯全亮
- 任意状态按KEY1:全灭
6.2 LED.h 头文件
#ifndef__LED_H__#define__LED_H__#include"CH58x_common.h"#defineRLED_RGPIO_Pin_11// PA11#defineRLED_LGPIO_Pin_15// PB15#defineGLED_RGPIO_Pin_4// PB4#defineGLED_LGPIO_Pin_14// PA14#defineKEY1_PINGPIO_Pin_8// PA8#defineKEY2_PINGPIO_Pin_9// PA9externuint8_tRun_flag;externuint8_tLed_All_Sta;voidLED_Init(void);voidRGB_LED_Off(void);voidRGB_LED_ON(void);voidRed_LED_STA(uint8_tOnOff);voidGrn_LED_STA(uint8_tOnOff);voidKEY_Init(void);uint8_tKEY_Scan(void);voidKEY_Process(uint8_tkey_val);voidLED_Running(void);#endif6.3 完整main.c
#include"CH58x_common.h"#include"LED.h"#defineKEY_DELAY_MS20// 按键消抖时间#defineFLOW_INTERVAL120// 跑马灯切换间隔(ms)uint8_tRun_flag=0;uint8_tLed_All_Sta=0;uint32_tsoft_tick=0;uint8_tflow_step=0;voidLED_Init(void){GPIOA_ModeCfg(GPIO_Pin_11,GPIO_ModeOut_PP_5mA);// PA11 RLED_RGPIOB_ModeCfg(GPIO_Pin_15,GPIO_ModeOut_PP_5mA);// PB15 RLED_LGPIOA_ModeCfg(GPIO_Pin_14,GPIO_ModeOut_PP_5mA);// PA14 GLED_LGPIOB_ModeCfg(GPIO_Pin_4,GPIO_ModeOut_PP_5mA);// PB4 GLED_RRGB_LED_Off();}voidRGB_LED_Off(void){GPIOB_SetBits(GPIO_Pin_4|GPIO_Pin_15);GPIOA_SetBits(GPIO_Pin_11|GPIO_Pin_14);}voidRGB_LED_ON(void){GPIOB_ResetBits(GPIO_Pin_4|GPIO_Pin_15);GPIOA_ResetBits(GPIO_Pin_11|GPIO_Pin_14);}voidRed_LED_STA(uint8_tOnOff){switch(OnOff){case0x00:GPIOB_ResetBits(GPIO_Pin_15);GPIOA_ResetBits(GPIO_Pin_11);break;case0x01:GPIOB_SetBits(GPIO_Pin_15);GPIOA_ResetBits(GPIO_Pin_11);break;case0x10:GPIOB_ResetBits(GPIO_Pin_15);GPIOA_SetBits(GPIO_Pin_11);break;case0x11:GPIOB_SetBits(GPIO_Pin_15);GPIOA_SetBits(GPIO_Pin_11);break;}}voidGrn_LED_STA(uint8_tOnOff){switch(OnOff){case0x00:GPIOB_ResetBits(GPIO_Pin_4);GPIOA_ResetBits(GPIO_Pin_14);break;case0x01:GPIOB_SetBits(GPIO_Pin_4);GPIOA_ResetBits(GPIO_Pin_14);break;case0x10:GPIOB_ResetBits(GPIO_Pin_4);GPIOA_SetBits(GPIO_Pin_14);break;case0x11:GPIOB_SetBits(GPIO_Pin_4);GPIOA_SetBits(GPIO_Pin_14);break;}}voidKEY_Init(void){GPIOA_ModeCfg(KEY1_PIN|KEY2_PIN,GPIO_ModeIN_PU);}uint8_tKEY_Scan(void){if(GPIOA_ReadPortPin(KEY1_PIN)==0){DelayMs(KEY_DELAY_MS);while(GPIOA_ReadPortPin(KEY1_PIN)==0);DelayMs(KEY_DELAY_MS);return1;}if(GPIOA_ReadPortPin(KEY2_PIN)==0){DelayMs(KEY_DELAY_MS);while(GPIOA_ReadPortPin(KEY2_PIN)==0);DelayMs(KEY_DELAY_MS);return2;}return0;}voidKEY_Process(uint8_tkey_val){switch(key_val){case1:Led_All_Sta=!Led_All_Sta;Run_flag=0;flow_step=0;soft_tick=0;if(Led_All_Sta)RGB_LED_ON();elseRGB_LED_Off();break;case2:if(Led_All_Sta==1){Run_flag=!Run_flag;flow_step=0;soft_tick=0;if(Run_flag==0)RGB_LED_ON();}break;}}voidLED_Running(void){if(Run_flag!=1||Led_All_Sta!=1){soft_tick=0;return;}soft_tick++;if(soft_tick>=FLOW_INTERVAL){soft_tick=0;switch(flow_step){case0:Red_LED_STA(0x01);break;case1:Red_LED_STA(0x10);break;case2:Grn_LED_STA(0x01);break;case3:Grn_LED_STA(0x10);break;}flow_step=(flow_step+1)%4;}}intmain(void){LED_Init();KEY_Init();while(1){uint8_tkey=KEY_Scan();KEY_Process(key);LED_Running();DelayMs(1);}}6.4 扩展练习
- 增加更多灯光模式(呼吸灯、随机闪烁等)
- 实现长按功能:短按切换模式,长按(>1秒)进入紧急闪烁
- 用第二个按键实现加速/减速功能
- 切换模式时用LED闪烁次数"播报"新模式编号
总结
本教程基于真实穿越机飞控板,从硬件架构到GPIO编程进行了完整讲解。核心知识点:
- CH582F硬件架构:RISC-V主控 + MPU-6050 + SPL06 + AT2401C + MOSFET驱动
- 开发环境:MounRiver Studio + WCH-Link/WCHISPTool
- GPIO输出:推挽/开漏模式,SDK API与寄存器两种操作方式
- GPIO输入:上拉输入,按键软件消抖标准流程
- 综合应用:状态机+非阻塞定时实现多模式切换
后续教程将涵盖I2C读取MPU-6050、SPI读取SPL06、PID控制算法、BLE通信等内容,敬请关注。
原创不易,觉得有用请点赞收藏,后续更新不迷路。