- #include <stc15.h>
- #include <string.h>
- #include <stdio.h>
- #include <intrins.h>
- #define u8 unsigned char
- #define u16 unsigned int
- /*串口*/
- #define FOSC 12000000L //系统频率
- #define BAUD 9600 //串口波特率
- #define TM (65536 - (FOSC/4/BAUD))
- /*LCD1602*/
- #define LCD_Set 0x38 //显示初始化: 16*2显示,5*7点阵,8位数
- #define LCD_Clear 0x01 //清屏
- #define LCD_Display 0x0C //显示功能设置:开显示,不显示光标,光标不闪烁
- #define LCD_Mode 0x06 //设置光标状态:读一个字符光标加1
- #define LCD_1 0x80 //第一行起始地址
- #define LCD_2 (0x80+0x40) //第二行起始地址
- /*EEPROM*/
- #define CMD_IDLE 0 //空闲模式
- #define CMD_READ 1 //IAP字节读命令
- #define CMD_PROGRAM 2 //IAP字节编程命令
- #define CMD_ERASE 3 //IAP扇区擦除命令
- //#define ENABLE_IAP 0x80 //if SYSCLK<30MHz
- //#define ENABLE_IAP 0x81 //if SYSCLK<24MHz
- #define ENABLE_IAP 0x82 //if SYSCLK<20MHz
- //#define ENABLE_IAP 0x83 //if SYSCLK<12MHz
- //#define ENABLE_IAP 0x84 //if SYSCLK<6MHz
- //#define ENABLE_IAP 0x85 //if SYSCLK<3MHz
- //#define ENABLE_IAP 0x86 //if SYSCLK<2MHz
- //#define ENABLE_IAP 0x87 //if SYSCLK<1MHz
- #define ENABLE_IAP 0x82
- #define KEY1_PRES 1
- #define KEY2_PRES 2
- #define KEY3_PRES 3
- #define KEY4_PRES 4
- sbit KEY1=P3^2;
- sbit KEY2=P3^3;
- sbit KEY3=P3^4;
- sbit KEY4=P3^5;
- u8 TEMP_String[10];
- u8 HUMI_String[10];
- u8 TH_String[4];
- u8 TL_String[4];
- sbit DHT11_Data=P1^0;
- sbit RS=P2^5;
- sbit RW=P2^6;
- sbit E=P2^7;
- sbit IN1=P1^1;
- sbit IN2=P1^2;
- sbit ENA=P1^3;
- sbit LED=P4^5;
- sbit Buzz=P5^5;
- u16 TH=30;
- u16 TL=15;
- u8 Flag=0;
- float temperature;
- void GPIO(void)
- {
- P0M0=0;
- P0M1=0;
- P1M0=0;
- P1M1=0;
- P2M0=0;
- P2M1=0;
- P3M0=0;
- P3M1=0;
- P4M0=0;
- P4M1=0;
- P5M0=0;
- P5M1=0;
- }
- void delay_ms(u16 ms)
- {
- u16 i,j;
- for(i=0;i<ms;i++)
- for(j=0;j<1147;j++); //在12MHz时,1ms
- }
- void delay_30us(void)
- {
- u16 i;
- for(i=0;i<20;i++)
- _nop_();
- }
- /*写控制命令函数*LCD1602*/
- void Write_Command(u8 Comm)
- {
- RS=0;
- RW=0;
- P0=Comm;
- E=1;
- delay_ms(1);
- E=0;
- }
- /*写数据函数*/
- void Write_Data(u8 Data)
- {
- RS=1;
- RW=0;
- P0=Data;
- E=1;
- delay_ms(1);
- E=0;
- }
- /*LCD1602初始化*/
- void LCD1602_Init(void)
- {
- Write_Command(LCD_Set);
- Write_Command(LCD_Display);
- Write_Command(LCD_Mode);
- Write_Command(LCD_Clear);
- delay_ms(5);
-
- }
- /*LCD1602在某行某列显示一个字符*/
- void LCD1602_Print_Char(u8 line,u8 Addr,u8 Data)
- {
- if(line)
- {
- Write_Command(LCD_2+Addr);
- Write_Data(Data);
-
- }
- else
- {
- Write_Command(LCD_1+Addr);
- Write_Data(Data);
-
- }
- }
- /*LCD1602在某行显示一串字符*/
- void LCD1602_Print_String(u8 line,u8 *table)
- {
- u8 i;
- if(line)
- {
- Write_Command(LCD_2);
- }
- else
- {
- Write_Command(LCD_1);
- }
- for(i=0;i<16;i++)
- {
- Write_Data(table[i]);
- }
- }
- //复位DHT11
- void DHT11_Rst(void)
- {
- DHT11_Data=0; //拉低Data
- delay_ms(20); //至少18ms
- DHT11_Data=1; //Data=1
- delay_30us();
- }
- //等待DHT11的回应
- //返回1:未检测到DHT11的存在
- //返回0:存在
- u8 DHT11_Check(void)
- {
- u8 retry=0;
- while (DHT11_Data&&retry<100)//DHT11会拉低40~80us
- {
- retry++;
- }
- if(retry>=100)return 1;
- else retry=0;
- while (!DHT11_Data&&retry<100)//DHT11拉低后会再次提高40~80us
- {
- retry++;
- }
- if(retry>=100)return 1;
- return 0;
- }
- //从DHT11读取一个位
- //返回值:1/0
- u8 DHT11_Read_Bit(void)
- {
- u8 retry=0;
- while(DHT11_Data&&retry<100)//等待变成低电平
- {
- retry++;
- }
- retry=0;
- while(!DHT11_Data&&retry<100)//等待变成高电平
- {
- retry++;
- }
- delay_30us();
- if(DHT11_Data)return 1;
- else return 0;
- }
- //从DHT11读取一个字节
- //返回值:读到的数据
- u8 DHT11_Read_Byte(void)
- {
- u8 i,dat;
- dat=0;
- for (i=0;i<8;i++)
- {
- dat<<=1;
- dat|=DHT11_Read_Bit();
- }
- return dat;
- }
- //从DHT11读取一次数据
- //temp:温度值(范围:0~50°)
- //humi:湿度值(范围:20%~90%)
- //返回值:0,正常;1,读取失败
- u8 DHT11_Read_Data(u8 *temp,u8 *humi)
- {
- u8 buf[5];
- u8 i;
- DHT11_Rst();
- if(DHT11_Check()==0)
- {
- for(i=0;i<5;i++)//读取40位数据
- {
- buf[i]=DHT11_Read_Byte();
- }
- if((buf[0]+buf[1]+buf[2]+buf[3])==buf[4])
- {
- *humi=buf[0];
- *temp=buf[2];
- }
- }
- else return 1;
- return 0;
- }
- //初始化DHT11的IO口 DQ 同时检测DHT11的存在
- //返回1:不存在
- //返回0:存在
- u8 DHT11_Init(void)
- {
- DHT11_Rst();
- return DHT11_Check();
- }
- void OtoC2(u8 value,u8 String[ ])
- {
- String[0]=value/10+0x30;
- String[1]=value%10+0x30;
- }
- void String_Join2bit(u8 Long_String [],u8 Short_String[],u8 Position)
- {
- u8 i;
- for(i=0;i<2;i++)
- Long_String[Position+i]=Short_String[i];
- }
- /*按键扫描程序*/
- u8 KEY_Scan(u8 mode)
- {
- static u8 key_up=1;//按键松开标志
- if(mode)key_up=1; //支持连按
- if(key_up&&(KEY1==0||KEY2==0||KEY3==0||KEY4==0))
- {
- delay_ms (10);//去抖动
- key_up=0;
- if(KEY1==0)
- return KEY1_PRES;
- else if(KEY2==0)
- return KEY2_PRES;
- else if(KEY3==0)
- return KEY3_PRES;
- else if(KEY4==0)
- return KEY4_PRES;
- }
- else if(KEY1==1&&KEY2==1&&KEY3==1&&KEY4==1)
- key_up=1;
- return 0;// 无按键按下
- }
- /*----------------------------
- 关闭IAP
- ----------------------------*/
- void IapIdle()
- {
- IAP_CONTR = 0; //关闭IAP功能
- IAP_CMD = 0; //清除命令寄存器
- IAP_TRIG = 0; //清除触发寄存器
- IAP_ADDRH = 0x80; //将地址设置到非IAP区域
- IAP_ADDRL = 0;
- }
- /*----------------------------
- 从ISP/IAP/EEPROM区域读取一字节
- ----------------------------*/
- u8 IapReadByte(u16 addr)
- {
- u8 dat; //数据缓冲区
- IAP_CONTR = ENABLE_IAP; //使能IAP
- IAP_CMD = CMD_READ; //设置IAP命令
- IAP_ADDRL = addr; //设置IAP低地址
- IAP_ADDRH = addr >> 8; //设置IAP高地址
- IAP_TRIG = 0x5a; //写触发命令(0x5a)
- IAP_TRIG = 0xa5; //写触发命令(0xa5)
- _nop_(); //等待ISP/IAP/EEPROM操作完成
- dat = IAP_DATA; //读ISP/IAP/EEPROM数据
- IapIdle(); //关闭IAP功能
- return dat; //返回
- }
- /*----------------------------
- 写一字节数据到ISP/IAP/EEPROM区域
- ----------------------------*/
- void IapProgramByte(u16 addr, u8 dat)
- {
- IAP_CONTR = ENABLE_IAP; //使能IAP
- IAP_CMD = CMD_PROGRAM; //设置IAP命令
- IAP_ADDRL = addr; //设置IAP低地址
- IAP_ADDRH = addr >> 8; //设置IAP高地址
- IAP_DATA = dat; //写ISP/IAP/EEPROM数据
- IAP_TRIG = 0x5a; //写触发命令(0x5a)
- IAP_TRIG = 0xa5; //写触发命令(0xa5)
- _nop_(); //等待ISP/IAP/EEPROM操作完成
- IapIdle();
- }
- /*----------------------------
- 扇区擦除
- ----------------------------*/
- void IapEraseSector(u16 addr)
- {
- IAP_CONTR = ENABLE_IAP; //使能IAP
- IAP_CMD = CMD_ERASE; //设置IAP命令
- IAP_ADDRL = addr; //设置IAP低地址
- IAP_ADDRH = addr >> 8; //设置IAP高地址
- IAP_TRIG = 0x5a; //写触发命令(0x5a)
- IAP_TRIG = 0xa5; //写触发命令(0xa5)
- _nop_(); //等待ISP/IAP/EEPROM操作完成
- IapIdle();
- }
- /*PWM初始化*/
- void PWM_Init(void)
- {
- P_SW1 &= ~(1<<4|1<<5); //在P1.0、P1.1输出
- CCON = 0; //初始化PCA寄存器
- CL = 0; //复位PCA寄存器
- CH = 0;
- CMOD = 0x02; //设置PCA时钟源SYSCLK/2
- PCA_PWM0 = 0x00; //PCA模块0工作于8位PWM
- CCAP0H = CCAP0L = 0x00; //PWM0的占空比为100%
- CCAPM0 = 0x42; //允许比较器功能、脉宽调节输出
- CR = 1; //PCA定时器开始工作
- }
- /*风扇转动*/
- void zhuan(float temperature)
- {
- u8 i;
- if((temperature>TH)&&(Flag==0)) //如果温度大于上限,则报警20次,并且使用全力风速
-
- {// IN1=1;
- IN2=0;
-
- for(i=0;i<20;i++)
- {
- LED=0;
- Buzz=0;
- delay_ms (100);
- LED=1;
- Buzz=1;
- delay_ms (100);
- }
- CCAP0H = CCAP0L = 0x00; //PWM0的占空比为100%
- Flag=1;
- }
-
- else if((TL<temperature)&&(temperature<TH))//大于下限,小于上限则为中速风力
- {
- // IN1=~IN1;
- IN2=0;
- LED=1;
- Buzz=1;
- CCAP0H = CCAP0L = 0x80;//PWM0的占空比为50%
- Flag=0;
- }
- else if((temperature<TL)&&(Flag==0))//小于下限则停止转动
- {
- // IN1=1;
- IN2=0;
- for(i=0;i<20;i++)
- {
- LED=0;
- Buzz=0;
- delay_ms (100);
- LED=1;
- Buzz=1;
- delay_ms (100);
- }
- CCAP0H = CCAP0L = 0xFF; //PWM0的占空比为0%
- Flag=1;
- }
- }
- /*串口中断程序*/
- void Uart1_INT() interrupt 4 using 1//使用蓝牙遥控;
- {
- u8 Ch;
- if (RI)
- {
- RI = 0; //清除RI位
- Ch= SBUF; //将接收到的字符保存
- switch (Ch)
- {
- case '1':
- {
- TH++;
- IapEraseSector(0);
- IapProgramByte(0,TH); //写EEPROM上限
- IapProgramByte(1,TL); //写EEPROM下限
- break;
- }
- case '2':
- {
- TH--;
- IapEraseSector(0);
- IapProgramByte(0,TH); //写EEPROM上限
- IapProgramByte(1,TL); //写EEPROM下限
- break;
- }
- case '3':
- {
- TL++;
- IapEraseSector(0);
- IapProgramByte(0,TH); //写EEPROM上限
- IapProgramByte(1,TL); //写EEPROM下限
- break;
- }
- case '4':
- {
- TL--;
- IapEraseSector(0);
- IapProgramByte(0,TH); //写EEPROM上限
- IapProgramByte(1,TL); //写EEPROM下限
- break;
- }
- case '5':
- {
- IN2=0;
- CCAP0H = CCAP0L = 0x00; //PWM0的占空比为100%
- break;
- }
- case '6':
- {
- IN1=1;
- IN2=1;
- break;
- }
- case 'G':
- {
- IN2=0;
- CCAP0H = CCAP0L = 0x40; //PWM0的占空比为75%
- break;
- }
- case 'K':
- {
- IN2=0;
- CCAP0H = CCAP0L = 0xC0; //PWM0的占空比为25%
- break;
- }
- }
- }
- }
- /*串口初始化*/
- void UART1_Init(void)
- {
- SCON = 0x50; //方式1,8位UART,波特率可变
- AUXR |= 1<<2|1<<0; //定时器2为1T模式,UART1使用T2
- // TMOD = 0x00; //定时器1为模式0(16位自动重载)
- T2L = TM; //设置波特率重装值
- T2H = TM>>8;
- AUXR |= 1<<4; //定时器2启动
- ES = 1; //使能串口中断
- EA = 1;
- }
- int main(void)
- {
- u8 t=0;
- u8 temperature=0;
- u8 humidity=0;
- // u8 TH_EEPROM_Value,TL_EEPROM_Value; 定义EEPROM温度上下限变量
- u8 String1[]="T: C H: %Rn ";
- u8 String2[]="TL: ,TH: ";
- u8 Stirng_Error[ ]=" DHT11 Error! ";
- GPIO();
- PWM_Init();
- UART1_Init();
- LCD1602_Init();
- TH=IapReadByte(0); //读取EEPROM
- TL=IapReadByte(1);
- IapProgramByte(0,TH); //写EEPROM上限
- IapProgramByte(1,TL); //写EEPROM下限
- while(DHT11_Init())
- LCD1602_Print_String(0,Stirng_Error);
- while(1)
- { t=KEY_Scan(0); //得到键值
- switch(t)
- {
- case KEY1_PRES:
- {
- TH++;
- IapEraseSector(0);
- IapProgramByte(0,TH); //写EEPROM上限
- IapProgramByte(1,TL); //写EEPROM下限
- break;
- }
- case KEY2_PRES:
- {
- TH--;
- IapEraseSector(0);
- IapProgramByte(0,TH); //写EEPROM上限
- IapProgramByte(1,TL); //写EEPROM下限
- break;
- }
- case KEY3_PRES:
- {
- TL++;
- IapEraseSector(0);
- IapProgramByte(0,TH); //写EEPROM上限
- IapProgramByte(1,TL); //写EEPROM下限
- break;
- }
- case KEY4_PRES:
- {
- TL--;
- IapEraseSector(0);
- IapProgramByte(0,TH); //写EEPROM上限
- IapProgramByte(1,TL); //写EEPROM下限
- break;
- }
- }
- DHT11_Read_Data(&temperature,&humidity) ;
- OtoC2(temperature,TEMP_String);
- String_Join2bit(String1,TEMP_String,2);
- OtoC2(humidity,HUMI_String);
- String_Join2bit(String1,HUMI_String,10);
- OtoC2(TH,TH_String);
- String_Join2bit(String2,TH_String,11);
- OtoC2(TL,TL_String);
- String_Join2bit(String2,TL_String,3);
- LCD1602_Print_String(0,String1);
- LCD1602_Print_String(1,String2);
- zhuan(temperature);
- }
- }
复制代码 |