#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的程序会写,还有按键的程序 |