EM78P153 智能风扇控制程序(支持调速调档)

基于 EM78P153(Elan 1KB OTP MCU)编写,使用纯 C 语言实现。程序包含 按键调档(4档)、温度传感器自动调速(NTC) 以及 软件 PWM 无级调速 功能。由于 EM78P153 资源极度受限(RAM: 36 Bytes, ROM: 1K x 12 bit),代码经过高度精简,未使用任何浮点运算和标准库函数。


一、 硬件资源配置与连接

EM78P153 引脚 硬件连接 功能说明
P60 (IO) 风扇 MOSFET/三极管 PWM 输出控制风扇风速
P61 (IO) 按键 1 档位切换键 (短按) / 开关机 (长按)
P62 (IO) 按键 2 手动风速加 (仅限手动模式)
P63 (IO) 按键 3 手动风速减 (仅限手动模式)
P64 (IO) NTC 温度传感器 接入 RC 充放电电路,检测环境温度
P67 (IO) LED / 数码管 显示当前档位或风速等级

二、 核心宏定义与全局变量 (main.c)

#include "EM78P153.h" // 引入 EM78P153 专用头文件 (需对应编译器)

// ===== 硬件抽象层宏定义 =====
#define FAN_PWM_PORT    P6CR    // 风扇 PWM 端口控制寄存器
#define FAN_PWM_PIN     0       // P60 控制风扇
#define KEY_PORT        P6      // 按键端口
#define TEMP_PORT       P6      // 温度端口
#define TEMP_PIN        4       // P64 连接 NTC

// ===== 系统参数定义 =====
#define SYS_CLK         4000000 // 假设系统时钟 4MHz
#define PWM_PERIOD      100     // PWM 周期分为 100 份 (0~99)
#define TEMP_SAMPLE_TIME 1000  // 温度采样间隔 (ms)

// ===== 全局变量 (EM78P153 RAM极小,需谨慎使用) =====
unsigned char g_fan_level = 0;     // 当前档位: 0=关机, 1=低, 2=中, 3=高, 4=自动
unsigned char g_pwm_duty = 0;      // 当前 PWM 占空比 (0-100)
unsigned char g_adc_value = 0;     // 温度 ADC 采样值 (0-255)
bit gb_auto_mode = 0;              // 自动模式标志位
bit gb_key_pressed = 0;            // 按键按下标志
unsigned int gui_system_ticks = 0; // 系统滴答计数器 (需用定时器中断或软件计数)

三、 底层驱动函数

3.1 简易软件延时函数

(注意:EM78P153 指令集简单,通常依靠 _nop() 或空循环实现粗略延时)

/**
 * @brief 粗略毫秒级延时 (基于 4MHz 主频估算)
 */
void delay_ms(unsigned int ms) {
    unsigned int i, j;
    for(i = 0; i < ms; i++)
        for(j = 0; j < 1141; j++) // 1141 约为 4MHz 下 1ms 的指令周期数
            _nop_(); // 空指令,占用一个机器周期
}

3.2 RC 充放电法读取 NTC 温度

由于 EM78P153 没有内置 ADC,利用 IO 口的电平翻转和内部定时器来测量 NTC 电阻值,从而计算温度。

/**
 * @brief 读取 NTC 温度值 (返回 0-255 的相对数值)
 */
unsigned char read_temperature(void) {
    unsigned char count = 0;
    
    // 1. 放电:将引脚设为输出,并拉低电平
    TEMP_PORT &= ~(1 << TEMP_PIN); 
    P6CR |= (1 << TEMP_PIN);       // 设为输出
    delay_ms(10);                  // 等待电容放电完毕
    
    // 2. 充电:将引脚设为输入(高阻态),电容通过 NTC 充电
    P6CR &= ~(1 << TEMP_PIN);      // 设为输入
    
    // 3. 计时:等待引脚电平升高至高电平阈值
    while((TEMP_PORT & (1 << TEMP_PIN)) == 0) {
        count++;
        if(count >= 250) break;   // 防止死循环,最大计时约 250us
        delay_us(10);              // 粗略延时 10us
    }
    
    // 4. 恢复引脚状态(根据后续电路需求,通常恢复为输出低或输入)
    P6CR |= (1 << TEMP_PIN);      
    TEMP_PORT &= ~(1 << TEMP_PIN); 
    
    return count; // count 越大,说明 NTC 阻值越大,温度越低
}

3.3 按键扫描函数 (三键独立)

/**
 * @brief 扫描按键并返回按下的键值
 * @return 0:无按键 1:按键1 2:按键2 3:按键3
 */
unsigned char key_scan(void) {
    static unsigned char s_last_key = 0;
    unsigned char key_val = 0;
    
    // 读取按键引脚状态 (假设按下为低电平 0)
    if((KEY_PORT & 0x06) != 0x06) { // 检查 P61 和 P62 (0110)
        if((KEY_PORT & 0x02) == 0) key_val = 1; // P61 按下
        if((KEY_PORT & 0x04) == 0) key_val = 2; // P62 按下
    }
    
    // 消抖处理:只有当前状态与上次状态不同且稳定时才确认按键
    if(key_val == s_last_key) {
        return 0; 
    } else {
        s_last_key = key_val;
        delay_ms(20); // 消抖延时
        return key_val;
    }
}

