智慧印刷工坊

智慧印刷工坊

电子制作1 -红外遥控风扇的制作

admin 90 76

天气太热,睡觉用鸿运扇吹风,有时候会觉得最慢档的风力还是嫌大。我先后尝试给鸿运扇串接一个吊扇的电感调速器,也试过用可控硅调压作调速器,但即便电源电压调到较低了,低到风扇勉强能启动的程度,但还是感到风扇转速偏大,边吹边睡不太舒服。

这也可能我的这个风扇低压启动性能不好。最后我改用单片机控制,用PWM方波控制这个鸿运扇。通过调整不同占空比来控制转速,结果效果比电感调速或者可控硅调压调速好,风扇转速可以调得很慢,还可以通过间隙性给风扇供电,模拟自然风效果。最后再加个红外遥控功能,用起来比较满意。

现将对应的51单片机红外接收遥控风扇控制电路及软件代码介绍如下,供有兴趣的朋友参考。



图3,装在饮料瓶里的红外接收电路+输出插座。


图4,红外接收+控制电路原理图。

软硬件说明:

图4里用标称输出5V的USB电源模块给系统供电。因为实测其输出电压为6V,所以在其5V输出端串接了一个二极管降压。

考虑到控制PWM输出的电源开关会频繁地通断,普通电磁继电器的触点寿命有限,所以采用固态继电器控制220V交流输出插座。

图4还画了一个双抛开关继电器,原来想用来控制风扇的快慢档线圈转换的。使用中发现,只要调整PWM不同占空比来控制风扇转速已经能基本满足要求,这个器件就多余了。

(4)此前是4keys控制:

0x16=“0”=总电源开关,控制固态继电器-》开通或关断,每按键一次翻转一次。

0x0c=“1”=快慢档控制,控制动圈继电器-》双刀双抛开关实现快慢档转换,每按键一次翻转一次。

0x44=“VOL-”=减速,主继电器断电时间控制,=speed-(主继电器断电时间增加到10就变1)。

0x40=“VOL+”=加速,主继电器开通时间控制,=speed-(主继电器开通时间增加到8就变1)。

(5)后来改为8keys控制:

0x43=“PAUSE/play”=总电源开关,控制固态继电器-》开通或关断,每按键一次翻转一次。

0x09=“EQ”=快慢档控制,控制动圈继电器-》双刀双抛开关转换,每按键一次翻转一次。

0x44=“PREV”=减速,主继电器断电时间增加到10就停止。

0x40=“NEXT”=加速,主继电器断电时间减少到1就停止)。

0x15=“VOL-”=减速,主继电器开通时间减少到1就停止。

0x07=“VOL+”=加速,主继电器开通时间增加到10就停止。

(6)单片机软件下载用CH340下载线(如下图5,只用TXD+RXD+GND等3根线)。


(7)P02=HYDZRbeeper(PIN38)=P02+10k上拉+1K串接9014-B极,9014-C极+LED+BEEPER.

(8)P03=J1(WANJIA双刀双抛继电器,5A250V)=P03+10k上拉+1K串接9014-B极,9014-C极+WJ113H继电器(RJ=55欧,IJ=58MA)

(9)P04=Jmain(总开关固态继电器)=P03+10k上拉+1K串接9014-B极,9014-C极+固态继电器(IJmain=12MA)。负载接50W灯,导通时,输出接点压降=8VAC。

(10)38k红外遥控器(配1838红外接收头=HS0038B):

(11)遥控器按键值

//ucharcodeTest1[4]={0x16,0x0c,0x08,0x42,};//遥控键0-1-4-7

//ucharcodeTest2[4]={0x18,0x5e,0x1c,0x5a,};//遥控键2-3-5-6

//ucharcodeTest3[4]={0x42,0x52,0x4a,0x15,};//遥控键7-8-9-+

按键名称数据码,按键名称数据码,按键名称数据码,按键名称数据码

00x1610x0c20x1830x5e

40x0850x1c60xaa70x42

80x5290xab-0x07+0x15

eq0x09next0x40prev0x44play0x87

PAUSE/PLAY0x43

--------------------------===================================------------------------------

(12)源码:

unsignedcharIRtime;//红外信号位周期时长计时器,由T0中断计数。

bitirpro_ok,IRrec_Ok;

unsignedcharIRcode[4];//将接收的红外32位数据按四个字节数据保存

