今天带大家做一个加湿器,成本仅需四元!

芯片用的Ai8H1K08,也就是我之前心心念念的AI系列(出自STC)

那么为什么选用这个型号呢?

这是因为要驱动雾化片是需要108KHz的PWM,因此需要用到的是16位高级PWM定时器。

图片

然后我选择了价格最低的Ai8H1K08,仅需0.69元。

PCB板的话每月可以免费打两次。

然后雾化片加支架是两块钱,再加上其他物料,七七八八的就差不多四块钱搞定。

其实没什么难点。

图片

唯一要注意的就是压电陶瓷片的驱动电路,也就是雾化片的驱动。

上图的U2就是三脚电感。可以回顾一下我之前的文章。

记得三脚电感的短边接+5V,长边接到雾化片上,公共端接上一个NMOS,NMOS是G极接到我们单片机的PWM上。

三角电感选择25uh:800uh,CD75,0805封装的。

封装什么的无所谓,PCB上对应着改改就行。

电感值选择25uh:800uh的,为什么选这个值的我就不清楚了,我也是参考别人的,咱这么用就行。

PWM的频率要108K,但差一点其实也没关系。

通过调节PWM的占空比可以调整雾化片的雾化强度,但是经过测试,占空比过了50%之后就基本没有变化了。

图片

Ai8H1K08的外围电路仅需俩电容。

其他我就接了俩按键,三个LED,还有一个RGB三色灯。

其实本不需要那么多元器件的,但是Ai8H1K08有十六个引脚,我寻思着不用也是浪费,所以就加上了。

俩按键,一个调加湿强度,一个调定时。

强度分为3级,占空比分别为9%,27%,68%,大家也可以根据自己调试去修改占空比来达到自己想要的结果,我就只调试了五分钟就定了着仨值。

强度的不同会反应在RGB上,我是设置了蓝色,颜色越深就表示强度越大(占空比越大),RGB灭就表示关闭加湿器。

另外仨LED就是拿来做定时用的,最高可以定时仨小时,分别对应三个灯。

图片

硬件就说这么多。

接下来是软件。

软件其实也没很复杂,使用的库函数,别看它是Ai系列,但是一样用的是STC库函数。

代码不多我直接贴下面,有注释,应该都看得懂。

这个代码不能直接用,因为我在定时器的中断函数里有点修改,还需要在对应的文件里简单改一下。

图片

图片

就是类似外部中断一样,通过读取一个可以外部访问的变量来判断是否触发中断。但是定时器中断里需要自己去写。

#include "STC8G_H_GPIO.h"
#include "STC8G_H_Delay.h"
#include "STC8H_PWM.h"
#include "STC8G_H_Timer.h"
#include "STC8G_H_NVIC.h"
#include "STC8G_H_Exti.h"

#define WS2812B_IN P37

// G、R、B
uint8 color[3] = {0, 0, 0};
uint8 hour = 0;
uint8 minute = 0;
uint8 second = 0;

// 复位
void WS2812B_SendReset(void) {
    unsigned char data i, j;
    WS2812B_IN = 0;  // 拉低80us
    i = 2;
    j = 219;
    do {
        while (--j)
            ;
    } while (--i);
}
// 发送1码
void WS2812B_SendOne(void) {
    WS2812B_IN = 1;  // 拉高延时0.6us
    _nop_();_nop_();_nop_();_nop_();_nop_();
    _nop_();_nop_();_nop_();_nop_();_nop_();
    _nop_();_nop_();_nop_();_nop_();
    WS2812B_IN = 0;  // 拉低延时0.3us
    _nop_();_nop_();_nop_();_nop_();
    _nop_();_nop_();
}
// 发送0码
void WS2812B_SendZero(void) {
    WS2812B_IN = 1;  // 拉高延时0.3us
    _nop_();_nop_();_nop_();_nop_();
    _nop_();_nop_();

    WS2812B_IN = 0;  // 拉低延时0.6us
    _nop_();_nop_();_nop_();_nop_();_nop_();
    _nop_();_nop_();_nop_();_nop_();_nop_();
    _nop_();_nop_();_nop_();_nop_();
}
// 发送自定义RGB颜色
void WS2812B_SendColor(void) {
    uint8 i, j;
    WS2812B_SendReset();
    for (i = 0; i < 3; ++i) {
        for (j = 0; j < 8; ++j) {   
            if (color[i] & (0x80 >> j))     // 高位在前
                WS2812B_SendOne();
            else
                WS2812B_SendZero();
        }
    }
}

// 初始化PWM
void PWM_Init(void){
    PWMx_InitDefine PWMx_InitStructure;

	PWMx_InitStructure.PWM_Mode = CCMRn_PWM_MODE1;	        // 模式1
	PWMx_InitStructure.PWM_Duty = 0;	                    // 阈值
	PWMx_InitStructure.PWM_EnoSelect = ENO1P;	            // 通道1的正通道
    PWMx_InitStructure.PWM_Period = 220;				    // 自动重装载寄存器 220 ≈ 108k的频率
	PWMx_InitStructure.PWM_DeadTime = 0;				    // 死区时间
	PWMx_InitStructure.PWM_MainOutEnable = ENABLE;			// 使能输出
	PWMx_InitStructure.PWM_CEN_Enable = ENABLE;			    // 使能计数器
	PWM_Configuration(PWM1, &PWMx_InitStructure);			// 初始化PWM1
	PWM_Configuration(PWMA, &PWMx_InitStructure);			// 初始化PWMA

    PWMA_CC1P_HighValid();
	PWM1_USE_P10P11();
}

