专业版
#第十届立创电赛#手电控制核心板

创建时间:2个月前

78 0

描述

<h1><strong>版本更新说明</strong></h1> <ul> <li><strong>V0.1</strong> 立项,调光功能完成</li> <li><strong>V0.2</strong> 引入档位关联的温度控制</li> <li><strong>V0.3</strong> 改用PID控制</li> <li><strong>V0.4</strong> 平滑PID温控</li> <li><strong>V1.0</strong> 首个完成版,开关机功能引入</li> <li><strong>V1.1</strong> 修改上电时序,修复若干()bug,现版本 <strong>注意:图片不是最新的,PCB版本号独立,修复开关机问题炸了我五块板子,彩蛋是感谢ME6203这个美丽到爆炸的LDO。若干/bug里面也能有违禁词?</strong> <hr> <h1><strong>一、项目功能介绍</strong></h1> <h3>1、核心功能概述</h3> <p>可拓展小电包-手电模块-控制核心板 这是一个手电项目的核心板,实现了受按键控制的双路PWM输出,用以控制LED恒流模块,以及通过NTC实现的温度检测及与之对应的风扇PWM控制,为LED模块提供温度管理。 其余可能的应用:加热台、风扇控制等。</p></li> </ul> <p><img src="https://image.lceda.cn/oshwhub/pullImage/81c98f080c2b443ea5c696014665c424.png" alt="7B932AB2F481FF918C3747F1E1D8B6FA.png"></p> <h3>2、LED调光控制</h3> <ul> <li>双通道独立控制: <ul> <li>通道A/B独立控制,支持单通道或双通道同时操作</li> <li>三种工作模式:仅A通道、仅B通道、双通道同步</li> </ul></li> <li>丝滑调光功能: <ul> <li>短按:±10%占空比调节(20kHz PWM)</li> <li>长按:无极调光(每60ms ±1%)</li> </ul></li> <li>状态记忆功能: <ul> <li>自动保存各通道亮度设置(不含掉电保存)</li> <li>模式切换时无缝恢复历史状态</li> </ul></li> </ul> <h3>3. 温度控制系统</h3> <ul> <li>温度监测: <ul> <li>10KΩ NTC温度传感器(B=3950)</li> <li>基于内部ADC电压检测</li> </ul></li> <li>风扇控制: <ul> <li>基于增量式PID</li> <li>带调整率限制平滑输出</li> </ul></li> </ul> <h3>4. 用户交互系统</h3> <ul> <li>三按键简洁操作: <ul> <li>KEY1:增加亮度(短按+10%占空比、长按每60ms+1%)</li> <li>KEY2:减少亮度(短按-10%占空比、长按每60ms-1%)</li> <li>KEY3:短按模式切换/长按开关机</li> </ul></li> </ul> <h1><strong>二、项目属性/开源协议</strong></h1> <p>项目首次公开,本人原创,转载商用请联系 仅开源部分源代码和一个可供烧录的固件 使用CC BY-NC-SA 4.0协议 商业应用请联系作者,无许可的商业应用会被追责</p> <h1><strong>三、硬件部分</strong></h1> <p>此部分乏善可陈 使用si2300和2301两颗mos及两颗二极管构建了开关机电路 使用ME6203这颗LDO将不高于40V的电压降压至3.3V 10K的NTC(B=3950)与另一颗10K电阻构成分压电路检测温度 按键板与核心板分离便于设计结构 提供一体的PCB以节约打样时间及费用 警告:因为SI2300与2301耐压仅支持到20V,故请勿将此方案用于输入电压高于20V的场景,可更换MOS及LDO支持更高的电压 最新的硬件版本修复了此问题,输入电源先经过LDO防止炸穿单片机,输出部分通过专门的板载低侧mos驱动输出较高的电压,或使用0R电阻跳过驱动芯片,将驱动集成在电源管理模块端(后者是最后采用的方案)</p> <h1><strong>四、软件部分</strong></h1> <h3>1. 系统架构</h3> <pre><code class="language-c">main.c ├── 初始化配置 │ ├── 时钟系统配置(64MHz) │ ├── GPIO初始化(按键/PWM/电源) │ ├── 定时器配置(TIM1/TIM3/TIM14) │ └── ADC初始化(温度采样) ├── 主循环 │ └── 电源保护检测 └── 中断系统 ├── TIM14中断(10ms按键扫描) └── PID计算和输出</code></pre> <h3>2. 核心算法实现</h3> <h4>PID算法</h4> <pre><code class="language-c">// 初始化PID控制器 void PID_Init(PID_Controller* pid, float setpoint, float Kp, float Ki, float Kd, float min, float max, float rate_max) { pid->setpoint = setpoint; pid->Kp = Kp; pid->Ki = Ki; pid->Kd = Kd; pid->output_min = min; pid->output_max = max; pid->output_rate_max = rate_max; pid->prev_error = 0.0; pid->prev_error2 = 0.0; pid->prev_output = 0.0; } // 增量式PID计算函数 float PID_Calculate(PID_Controller* pid, float measured_value) { // 1. 计算误差 (保持您原来的定义) float error = measured_value - pid->setpoint; // 2. 计算增量 (根据增量式PID公式: Δu = Kp*(e[k]-e[k-1]) + Ki*e[k] + Kd*(e[k]-2e[k-1]+e[k-2])) float delta_output = 0.0; delta_output += pid->Kp * (error - pid->prev_error); // 比例项 delta_output += pid->Ki * error; // 积分项 delta_output += pid->Kd * (error - 2 * pid->prev_error + pid->prev_error2); // 微分项 // 3. 更新历史误差 pid->prev_error2 = pid->prev_error; pid->prev_error = error; // 4. 计算本次的目标输出值 float target_output = pid->prev_output + delta_output; // 5. 对目标输出进行限幅 if (target_output > pid->output_max) { target_output = pid->output_max; } else if (target_output < pid->output_min) { target_output = pid->output_min; } // 6. 应用输出变化率限制 float final_output = target_output; // 先假设最终输出等于目标输出 // 计算允许的最大和最小输出(基于上一次输出和变化率限制) float max_output_allowed = pid->prev_output + pid->output_rate_max; float min_output_allowed = pid->prev_output - pid->output_rate_max; // 如果目标输出超出了变化率允许的范围,则将其限制在边界上 if (target_output > max_output_allowed) { final_output = max_output_allowed; } else if (target_output < min_output_allowed) { final_output = min_output_allowed; } // 确保最终输出仍在绝对限幅范围内(二次保护) if (final_output > pid->output_max) final_output = pid->output_max; if (final_output < pid->output_min) final_output = pid->output_min; // 7. 保存本次输出,用于下一次计算 pid->prev_output = final_output; return final_output; }</code></pre> <h4>LED通道控制</h4> <pre><code class="language-c">// KEY3短按处理(通道切换) void Handle_Key3_Short(void) { // 切换到下一个通道 current_channel = (current_channel == CH_BOTH) ? CH_A : (current_channel + 1); // 根据通道模式更新PWM输出 switch(current_channel) { case CH_A: saved_dutyB = dutyB; //保存B的占空比 saved_dutyA = dutyA; //保存A的占空比 dutyB = 0; //关闭通道B dutyA = saved_dutyA; //恢复通道A break; case CH_B: saved_dutyA = dutyA; dutyA = 0; dutyB = saved_dutyB; break; case CH_BOTH: // 恢复A通道的保存值 dutyA = saved_dutyA; break; } // 更新PWM输出 __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, dutyA * 32); __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_2, dutyB * 32); }</code></pre> <h4>按键扫描函数</h4> <pre><code class="language-c">// 按键扫描函数(在TIM14中断中调用) void Key_Scan(void) { for(int i = 0; i < 3; i++) { uint8_t current = HAL_GPIO_ReadPin(keys[i].port, keys[i].pin); switch(keys[i].state) { case 0: // IDLE状态 if(current == GPIO_PIN_RESET) { // 按键按下 keys[i].state = 1; // 进入DEBOUNCE状态 keys[i].press_timer = 0; } break; case 1: // DEBOUNCE状态 if(++keys[i].press_timer > 2) { // 20ms消抖 keys[i].state = (current == GPIO_PIN_RESET) ? 2 : 0; // PRESSED或IDLE } break; case 2: // PRESSED状态 if(current == GPIO_PIN_SET) { // 按键释放 if(i == 2) Handle_Key3_Short(); // KEY3短按 else Handle_ShortPress(i); // KEY1/KEY2短按 keys[i].state = 0; // 回到IDLE } else { // 长按判断:KEY1/KEY2为1秒(100*10ms),KEY3为3秒(300*10ms) uint16_t threshold = (i == 2) ? 300 : 100; if(++keys[i].press_timer > threshold) { Handle_LongPress(i); keys[i].state = 3; // 进入LONG_PRESS状态 } } break; case 3: // LONG_PRESS状态 if(current == GPIO_PIN_SET) { // 按键释放 keys[i].state = 0; // 回到IDLE } else if(i != 2) { // 仅KEY1/KEY2有无极调光 // 每60ms调整一次 (10ms中断 * 6 = 60ms) if(keys[i].press_timer % 6 == 0) { Handle_ContinuousAdjust(i); } keys[i].press_timer++; } break; } } } </code></pre> <h4>温度计算</h4> <pre><code class="language-c">float Read_Temperature(void) { //获取ADC值 uint32_t adc_value = HAL_ADC_GetValue(&hadc1); //计算电阻值 float R_ntc = ((4095.0f - adc_value) / adc_value) * 10000.0f; // Steinhart-Hart方程计算温度 (B=3950) float T0 = 25.0f + 273.15f; // 25°C in Kelvin float B = 3950.0f; float R0 = 10000.0f; // NTC在25°C时的电阻值 float steinhart = logf(R_ntc / R0) / B + 1.0f / T0; float temp_kelvin = 1.0f / steinhart; return temp_kelvin - 273.15f; // 返回摄氏度 }</code></pre> <h3>3. 关键设计特点</h3> <ul> <li>往tim14中断里塞塞塞,有按键扫描、PID计算和开机计时</li> <li>较为清晰的函数封装,代价是注释写爽了 <h1><strong>五、复刻注意</strong></h1> <p>注意:复刻项目时务必注意mos耐压,防止过压烧穿单片机 目前版本并无问题,以下再次重复注意点</p> <p>输出部分通过专门的板载低侧mos驱动输出较高的电压,或使用0R电阻跳过驱动芯片,将驱动集成在电源管理模块端(后者是最后采用的方案)</p> </li> </ul> <p><strong>详细的装配教程会在后续专门的手电工程开源,敬请期待哦~</strong></p> <h3>1. 烧录:本项目使用SW烧录,需购买ST-link烧录器,依次链接以下引脚</h3> <ul> <li>GND-GND</li> <li>5V-PWR</li> <li>SWDIO-DIO</li> <li>SWCLK-CLK</li> </ul> <h3>2.焊接</h3> <p>注意STM32G030F6P6引脚比较密集,不要连锡,上电前排查短路情况</p> <h1>六、大赛LOGO及演示视频</h1> <p>请见附件及图片</p> <p><img src="https://image.lceda.cn/oshwhub/pullImage/cbbfec07247e440d9c4aee7be04ee4a3.png" alt="1EA8DD147D4B6FFE0FC4D7E17E4FC9F7.png"></p>

文档

BOM

暂无

附件

附件名 下载
IMG_2458.MP4
Release-V1.1.hex
Release-V1.1.bin

评论(0)

  • 表情
    emoji
    小嘉工作篇
    小嘉日常篇
  • 图片
成功
工程所有者当前已关闭评论
goToTop
svg-battery svg-battery-wifi svg-books svg-more svg-paste svg-pencil svg-plant svg-ruler svg-share svg-user svg-logo-cn svg-double-arrow