找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 1484|回复: 0
打印 上一主题 下一主题
收起左侧

基于stc15单片机的只能蓝牙温控风扇程序

[复制链接]
跳转到指定楼层
楼主
ID:944617 发表于 2021-6-25 15:46 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
  1. #include <stc15.h>
  2. #include <string.h>
  3. #include <stdio.h>
  4. #include <intrins.h>

  5. #define u8 unsigned char
  6. #define u16 unsigned int
  7. /*串口*/        
  8. #define FOSC 12000000L                         //系统频率
  9. #define BAUD 9600                                 //串口波特率
  10. #define TM (65536 - (FOSC/4/BAUD))
  11. /*LCD1602*/
  12. #define LCD_Set 0x38                   //显示初始化: 16*2显示,5*7点阵,8位数
  13. #define LCD_Clear 0x01                //清屏
  14. #define LCD_Display 0x0C        //显示功能设置:开显示,不显示光标,光标不闪烁
  15. #define LCD_Mode 0x06                //设置光标状态:读一个字符光标加1
  16. #define LCD_1 0x80                        //第一行起始地址
  17. #define LCD_2 (0x80+0x40)        //第二行起始地址
  18. /*EEPROM*/
  19. #define CMD_IDLE 0                 //空闲模式
  20. #define CMD_READ 1                 //IAP字节读命令
  21. #define CMD_PROGRAM 2         //IAP字节编程命令
  22. #define CMD_ERASE 3         //IAP扇区擦除命令
  23. //#define ENABLE_IAP 0x80 //if SYSCLK<30MHz
  24. //#define ENABLE_IAP 0x81 //if SYSCLK<24MHz
  25. #define ENABLE_IAP 0x82 //if SYSCLK<20MHz
  26. //#define ENABLE_IAP 0x83 //if SYSCLK<12MHz
  27. //#define ENABLE_IAP 0x84 //if SYSCLK<6MHz
  28. //#define ENABLE_IAP 0x85 //if SYSCLK<3MHz
  29. //#define ENABLE_IAP 0x86 //if SYSCLK<2MHz
  30. //#define ENABLE_IAP 0x87 //if SYSCLK<1MHz
  31. #define ENABLE_IAP 0x82   
  32. #define  KEY1_PRES  1
  33. #define  KEY2_PRES  2
  34. #define  KEY3_PRES  3
  35. #define  KEY4_PRES  4
  36. sbit KEY1=P3^2;
  37. sbit KEY2=P3^3;
  38. sbit KEY3=P3^4;
  39. sbit KEY4=P3^5;
  40. u8 TEMP_String[10];
  41. u8 HUMI_String[10];
  42. u8 TH_String[4];
  43. u8 TL_String[4];
  44. sbit DHT11_Data=P1^0;
  45. sbit RS=P2^5;
  46. sbit RW=P2^6;
  47. sbit E=P2^7;
  48. sbit IN1=P1^1;
  49. sbit IN2=P1^2;
  50. sbit ENA=P1^3;
  51. sbit LED=P4^5;
  52. sbit Buzz=P5^5;
  53. u16 TH=30;
  54. u16 TL=15;
  55. u8 Flag=0;
  56. float temperature;
  57. void GPIO(void)
  58. {
  59.         P0M0=0;
  60.         P0M1=0;
  61.         P1M0=0;
  62.         P1M1=0;
  63.         P2M0=0;
  64.         P2M1=0;
  65.         P3M0=0;
  66.         P3M1=0;
  67.         P4M0=0;
  68.         P4M1=0;
  69.         P5M0=0;
  70.         P5M1=0;
  71. }

  72. void delay_ms(u16 ms)
  73. {
  74.         u16 i,j;
  75.         for(i=0;i<ms;i++)
  76.                 for(j=0;j<1147;j++);        //在12MHz时,1ms
  77. }
  78. void delay_30us(void)
  79. {
  80.         u16 i;
  81.         for(i=0;i<20;i++)
  82.                 _nop_();        
  83. }
  84. /*写控制命令函数*LCD1602*/
  85. void Write_Command(u8 Comm)
  86. {
  87.         RS=0;
  88.         RW=0;
  89.         P0=Comm;
  90.         E=1;
  91.         delay_ms(1);
  92.         E=0;
  93. }

  94. /*写数据函数*/
  95. void Write_Data(u8 Data)
  96. {
  97.         RS=1;
  98.         RW=0;
  99.         P0=Data;
  100.         E=1;
  101.         delay_ms(1);
  102.         E=0;
  103. }

  104. /*LCD1602初始化*/
  105. void LCD1602_Init(void)
  106. {
  107.         Write_Command(LCD_Set);
  108.         Write_Command(LCD_Display);
  109.         Write_Command(LCD_Mode);
  110.         Write_Command(LCD_Clear);
  111.         delay_ms(5);
  112.         
  113. }
  114. /*LCD1602在某行某列显示一个字符*/
  115. void LCD1602_Print_Char(u8 line,u8 Addr,u8 Data)
  116. {
  117.         if(line)
  118.         {
  119.                 Write_Command(LCD_2+Addr);
  120.                 Write_Data(Data);
  121.                
  122.         }
  123.         else
  124.         {
  125.                 Write_Command(LCD_1+Addr);
  126.                 Write_Data(Data);
  127.                
  128.         }
  129. }
  130. /*LCD1602在某行显示一串字符*/
  131. void LCD1602_Print_String(u8 line,u8 *table)
  132. {
  133.         u8 i;
  134.         if(line)
  135.         {
  136.                 Write_Command(LCD_2);
  137.         }
  138.         else
  139.         {
  140.                 Write_Command(LCD_1);
  141.         }
  142.         for(i=0;i<16;i++)
  143.         {
  144.                 Write_Data(table[i]);
  145.         }
  146. }
  147. //复位DHT11
  148. void DHT11_Rst(void)           
  149. {                 
  150.     DHT11_Data=0;         //拉低Data
  151.     delay_ms(20);            //至少18ms
  152.     DHT11_Data=1;         //Data=1
  153.          delay_30us();
  154. }
  155. //等待DHT11的回应
  156. //返回1:未检测到DHT11的存在
  157. //返回0:存在
  158. u8 DHT11_Check(void)            
  159. {   
  160.         u8 retry=0;
  161.         while (DHT11_Data&&retry<100)//DHT11会拉低40~80us
  162.         {
  163.                 retry++;
  164.         }         
  165.         if(retry>=100)return 1;
  166.         else retry=0;
  167.     while (!DHT11_Data&&retry<100)//DHT11拉低后会再次提高40~80us
  168.         {
  169.                 retry++;
  170.         }
  171.         if(retry>=100)return 1;            
  172.         return 0;
  173. }
  174. //从DHT11读取一个位
  175. //返回值:1/0
  176. u8 DHT11_Read_Bit(void)                          
  177. {
  178.          u8 retry=0;
  179.         while(DHT11_Data&&retry<100)//等待变成低电平
  180.         {
  181.                 retry++;
  182.         }
  183.         retry=0;
  184.         while(!DHT11_Data&&retry<100)//等待变成高电平
  185.         {
  186.                 retry++;
  187.         }
  188.         delay_30us();
  189.         if(DHT11_Data)return 1;
  190.         else return 0;                  
  191. }
  192. //从DHT11读取一个字节
  193. //返回值:读到的数据
  194. u8 DHT11_Read_Byte(void)   
  195. {        
  196.     u8 i,dat;
  197.     dat=0;
  198.         for (i=0;i<8;i++)
  199.         {
  200.                    dat<<=1;
  201.                      dat|=DHT11_Read_Bit();
  202.     }                                                   
  203.     return dat;
  204. }
  205. //从DHT11读取一次数据
  206. //temp:温度值(范围:0~50°)
  207. //humi:湿度值(范围:20%~90%)
  208. //返回值:0,正常;1,读取失败
  209. u8 DHT11_Read_Data(u8 *temp,u8 *humi)   
  210. {        
  211.          u8 buf[5];
  212.         u8 i;
  213.         DHT11_Rst();
  214.         if(DHT11_Check()==0)
  215.         {
  216.                 for(i=0;i<5;i++)//读取40位数据
  217.                 {
  218.                         buf[i]=DHT11_Read_Byte();
  219.                 }
  220.                 if((buf[0]+buf[1]+buf[2]+buf[3])==buf[4])
  221.                 {
  222.                         *humi=buf[0];
  223.                         *temp=buf[2];
  224.                 }
  225.         }
  226.         else return 1;
  227.         return 0;            
  228. }
  229. //初始化DHT11的IO口 DQ 同时检测DHT11的存在
  230. //返回1:不存在
  231. //返回0:存在
  232. u8 DHT11_Init(void)
  233. {
  234.         DHT11_Rst();
  235.         return DHT11_Check();
  236. }
  237. void OtoC2(u8 value,u8 String[ ])
  238. {
  239.         String[0]=value/10+0x30;
  240.         String[1]=value%10+0x30;

  241. }
  242. void String_Join2bit(u8 Long_String [],u8 Short_String[],u8 Position)
  243. {
  244.          u8 i;
  245.         for(i=0;i<2;i++)
  246.                 Long_String[Position+i]=Short_String[i];        
  247. }
  248. /*按键扫描程序*/
  249. u8 KEY_Scan(u8 mode)
  250. {
  251.     static u8 key_up=1;//按键松开标志
  252.     if(mode)key_up=1; //支持连按
  253.     if(key_up&&(KEY1==0||KEY2==0||KEY3==0||KEY4==0))
  254.     {
  255.         delay_ms (10);//去抖动
  256.         key_up=0;
  257.         if(KEY1==0)
  258.                           return KEY1_PRES;
  259.         else if(KEY2==0)
  260.                           return KEY2_PRES;
  261.                                 else if(KEY3==0)
  262.                           return KEY3_PRES;
  263.                                 else if(KEY4==0)
  264.                           return KEY4_PRES;
  265.     }
  266.     else if(KEY1==1&&KEY2==1&&KEY3==1&&KEY4==1)
  267.         key_up=1;
  268.     return 0;// 无按键按下
  269. }
  270. /*----------------------------
  271.                         关闭IAP
  272. ----------------------------*/
  273. void IapIdle()
  274. {
  275.         IAP_CONTR = 0;         //关闭IAP功能
  276.         IAP_CMD = 0;                 //清除命令寄存器
  277.         IAP_TRIG = 0;                 //清除触发寄存器
  278.         IAP_ADDRH = 0x80; //将地址设置到非IAP区域
  279.         IAP_ADDRL = 0;
  280. }
  281. /*----------------------------
  282. 从ISP/IAP/EEPROM区域读取一字节
  283. ----------------------------*/
  284. u8 IapReadByte(u16 addr)
  285. {
  286.         u8 dat;                                                         //数据缓冲区
  287.         IAP_CONTR = ENABLE_IAP;         //使能IAP
  288.         IAP_CMD = CMD_READ;                         //设置IAP命令
  289.         IAP_ADDRL = addr;                         //设置IAP低地址
  290.         IAP_ADDRH = addr >> 8;                 //设置IAP高地址
  291.         IAP_TRIG = 0x5a;                                 //写触发命令(0x5a)
  292.         IAP_TRIG = 0xa5;                                 //写触发命令(0xa5)
  293.         _nop_();                                                 //等待ISP/IAP/EEPROM操作完成
  294.         dat = IAP_DATA;                                 //读ISP/IAP/EEPROM数据
  295.         IapIdle();                                                 //关闭IAP功能
  296.         return dat;                                         //返回
  297. }
  298. /*----------------------------
  299. 写一字节数据到ISP/IAP/EEPROM区域
  300. ----------------------------*/
  301. void IapProgramByte(u16 addr, u8 dat)
  302. {
  303.         IAP_CONTR = ENABLE_IAP;         //使能IAP
  304.         IAP_CMD = CMD_PROGRAM;                 //设置IAP命令
  305.         IAP_ADDRL = addr;                         //设置IAP低地址
  306.         IAP_ADDRH = addr >> 8;                 //设置IAP高地址
  307.         IAP_DATA = dat;                                 //写ISP/IAP/EEPROM数据
  308.         IAP_TRIG = 0x5a;                                 //写触发命令(0x5a)
  309.         IAP_TRIG = 0xa5;                                 //写触发命令(0xa5)
  310.         _nop_();                                                 //等待ISP/IAP/EEPROM操作完成
  311.         IapIdle();
  312. }

  313. /*----------------------------
  314.                         扇区擦除
  315. ----------------------------*/
  316. void IapEraseSector(u16 addr)
  317. {
  318.         IAP_CONTR = ENABLE_IAP;         //使能IAP
  319.         IAP_CMD = CMD_ERASE;                 //设置IAP命令
  320.         IAP_ADDRL = addr;                         //设置IAP低地址
  321.         IAP_ADDRH = addr >> 8;                 //设置IAP高地址
  322.         IAP_TRIG = 0x5a;                                 //写触发命令(0x5a)
  323.         IAP_TRIG = 0xa5;                                 //写触发命令(0xa5)
  324.         _nop_();                                                 //等待ISP/IAP/EEPROM操作完成
  325.         IapIdle();
  326. }
  327. /*PWM初始化*/
  328. void PWM_Init(void)
  329. {
  330.         P_SW1 &= ~(1<<4|1<<5);         //在P1.0、P1.1输出        
  331.         CCON = 0;         //初始化PCA寄存器
  332.         CL = 0;         //复位PCA寄存器
  333.         CH = 0;
  334.         CMOD = 0x02;                 //设置PCA时钟源SYSCLK/2
  335.         PCA_PWM0  = 0x00;         //PCA模块0工作于8位PWM
  336.         CCAP0H = CCAP0L = 0x00;         //PWM0的占空比为100%
  337.         CCAPM0 = 0x42;         //允许比较器功能、脉宽调节输出
  338.         CR = 1;                 //PCA定时器开始工作
  339. }
  340. /*风扇转动*/
  341. void zhuan(float temperature)
  342. {               
  343.                 u8 i;
  344.         if((temperature>TH)&&(Flag==0)) //如果温度大于上限,则报警20次,并且使用全力风速
  345.                   
  346.         {//                IN1=1;
  347.                         IN2=0;
  348.                         
  349.                         for(i=0;i<20;i++)
  350.                         {
  351.                         LED=0;
  352.                         Buzz=0;
  353.                         delay_ms (100);
  354.                         LED=1;
  355.                         Buzz=1;
  356.                         delay_ms (100);
  357.                         }
  358.                         CCAP0H = CCAP0L = 0x00; //PWM0的占空比为100%
  359.                         Flag=1;
  360.                 }
  361.                
  362.          else if((TL<temperature)&&(temperature<TH))//大于下限,小于上限则为中速风力
  363.                 {
  364. //                IN1=~IN1;
  365.                         IN2=0;
  366.                         LED=1;
  367.                         Buzz=1;
  368.                         CCAP0H = CCAP0L = 0x80;//PWM0的占空比为50%
  369.       Flag=0;                        
  370.                 }
  371.                 else if((temperature<TL)&&(Flag==0))//小于下限则停止转动
  372.                 {
  373. //                IN1=1;
  374.                         IN2=0;
  375.                         for(i=0;i<20;i++)
  376.                         {
  377.                         LED=0;
  378.                         Buzz=0;
  379.                         delay_ms (100);
  380.                         LED=1;
  381.                         Buzz=1;
  382.                         delay_ms (100);
  383.                         }
  384.                         CCAP0H = CCAP0L = 0xFF; //PWM0的占空比为0%
  385.                         Flag=1;
  386.                 }
  387. }
  388. /*串口中断程序*/
  389. void Uart1_INT() interrupt 4 using 1//使用蓝牙遥控;
  390. {
  391.         u8 Ch;
  392.         if (RI)
  393.         {
  394.                 RI = 0;         //清除RI位
  395.                 Ch= SBUF;         //将接收到的字符保存
  396.                 switch (Ch)        
  397.                 {
  398.                         case '1':
  399.                         {
  400.                                 TH++;
  401.                         IapEraseSector(0);
  402.                         IapProgramByte(0,TH);        //写EEPROM上限
  403.                         IapProgramByte(1,TL);        //写EEPROM下限
  404.                                 break;
  405.                         }
  406.                         case '2':
  407.                         {
  408.                                 TH--;
  409.                         IapEraseSector(0);
  410.                         IapProgramByte(0,TH);        //写EEPROM上限
  411.                         IapProgramByte(1,TL);        //写EEPROM下限
  412.                                 break;
  413.                         }
  414.                         case '3':
  415.                         {
  416.                                 TL++;
  417.                         IapEraseSector(0);
  418.                         IapProgramByte(0,TH);        //写EEPROM上限
  419.                         IapProgramByte(1,TL);        //写EEPROM下限
  420.                                 break;
  421.                         }
  422.                         case '4':
  423.                         {
  424.                                 TL--;
  425.                         IapEraseSector(0);
  426.                         IapProgramByte(0,TH);        //写EEPROM上限
  427.                         IapProgramByte(1,TL);        //写EEPROM下限
  428.                                 break;
  429.                         }
  430.                         case '5':
  431.                         {
  432.                                 IN2=0;
  433.                                 CCAP0H = CCAP0L = 0x00; //PWM0的占空比为100%
  434.                                 break;
  435.                         }
  436.                         case '6':
  437.                         {
  438.                                 IN1=1;
  439.                                 IN2=1;
  440.                                 break;
  441.                         }
  442.                         case 'G':
  443.                         {
  444.                                 IN2=0;
  445.                                 CCAP0H = CCAP0L = 0x40; //PWM0的占空比为75%
  446.                                 break;
  447.                         }
  448.                         case 'K':
  449.                         {
  450.                                 IN2=0;
  451.                                 CCAP0H = CCAP0L = 0xC0; //PWM0的占空比为25%
  452.                                 break;
  453.                         }
  454.                 }
  455.         }
  456. }
  457. /*串口初始化*/
  458. void UART1_Init(void)
  459. {
  460.         SCON = 0x50;        //方式1,8位UART,波特率可变
  461.         AUXR |= 1<<2|1<<0;         //定时器2为1T模式,UART1使用T2
  462. //        TMOD = 0x00;         //定时器1为模式0(16位自动重载)
  463.         T2L = TM; //设置波特率重装值
  464.         T2H = TM>>8;
  465.         AUXR |= 1<<4; //定时器2启动
  466.         ES = 1; //使能串口中断
  467.         EA = 1;
  468. }

  469. int main(void)
  470. {
  471.         u8 t=0;
  472.         u8 temperature=0;              
  473.         u8 humidity=0;
  474. //        u8 TH_EEPROM_Value,TL_EEPROM_Value;        定义EEPROM温度上下限变量  
  475.         u8 String1[]="T:   C  H:   %Rn ";               
  476.         u8 String2[]="TL:    ,TH:      ";
  477.         u8 Stirng_Error[ ]="  DHT11 Error!  ";
  478.         GPIO();
  479.         PWM_Init();
  480.         UART1_Init();
  481.         LCD1602_Init();
  482.         TH=IapReadByte(0);        //读取EEPROM
  483.         TL=IapReadByte(1);
  484.                         IapProgramByte(0,TH);        //写EEPROM上限
  485.                         IapProgramByte(1,TL);        //写EEPROM下限
  486.         while(DHT11_Init())
  487.                 LCD1602_Print_String(0,Stirng_Error);
  488.         while(1)
  489.                 {        t=KEY_Scan(0);  //得到键值
  490.           switch(t)
  491.           {
  492.                  case KEY1_PRES:
  493.                  {
  494.                          TH++;
  495.                          IapEraseSector(0);
  496.                         IapProgramByte(0,TH);        //写EEPROM上限
  497.                         IapProgramByte(1,TL);        //写EEPROM下限
  498.                          break;
  499.                  }
  500.                  case KEY2_PRES:
  501.                  {
  502.                         TH--;
  503.                         IapEraseSector(0);
  504.                         IapProgramByte(0,TH);        //写EEPROM上限
  505.                         IapProgramByte(1,TL);        //写EEPROM下限
  506.                         break;
  507.                  }
  508.                  case KEY3_PRES:
  509.                  {
  510.                         TL++;
  511.                         IapEraseSector(0);
  512.                         IapProgramByte(0,TH);        //写EEPROM上限
  513.                         IapProgramByte(1,TL);        //写EEPROM下限
  514.                         break;
  515.                  }
  516.                  case KEY4_PRES:
  517.                  {
  518.                         TL--;
  519.                         IapEraseSector(0);
  520.                         IapProgramByte(0,TH);        //写EEPROM上限
  521.                         IapProgramByte(1,TL);        //写EEPROM下限
  522.                         break;
  523.                  }
  524.           }
  525.                         DHT11_Read_Data(&temperature,&humidity) ;
  526.                         OtoC2(temperature,TEMP_String);        
  527.                         String_Join2bit(String1,TEMP_String,2);        
  528.                         OtoC2(humidity,HUMI_String);                 
  529.                         String_Join2bit(String1,HUMI_String,10);
  530.                         OtoC2(TH,TH_String);        
  531.                         String_Join2bit(String2,TH_String,11);
  532.                         OtoC2(TL,TL_String);
  533.                         String_Join2bit(String2,TL_String,3);
  534.                         LCD1602_Print_String(0,String1);        
  535.                         LCD1602_Print_String(1,String2);
  536.                         zhuan(temperature);
  537.                 }
  538. }

复制代码
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表