
前言一、基本元器件说明单片机类型51单片机普中传感器的使用DS18B20温度传感器、LD3320语音模块、JQ8900-16P语音播报、LCD1602显示屏、hc-sr501人体感应模块等二、具体功能说明设计有三个模式模式1根据温度变化进行风扇速度的调节模式2自主控制温度的风扇变化模式3采用人体感应模块监测风扇前是否有人进行风扇开启与关闭三种控制方式语音控制、按键控制、红外遥控控制三、设计说明本设计是根据百家之所长有很多参考的地方写本次文章的目的是在于记录与分享在设计中遇见的问题与自己的一些理解供大家参考与交流网上很多模块的使用都有很详细的解释我这只说一些我使用的理解描述不准确多指正。四、分享说明这是我第一次写这样的内容肯定会有很多表达不清楚或者不准确的地方如果有指正一下共同进步我主要是针对主函数的讲解分享我的设计思路具体模块的头文件部分并没有展示因为这些模块很多地方都可以找到。内容展示设计流程我的大体设计流程是1按键控制风扇的速度调节2LCD1602显示温度的变化3风扇和温度相互结合4模式2部分就是按键控制风扇的旋转模式1中已经解决5模式3部分就是加上人体感应模块即可6加入JQ9600-16P进行语音播报7操作控制的设计是逐个增加按键控制-----红外遥控-------语音控制具体设计【1】按键控制风扇的速度调节1. 按键部分我是采用的51单片机上面有矩阵按键与独立按键因为我需要用到的按键比较多我在设计中使用的是矩阵按键按键这部分不详细说明。2. 对于风扇速度的调节使用的是PWM调速对于使用注意几点2.1 采用的是直流电机51已经有了驱动模块所以直接对端口赋值1开启、0关闭即可2.2 对于PWM调速单片机的IO口输出的是数字信号IO口只能输出高电平和低电平理论上通过连接和断开可以输出在范围内的任意模拟电压2.3 对于PWM其核心就是占空比可以理解为高电平在周期中占据多少时间转换成单片机就是电平1占据的时间占空比50%那就是高低电平各占一半2.4 为什么采用定时器产生PWM我的理解是快、反复只要开启定时器就可以一直反复快速操作3.相关代码3.1定时器代码采用的是定时器2中断号别搞错了void Timer2_Routine() interrupt 5 { RCAP2L 0x66; //设置定时重载值 RCAP2H 0xFC; //设置定时重载值 TF20; Counter; Counter%100; //计数值变化范围限制在0~99 if(CounterCompare) //计数值小于比较值 { Motor1; //输出1 } else //计数值大于比较值 { Motor0; //输出0 } }比如我们现在设置Compare 50定时器开启后Counter会迅速的自加在小于50的部分都是高电平1超过50的部分都是低电平0这样就产生了占空比50%那就是高低电平各占一半高电平占的越多风扇转的越快所以我们想改变风扇的档位将Compare设置的大一点就可以了这就是调速的方法。因为在定时器中Counter%100;这样就可以实现反复的进行操作这就是用定时器的原因3.2 按键控制代码以模式2代码为例主要看KeyNum 、Compare 、M 这三个值就行KeyNum就是按键值的获取Compare改变值从而来控制速度M就是档位显示0-3档if(KeyNum5 || CommandIR_0 || Flag8) { Flag0; Delay(200); play_song_num(0x04); LCD_ShowString(1,1,Nat T: );//正常模式显示 LCD_ShowString(2,1,Now File M:M); Compare0; M0; } //设置比较值改变PWM占空比 if(KeyNum6 || CommandIR_1 || Flag9) { Flag0; Delay(200); play_song_num(0x05); LCD_ShowString(1,1,Nat T: );//正常模式显示 LCD_ShowString(2,1,Now File M:M); Compare50; M1; } if(KeyNum7 || CommandIR_2 || Flag10) { Flag0; Delay(200); play_song_num(0x06); LCD_ShowString(1,1,Nat T: );//正常模式显示 LCD_ShowString(2,1,Now File M:M); Compare75; M2; } if(KeyNum8 || CommandIR_3 || Flag11)//3挡 { Flag0; Delay(200); play_song_num(0x07); LCD_ShowString(1,1,Nat T: );//正常模式显示 LCD_ShowString(2,1,Now File M:M); Compare100; M3; } LCD_ShowNum(2,16,M,1);【2】DS18b20与LCD1602这两个资料太多了其实直接调用就行这里主要补充一下对于数据的保存采用了AT24c02。1.为什么使用AT24c02 在我的设计中我希望我设置的温度上下限并不会因为关机重启而导致我还需要再设置一遍所以我希望保存我设置的数据那么就需要掉电不丢失这就是为什么使用AT24c022.相关说明1对于AT24c0251单片中有这个模块2这部分是针对的模式1所以将风扇和温度结合3.模式1相关代码3.1 读取AT24C02的上次存储的值/*****温度初始化***/ DS18B20_ConvertT(); //上电先转换一次温度防止第一次读数据错误 Delay(1000); //等待转换完成 THighAT24C02_ReadByte(0); //读取温度阈值数据 TLowAT24C02_ReadByte(1); //读取事先存储的温度 if(THigh125 || TLow-55 || THighTLow)//判断AT24C02数据是否非法 { THigh20; //如果阈值非法则设为默认值 TLow15; }3.2温度数据在LCD1602上的显示DS18B20_ConvertT(); //转换温度 TDS18B20_ReadT(); //读取温度 if(T0) //如果温度小于0 { LCD_ShowChar(1,7,-); //显示负号 TShow-T; //将温度变为正数 } else //如果温度大于等于0 { LCD_ShowChar(1,7,); //显示正号 TShowT; } LCD_ShowNum(1,8,TShow,2); //显示温度整数部分 LCD_ShowChar(1,10,.); //显示小数点 LCD_ShowNum(1,11,(unsigned long)(TShow*100)%100,2);//显示温度小数部分3.3根据温度的变化显示数据以及调整风扇速度具体说明这部分代码主要分为三个部分 /********分割线********/作为区分3.3.1温度上下限调节与相关显示这部分就是调节设置温度上下限显示部分如果温度在我们所设定的范围内LCD_ShowString(1,13, N );超过我们所设定的温度范围显示LCD_ShowString(1,13, H);3.3.2温度超过上下限风扇转速的变化Temp1THigh2;//超过上限2度Temp2THigh4;//超过上限4度这就是为根据温度变化调整转速的根据达到Temp1就是2档Compare 75达到Temp2就是3档compare 1003.3.3数据存储使用AT24C02if(KeyNum1 || CommandIR_Mode1 || Flag1)//Mode1温度模式 { Mode1; Flag0; Delay(200); play_song_num(0x01); //先不看这句 LCD_ShowString(1,13, ); LCD_ShowString(1,1,Tep );//温度模式 LCD_ShowString(1,5,T:);//显示采集温度 LCD_ShowString(2,1,TH:);//显示温度上限 LCD_ShowString(2,8,TL:);//显示温度下限 LCD_ShowString(2,7, ); LCD_ShowSignedNum(2,4,THigh,2);//显示上下限值 LCD_ShowSignedNum(2,11,TLow,2); LCD_ShowString(2,14,M:); } if(Mode1) { /***温度高位***/ if(KeyNum5 || CommandIR_THADD || Flag4)// { Flag0; THigh; if(THigh125){THigh125;}//超过最高范围 } /***温度高位-***/ if(KeyNum6 || CommandIR_THMINU || Flag5)//- { Flag0; THigh--; if(THighTLow){THigh;} } /***温度低位***/ if(KeyNum7 || CommandIR_TLADD || Flag6)// { Flag0; TLow; if(TLowTHigh){TLow--;}//超过最低温度 } /***温度低位-***/ if(KeyNum8 || CommandIR_TLMINU || Flag7)//- { Flag0; TLow--; if(TLow-55){TLow-55;} } /********分割线********/ Temp1THigh2;//超过上限2度 Temp2THigh4;//超过上限4度 LCD_ShowNum(2,16,0,1); if(TTHigh TTemp1) //越界判断 { LCD_ShowString(1,13, H); LCD_ShowNum(2,16,1,1); Compare50; } else if(TTemp1 TTemp2) { LCD_ShowString(1,13, H); LCD_ShowNum(2,16,2,1); Compare75; } else if(TTemp2) { LCD_ShowString(1,13, H); LCD_ShowNum(2,16,3,1); Compare100; } /*else if(TTHigh) //越界判断 { LCD_ShowString(1,13, ); Compare0; }*/ else if(TTLow) { LCD_ShowString(1,13, L); LCD_ShowNum(2,16,0,1); Compare0; } else { LCD_ShowString(1,15, ); } if(TTLow TTHigh) { LCD_ShowString(1,13, N ); LCD_ShowNum(2,16,1,1); Compare50; } LCD_ShowSignedNum(2,4,THigh,2); //显示阈值数据 LCD_ShowSignedNum(2,11,TLow,2); /********分割线********/ AT24C02_WriteByte(0,THigh); //写入到At24C02中保存 Delay(5); AT24C02_WriteByte(1,TLow); Delay(5);【3】模式3的设计模式3就是一个人体感应模块有人在输出1没人输出0吐槽不知道是我使用的问题还是这个模块的问题有时候很不灵敏if(Pep1 Mode3) { LCD_ShowString(1,1,ECO T:); LCD_ShowString(1,14,YES); LCD_ShowString(2,1,People Detection); Compare75; } if(Pep0 Mode3) { LCD_ShowString(1,1,ECO T:); LCD_ShowString(1,14,NO ); LCD_ShowString(2,1,People Detection); Compare0; }以上就是三个模块的具体设计【4】JQ8900-16的介绍1.JQ8900-16P有三种处理方式IO口触发播放、双线串口、单线串口我使用的是IO口触发播放这个简单端口sbit sdaP2^7;主函数代码就是主函数中这样的数据play_song_num(0x01);具体使用1.生成我们所需要的音频mp3格式好像IO口触发最多只支持9条不太清楚命名格式为00001.mp3玄学按照顺序排下来00001.mp3、00002.mp3这样按顺序排这里用我画圈那个地方写入像u盘一样将文件放进去就行2.主函数中play_song_num(0x01); 这样调用即可【5】语音控制模块购买LD3320后淘宝店家会给很详细的资料按照步骤操作就行1.接收void UART_Routine() interrupt 4 { if(RI1) //如果接收标志位为1接收到了数据 { RI0; receive_data SBUF; } }2.接收后switch(receive_data) { case A:receive_data0;Delay(300);Flag1;break;//温度模式语音模块 case B:receive_data0;Delay(300);Flag2;break;//正常模式语音模块 case C:receive_data0;Delay(300);Flag3;break;//节能模式语音模块 case D:receive_data0;Delay(300);Flag4;break;//温度上限语音模块 case E:receive_data0;Delay(300);Flag5;break;//温度上限-语音模块 case F:receive_data0;Delay(300);Flag6;break;//温度下限语音模块 case G:receive_data0;Delay(300);Flag7;break;//温度下限-语音模块 case H:receive_data0;Delay(300);Flag8;break;//风扇关闭语音模块 case I:receive_data0;Delay(300);Flag9;break;//风扇1挡语音模块 case J:receive_data0;Delay(300);Flag10;break;//风扇2挡语音模块 case K:receive_data0;Delay(300);Flag11;break;//风扇3挡语音模块 }【6】按键和红外操作我直接放主函数#include REGX52.H #include AT24C02.h #include Delay.h #include DS18B20.h #include I2C.h #include LCD1602.h #include OneWire.h #include Timer0.h #include Timer2.h #include IR.h #include Int0.h #include MatrixKey.h #include UART.h #include jq8900.h sbit MotorP1^0;//风扇驱动 sbit PepP3^4;//人体检测 sbit sdaP2^7; unsigned int RunNum0;//步进电机摇头 float T,TShow;//T是实际温度Tshow是显示温度可以变号 char TLow,THigh;//-127--127 unsigned char KeyNum;//用于读取按键值 unsigned char Counter,Compare; //计数值和比较值用于输出PWM unsigned char Speed,M,Mode,Temp1,Temp2,Command; unsigned char receive_data; //接收串口标志位 unsigned int Flag;//语言标识符 //KeyNum读取按下按键值Speed风扇模式切换M档位显示Mode模式 //Temp1,Temp2高温值设置 void main() { /*****温度初始化***/ DS18B20_ConvertT(); //上电先转换一次温度防止第一次读数据错误 Delay(1000); //等待转换完成 THighAT24C02_ReadByte(0); //读取温度阈值数据 TLowAT24C02_ReadByte(1); //读取事先存储的温度 if(THigh125 || TLow-55 || THighTLow)//判断AT24C02数据是否非法 { THigh20; //如果阈值非法则设为默认值 TLow15; } /***显示初始化***/ LCD_Init(); LCD_ShowString(1,1,NowT: );//初步显示模块 LCD_ShowString(2,1,K1:T K2:N K3:E); Timer0_Init();//定时器初始化红外线部分 Timer2_Init();//控制直流电机PWM IR_Init();//红外线遥控 UART_Init();//串口初始化语音模块 while(1) { /****显示模块*****/ KeyNumMatrixKey();//矩阵键盘控制 DS18B20_ConvertT(); //转换温度 TDS18B20_ReadT(); //读取温度 if(T0) //如果温度小于0 { LCD_ShowChar(1,7,-); //显示负号 TShow-T; //将温度变为正数 } else //如果温度大于等于0 { LCD_ShowChar(1,7,); //显示正号 TShowT; } LCD_ShowNum(1,8,TShow,2); //显示温度整数部分 LCD_ShowChar(1,10,.); //显示小数点 LCD_ShowNum(1,11,(unsigned long)(TShow*100)%100,2);//显示温度小数部分 /*******语音控制模块*******/ switch(receive_data) { case A:receive_data0;Delay(300);Flag1;break;//温度模式语音模块 case B:receive_data0;Delay(300);Flag2;break;//正常模式语音模块 case C:receive_data0;Delay(300);Flag3;break;//节能模式语音模块 case D:receive_data0;Delay(300);Flag4;break;//温度上限语音模块 case E:receive_data0;Delay(300);Flag5;break;//温度上限-语音模块 case F:receive_data0;Delay(300);Flag6;break;//温度下限语音模块 case G:receive_data0;Delay(300);Flag7;break;//温度下限-语音模块 case H:receive_data0;Delay(300);Flag8;break;//风扇关闭语音模块 case I:receive_data0;Delay(300);Flag9;break;//风扇1挡语音模块 case J:receive_data0;Delay(300);Flag10;break;//风扇2挡语音模块 case K:receive_data0;Delay(300);Flag11;break;//风扇3挡语音模块 } /****红外线初始化******/ if(IR_GetDataFlag() || KeyNum || Flag!0) { CommandIR_GetCommand(); //获取遥控器命令码 /******Mode1温度模式******/ if(KeyNum1 || CommandIR_Mode1 || Flag1)//Mode1温度模式 { Mode1; Flag0; Delay(200); play_song_num(0x01); LCD_ShowString(1,13, ); LCD_ShowString(1,1,Tep );//温度模式 LCD_ShowString(1,5,T:);//显示采集温度 LCD_ShowString(2,1,TH:);//显示温度上限 LCD_ShowString(2,8,TL:);//显示温度下限 LCD_ShowString(2,7, ); LCD_ShowSignedNum(2,4,THigh,2);//显示上下限值 LCD_ShowSignedNum(2,11,TLow,2); LCD_ShowString(2,14,M:); } if(Mode1) { /***温度高位***/ if(KeyNum5 || CommandIR_THADD || Flag4)// { Flag0; THigh; if(THigh125){THigh125;}//超过最高范围 } /***温度高位-***/ if(KeyNum6 || CommandIR_THMINU || Flag5)//- { Flag0; THigh--; if(THighTLow){THigh;} } /***温度低位***/ if(KeyNum7 || CommandIR_TLADD || Flag6)// { Flag0; TLow; if(TLowTHigh){TLow--;}//超过最低温度 } /***温度低位-***/ if(KeyNum8 || CommandIR_TLMINU || Flag7)//- { Flag0; TLow--; if(TLow-55){TLow-55;} } Temp1THigh2;//超过上限2度 Temp2THigh4;//超过上限4度 LCD_ShowNum(2,16,0,1); if(TTHigh TTemp1) //越界判断 { LCD_ShowString(1,13, H); LCD_ShowNum(2,16,1,1); Compare50; } else if(TTemp1 TTemp2) { LCD_ShowString(1,13, H); LCD_ShowNum(2,16,2,1); Compare75; } else if(TTemp2) { LCD_ShowString(1,13, H); LCD_ShowNum(2,16,3,1); Compare100; } /*else if(TTHigh) //越界判断 { LCD_ShowString(1,13, ); Compare0; }*/ else if(TTLow) { LCD_ShowString(1,13, L); LCD_ShowNum(2,16,0,1); Compare0; } else { LCD_ShowString(1,15, ); } if(TTLow TTHigh) { LCD_ShowString(1,13, N ); LCD_ShowNum(2,16,1,1); Compare50; } LCD_ShowSignedNum(2,4,THigh,2); //显示阈值数据 LCD_ShowSignedNum(2,11,TLow,2); AT24C02_WriteByte(0,THigh); //写入到At24C02中保存 Delay(5); AT24C02_WriteByte(1,TLow); Delay(5); } /*****正常模式Mode2*****/ if(KeyNum2 || CommandIR_Mode2 || Flag2)//Mode2,正常模式 { Compare0; Flag0; Mode2; Delay(200); play_song_num(0x02); LCD_ShowString(1,1,Nat T: );//正常模式显示 LCD_ShowString(2,1,Exchange Mode );// LCD_ShowString(2,15, );// } if(Mode2) { if(KeyNum5 || CommandIR_0 || Flag8) { Flag0; Delay(200); play_song_num(0x04); LCD_ShowString(1,1,Nat T: );//正常模式显示 LCD_ShowString(2,1,Now File M:M); Compare0; M0; } //设置比较值改变PWM占空比 if(KeyNum6 || CommandIR_1 || Flag9) { Flag0; Delay(200); play_song_num(0x05); LCD_ShowString(1,1,Nat T: );//正常模式显示 LCD_ShowString(2,1,Now File M:M); Compare50; M1; } if(KeyNum7 || CommandIR_2 || Flag10) { Flag0; Delay(200); play_song_num(0x06); LCD_ShowString(1,1,Nat T: );//正常模式显示 LCD_ShowString(2,1,Now File M:M); Compare75; M2; } if(KeyNum8 || CommandIR_3 || Flag11)//3挡 { Flag0; Delay(200); play_song_num(0x07); LCD_ShowString(1,1,Nat T: );//正常模式显示 LCD_ShowString(2,1,Now File M:M); Compare100; M3; } LCD_ShowNum(2,16,M,1); } if(KeyNum3 || CommandIR_Mode3 || Flag3)//Mode3,节能模式 { Flag0; Mode3; Delay(200); play_song_num(0x03); LCD_ShowString(1,1,ECO T: ); LCD_ShowString(2,1,People Detection); } } /****节能模式模式3****/ if(Pep1 Mode3) { LCD_ShowString(1,1,ECO T:); LCD_ShowString(1,14,YES); LCD_ShowString(2,1,People Detection); Compare75; } if(Pep0 Mode3) { LCD_ShowString(1,1,ECO T:); LCD_ShowString(1,14,NO ); LCD_ShowString(2,1,People Detection); Compare0; } } } void UART_Routine() interrupt 4 { if(RI1) //如果接收标志位为1接收到了数据 { RI0; receive_data SBUF; } } void Timer2_Routine() interrupt 5 { RCAP2L 0x66; //设置定时重载值 RCAP2H 0xFC; //设置定时重载值 TF20; Counter; Counter%100; //计数值变化范围限制在0~99 if(CounterCompare) //计数值小于比较值 { Motor1; //输出1 } else //计数值大于比较值 { Motor0; //输出0 } }