受远在太平洋的拉尼娜现象影响,今年入夏困难,已经五月天气依然凉爽。风扇基本用不上,如果实在想用最好限制一下转速,免得凉意更浓。
增加几个功能模式,实现对电机转速控制与电流监测形成完整闭环。
一、电子开关控制风扇转速
使用电子开关可以控制风扇的转速,也可以称电子开关为PWM调节电子开关控制板或大功率MOS管模块
特点:
采用双MOS并联有源输出,内阻低,电流打,功率强,常温下15A,400W,宽电压,支持PWM,工作电压:DC5V-36V
触发信号源:数字量高低电平(DC3.3V-20V),可以接单片机IO口,PLC接口、直流电源等,可以接PWM信号,信号频率0-20khz。
输出能力:直流DC5V-36V,常温下15A,400W,辅助散热条件下,最大电流可达30A
二、旋转编码器改变PWM占空比
电子开关的PWM信号由单片机提供,PWM的占空比决定了电子开关输出功率。
为了控制PWM占空比,再添加一个旋转编码器
三、整理一下示意图
1、旋转编码器调节电子开关PWM信号的占空比
2、电子开关在PWM信号作用下,开关,调速控制电机(风扇)旋转
3、INA219测量电压电流功率,如果电流超过电流阈值,启动过流保护(自锁或打嗝)
4、OLED显示相关信息
实物:
电子开关
旋转编码器
风扇
取电5V
四、软件部分
1、电子开关使用TIM1
频率:32MHZ/(31+1)/(49+1)=200KHZ
占空比:25/50=50%
改变占空比函数,通过这个函数可以控制风扇转速:
void TIM_SetTIM1Compare2(uint32_t compare) { if(compare<0||compare>50) return; __HAL_TIM_SET_COMPARE(htimPwm, TIM_CHANNEL_2, compare); // compare为新的占空比值 }
TIM1配置函数,启动PWM。
void pwm_config(TIM_HandleTypeDef *htim) { htimPwm=htim; if (HAL_TIM_PWM_Start(htimPwm, TIM_CHANNEL_2) != HAL_OK) { /* PWM Generation Error */ Error_Handler(); } }
2、旋转编码器使用TIM3
GPIO使用:
void encoder_config(TIM_HandleTypeDef *htim) { htimEncoder=htim; __HAL_TIM_GET_COUNTER(htimEncoder) = 40; //计数器值置位 HAL_TIM_Encoder_Start(htimEncoder, TIM_CHANNEL_ALL); } void encoder_process(void) { CaptureNumber=get_encoder_value(); if(CaptureNumber<0){ CaptureNumber=0; __HAL_TIM_GET_COUNTER(htimEncoder) = 0; } if(CaptureNumber>50){ CaptureNumber=50; __HAL_TIM_GET_COUNTER(htimEncoder) = 50; } printf("电子开关PWM占空比:%d%%\r\n",CaptureNumber*2); TIM_SetTIM1Compare2(CaptureNumber); //} }
设置编码器起始值40(最大50,40对应TIM180%占空比)
调节编码器数值在0-50之间,对应TIM1(0%-100%占空比)
通过get_encoder_value获得当期编码器数值:
int16_t get_encoder_value() { return (int16_t)TIM3->CNT; // 返回当前编码器计数值(带方向) }
通过__HAL_TIM_GET_COUNTER(htimEncoder) 设置编码器数值。
通过TIM_SetTIM1Compare2(CaptureNumber)以CaptureNumber为参数设置电子开关占空比。
3、INA219过流处理
#define cur_threshold 190 //过流阈值190毫安
uint8_t overcur_flag=0; //过流自锁生效标志
uint8_t hiccup_flag=0; //过流打嗝生效标志
volatile uint8_t wait_flag=0; //过流自锁后等待标志
#define Self_Locking_Mode 0 //自锁模式
#define Hiccup_Mode 1 //打嗝模式
static uint8_t CTR_Mode=Self_Locking_Mode; //当期过流模式选择:缺省自锁
用USER BUTTON(PC13)外部中断方式切换过流处理模式:
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { if (GPIO_Pin == B1_Pin) { // 检查是哪个引脚触发的中断 if(CTR_Mode==Self_Locking_Mode){ CTR_Mode=Hiccup_Mode; printf("Change mode to Hiccup_Mode\r\n"); }else { CTR_Mode=Self_Locking_Mode; printf("Change mode to Self_Locking_Mode\r\n"); } } }
处理INA219传感器数据并显示:
void INA219_process(void) { static uint32_t Hiccup_Time; static uint32_t lastDisplayUpdate = 0; const uint32_t DISPLAY_UPDATE_INTERVAL = 250; // 显示更新间隔(ms) // 读取传感器数据 float busVoltage = INA219_ReadBusVoltage(); float shuntVoltage = INA219_ReadShuntVoltage(); float current = INA219_ReadCurrent(); float power = busVoltage * current; // 调试信息输出 printf("Bus Voltage: %.2f V\n", busVoltage); printf("Shunt Voltage: %.2f mV\n", shuntVoltage * 1000); printf("Current: %.2f mA\n", current * 1000); printf("Power: %.2f mW\n", power * 1000); printf("\r\n"); // Hiccup模式处理 if((HAL_GetTick() - Hiccup_Time) >= 3000 && hiccup_flag == 1 && CTR_Mode == Hiccup_Mode) { hiccup_flag = 0; Hiccup_Time = HAL_GetTick(); __HAL_TIM_SET_COUNTER(htimEncoder, 40); TIM_SetTIM1Compare2(40); } // 过流处理 if(current * 1000 > cur_threshold) { if(CTR_Mode == Self_Locking_Mode) { overcur_flag = 1; } else if(CTR_Mode == Hiccup_Mode) { hiccup_flag = 1; } __HAL_TIM_SET_COUNTER(htimEncoder, 0); TIM_SetTIM1Compare2(0); } // 显示处理 if(wait_flag == 1) { App_Show_Clock_Info(); HAL_Delay(200); } if(CaptureNumber > 0 && wait_flag == 1) { wait_flag = 0; overcur_flag = 0; OLED_ShowChineseString16(0, 0, (uint8_t*)"DIY功率监测与控制", 1); } if(wait_flag != 1) { if(overcur_flag == 1 || hiccup_flag == 1) { App_Show_Clock_Info(); HAL_Delay(500); wait_flag = 1; } else { // 仅在需要更新时刷新显示 if(HAL_GetTick() - lastDisplayUpdate >= DISPLAY_UPDATE_INTERVAL) { lastDisplayUpdate = HAL_GetTick(); char buff[20] = {0}; // 显示电流、电压、功率 sprintf(buff, "电流:%5.2fmA ", current * 1000); OLED_ShowChineseString16(0, 16, (uint8_t*)buff, 1); sprintf(buff, "电压:%5.2fV ", busVoltage); OLED_ShowChineseString16(0, 32, (uint8_t*)buff, 1); sprintf(buff, "功率:%5.2fmW ", power * 1000); OLED_ShowChineseString16(0, 48, (uint8_t*)buff, 1); // 绘制条形图边框 OLED_DrawRectangle(117, 16, 127, 63); // 更新垂直条形图(高度根据CaptureNumber计算) OLED_DrawVerticalBar(117, 16, 10, 47, 2 * CaptureNumber); // 根据控制模式显示不同图标 if(CTR_Mode == Self_Locking_Mode) { OLED_DrawFillRectangle(111, 17, 115, 40); OLED_DrawFillRectangleClear(111, 41, 115, 63); } else if(CTR_Mode == Hiccup_Mode) { OLED_DrawFillRectangle(111, 41, 115, 63); OLED_DrawFillRectangleClear(111, 17, 115, 40); } // 优化后的滚动效果 for(uint8_t i = 0; i < 4; i++) { OLED_ShiftTwoRowsLeft(0, 3); HAL_Delay(DISPLAY_UPDATE_INTERVAL); } OLED_Refresh(); } } } }
4、OLED显示相关
在第一行显示过流状态:
void App_Show_Clock_Info(void) { static uint8_t i=0; if(CTR_Mode==Self_Locking_Mode) { OLED_ShowChineseString16(0,0,(uint8_t*)"过流状态:Locking ",i); }else OLED_ShowChineseString16(0,0,(uint8_t*)"过流状态:Hiccup ",i); OLED_Refresh(); i=~i; }
分段显示Bmp:从上到下分四段显示bmp1,最后显示Title
void App_Show_Title_Info(void) { OLED_Clear(); OLED_Copy_Bmp(0,0,128,16,bmp1,0,0); OLED_Refresh(); HAL_Delay(100); OLED_Copy_Bmp(0,16,128,16,bmp1,0,16); OLED_Refresh(); HAL_Delay(100); OLED_Copy_Bmp(0,32,128,16,bmp1,0,32); OLED_Refresh(); HAL_Delay(100); OLED_Copy_Bmp(0,48,128,16,bmp1,0,48); OLED_Refresh(); HAL_Delay(100); OLED_Clear(); OLED_Clear_Buffer(); OLED_ShowChineseString16(0,0,(uint8_t*)"DIY功率监测与控制",1); OLED_Refresh(); }
绘制垂直百分比条形图函数,用来绘制TIM1占空比示意
/** * @brief 绘制垂直百分比条形图 * @param x: 条形图左上角x坐标 * @param y: 条形图左上角y坐标 * @param width: 条形图宽度 * @param height: 条形图总高度(100%对应的高度) * @param percent: 要显示的百分比(0-100) * @param filled: 是否填充(1=填充,0=空心) * @retval 无 */ void OLED_DrawVerticalBar(uint8_t x, uint8_t y, uint8_t width, uint8_t height, uint8_t percent) { // 计算实际填充高度 uint8_t bar_height = (height * percent) / 100; // 确保不超过最大高度 if(bar_height > height) { bar_height = height; } // 计算条形图底部y坐标 uint8_t bar_bottom = y + height - 1; // 计算填充部分的顶部y坐标 uint8_t fill_top = bar_bottom - bar_height + 1; OLED_DrawFillRectangleClear(x,y,x+width,bar_bottom-bar_height); // 绘制填充条形图 OLED_DrawFillRectangle(x, fill_top, x + width - 1, bar_bottom); }
五、运行效果
1、自锁
2、打嗝
3、调节电子开关输入信号占空比
4、切换过流模式