四、 业务逻辑控制层

4.1 PWM 波形生成与风扇驱动

在主循环或定时中断中调用此函数,产生 100 级可调的 PWM 波。

/**
 * @brief 更新风扇 PWM 输出
 * @param duty 占空比 (0-100)
 */
void fan_update_pwm(unsigned char duty) {
    static unsigned char pwm_counter = 0;
    
    pwm_counter++;
    if(pwm_counter >= PWM_PERIOD) {
        pwm_counter = 0;
    }

    if(g_fan_level == 0) { // 关机状态
        FAN_PWM_PORT &= ~(1 << FAN_PWM_PIN); 
    } else {
        if(pwm_counter < duty) {
            FAN_PWM_PORT |= (1 << FAN_PWM_PIN);  // 输出高电平
        } else {
            FAN_PWM_PORT &= ~(1 << FAN_PWM_PIN); // 输出低电平
        }
    }
}

4.2 智能温控与档位管理

/**
 * @brief 根据温度自动调节 PWM 占空比
 */
void auto_temp_control(void) {
    unsigned char target_duty = 0;
    
    if(gb_auto_mode) {
        g_adc_value = read_temperature();
        
        // 简单的分段线性控制 (根据实际 NTC 特性校准)
        // 假设 g_adc_value: 小于50为高温,大于200为低温
        if(g_adc_value < 50) { 
            target_duty = 30; // 高温 -> 低速 (省电)
        } else if(g_adc_value < 150) {
            target_duty = 60; // 中温 -> 中速
        } else {
            target_duty = 95; // 低温 -> 高速 (强力制热/吹风)
        }

        // 平滑过渡:防止风速突变引起电机异响
        if(g_pwm_duty < target_duty) g_pwm_duty++;
        else if(g_pwm_duty > target_duty) g_pwm_duty--;
    }
}

/**
 * @brief 处理按键事件并更新档位
 */
void process_keys(void) {
    unsigned char key = key_scan();
    if(key == 0) return;

    switch(key) {
        case 1: // 按键1:切换档位 (循环: 关 -> 低 -> 中 -> 高 -> 自动)
            g_fan_level++;
            if(g_fan_level > 4) g_fan_level = 0;
            
            gb_auto_mode = (g_fan_level == 4) ? 1 : 0;
            
            // 设定各档位固定风速
            if(g_fan_level == 1) g_pwm_duty = 30;  // 低档
            else if(g_fan_level == 2) g_pwm_duty = 60; // 中档
            else if(g_fan_level == 3) g_pwm_duty = 90; // 高档
            break;
            
        case 2: // 按键2:手动加速 (仅在非自动模式下有效)
            if(!gb_auto_mode && g_fan_level > 0) {
                if(g_pwm_duty < 90) g_pwm_duty += 10;
            }
            break;
            
        case 3: // 按键3:手动减速
            if(!gb_auto_mode && g_fan_level > 0) {
                if(g_pwm_duty > 10) g_pwm_duty -= 10;
            }
            break;
    }
}

五、 主函数入口 (main)

void main(void) {
    // ===== 1. 芯片初始化 =====
    WDTC = 0x07;        // 关闭看门狗定时器 (根据具体型号配置)
    P6CR = 0x00;        // 默认所有 P6 口为输入
    P6PH = 0xFF;        // 开启 P6 上拉电阻
    P6IE = 0x00;        // 关闭 P6 中断
    
    // 配置控制引脚为输出
    P6CR |= (1 << FAN_PWM_PIN); 

    // ===== 2. 上电默认状态 =====
    g_fan_level = 1;    // 默认低档启动
    g_pwm_duty = 30;
    gui_system_ticks = 0;

    // ===== 3. 主循环 =====
    while(1) {
        // 任务1:处理按键输入
        process_keys();

        // 任务2:智能温控调节 (每 100ms 调整一次,避免过于频繁)
        if((gui_system_ticks % 100) == 0) {
            auto_temp_control();
        }

        // 任务3:更新 PWM 输出 (建议在定时器中断中做,此处用循环延时模拟)
        fan_update_pwm(g_pwm_duty);
        
        // 任务4:系统节拍延时 (替代简易 RTOS 的时基)
        delay_ms(1);
        gui_system_ticks++;
        if(gui_system_ticks >= 60000) gui_system_ticks = 0; // 防止溢出
    }
}

参考代码 EM78P153 程序可以调速调档智能风扇 www.youwenfan.com/contentcnv/72248.html

六、 特点与移植

  1. 极低资源占用
    • 全程采用 unsigned char (单字节) 进行计算,避免多字节运算占用宝贵的指令周期和 RAM。
    • 舍弃复杂的浮点运算,PWM 采用 0-100 的整数占比。
  2. 无硬件依赖抽象
    • 代码中 EM78P153.h 需替换为您实际使用的编译器提供的头文件。
    • delay_us / delay_ms 需根据实际晶振频率调整内循环次数。
  3. 扩展建议
    • 休眠节能:若风扇长时间无操作,可在主循环中进入 HALT 模式,通过外部按键中断唤醒。
    • IR 遥控:可复用按键处理逻辑,在 P63 接入红外接收头,解码 NEC 协议实现遥控调速。
posted @ 2026-05-26 16:05  bqyfa66984  阅读(15)  评论(0)    收藏  举报