基于stm32的自动调速风扇(只是资料程序,无实物) 1)使用的芯片为STM32最小系统板来作为中心控制器。 (2)驱动电机用L298N芯片驱动直流电机。 (3)传感器模块使用热释电人体红外传感模块HC-SR501. (4)用数字式集成温度传感器DS1820来作为测试温度的主要元件。 (5)显示数字使用的是0.96七位OLBD显示屏。 第一:电源开启,默认为自动模式、温度随时显示在OLED上 第二:模式选择: 按键1是选择键 按键2是确定键 按键3是加键 按键4是减键 第三:当按1时,有两个选择为自动模式和手动模式,选择完毕后,按2, 第四:当选择自动模式时,红外检测是否有人,电机转速随着温度的变化而变化,当室温低于25度时,就算红外传感器检测到人,电机也不会转动为零档,占空比为0%;当室温大于等于25度且低于28度时,电机开始转动为一档,占空比为30%;当室温大于等于28度且低于32度时,电机转动为二档,占空比为50%;当室温大于等于32度且低于36度时,电机转动为三档,占空比为80%;当室温大于等于36度,电机转动最大为四档,占空比为100% 第五:当选择手动模式时,按“确定”键,系统默认开始时为一档,通过按键的加键来实现对档数的增加,也通过度按键的诚键来实现对档数的减少,但是在一档即最小档的时候无法减少,在最大档即第四档的时候无法增加,最后确定自己所需要的档数按下确定键,则芯片会根据所选择的档数来实现对电机转速的增加或减少。 电机PW1转速为30%时为一档当电机PW1转速为50%时为二档,当电机PV1转速为80%时为三档,当电机PVI转速为100%时为最高档。

先说说这个自动调速风扇的脑回路。整个系统用STM32F103C8T6最小系统板当大脑,搭配L298N电机驱动模块给风扇供电,OLED实时显示温度。这玩意儿核心玩法就是根据温度变化自动调风速,或者手动装X调档位。

先上点硬核代码,看看PWM初始化怎么搞。定时器3通道1输出,GPIOB第4脚:

void PWM_Init(void){
    GPIO_InitTypeDef GPIO_InitStructure;
    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
    TIM_OCInitTypeDef TIM_OCInitStructure;

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB, &GPIO_InitStructure);

    TIM_TimeBaseStructure.TIM_Period = 999; 
    TIM_TimeBaseStructure.TIM_Prescaler = 71;
    TIM_TimeBaseStructure.TIM_ClockDivision = 0;
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);

    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
    TIM_OCInitStructure.TIM_Pulse = 0; 
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
    TIM_OC1Init(TIM3, &TIM_OCInitStructure);

    TIM_Cmd(TIM3, ENABLE);
}

这段配置生成了10kHz的PWM波,ARR寄存器设999,预分频72MHz主频除以72得1MHz,这样每个周期1ms刚好对应1000级精度。注意TIM3_CH1对应的PB4引脚需要复用推挽输出。

温度检测用DS18B20这老伙计,单总线协议得伺候好时序:

float DS18B20_GetTemp(void){
    uint8_t tempL, tempH;
    int16_t temp;
    DS18B20_Start();
    DS18B20_ReadByte(); // 跳过ROM
    tempL = DS18B20_ReadByte();
    tempH = DS18B20_ReadByte();
    temp = (tempH << 8) | tempL;
    return temp * 0.0625; // 12位精度转换
}

重点在0.0625这个系数,DS18B20返回的是12位整型数据,最低4位是小数部分。比如读到0x0191(401),实际温度就是25.0625℃。这里直接浮点运算简单粗暴,实际项目建议用定点数优化。

基于stm32的自动调速风扇(只是资料程序,无实物) 1)使用的芯片为STM32最小系统板来作为中心控制器。 (2)驱动电机用L298N芯片驱动直流电机。 (3)传感器模块使用热释电人体红外传感模块HC-SR501. (4)用数字式集成温度传感器DS1820来作为测试温度的主要元件。 (5)显示数字使用的是0.96七位OLBD显示屏。 第一:电源开启,默认为自动模式、温度随时显示在OLED上 第二:模式选择: 按键1是选择键 按键2是确定键 按键3是加键 按键4是减键 第三:当按1时,有两个选择为自动模式和手动模式,选择完毕后,按2, 第四:当选择自动模式时,红外检测是否有人,电机转速随着温度的变化而变化,当室温低于25度时,就算红外传感器检测到人,电机也不会转动为零档,占空比为0%;当室温大于等于25度且低于28度时,电机开始转动为一档,占空比为30%;当室温大于等于28度且低于32度时,电机转动为二档,占空比为50%;当室温大于等于32度且低于36度时,电机转动为三档,占空比为80%;当室温大于等于36度,电机转动最大为四档,占空比为100% 第五:当选择手动模式时,按“确定”键,系统默认开始时为一档,通过按键的加键来实现对档数的增加,也通过度按键的诚键来实现对档数的减少,但是在一档即最小档的时候无法减少,在最大档即第四档的时候无法增加,最后确定自己所需要的档数按下确定键,则芯片会根据所选择的档数来实现对电机转速的增加或减少。 电机PW1转速为30%时为一档当电机PW1转速为50%时为二档,当电机PV1转速为80%时为三档,当电机PVI转速为100%时为最高档。

模式切换的状态机才是精髓所在:

typedef enum {AUTO_MODE, MANUAL_MODE} ModeType;

void Key_Process(ModeType *mode){
    static uint8_t menu_level = 0;
    
    if(KEY1_DOWN){ // 模式选择
        menu_level = !menu_level;
        OLED_Clear();
    }
    
    if(KEY2_DOWN){ // 确认
        if(menu_level == 0) *mode = AUTO_MODE;
        else *mode = MANUAL_MODE;
    }
    
    if(*mode == MANUAL_MODE){
        if(KEY3_DOWN) current_gear = MIN(current_gear+1, 4);
        if(KEY4_DOWN) current_gear = MAX(current_gear-1, 1);
    }
}

这个状态机处理了三级菜单交互:按KEY1切换自动/手动选项,KEY2确认选择,手动模式下用KEY3/KEY4调档。注意MIN和MAX宏防止档位越界,比if判断更简洁。

最后是PWM占空比映射,直接查表省事:

const uint16_t duty_table[] = {0, 300, 500, 800, 1000};

void Set_PWM_Duty(ModeType mode, float temp){
    if(mode == AUTO_MODE){
        if(temp < 25) gear = 0;
        else if(temp <28) gear = 1;
        else if(temp <32) gear = 2;
        else if(temp <36) gear = 3;
        else gear = 4;
    }
    TIM_SetCompare1(TIM3, duty_table[gear]);
}

这里gear变量范围0-4对应停止和四个档位,duty_table直接存储ARR的百分比数值。比如ARR是999,30%占空比就是999*0.3≈300。用查表法比实时计算更节省计算资源。

整个系统最骚的操作在于红外和温控的联动——只有检测到人体且温度达标才会启动。这个逻辑用个与门就搞定:

if((HC_SR501_Read() == HUMAN_PRESENCE) && (gear > 0)){
    L298N_Enable();
} else {
    L298N_Disable();
}

但要注意红外模块的误触发问题,实际应该加个滤波延时,比如连续检测到3次信号才认为真有人。

最后吐个槽,L298N驱动小风扇其实有点杀鸡用牛刀,用个MOS管更省电。不过作为练手项目,用来理解PWM和状态机还是挺合适的。下次可以试试用PID做连续调速,比这个分段控制更丝滑。

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