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)
}
审核编辑:汤梓红
全部0条评论
快来发表一下你的评论吧 !