SHT11驱动

描述

C文件

#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)
}


  审核编辑:汤梓红
打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分