嵌入式多路温湿度监控系统(十51单片机温湿度采集模块)

2019-07-13 01:21发布

硬件:STC89C52开发板、1602数显、DHT温湿度传感器(利用其I2C数据线) 软件:Keil v4 C语言编译平台,stc-ipc-15xx-v6.85烧录程序 对DHT温度数据的解析有点问题,室温25度左右,温度的高、低位的最高位均为1,这与硬件说明文档不符,我就都屏蔽掉了最高位,得出的温度数据还比较靠谱,也不知怎么回事,各位读者如果知道的话不吝赐教!!!

DHT12的SDA、SCL分别接P2.0、P2.1,连接好电源、接地后采集结果如下图:

串口传出的数据分别通过P3.0 、P3.1传送给arm开发板
数据格式是每个数据前后各加一个空格,如:“空格78.5空格空格25.6空格……”,51单片机开发板的miniUSB是一个串口转USB的设备,通过它插入PC,就可以在PC端查看串口传出来的数据了,PC上通过串口助手看到单片机输出的结果,如下图:


代码:包括了利用I2C时序采集DHT的温湿度数据、1602显示采集到数据、利用串口中断将数据发送出去三大部分 #include #include #define AddWr 0xb8 //自己买的温湿度传感器DHT12器件地址 sbit sda=P2^0; sbit scl=P2^1; sbit rw = P1^1; sbit RS = P1^0; sbit LCDEN = P2^5; unsigned char bai,shi,ge; unsigned char table1[]="wendu:"; unsigned char table2[]="shidu:"; unsigned char table3[]="0123456789"; unsigned char table4[]="CRC Error !!!"; unsigned char table5[]="Sensor Error !!"; int Temprature,Humi; void delayUs() { _nop_(); } void delayMs(unsigned int a) { unsigned int i, j; for(i = a; i > 0; i--) for(j = 100; j > 0; j--); } void delay(unsigned char dat) { unsigned char i; for(i=dat;i>0;i--)_nop_(); } /******************************************************************* 总线初始化 函数原型: void I2c_Init(); 功能: 启动I2C总线,即发送I2C起始条件. ********************************************************************/ void I2c_Init() { sda=1; _nop_(); /*起始条件建立时间大于4.7us,延时*/ _nop_(); _nop_(); _nop_(); _nop_(); scl=1; _nop_(); /*起始条件建立时间大于4.7us,延时*/ _nop_(); _nop_(); _nop_(); _nop_(); } /******************************************************************* 起动总线函数 函数原型: void IIC_Start(); 功能: 启动I2C总线,即发送I2C起始条件. ********************************************************************/ void IIC_Start() { sda=1; /*发送起始条件的数据信号*/ _nop_(); scl=1; _nop_(); /*起始条件建立时间大于4.7us,延时*/ _nop_(); _nop_(); _nop_(); _nop_(); sda=0; /*发送起始信号*/ _nop_(); /* 起始条件锁定时间大于4μs*/ _nop_(); _nop_(); _nop_(); _nop_(); scl=0; /*钳住I2C总线,准备发送或接收数据 */ _nop_(); _nop_(); } /******************************************************************* 结束总线函数 函数原型: void IIC_Stop(); 功能: 结束I2C总线,即发送I2C结束条件. ********************************************************************/ void IIC_Stop() { sda=0; /*发送结束条件的数据信号*/ _nop_(); /*发送结束条件的时钟信号*/ scl=1; /*结束条件建立时间大于4μs*/ _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); sda=1; /*发送I2C总线结束信号*/ _nop_(); _nop_(); _nop_(); _nop_(); } /******************************************************************* 字节数据发送函数 函数原型: void IIC_Send_Byte(UCHAR c); 功能: 将数据c发送出去,可以是地址,也可以是数据,发完后等待应答,并对 此状态位进行操作.(不应答或非应答都使ack=0) 发送数据正常,ack=1; ack=0表示被控器无应答或损坏。 ********************************************************************/ void IIC_Send_Byte(unsigned char c) { unsigned char i; for(i=0;i<8;i++) /*要传送的数据长度为8位*/ { if((c<250) { IIC_Stop(); return 1; } delay(1); } scl=0;//时钟输出0 delay(50); //这个等待很重要,校验错误的几率小多了 return 0; } /*****************************1602*******************************/ void writeComm(unsigned char comm) { RS = 0; P0 = comm; LCDEN = 1; delayUs(); LCDEN = 0; delayMs(1); } void init1602() { rw = 0; writeComm(0x38); writeComm(0x0c); writeComm(0x06); writeComm(0x01); } //写数据:RS=1, RW=0; void writeData(unsigned char dat) { RS = 1; P0 = dat; LCDEN = 1; delayUs(); LCDEN = 0; delayMs(1); } void writeString(unsigned char * str, unsigned char length) { unsigned char i; for(i = 0; i < length; i++) { writeData(str[i]); } } /*------------------------------------------------ 把uint 类型的温度、值转化为ascii码字符, 通过串口输出温度采集值 ------------------------------------------------*/ void serialOutput(int num) { SBUF=' '; delay(50); SBUF=num/100+'0'; delay(50); SBUF=num/10%10+'0'; delay(50); SBUF='.'; delay(50); SBUF=num%10+'0'; delay(50); SBUF=' '; delay(50); } /*------------------------------------------------ 串口输出初始化函数 ------------------------------------------------*/ void serial_init() { SCON=0x40;//初始化串口方式1,REN=0不允许接受 PCON=0x80; //SMOD=1 波特率倍增 TMOD=0x20; //T1初始化为方式2,自动填充 TL1=0xF4; //波特率4800b/s TH1=0xF4; ES=1; //不打开串口中断,TI=1时依然可以串口输出,需要在上次输出后加点延时 EA=1; //打开中断总开关 TR1=1; //T1开始运转 } /*------------------------------------------------ 串口输出中断函数 ------------------------------------------------*/ void SISR() interrupt 4 { T1=0; } /********************************************************************************************************* 功能:DHT12读取温湿度函数 变量:Humi_H:湿度高位;Humi_L:湿度低位;Temp_H:温度高位;Temp_L:温度低位;Temp_CAL:校验位 数据格式为:湿度高位(湿度整数)+湿度低位(湿度小数)+温度高位(温度整数)+温度低位(温度小数)+ 校验位 校验:校验位=湿度高位+湿度低位+温度高位+温度低位 *********************************************************************************************************/ void sensor_read(void) { int i; unsigned char Humi_H,Humi_L,Temp_H,Temp_L,Temp_CAL,temp; IIC_Start(); //主机发送起始信号 IIC_Send_Byte(0Xb8); //发送IIC地址 if(!IIC_Wait_Ack()) //等待从机应答信号(如无应答:考虑IIC通讯频率是否太快,或者传感器接线错误) { i=0; IIC_Send_Byte(0); while(IIC_Wait_Ack())//等待从机应答信号 { if(++i>=500) { break; } } i=0; IIC_Start(); //主机发送起始信号 IIC_Send_Byte(0Xb9); //发送读指令 while(IIC_Wait_Ack()) //等待从机应答信号 { if(++i>=500) { break; } } Humi_H=IIC_Read_Byte(); //读取湿度高位 Ack_I2c(0); Humi_L=IIC_Read_Byte(); //读取湿度低位 Ack_I2c(0); Temp_H=IIC_Read_Byte(); //读取温度高位 Ack_I2c(0); Temp_L=IIC_Read_Byte(); //读取温度低位 Ack_I2c(0); Temp_CAL=IIC_Read_Byte(); //读取校验位 Ack_I2c(1); IIC_Stop(); //发送停止信号 temp = (unsigned char)(Humi_H+Humi_L+Temp_H+Temp_L);//只取低8位 if(Temp_CAL==temp)//如果校验成功,往下运行 { Humi=Humi_H*10+Humi_L; //湿度 //实践得出,在室温约27°时,温度高位Temp_H、温度低位Temp_L的最高位都是1,按照DHT12的技术说明,温度低位Temp_L的最高位是1的话表示是负值,明显不对 //温度高位Temp_H的数值是10011011(155)也不对啊,那有这高的温度,将最高位去掉为0时,温度高位为27度,这还差不多。 //温度高位Temp_H的数值是128-137,如果去掉最高位为零的话,那么是0-9,这是对的 //Temp_H、Temp_L都去掉最高位后合体的温度约为27.5度,且可以环境温度上下浮动变化,感觉这样就对了。 //那么我的这个传感器的负温度是怎么表示的呢?这个得在温度小于零的环境中试试Temp_H、Temp_L读到的都是什么值就可以了 Temprature =(Temp_H&0x7F)*10+(Temp_L&0x7F); /*if(Temp_L&0X80) //为负温度 { //Temprature =0-(Temp_H*10+((Temp_L&0x7F))); // Temprature=Temp_L; //Temprature =(int)((char)0-(Temp_L&0x7F)); //Temprature=Temp_H&0x7F; Temprature =(int)((char)0-((Temp_H&0x7F)*10+(Temp_L&0x7F))); } else //为正温度 { //Temprature=(Temp_H*10+(Temp_L&0x7F));//为正温度 Temprature=Temp_H; }*/ //判断温湿度是否超过测量范围(温度:-20℃~60摄氏度;湿度:20%RH~95%RH) if(Humi>950) { Humi=950; } if(Humi<200) { Humi =200; } if(Temprature>1000) { Temprature=1000; } if(Temprature<-200) { Temprature = -200; } i=Humi; bai=i/100;shi=i%100/10;ge=i%100%10; writeComm(0x80); writeString(table2,6); writeData(table3[bai]); writeData(table3[shi]); writeData('.'); writeData(table3[ge]); writeData('%'); writeData('R'); writeData('H'); i=Temprature; if(i<0) { i=-i; bai=i/100;shi=i%100/10;ge=i%100%10; writeComm(0x80+0x40); writeString(table1,6); writeData('-'); writeData(table3[bai]); writeData(table3[shi]); writeData('.'); writeData(table3[ge]); writeData(0xdf); writeData('C'); }else{ bai=i/100;shi=i%100/10;ge=i%100%10; writeComm(0x80+0x40); writeString(table1,6); writeData('+'); writeData(table3[bai]); writeData(table3[shi]); writeData('.'); writeData(table3[ge]); writeData(0xdf); //"℃中的左上角圆圈的ascii码" writeData('C'); } serialOutput(Humi); serialOutput(Temprature); } else //校验失败 { writeComm(0x80); writeString(table4,12); } }else { writeComm(0x80+0x40); writeString(table5,15); } } //******************main()主函数******************************** void main() { void I2c_Init(); init1602(); serial_init(); while(1) { sensor_read(); delayMs(2000); } }