控制/MCU
今天分享一个基于51单片机的湿度监测仿真和程序。
仿真所用的湿度传感器为SHT11。SHT11是瑞士Scnsirion公司推出的一款数字温湿度传感器芯片。该芯片广泛应用于暖通空调、汽车、消费电子、自动控制等领域。
其主要特点如下: 高度集成,将温度感测、湿度感测、信号变换、A/D转换和加热器等功能集成到一个芯片上;
提供二线数字串行接口SCK和DATA,接口简单,支持CRC传输校验,传输可靠性高;
测量精度可编程调节,内置A/D转换器(分辨率为8~12位,可以通过对芯片内部寄存器编程米选择);
引脚 | 名称 | 功能 |
1 | GND | 地线 |
2 | DATA | 串行数据线 |
3 | SCK | 串行时钟线 |
4 | VDD | 电源正 |
NC | NC | 悬空 |
传输启动
数据传输初始化:
当SCK时钟为高电平时,DATA翻转位低电平,紧接着SCK变为低电平,
随后在SCK时钟高电平时,DATA翻转为高电平。
void start_sht11(void) //启动 //-------------------------------------------------------- { DATA=1; SCK=0; //数据为1,SCK=0 _nop_(); SCK=1; //第一个脉冲 _nop_(); DATA=0; //数据跌落 _nop_ (); SCK=0; //完成一个脉冲 _nop_(); _nop_(); _nop_(); SCK=1; //再一个脉冲 _nop_(); DATA=1; //数据变为1 _nop_(); SCK=0; //完成该脉冲 }
读写数据
控制器向传感器发送命令的过程中,DATA在SCK上升沿有效,且在SCK高电平时必须保持稳定;DATA在SCK下降沿之后改变。(参考上图 DATA valid write 段)
从传感器读取数据读取数据的过程中,DATA Tv在SCK变低以后有效,且维持到下一个SCK的下降沿。(参考上图 DATA valid read 段)
char read(void) //读一个字节 返回应答信号 //---------------------------------------------------------------------------------- // reads a byte form the Sensibus and gives an acknowledge in case of "ack=1" { unsigned char i,val=0; temp_LL=0; temp_h=0; DATA=1; //释放数据总线 for (i=0x80;i>0;i/=2) //位移8位 { SCK=1; //上升沿读入 if (DATA) val=(val | i); //确定值 SCK=0; } DATA=0; //读应答信号,有应答为1,为应答为0 通过CPU下拉为应答 SCK=1; //第9个脉冲 _nop_(); _nop_(); _nop_(); //pulswith approx. 5 us SCK=0; DATA=1; //释放数据总线 temp_h=val; val=0; ////低8位///////////////////////////// DATA=1; //释放数据总线 for (i=0x80;i>0;i/=2) //位移8位 { SCK=1; //上升沿读入 if (DATA) val=(val | i); //确定值 SCK=0; } DATA=1;//0; //不需要应答 通过CPU下拉为应答 SCK=1; //第9个脉冲 _nop_(); _nop_(); _nop_(); //pulswith approx. 5 us SCK=0; DATA=1; //释放数据总线 temp_LL=val; return val ; } //////////// char write(unsigned char value) //写一个字节 返回应答信号 //--------------------------------------------------------- { unsigned char i ; ack=0; for (i=0x80;i>0;i/=2) //释放数据总线 { if (i & value) DATA=1; //写入值 else DATA=0; SCK=1; //上升沿写入 _nop_(); _nop_(); _nop_(); //延时 SCK=0; } DATA=1; //释放数据总线 SCK=1; //第9个脉冲 if (DATA==1) ack=1; //读应答信号 SCK=0; return ack; //error=1 表示没有应答 }
传感器复位
如果出现通讯中断,当DATA保持高电平时,触发SCK时钟9次或更多,然后发送“传输启动”时序就可以完成传感器的复位。
////////////////////////////////// void sht_rest(void) //复位 { unsigned char i; DATA=1; SCK=0; //数据为1 时钟为0 for(i=0;i<9;i++) //9 个脉冲为 复位 { SCK=1; SCK=0; } start_sht11(); //启动 }
Proteus仿真如下图。主要功能是利用SHT11进行湿度的采集,并通过LCD1602显示 。在仿真中通过SHT11上面的操作按钮就可以改变SHT11的温度和湿度数值。该仿真没有对温度数据进行采集和现实。
完整的程序如下
#include#include #define uint unsigned int #define uchar unsigned char /*------------------------------------------------ 硬件端口定义 ------------------------------------------------*/ sbit RS = P2^0; //定义端口 sbit RW = P2^1; sbit EN = P2^2; sbit LED = P2^4 ; sbit RELAY = P1^0 ; #define DataPort P0 sbit DATA =P2^6; //数据 sbit SCK=P2^7; //时钟 uchar cnt = 0 ; unsigned char temp_h ; //全局应答变量 unsigned char temp_LL ;//全局应答变量 unsigned char error ; //全局错误变量 unsigned char ack ; //全局应答变量 #define RS_CLR RS=0 #define RS_SET RS=1 #define RW_CLR RW=0 #define RW_SET RW=1 #define EN_CLR EN=0 #define EN_SET EN=1 #define TEMP_ML 0x03 //000 0001 1 温度命令 #define HUMI_ML 0x05 //000 0010 1 温度命令 unsigned int xianzhi_h=0;//湿度显值 uchar key ; uchar key_buf ; uchar temp ; uchar frq_cnt = 0; bit updat = 0 ; uchar delay_cnt = 0 ; #define TH0_BUF 0x3c #define TL0_BUF 0xaf void text_jisuan_humi(void); /*------------------------------------------------ uS延时函数,含有输入参数 unsigned char t,无返回值 unsigned char 是定义无符号字符变量,其值的范围是 0~255 这里使用晶振12M,精确延时请使用汇编,大致延时 长度如下 T=tx2+5 uS ------------------------------------------------*/ void DelayUs2x(unsigned char t) { while(--t); } /*------------------------------------------------ mS延时函数,含有输入参数 unsigned char t,无返回值 unsigned char 是定义无符号字符变量,其值的范围是 0~255 这里使用晶振12M,精确延时请使用汇编 ------------------------------------------------*/ void DelayMs(unsigned char t) { while(t--) { //大致延时1mS DelayUs2x(245); DelayUs2x(245); } } /*------------------------------------------------ 判忙函数 ------------------------------------------------*/ bit LCD_Check_Busy(void) { DataPort= 0xFF; RS_CLR; RW_SET; EN_CLR; _nop_(); EN_SET; return (bit)(DataPort & 0x80); } /*------------------------------------------------ 写入命令函数 ------------------------------------------------*/ void LCD_Write_Com(unsigned char com) { // while(LCD_Check_Busy()); //忙则等待 DelayMs(5); RS_CLR; RW_CLR; EN_SET; DataPort= com; _nop_(); EN_CLR; } /*------------------------------------------------ 写入数据函数 ------------------------------------------------*/ void LCD_Write_Data(unsigned char Data) { //while(LCD_Check_Busy()); //忙则等待 DelayMs(5); RS_SET; RW_CLR; EN_SET; DataPort= Data; _nop_(); EN_CLR; } /*------------------------------------------------ 清屏函数 ------------------------------------------------*/ void LCD_Clear(void) { LCD_Write_Com(0x01); DelayMs(5); } /*------------------------------------------------ 写入字符串函数 ------------------------------------------------*/ void LCD_Write_String(unsigned char x,unsigned char y,unsigned char *s) { if (y == 0) { LCD_Write_Com(0x80 + x); //表示第一行 } else { LCD_Write_Com(0xC0 + x); //表示第二行 } while (*s) { LCD_Write_Data( *s); s ++; } } /*------------------------------------------------ 写入字符函数 ------------------------------------------------*/ void LCD_Write_Char(unsigned char x,unsigned char y,unsigned char Data) { if (y == 0) { LCD_Write_Com(0x80 + x); } else { LCD_Write_Com(0xC0 + x); } LCD_Write_Data( Data); } /*------------------------------------------------ 初始化函数 ------------------------------------------------*/ void LCD_Init(void) { LCD_Write_Com(0x38); /*显示模式设置*/ DelayMs(5); LCD_Write_Com(0x38); DelayMs(5); LCD_Write_Com(0x38); DelayMs(5); LCD_Write_Com(0x38); LCD_Write_Com(0x08); /*显示关闭*/ LCD_Write_Com(0x01); /*显示清屏*/ LCD_Write_Com(0x06); /*显示光标移动设置*/ DelayMs(5); LCD_Write_Com(0x0C); /*显示开及光标设置*/ } /*------------------------------------------------ 定时器0中断 ------------------------------------------------*/ void TIM0_ISR() interrupt 1 { TR0=0; TH0 = TH0_BUF ; TL0 = TL0_BUF ; if(cnt<5) { cnt ++ ; }else { cnt = 0 ; updat = 1 ; } TR0=1; } /*******************************基本驱动程 *************************************/ ///////////////// ////////////////////// char read(void) //读一个字节 返回应答信号 //---------------------------------------------------------------------------------- // reads a byte form the Sensibus and gives an acknowledge in case of "ack=1" { unsigned char i,val=0; temp_LL=0; temp_h=0; DATA=1; //释放数据总线 for (i=0x80;i>0;i/=2) //位移8位 { SCK=1; //上升沿读入 if (DATA) val=(val | i); //确定值 SCK=0; } DATA=0; //读应答信号,有应答为1,为应答为0 通过CPU下拉为应答 SCK=1; //第9个脉冲 _nop_(); _nop_(); _nop_(); //pulswith approx. 5 us SCK=0; DATA=1; //释放数据总线 temp_h=val; val=0; ////低8位///////////////////////////// DATA=1; //释放数据总线 for (i=0x80;i>0;i/=2) //位移8位 { SCK=1; //上升沿读入 if (DATA) val=(val | i); //确定值 SCK=0; } DATA=1;//0; //不需要应答 通过CPU下拉为应答 SCK=1; //第9个脉冲 _nop_(); _nop_(); _nop_(); //pulswith approx. 5 us SCK=0; DATA=1; //释放数据总线 temp_LL=val; return val ; } //////////// char write(unsigned char value) //写一个字节 返回应答信号 //--------------------------------------------------------- { unsigned char i ; ack=0; for (i=0x80;i>0;i/=2) //释放数据总线 { if (i & value) DATA=1; //写入值 else DATA=0; SCK=1; //上升沿写入 _nop_(); _nop_(); _nop_(); //延时 SCK=0; } DATA=1; //释放数据总线 SCK=1; //第9个脉冲 if (DATA==1) ack=1; //读应答信号 SCK=0; return ack; //error=1 表示没有应答 } //////// void start_sht11(void) //启动 //-------------------------------------------------------- { DATA=1; SCK=0; //数据为1,SCK=0 _nop_(); SCK=1; //第一个脉冲 _nop_(); DATA=0; //数据跌落 _nop_ (); SCK=0; //完成一个脉冲 _nop_(); _nop_(); _nop_(); SCK=1; //再一个脉冲 _nop_(); DATA=1; //数据变为1 _nop_(); SCK=0; //完成该脉冲 } ////////////////////////////////// void sht_rest(void) //复位 { unsigned char i; DATA=1; SCK=0; //数据为1 时钟为0 for(i=0;i<9;i++) //9 个脉冲为 复位 { SCK=1; SCK=0; } start_sht11(); //启动 } //////////////////////////////// //测量温度或者是温度,返回校验值 void convert_data(unsigned char ml) { unsigned int i; start_sht11(); //启动 write(ml);//写入测温度 if(ack==1) { sht_rest() ;//复位 write(ml);//写入测温度 } for (i=0;i<55535;i++){ if(DATA==0) break; } read();//读温度 } /////////湿度采集处理////// void get_humidata(void) { error=0; ack=0; sht_rest() ; //复位 convert_data(HUMI_ML); text_jisuan_humi(); } ///////计算湿度////// void text_jisuan_humi(void) { float aa=0,bb=0,humi_zi; int abcd=0; abcd = temp_h ; abcd = abcd <<8|temp_LL; aa = (float) abcd ; bb=aa*aa*2.8/1000000; aa=0.0405*aa; aa=aa-4-bb; humi_zi=aa; humi_zi=(humi_zi-3.3)*10; xianzhi_h=(int)humi_zi; } void Timer_Init(void) { TMOD|=0x01; //置定时器0工作方式1 EA=1; //打开全局中断 ET0=1; //打开 定时器0 中断 TR0=1; } void main(void) { char delay_cnt = 0; LED = 0 ; RELAY = 0 ; LCD_Init(); //液晶初始化 LCD_Clear(); //清屏 LCD_Write_String(0,0,"Humi:00.0%"); //初始显示内容 Timer_Init(); //定时器初始化 while(1) { if(updat) //数更新 { updat = 0 ; get_humidata(); LCD_Write_Char(5,0,0x30+xianzhi_h/100%10); LCD_Write_Char(6,0,0x30+xianzhi_h/10%10); LCD_Write_Char(8,0,0x30+xianzhi_h%10); } } }
审核编辑:刘清
全部0条评论
快来发表一下你的评论吧 !