基于官方 openwch/ch583 SDK 的 EVT/EXAM/BLE/Peripheral 例程改,用 MounRiver Studio 编译,核心板 USB 口 + WCHISPTool 下载。功能:蓝牙开关/调光 + 旋转编码器调光 + 按键(开关/延时关机) + PWM 调光输出。对应你们手绘原理图:调光 PWM 直接驱动 TLV62569 的 EN 脚(占空比=亮度,0%=关灯),电流由 LMV321 采样放大器恒定。
mounriver.com/download,RISC-V 版)。github.com/openwch/ch583。用 MounRiver 打开 EVT/EXAM/BLE/Peripheral 工程(.wvproj)。先原样编译烧一遍确认工具链通,手机用 nRF Connect 能搜到 "Simple Peripheral" 再往下改。wchisp)下载 .hex/.bin。之后普通复位运行。| 功能 | CH582F 脚 | 接到 |
|---|---|---|
| 调光 PWM(→EN) | PB22 (TMR3) | TLV62569 EN(占空比=亮度) |
| 编码器 A | PB10 | EC11 A |
| 编码器 B | PB11 | EC11 B |
| 编码器按下 K0 | PB12 | EC11 按键 |
| 按键 K1 开/关 | PB14 | 轻触开关→GND |
| 按键 K2 延时关机 | PB15 | 轻触开关→GND |
| 按键 K3 备用 | PA4 | 轻触开关→GND |
| 调试串口 | PB7=TXD0 | printf 调试(可选) |
若你们原理图上的 PWM/按键接的是别的脚,改下面 lamp.h 的宏即可,逻辑不变。全部输入用内部上拉,按键/编码器另一端接 GND。所有 GPIO 都是 3.3V,别接 5V。
// lamp.h —— 台灯硬件控制层 #ifndef __LAMP_H #define __LAMP_H #include "CH58x_common.h" // ---- 引脚(按原理图/核心板丝印改)---- #define PWM_PORT_B // 调光PWM在PB22(TMR3) #define ENC_A_PIN GPIO_Pin_10 // PB10 编码器A #define ENC_B_PIN GPIO_Pin_11 // PB11 编码器B #define ENC_K_PIN GPIO_Pin_12 // PB12 编码器按下 #define KEY1_PIN GPIO_Pin_14 // PB14 开/关 #define KEY2_PIN GPIO_Pin_15 // PB15 延时关机 // KEY3 在 PA4,单独处理 #define BRIGHT_MAX 255 // 亮度 0~255 #define BRIGHT_STEP 13 // 编码器每格±13(0~255满量程约20格) void Lamp_Init(void); // 初始化PWM+GPIO+中断 void Lamp_SetLevel(uint8_t level); // 设亮度0~255(0=关) uint8_t Lamp_GetLevel(void); void Lamp_On(void); // 恢复上次亮度 void Lamp_Off(void); // 关(PWM=0) void Lamp_Toggle(void); void Lamp_StartDelayOff(uint16_t sec); // 延时关机 void Lamp_Poll(void); // 主循环轮询(消抖/延时计时),放tmos周期任务 #endif
// lamp.c #include "lamp.h" static uint8_t s_level = 0; // 当前亮度 static uint8_t s_lastLevel = 128; // 关灯前的亮度(用于开灯恢复) static volatile uint8_t s_encA_last = 1; static uint32_t s_delayTicks = 0; // 延时关机剩余(10ms为单位) // ---- PWM: TMR3 输出到 PB22,频率≈200Hz(EN软启动要求低频) ---- // Fsys=60MHz。周期计数 = 60e6/200 = 300000 #define PWM_CYCLE 300000UL void PWM_Init(void) { GPIOB_ModeCfg(GPIO_Pin_22, GPIO_ModeOut_PP_5mA); GPIOB_ResetBits(GPIO_Pin_22); // TMR3 PWM 模式,高电平有效 TMR3_PWMInit(High_Level, PWM_Times_1); TMR3_PWMCycleCfg(PWM_CYCLE); // 设周期→200Hz TMR3_PWMActDataWidth(0); // 初始占空0=关 TMR3_Disable(); // 灯默认关 // 注意:TMR3 PWM 输出脚映射到 PB22,若SDK需要remap请查 CH58x_timer/GPIOPinRemap } void Lamp_SetLevel(uint8_t level) { if(level > BRIGHT_MAX) level = BRIGHT_MAX; s_level = level; if(level == 0){ TMR3_PWMActDataWidth(0); TMR3_Disable(); // 0%→关灯,EN一直低 }else{ uint32_t duty = (uint32_t)PWM_CYCLE * level / BRIGHT_MAX; TMR3_PWMActDataWidth(duty); TMR3_Enable(); s_lastLevel = level; } // 亮度变了→通过BLE notify上报(见peripheral.c里的hook) } uint8_t Lamp_GetLevel(void){ return s_level; } void Lamp_On(void){ Lamp_SetLevel(s_lastLevel ? s_lastLevel : 128); } void Lamp_Off(void){ Lamp_SetLevel(0); } void Lamp_Toggle(void){ if(s_level) Lamp_Off(); else Lamp_On(); } void Lamp_StartDelayOff(uint16_t sec){ s_delayTicks = (uint32_t)sec * 100; } // 10ms单位 // ---- GPIO 初始化:编码器+按键,全部上拉输入+中断 ---- void Lamp_Init(void) { PWM_Init(); // 编码器 A/B/按下 (PB10/11/12) GPIOB_ModeCfg(ENC_A_PIN|ENC_B_PIN|ENC_K_PIN, GPIO_ModeIN_PU); GPIOB_ITModeCfg(ENC_A_PIN, GPIO_ITMode_FallEdge); // A相下降沿触发解码 GPIOB_ITModeCfg(ENC_K_PIN, GPIO_ITMode_FallEdge); // 按键 K1/K2 (PB14/15) + K3(PA4) GPIOB_ModeCfg(KEY1_PIN|KEY2_PIN, GPIO_ModeIN_PU); GPIOA_ModeCfg(GPIO_Pin_4, GPIO_ModeIN_PU); PFIC_EnableIRQ(GPIO_B_IRQn); s_encA_last = (GPIOB_ReadPortPin(ENC_A_PIN)?1:0); } // ---- 编码器中断:A相边沿时读B相判方向 ---- __INTERRUPT __HIGH_CODE void GPIOB_IRQHandler(void) { uint16_t flag = GPIOB_ReadITFlagPort(); if(flag & ENC_A_PIN){ uint8_t b = GPIOB_ReadPortPin(ENC_B_PIN)?1:0; // A下降沿:B=1顺时针(增),B=0逆时针(减) int16_t lv = s_level + (b ? BRIGHT_STEP : -BRIGHT_STEP); if(lv < 0) lv = 0; if(lv > BRIGHT_MAX) lv = BRIGHT_MAX; Lamp_SetLevel((uint8_t)lv); } if(flag & ENC_K_PIN){ // 编码器按下=开关 Lamp_Toggle(); } GPIOB_ClearITFlagBit(flag); } // ---- 主循环轮询:按键消抖 + 延时关机计时。放tmos周期任务里,每10ms调一次 ---- void Lamp_Poll(void) { static uint8_t k1=0,k2=0; // K1 开/关 (低有效,简单消抖) if(!GPIOB_ReadPortPin(KEY1_PIN)){ if(++k1==2) Lamp_Toggle(); } else k1=0; // K2 延时关机:按一下设30分钟(可改) if(!GPIOB_ReadPortPin(KEY2_PIN)){ if(++k2==2) Lamp_StartDelayOff(30*60); } else k2=0; // 延时关机倒计时 if(s_delayTicks){ if(--s_delayTicks==0) Lamp_Off(); } }
官方 Peripheral 例程自带 SimpleProfile(服务 UUID 0xFFF0)。直接复用它的特征值:
| 特征 | UUID | 属性 | 本项目用途 |
|---|---|---|---|
| CHAR1 | 0xFFF1 | 读+写 | 亮度 0~255(App 写=调光,读=当前值) |
| CHAR3 | 0xFFF3 | 写 | 开关:写 1=开, 0=关 |
| CHAR4 | 0xFFF4 | 通知 | 状态上报(亮度/开关变化时 notify 给 App) |
在 peripheral.c 的写回调 simpleProfileChangeCB() 里,把收到的值转成台灯动作:
// peripheral.c —— 找到 simpleProfileChangeCB,改成: static void simpleProfileChangeCB(uint8_t paramID, uint8_t *pValue, uint16_t len) { switch(paramID){ case SIMPLEPROFILE_CHAR1: // App写亮度 0~255 Lamp_SetLevel(pValue[0]); break; case SIMPLEPROFILE_CHAR3: // App写开关 if(pValue[0]) Lamp_On(); else Lamp_Off(); break; default: break; } // 变化后把最新亮度回写CHAR1并notify(CHAR4),让App同步 uint8_t lv = Lamp_GetLevel(); SimpleProfile_SetParameter(SIMPLEPROFILE_CHAR1, 1, &lv); }
SimpleProfile_AddService()、simpleProfile_ReadAttrCB/WriteAttrCB 都是现成的,你只改 simpleProfileChangeCB 的分支即可。要 notify 状态就用例程里 CHAR4 的 simpleProfile_Notify 那套(Peripheral 例程有演示定时 notify,照抄改成"亮度变化时 notify")。GATT 服务名/UUID 想自定义可改 gattprofile.c 里的 UUID 表。// main.c 或 peripheral.c 的 Peripheral_Init() 末尾加: Lamp_Init(); // 用 tmos 周期任务跑 Lamp_Poll() —— 在 Peripheral_ProcessEvent 里加一个事件: #define LAMP_POLL_EVT (1 << 4) // 选个没用的事件位 // Peripheral_Init() 里启动周期任务: tmos_start_task(Peripheral_TaskID, LAMP_POLL_EVT, MS1_TO_SYSTEM_TICK(10)); // 10ms // Peripheral_ProcessEvent() 里处理: if(events & LAMP_POLL_EVT){ Lamp_Poll(); tmos_start_task(Peripheral_TaskID, LAMP_POLL_EVT, MS1_TO_SYSTEM_TICK(10)); return (events ^ LAMP_POLL_EVT); }
别忘了 #include "lamp.h",并把 lamp.c 加进工程源文件。TMR3/GPIO 相关头(CH58x_timer.h、CH58x_gpio.h)SDK 已 include 在 CH58x_common.h。
Lamp_Init+Lamp_SetLevel,串口/按键把亮度从 0→100,示波器看 PB22 PWM 占空比、万用表看 LED 电流(量 Rcs 压降 ÷ Rcs)。TMR3_PWMInit / TMR3_PWMCycleCfg / TMR3_PWMActDataWidth、GPIO 中断 GPIOB_ITModeCfg/ReadITFlagPort/ClearITFlagBit)。以你们下载的 SDK 里 StdPeriphDriver/inc/CH58x_timer.h、CH58x_gpio.h 的实际声明为准,对不上就按头文件里的名字调。TMR3 PWM 输出到 PB22 若需要引脚重映射,查 GPIOPinRemap()。基于 openwch/ch583 · Peripheral 例程 · MounRiver Studio 编译 · WCHISPTool USB 下载 · 手机 App 另发