- #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);
- }
- }
復制代碼 |