// 初始化GPIO口
void GPIO_Init(void){
    P1_MODE_OUT_PP(GPIO_Pin_3);     // LED1
    P1_MODE_OUT_PP(GPIO_Pin_4);     // LED2
    P1_MODE_OUT_PP(GPIO_Pin_5);     // LED3
    P3_MODE_OUT_PP(GPIO_Pin_7);     // RGB
    P3_MODE_IN_HIZ(GPIO_Pin_2);     // Mode按键
    P3_MODE_IN_HIZ(GPIO_Pin_3);     // Time按键
    P3_PULL_UP_ENABLE(GPIO_Pin_2);  // 加上上拉电阻
    P3_PULL_UP_ENABLE(GPIO_Pin_3);
    P13 = 1;
    P14 = 1;
    P15 = 1;
}

// 初始化外部中断 俩按键
void EXTI_Init(void){
    EXTI_InitTypeDef initer;
    initer.EXTI_Mode = EXT_MODE_Fall;   // 下降沿触发
    Ext_Inilize(EXT_INT0, &initer);
    Ext_Inilize(EXT_INT1, &initer);

    NVIC_INT0_Init(ENABLE, Priority_1); // 使能INT0,优先级1
    NVIC_INT1_Init(ENABLE, Priority_1); // 使能INT1,优先级1
}

void Timer_Init(void) {
    // 每25ms中断一次.
    TIM_InitTypeDef initer;
    initer.TIM_Mode = TIM_16BitAutoReload;          // 模式0,16位自动重装载寄存器.
    initer.TIM_ClkOut = DISABLE;                    // 失能可编程时钟输出
    initer.TIM_ClkSource = TIM_CLOCK_12T;           // 12T工作模式
    initer.TIM_Value = 15536;                       // 计数寄存器和重装载寄存器的值设为15536
    initer.TIM_Run = ENABLE;                        // 定时器,启动!

    Timer_Inilize(Timer0, &initer);

    ET0 = 0;    // 先关闭中断

    NVIC_Timer0_Init(ENABLE, Priority_2);   // 使能定时器0的NVIC中断
}

// 修改PWM的占空比,控制压变陶瓷片的强度
void ChangePWM(uint8 val){
    PWMx_Duty duty;
    duty.PWM1_Duty = val;
    UpdatePwm(PWM1, &duty);
}

void main(void){
    uint16 timeCount = 0;

    EAXSFR();		/* 扩展寄存器访问使能 */

    GPIO_Init();
    PWM_Init();
    EXTI_Init();
    Timer_Init();

    EA = 1;

    WS2812B_SendColor();

    while(1){
        if(WakeUpSource == 1){      // Mode按键按下
            WakeUpSource = 0;       // 清除标志
            delay_ms(5);    if(P32) break;  // 这行可加可不加,因为已经有电容滤波消抖了
            if(color[2] == 0){
                color[2] = 3;
                ChangePWM(20);
            }else if(color[2] == 3){
                color[2] = 10;
                ChangePWM(60);
            }else if(color[2] == 10){
                color[2] = 30;
                ChangePWM(150);
            }else if(color[2] == 30){
                color[2] = 0;
                ChangePWM(0);
            }
            WS2812B_SendColor();
        }
        if(WakeUpSource == 2){              // Time按键按下
            WakeUpSource = 0;               // 清除标志
            delay_ms(5);    if(P33) break;  // 这行可加可不加,因为已经有电容滤波消抖了
            if(hour == 0 && minute == 0 && second == 0){    // 没有定时任务
                minute = 59;    
                second = 59;
                ET0 = 1;        // 开启定时器
                P13 = 0;
            }else if(hour == 0 && (minute!= 0 || second != 0)){ // 定时时间在0~1小时内
                hour = 1;
                P14 = 0;
            }else if(hour == 1){    // 定时时间在1~2小时内
                hour = 2;
                P15 = 0;
            }else if(hour == 2){    // 定时时间在2~3小时内
                P13 = 1;
                P14 = 1;
                P15 = 1;
                ET0 = 0;        // 关闭定时器
                hour = 0; minute = 0; second = 0;
            }
        }
        if(TimeWakeUp == 1){
            TimeWakeUp = 0;
            if(++timeCount >= 40){      // 每过1秒
                timeCount = 0;
                if(second == 0){        // 秒数不够减
                    if(minute == 0){    // 分数不够减
                        if(hour == 0){  // 小时数也不够减,那么关闭最后一个LED,关闭定时器,关闭加湿器
                            ET0 = 0;
                            P13 = 1;    // 灭第一个LED
                            ChangePWM(0); 
                        }else{          // 小时数够减
                            hour--;     // 小时数-1
                            minute = 59;// 将分数补上
                            second = 59;// 将秒数BUS
                            if(hour == 0) P14 = 1;  // 如果原本有1小时,那么灭第二个LED
                            else P15 = 1;           // 如果原本有2小时,那么灭第三个LED
                        }
                    }else{          // 分数够减
                        minute--;   // 分数-1
                        second = 59;// 秒数补上
                    }
                }else{              // 秒数够减
                    second--;       // 秒数-1
                }
            }
        }
    }
}

我开源到立创开源平台了,在那边可以直接查看原理图和PCB,用户名直接搜“折途”。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