unsignedcharIR_time[33];//分别寄存33个bit的时间

sbitBeep=P0^2;//红外接收提示LED灯+beeper

sbitSpeed=P0^3;//9014驱动的动圈继电器J1-快慢档输出端口

sbitPower=P0^4;//固态继电器Jmain-总电源控制输出端口

defineOFF0;//定义led=0=off

defineFALSE0;

ucharTon,Toff;//Ton是主继电器开通延时时间,Toff是主继电器关断延时时间。

ucharTon_count,Toff_count;//Ton_count是主继电器开通计数器,Toff_count是主继电器关断计数器。

ucharF_Speed;//调速模式标志,=TRUE=1是调速状态,=0是正常速度状态。

/*--------------------函数声明----------*/

voidIr_work(void);

voidIrcode_pro(void);

voidDelay_1ms(unsignedintTx)

{unsignedintt1,t2;

for(t1=0;t1Tx;t1++)for(t2=0;t2120;t2++);

}

voidBeeper(unsignedintTx)

{Beep=ON;Delay_1ms(Tx);Beep=OFF;Delay_1ms(10);

}

definePreloadT0L(65536-250)%256;

definePreloadT1L(65536-50000)%256;

unsignedintPreT0h,PreT0l;

unsignedintPreT1h,PreT1l;

//===================================================================

//T0=0001,设为16位定时工作方式0

voidTIME0_init(void)

{TMOD=0Xf0;//低位T0计数方式清0

TMOD|=0X01;//T0=计数方式1=16位,

//T0方式选择位C/T=0=定时工作方式1,=16位,不自动重装参数

PreT0h=PreloadT0H;PreT0l=PreloadT0L;

TH0=PreT0h;TL0=PreT0l;

TR0=1;

ET0=1;//允许计数器0中断

PT0=1;//T0为最高优先级

}

/*-----------------------*/

voidtime0_isr(void)interrupt1using1

{IRtime++;//用于计数2个下降沿之间的时间

TH0=PreT0h;TL0=PreT0l;

}

//==================================================================

//T1设为16位定时工作方式0

voidTIME1_init(void)

{

TMOD=0X0f;//高位T1计数方式清0

TMOD|=0X10;//T1=计数方式1=16位,

//T1方式选择位C/T=0=定时工作方式1=16位,不自动重装参数

PreT1h=PreloadT1H;PreT1l=PreloadT1L;

TH1=PreT1h;TL1=PreT1l;

TR1=1;

ET1=1;//允许计数器1中断

}

/*----------------------------------*/

ucharTxms_count=0;

voidtime1_isr(void)interrupt3

{TH1=PreT1h;TL1=PreT1l;

if(Txms_count++=20)

{Txms_count=0;

if(F_Speed==1)//=1是调速状态

{

if(Ton_count++Ton)

{Power=ON;}

elseif((Ton_count=Ton)(Toff_count++Toff))

{Power=OFF;}

if((Ton_count=Ton)(Toff_count=Toff))

{Beeper(2);//=心跳信号,在慢速工作状态时,每个"通电+断电结束"周期响一短声。

Ton_count=0;Toff_count=0;}//定时时间到,计数器清零

}

}

}

/*----------------------------*/

voidEX0init(void)

{IT0=1;//指定外部中断0下降沿触发,INT0()

EX0=1;//使能外部中断

}

/*-----------------------------*/

voidEX0_ISR(void)interrupt0//外部中断0服务函数

{//接收红外信号处理,将接收到各位数占时存储下来

staticunsignedcharIRcount;//接收位数计数器

staticbitstartflag;//是否开始处理标志位

if(startflag)

{

if(IRtime32)//IRtime32即认为是引导码,丢弃

//引导码=TC9012的头码=53*IRtime=9ms+4.5ms,33*IRtime=8.448ms

//whenIRtime=250us,33*IRtime=8250us,32*IRtime=8000us

{IRcount=0;}//IR_time[0]=引导码的时间长度=9ms+4.5ms,

IR_time[IRcount]=IRtime;//存储每个位电平的持续时间,用于以后判断是0还是1

IRtime=0;//清零

IRcount++;//接收位数计数器

if(IRcount==33)//收够32位数据了

{IRrec_Ok=1;IRcount=0;}

}

else

{IRtime=0;startflag=1;}

}

voidIr_work(void)//根据接收到的红外键值跳转处理程序--

