![]() |
#include "reg52.H" #include "stdio.h" #include "intrins.h" #include <math.h> #define DB P0//液晶并行數據接口 sbit RS = P2^0;//液晶指令數據信號 sbit RW = P2^1;//液晶讀寫信號 sbit E = P2^2;//液晶使能信號 unsigned char key_value;//獲取到按鍵的值 sbit Sck_P = P1^1; // SHT11傳感器的時鐘管腳 sbit Data_P = P1^0; // SHT11傳感器的數據管腳 unsigned char temp; // 保存溫度 unsigned char humi; // 保存濕度 enum { TEMP,HUMI }; typedef union //定義共用同類型 { unsigned int i; float f; }value; //是否應答 #define NACK 0 #define ACK 1 //SHT75傳感器命令集 地址 命令 讀/寫 #define MEASURE_TEMP 0x03 //000 0001 1 #define MEASURE_HUMI 0x05 //000 0010 1 #define STATUS_REG_W 0x06 //000 0011 0 #define STATUS_REG_R 0x07 //000 0011 1 #define RESET 0x1E //000 1111 0 unsigned char now_window;//當前顯示窗口 unsigned char curr_menu; #define normal_mode 0x10//輸入密碼狀態 #define set_mode 0x20//輸入密碼狀態 signed char AlarmTL=10; // 溫度下限報警值 signed char AlarmTH=30; // 溫度上限報警值 signed char AlarmHL=40; // 濕度下限報警值 signed char AlarmHH=80; // 濕度上限報警值 unsigned char i; unsigned char cnt_100ms; unsigned char time_100ms_flag; unsigned char open_del;//開鎖成功延時計數 unsigned char open_flag;//鎖狀態標志 sbit beep = P1^2; sbit LedTL_P = P1^3; // 溫度過低報警指示燈 sbit LedTH_P = P1^4; // 溫度過高報警指示燈 sbit LedHL_P = P1^5; // 濕度過低報警指示燈 sbit LedHH_P = P1^6; // 濕度過高報警指示燈 /******************************************************************************* * 函 數 名 : delay_ms * 函數功能 : 延時函數,延時1ms * 輸 入 : cnt * 輸 出 : 無 * 說 名 : 該函數是在12MHZ晶振下,12分頻單片機的延時。 *******************************************************************************/ void delay_ms(unsigned int cnt) // { unsigned int x; for( ; cnt>0; cnt--) { for(x=110; x>0; x--);//軟件延時為1MS } } #if 0 void delay_us(unsigned int cnt) // { while(cnt--); } #endif /****************************************************** ** 函數名:time_init ** 描述 :定時器初始化 ** 輸入 :無 ** 輸出 :無 ******************************************************/ void time_init(void) { TMOD |= 0x01;//time0 工作方式為1 TH0 = 0xf8;//裝載初值 TL0 = 0x2f;//裝載初值,為2ms(65535-63535) TR0 = 1;//開啟定時器 ET0 = 1;//打開中斷 EA=1; } /****************************************************** ** 函數名:key_scan ** 描述 :按鍵掃描 ** 輸入 :無 ** 輸出 :無 ******************************************************/ void key_scan(void) { static unsigned char key_in_flag = 0;//按鍵按下標志 unsigned char key_l;//存儲掃描到行列值。 key_value = 20;//按鍵值清除 if((P3 & 0x0f) != 0x0f)//按鍵按下 { delay_ms(1);//按鍵消抖動 if(((P3 & 0x0f) != 0x0f) && (key_in_flag == 1)) { key_in_flag = 0;//松手檢測防止一直觸發 P3 = 0x0f; //delay_ms(1);//按鍵消抖動 key_l = P3;//掃描得到按鍵值 switch(key_l) { //獲取按鍵值 case 0x0e: { key_value = 1; } break; case 0x0d: { key_value = 2; } break; case 0x0b: { key_value = 3; } break; //case 0x70: //break; } } } else { key_in_flag = 1;//(按鍵松開標志) } } /******************************************************************************* * 函 數 名 : LcdWriteCom * 函數功能 : 向LCD寫入一個字節的命令 * 輸 入 : u8com * 輸 出 : 無 *******************************************************************************/ void lcd_wri_com(unsigned char com) //寫入命令 { E = 0; //使能清零 RS = 0; //選擇寫入命令 RW = 0; //選擇寫入 DB = com; delay_ms(1); E = 1; //寫入時序 delay_ms(5); E = 0; } /******************************************************************************* * 函 數 名 : LcdWriteData * 函數功能 : 向LCD寫入一個字節的數據 * 輸 入 : u8dat * 輸 出 : 無 *******************************************************************************/ void lcd_wri_data(unsigned char dat)//寫入數據 { E = 0; //使能清零 RS = 1; //選擇寫入數據 RW = 0; //選擇寫入 DB = dat; delay_ms(1); E = 1; //寫入時序 delay_ms(5); E = 0; } /******************************************************************************* * 函 數 名 : WriString * 函數功能 : 刷新屏幕顯示 * 輸 入 : hang,add,*p * 輸 出 : 無 *******************************************************************************/ void wri_string(unsigned char y,unsigned char x,unsigned char *p) { if(y==1)//如果選擇第一行 lcd_wri_com(0x80+x);//選中地址 else lcd_wri_com(0xc0+x);//選中地址 while(*p) { lcd_wri_data(*p);//寫入數據 p++; } } /******************************************************************************* * 函 數 名 : lcd_write_char * 函數功能 : * 輸 入 : * 輸 出 : 無 *******************************************************************************/ void lcd_write_char(unsigned char y, unsigned char x, unsigned char dat) //列x=0~15,行y=0,1 { unsigned char temp_l, temp_h; if(y==1)//如果選擇第一行 lcd_wri_com(0x80+x);//選中地址 else lcd_wri_com(0xc0+x);//選中地址 temp_l = dat % 10; temp_h = dat / 10; lcd_wri_data(temp_h + 0x30); //convert to ascii lcd_wri_data(temp_l + 0x30); } /*********************光標控制***********************/ void lcd1602_guanbiao(unsigned char y, unsigned char x,unsigned char on_off) { if(on_off == 1) //開光標 { if(y==1)//如果選擇第一行 lcd_wri_com(0x80+x); else lcd_wri_com(0xc0+x);//將光標移動到秒個位 lcd_wri_com(0x0f);//顯示光標并且閃爍 } else { if(y==1)//如果選擇第一行 lcd_wri_com(0x80+x); else lcd_wri_com(0xc0+x);//將光標移動到秒個位 lcd_wri_com(0x0c); //關光標 } } /******************************************************************************* * 函 數 名 : LcdInit() * 函數功能 : 初始化LCD屏 * 輸 入 : 無 * 輸 出 : 無 *******************************************************************************/ void lcd_init(void) //LCD初始化子程序 { lcd_wri_com(0x38);//置功能8位雙行 lcd_wri_com(0x0c);//顯示開關光標 lcd_wri_com(0x06);//字符進入模式屏幕不動字符后移 delay_ms(5);//延時5ms lcd_wri_com(0x01); //清屏 wri_string(1,0,"welcome user DHT");//初始化顯示 wri_string(2,0,"H: %RH T: C ");//初始化顯示 } /*********************************************************/ // 往SHT11寫入一個字節 /*********************************************************/ char ShtWriteByte(unsigned char value) { unsigned char i,error=0; for(i=128;i>0;i>>=1) // 高位為1,循環右移 { if (i&value) Data_P=1; // 和要發送的數相與,結果為發送的位 else Data_P=0; Sck_P=1; _nop_(); // 延時3us _nop_(); _nop_(); Sck_P=0; } Data_P=1; // 釋放數據線 Sck_P=1; error=Data_P; // 檢查應答信號,確認通訊正常 _nop_(); _nop_(); _nop_(); Sck_P=0; Data_P=1; return error; // error=1 通訊錯誤 } /*********************************************************/ // 從SHT11讀出一個字節 /*********************************************************/ char ShtReadByte(unsigned char ack) { unsigned char i,val=0; Data_P=1; // 釋放數據線 for(i=0x80;i>0;i>>=1) // 高位為1,循環右移 { Sck_P=1; if(Data_P) val=(val|i); // 讀一位數據線的值 Sck_P=0; } Data_P=!ack; // 如果是校驗,讀取完后結束通訊 Sck_P=1; _nop_(); // 延時3us _nop_(); _nop_(); Sck_P=0; _nop_(); _nop_(); _nop_(); Data_P=1; // 釋放數據線 return val; } /*********************************************************/ // SHT11啟動傳輸 /*********************************************************/ void ShtTransStart(void) { Data_P=1; Sck_P=0; _nop_(); Sck_P=1; _nop_(); Data_P=0; _nop_(); Sck_P=0; _nop_(); _nop_(); _nop_(); Sck_P=1; _nop_(); Data_P=1; _nop_(); Sck_P=0; } /*********************************************************/ // SHT11連接復位 /*********************************************************/ void ShtConnectReset(void) { unsigned char i; Data_P=1; //準備 Sck_P=0; for(i=0;i<9;i++) //DATA保持高,SCK時鐘觸發9次,發送啟動傳輸,通迅即復位 { Sck_P=1; Sck_P=0; } ShtTransStart(); //啟動傳輸 } /*********************************************************/ // SHT11溫濕度檢測 /*********************************************************/ char ShtMeasure(unsigned char *p_value, unsigned char *p_checksum, unsigned char mode) { unsigned error=0; unsigned int i; ShtTransStart(); // 啟動傳輸 switch(mode) // 選擇發送命令 { case 1 : // 測量溫度 error+=ShtWriteByte(0x03); break; case 2 : // 測量濕度 error+=ShtWriteByte(0x05); break; default: break; } for(i=0;i<65535;i++) if(Data_P==0) break; // 等待測量結束 if(Data_P) error+=1; // 如果長時間數據線沒有拉低,說明測量錯誤 *(p_value) =ShtReadByte(1); // 讀第一個字節,高字節 (MSB) *(p_value+1)=ShtReadByte(1); // 讀第二個字節,低字節 (LSB) *p_checksum =ShtReadByte(0); // read CRC校驗碼 return error; // error=1 通訊錯誤 } /*********************************************************/ // SHT11溫濕度值標度變換及溫度補償 /*********************************************************/ void CalcSHT11(float *p_humidity ,float *p_temperature) { const float C1=-4.0; // 12位濕度精度 修正公式 const float C2=+0.0405; // 12位濕度精度 修正公式 const float C3=-0.0000028; // 12位濕度精度 修正公式 const float T1=+0.01; // 14位溫度精度 5V條件 修正公式 const float T2=+0.00008; // 14位溫度精度 5V條件 修正公式 float rh=*p_humidity; // rh: 12位 濕度 float t=*p_temperature; // t: 14位 溫度 float rh_lin; // rh_lin: 濕度 linear值 float rh_true; // rh_true: 濕度 ture值 float t_C; // t_C : 溫度 ℃ t_C=t*0.01 - 40; //補償溫度 rh_lin=C3*rh*rh + C2*rh + C1; //相對濕度非線性補償 rh_true=(t_C-25)*(T1+T2*rh)+rh_lin; //相對濕度對于溫度依賴性補償 *p_temperature=t_C; //返回溫度結果 *p_humidity=rh_true; //返回濕度結果 } /*********************************************************/ // 溫度校正 /*********************************************************/ unsigned char TempCorrect(int temp) { if(temp<0) temp=0; if(temp>970) temp=970; if(temp>235) temp=temp+10; if(temp>555) temp=temp+10; if(temp>875) temp=temp+10; temp=(temp%1000)/10; return temp; } /*********************************************************/ // 濕度校正 /*********************************************************/ unsigned char HumiCorrect(unsigned int humi) { if(humi>999) humi=999; if((humi>490)&&(humi<951)) humi=humi-10; humi=(humi%1000)/10; return humi+4; } /*********************************************************/ // 讀取SHT11的溫濕度數據 /*********************************************************/ void ReadShtData() { value humi_val,temp_val; // 定義兩個共同體,一個用于濕度,一個用于溫度 unsigned char error; // 用于檢驗是否出現錯誤 unsigned char checksum; // CRC unsigned int temp1,humi1; // 臨時讀取到的溫濕度數據 error=0; //初始化error=0,即沒有錯誤 error+=ShtMeasure((unsigned char*)&temp_val.i,&checksum,1); //溫度測量 error+=ShtMeasure((unsigned char*)&humi_val.i,&checksum,2); //濕度測量 if(error!=0) //如果發生錯誤,系統復位 ShtConnectReset(); else { humi_val.f=(float)humi_val.i; //轉換為浮點數 temp_val.f=(float)temp_val.i; //轉換為浮點數 CalcSHT11(&humi_val.f,&temp_val.f); //修正相對濕度及溫度 temp1=temp_val.f*10; temp=TempCorrect(temp1); humi1=humi_val.f*10-50; humi=HumiCorrect(humi1); humi = humi + 2; } } void AlarmJudge(void) { if(temp>AlarmTH) // 溫度是否過高 { LedTH_P=0; LedTL_P=1; } else if(temp<AlarmTL) // 溫度是否過低 { LedTL_P=0; LedTH_P=1; } else // 溫度正常 { LedTH_P=1; LedTL_P=1; } if(humi>AlarmHH) // 濕度是否過高 { LedHH_P=0; LedHL_P=1; } else if(humi<AlarmHL) // 濕度是否過低 { LedHL_P=0; LedHH_P=1; } else // 濕度正常 { LedHH_P=1; LedHL_P=1; } if((LedHH_P==0)||(LedHL_P==0)||(LedTH_P==0)||(LedTL_P==0)) // 蜂鳴器判斷,只要至少1個報警燈亮,蜂鳴器就報警 { for(i=0;i<3;i++) { beep=0; delay_ms(100); beep=1; delay_ms(100); } } } /****************************************************** ** 函數名:key_service ** 描述 :按鍵服務函數 ** 輸入 :無 ** 輸出 :無 ** 調用 :主程序 ******************************************************/ void key_service(void) { switch (now_window) { case normal_mode: { if (key_value == 1) { now_window = set_mode; curr_menu = 0; wri_string(1,0,"T: - ");//初始化顯示 wri_string(2,0,"H: - ");//初始化顯示 lcd_write_char(1,2,AlarmTL); lcd_write_char(1,6,AlarmTH); lcd_write_char(2,2,AlarmHL); lcd_write_char(2,6,AlarmHH); lcd1602_guanbiao(1,3,1); } } break; case set_mode: { if (key_value == 1) { ++curr_menu; if (curr_menu==1) { lcd1602_guanbiao(1,7,1); } else if(curr_menu==2) { lcd1602_guanbiao(2,3,1); } else if(curr_menu==3) { lcd1602_guanbiao(2,7,1); } if(curr_menu>3) { curr_menu = 0; lcd1602_guanbiao(2,7,0); now_window = normal_mode; wri_string(1,0,"welcome user DHT");//初始化顯示 wri_string(2,0,"H: %RH T: C ");//初始化顯示 lcd_write_char(2,2,humi); lcd_write_char(2,11,temp); lcd_wri_com(0xcd); lcd_wri_data(0xdf); } } if (key_value == 2) { if(curr_menu==0) { if(++AlarmTL>99) { AlarmTL = 0; } lcd_write_char(1,2,AlarmTL); lcd1602_guanbiao(1,3,1); } else if (curr_menu==1) { if(++AlarmTH>99) { AlarmTH = 0; } lcd_write_char(1,6,AlarmTH); lcd1602_guanbiao(1,7,1); } else if(curr_menu==2) { if(++AlarmHL>99) { AlarmHL = 0; } lcd_write_char(2,2,AlarmHL); lcd1602_guanbiao(2,3,1); } else if(curr_menu==3) { if(++AlarmHH>99) { AlarmHH = 0; } lcd_write_char(2,6,AlarmHH); lcd1602_guanbiao(2,7,1); } } if (key_value == 3) { if(curr_menu==0) { if(--AlarmTL<0) { AlarmTL = 99; } lcd_write_char(1,2,AlarmTL); lcd1602_guanbiao(1,3,1); } else if (curr_menu==1) { if(--AlarmTH<0) { AlarmTH = 99; } lcd_write_char(1,6,AlarmTH); lcd1602_guanbiao(1,7,1); } else if(curr_menu==2) { if(--AlarmHL<0) { AlarmHL = 99; } lcd_write_char(2,2,AlarmHL); lcd1602_guanbiao(2,3,1); } else if(curr_menu==3) { if(--AlarmHH<0) { AlarmHH = 99; } lcd_write_char(2,6,AlarmHH); lcd1602_guanbiao(2,7,1); } } } break; } } /****************************************************** ** 函數名:alm ** 描述 :定時閃爍函數 ** 輸入 : 無 ** 輸出 :無 ** 調用 :中斷調用 ******************************************************/ void time_service(void) { if(time_100ms_flag) { time_100ms_flag = 0; if(now_window == normal_mode) { ReadShtData(); lcd_write_char(2,2,humi); lcd_write_char(2,11,temp); AlarmJudge();//報警函數 } } } /****************************************************** ** 函數名:init_all_hardware ** 描述 :初始化所有硬件,及其變量參數。 ** 輸入 :無 ** 輸出 :無 ** 調用 :主程序 ******************************************************/ void init_all_hardware(void) { delay_ms(100); time_init();//定時器初始化 ShtConnectReset(); ReadShtData(); lcd_init(); lcd_write_char(2,2,humi); lcd_write_char(2,11,temp); lcd_wri_com(0xcd); lcd_wri_data(0xdf); key_value = 20; now_window = normal_mode; cnt_100ms = 0; time_100ms_flag = 0; curr_menu = 0; } void main(void) { init_all_hardware();//初始化硬件,IO和定時器 while(1) { key_scan();//按鍵掃描 key_service();//按鍵服務處理函數 time_service();//時間處理函數 } } /****************************************************** ** 函數名:time0_interrupt ** 描述 :按鍵掃描函數 ** 輸入 :無 ** 輸出 :無 ******************************************************/ void time0_interrupt() interrupt 1 { TF0 = 0;//清除標志 TR0 = 0; if (++cnt_100ms>50) { cnt_100ms = 0; time_100ms_flag = 1; } TR0 = 1; TH0 = 0xf8; TL0 = 0x2f;//裝載初值2ms(65535-63535) } |
sht10+1602這個程序你先發上來,然后大家可以在你的基礎上面修改 |
報警的程序不會寫,sht10+1602的程序會寫,還有按鍵的程序 |