{

switch(IRcode[2])//只判断第三个数码值

{

case0x43://key=PAUSE/play=暂停=Jmain主继电器开通或关断,每按键一次翻转一次

F_Speed=FALSE;//FALSE=0==正常速度状态

Power=!Power;Beeper(200);//跟踪Power=~Power;是同样效果-20220731

break;

case0x09://key=EQ=快慢控制继电器)快速或慢速控制(接通1为慢速,接通2为快速)

F_Speed=FALSE;//FALSE=0=正常速度状态

Speed=!Speed;Beeper(200);//每按键一次翻转一次

break;

case0x44://=PREV=Toff--(Jmain主继电器开通时间减少)

F_Speed=TRUE;//TRUE=1=调速状态

if(Toff--2)

{Toff=1;Beeper(1000);}//从2开始,10档速度,每按键一次,断电时间-1s

Beeper(200);break;

case0x40://=NEXT=Toff++(Jmain主继电器开通时间++)

F_Speed=TRUE;//TRUE=1

if(Toff++10)

{Toff=10;Beeper(1000);}//从2开始,10档速度,每按键一次,断电时间+1s

Beeper(200);break;

case0x15://=VOL-=Ton--(Jmain主继电器开通时间--

F_Speed=TRUE;//TRUE=1

if(Ton--2)

{Ton=1;Beeper(1000);}//从2开始,8档速度,每按键一次,通电时间-1s

Beeper(200);break;

case0x07://=VOL+=Ton++(Jmain主继电器开通时间--

F_Speed=TRUE;//TRUE=1

if(Ton++8)

{Ton=8;Beeper(1000);}//从2开始,8档速度,每按键一次,通电时间+1s

Beeper(200);break;

default:F_Speed=FALSE;break;

}

irpro_ok=0;//处理完成标志

}

voidIrcode_pro(void)

//将接收的32字节存储在IR_time[32],根据时长判断个位是0或1,转为四个字节保存

{unsignedchari,j,k;unsignedcharCode32b,value;

k=1;//将引导码=IR_time[0]去掉,所以令k=1;

for(i=0;i4;i++)//处理4个字节

{

for(j=1;j=8;j++)//处理每1个字节的8位数

{

Code32b=IR_time[k];//1th,取出32位数的的第一位IR_time[1],根据时长来判断是0或1。

if(Code32b6)//大于某值为1,这个和晶振有关系

//如果收到1,对应的高电平时间=1.168ms,IR_time[]=1.168ms/IRtime,必定大于等于4。

//如果收到0,对应的高电平时间=0.56ms,IR_time[]=0.56ms/IRtime,必定=2。

//7*IRtime=1750us,6*IRtime=1500us,560/250=2.24,1168/250=4.67个IR_time

//另有资料说,1对应的高电平时间=1.69ms,IR_time[]=1690us/250=6.76个IR_time。

//结论:用4或8会得乱码。用5-7解码结果都对,取6较合理。

value|=0x80;//令最高位=1

if(j8){value=1;}//处理下一位

k++;

}

IRcode[i]=value;//将接收的8位数据按1个字节保存

value=0;

}

irpro_ok=1;//将接收的32位数据按四个字节保存,处理完毕标志位置1

}

/*-----------主函数-------*/

voidmain(void)

{//MCU通电瞬间的端口高电平,会令各输出端口的9014导通+继电器吸合通电,改用PNP的9012可避免此问题

Power=OFF;Speed=OFF;Beep=OFF;//开机先令几个输出端口=0,防止继电器通电!

Delay_1ms(500);Beeper(200);

EX0init();//初始化外部中断

TIME0_init();//初始化定时器0-红外接收定时

TIME1_init();//初始化定时器1-继电器开关定时

Ton=3;Toff=2;//Ton是主继电器开通和关断的延时时间,一秒为单位,调速才用到

Ton_count=0;Toff_count=0;//主继电器开通和关断计数器,调速时,在T1中断1S后计数

EA=1;//开总中断

while(1)//主循环

{

if(IRrec_Ok)//如果在INT0接收到正确的红外信号,就跳转这里进行红外数据处理

{Beeper(30);//接收到红外按键信号,发出提示音

Ircode_pro();//将接收的32位时长数据按四个字节提取并保存到IRcode[i]

IRrec_Ok=0;

}

if(irpro_ok)//数据处理好后,做对应工作

{Ir_work();}//根据红外键值跳转处理程序

}

}

写于20220813