这是经过普中开发板试验正确的程序,很稳定。温度检测用DS18b20,显示用DS1602,1602第一行显示设定温度上限值和下限值,第二行显示检测温度值。独立按键K1接P1.0用以设定温度,K2接P1.1用以设定温度上限值,K3接P1.2用以设定温度下限值。晶振11.0592MHz或12MHz。
#include<reg52.h>
#include<intrins.h>
#define uint unsigned int
#define uchar unsigned char
sbit IO_18B20=P3^7; //DS18B20的数据IO口
sbit EN_1602=P2^7; //1602时序操作:使能
sbit RS_1602=P2^6; //1602时序操作:读写选择端R/W=L
sbit RW_1602=P2^5; //1602时序操作:写状态或写数据选择端RS=L
sbit GND=P2^4;
sbit K1=P1^0; //设置键
sbit K2=P1^1; //增加键
sbit K3=P1^2; //减少键
sbit buzzer=P1^7;
uchar S1num;//秒、分、时、星期、日、月、年
uchar data Display[5];
uchar tflag; //温度正负标志
uchar L_ge=2;
char L_shi=2;
uchar H_ge=4;
uchar H_shi=2;
uchar H_bai=0;
uint T_Value; //温度值
bit keyflag=0;
//void readtime();
void delay(uint z) //延时子程序
{
uint x,y;
for(x=z;x>0;x--)
for(y=110;y>0;y--);
}
void delay_18B20(unsigned int i) //18B20延时1微秒
{
while(i--);
}
/*********************将地址命令和时钟数据传送DS1602***************/
void write_1602dat(uchar dat) /*时钟数据传送P0*/
{
RS_1602=1; //1602的rs为0时,接收命令,为1时接收数据
P0=dat; //把void write_shu(uchar shu)中的COM中的数据给P0口
delay(5);
EN_1602=1;
delay(5);
EN_1602=0;
delay(5);
}
void write_1602com(uchar com) /*地址命令传送P0*/
{
RS_1602=0; //1602的rs为0时,接收命令,为1时接收数据
P0=com; //把void write_com(uchar com)中的COM中的数据给P0口
delay(5);
EN_1602=1;
delay(5);
EN_1602=0;
delay(5);
}
/************************地址和数据过度缓冲函数**********************/
void Write1602(uchar add,uchar dat) /*写入地址和时钟数据函数*/
{
write_1602com(add); //写入地址函数
write_1602dat(dat); //写入时钟数据函数
}
/****************************1602初始化*******************************/
void init_1602() /*定义一个初始化子程序*/
{
EN_1602=0;
RW_1602=0;
write_1602com(0x38); //将0x38赋com,设置显示模式:4位总线、双行显示、显示5x7的点阵字符
write_1602com(0x0e); //将0x0e赋com,设置光标:开显示、无光标,光标不闪烁
write_1602com(0x06); //将0x06赋com,写一个数据,指针自动加1,整屏不移动,N=1、S=0
write_1602com(0x80); //将0x80赋com,设置数据指针起点,第一行左边第一个字符
write_1602com(0x01); //将0x01赋com,清屏
Write1602(0x80+0x40+1,(0x54)); //第2行第2位,设定'符号T'
Write1602(0x80+0x40+2,(0x65)); //第2行第3位,设定'符号e'
Write1602(0x80+0x40+3,(0x6d)); //第2行第4位,设定'符号m'
Write1602(0x80+0x40+4,(0x70)); //第2行第5位,设定'符号p'
Write1602(0x80+0x40+5,':'); //第2行第6位,设定':'
Write1602(0x80+0x40+13,(0xdf)); //第2行第14位,设定'0'
Write1602(0x80+0x40+14,'C'); //第2行第15位,设定'C'
Write1602(0x80,(0x48)); //第1行第1位,设定'H'
Write1602(0x80+1,':'); //第1行第2位,设定':'
Write1602(0x80+6,(0xdf)); //第1行第7位,设定'温度符号'
Write1602(0x80+7,'C'); //第1行第8位,设定'温度符号'
Write1602(0x80+9,(0x4c)); //第1行第10位,设定'L'
Write1602(0x80+10,':'); //第1行第11位,设定':'
Write1602(0x80+14,(0xdf)); //第1行第15位,设定'温度符号'
Write1602(0x80+15,'C'); //第1行第16位,设定'温度符号'
}
/***********************ds1820温度显示子函数*********************/
void Ds1820RST() /*ds1820复位*/
{
unsigned char x=0;
IO_18B20 = 1; //IO_1302复位
delay_18B20(4); //延时
IO_18B20 = 0; //DQ拉低
delay_18B20(100); //精确延时大于480us
IO_18B20 = 1; //拉高
delay_18B20(40);
}
uchar Read18B20() /*读数据*/
{
uchar i=0;
uchar dat = 0;
for (i=8;i>0;i--)
{
IO_18B20 = 0; //给脉冲信号
dat>>=1;
IO_18B20 = 1; //给脉冲信号
if(IO_18B20) dat|=0x80;
delay_18B20(10);
}
return(dat);
}
void Write18B20(uchar wdata) /*写数据*/
{
unsigned char i=0;
for (i=8; i>0; i--)
{
IO_18B20 = 0;
IO_18B20 = wdata&0x01; //从最低位输入
delay_18B20(10);
IO_18B20 = 1;
wdata>>=1;
}
}
read_temp() /*读取温度值并转换*/
{
uchar Temp_L,Temp_H;
Ds1820RST(); //Ds1820复位(初始化)
Write18B20(0xcc); //跳过读序列号
Write18B20(0x44); //启动温度转换
Ds1820RST(); //Ds1820复位(初始化)
Write18B20(0xcc); //跳过读序列号
Write18B20(0xbe); //读取温度
Temp_L=Read18B20();
Temp_H=Read18B20();
T_Value=Temp_H;
T_Value<<=8;
T_Value=T_Value|Temp_L;
if(T_Value<0x0fff)
tflag=0;
else
{
T_Value=~T_Value+1;
tflag=1;
}
T_Value=T_Value*(0.625); //T_Value是2进制,每一个单位'1'=0.625度
return(T_Value);
}
/**************************检测温度值显示***********************/
void ds1820disp() /*温度值显示*/
{
uchar Symbol;
read_temp();
Display[0]=T_Value/1000+0x30; //分解百位数
Display[1]=T_Value%1000/100+0x30; //分解十位数
Display[2]=T_Value%100/10+0x30; //分解个位数
Display[3]=T_Value%10+0x30; //分解小数点后第1位
if(tflag==0)
Symbol=0x2b;//正温度不显示符号,地址来源液晶屏字符表
else
Symbol=0x2d;//负温度显示负号:-,地址来源液晶屏字符表
/* if(Display[0]==0x30)
{
Display[0]=0x20;//如果百位为0,不显示,地址来源液晶屏字符表
if(Display[1]==0x30)
{
Display[1]=0x20;//如果百位为0,十位为0也不显示,地址来源液晶屏字符表
}
}*/
write_1602com(0x80+0x40+6); //符号显示地址
write_1602dat(Symbol); //显示符号
write_1602com(0x80+0x40+7); //温度百位显示地址
write_1602dat(Display[0]); //显示测量温度百位
write_1602com(0x80+0x40+8); //温度十位显示地址
write_1602dat(Display[1]); //显示测量温度十位
write_1602com(0x80+0x40+9); //温度个位显示地址
write_1602dat(Display[2]); //显示测量温度个位
write_1602com(0x80+0x40+10); //温度小数点位显示地址
write_1602dat(0x2e); //显示小数点,地址来源液晶屏字符表
write_1602com(0x80+0x40+11); //温度小数位显示地址
write_1602dat(Display[3]); //显示测量温度小数点后第1位
Write1602(0x80+11,'+'); //将ASC码
Write1602(0x80+2,'+'); //将ASC码
}
void L_ge_xs() //低温度设定
{
Write1602(0x80+13,0x30+L_ge); //将ASC码
}
void L_shi_xs() //低温度设定
{
Write1602(0x80+12,0x30+L_shi); //将ASC码
}
void H_ge_xs() //低温度设定
{
Write1602(0x80+5,0x30+H_ge); //将ASC码
}
void H_shi_xs() //低温度设定
{
Write1602(0x80+4,0x30+H_shi); //将ASC码
}
void H_bai_xs() //低温度设定
{
Write1602(0x80+3,0x30+H_bai); //将ASC码
}
void compare()
{
uint H_value=(H_bai*100)+(H_shi*10)+H_ge;
uint L_value=(L_shi*10)+L_ge;
T_Value=T_Value/10;
if(T_Value>=H_value)
{
buzzer=0;
delay(2000);
buzzer=1;
delay(2000);
}
if(T_Value<=L_value)
{
buzzer=0;
delay(2000);
buzzer=1;
delay(2000);
}
}
/*********************键盘扫描****************************/
void key_scan() /*键盘扫描*/
{
if(K1==0) //key时钟设置键,K1=0时,说明设置键key按下
{
delay(20); //延时5ms,防止抖动
if(K1==0); //在检测一次,防止误动作
{
while(!K1); //判断功能键是否放开
S1num++; //K1按下次数检测变量+1
if(S1num==9) //如果键值key1n+1=9执行下一句,如果键值key1n+1!=9执行switch(key1n)
S1num=1; //设置按键共有秒、分、时、星期、日、月、年、返回,8个功能循环
switch(S1num) //如果S1num=1执行case 1,如果S1num=2执行case 2,以此类推
{
case 1:
keyflag=1; //K1键按下检测标记,keyflag=1,说明K1键被按下
write_1602com(0x80+14);
write_1602com(0x0f); break; //开显示、开光标、光标闪烁
case 2: write_1602com(0x80+13); break; //光标选择
case 3: write_1602com(0x80+12); break;
case 4: write_1602com(0x80+6); break;
case 5: write_1602com(0x80+5); break;
case 6: write_1602com(0x80+4); break;
case 7: write_1602com(0x80+3); break;
case 8: S1num=0;
keyflag=0;
write_1602com(0x0c);//不显示光标
break;
}
}
}
if(S1num!=0) //如果key按下次数检测变量S1num!=0,说明时钟调整还在进行,可以检测K1键
{
if(K2==0) //K2键是时钟调整增加键,如果K1==0,K2键被按下,可以向下运行
{
delay(5); //延时5ms
while(!K2); //K2==0取反K2=1,进入大循环
switch(S1num) //如果S1num=1执行case 1,如果S1num=2执行case 2,以此类推
{
case 1: L_ge++;
if(L_ge==10) L_ge=0x00;
Write1602(0x80+13,0x30+L_ge); //将ASC码
break;
case 2: L_shi++;
if(L_shi==10) L_shi=0x00;
Write1602(0x80+12,0x30+L_shi); //将ASC码
break;
case 3:
Write1602(0x80+11,'+'); //将ASC码
break;
case 4: H_ge++;
if(H_ge==10) H_ge=0x00;
Write1602(0x80+5,0x30+H_ge); //将ASC码
break;
case 5: H_shi++;
if(H_shi==10) H_shi=0x00;
Write1602(0x80+4,0x30+H_shi); //将ASC码
break;
case 6: H_bai++;
if(H_bai==10) H_bai=0x00;
Write1602(0x80+3,0x30+H_bai); //将ASC码
break;
case 7:
Write1602(0x80+2,'+'); //将ASC码
break;
default:break;
}
}
if(K3==0)
{
delay(5);
while(!K3);
switch(S1num)
{
case 1: L_ge--;
if(L_ge==-1) L_ge=9;
Write1602(0x80+13,0x30+L_ge); //将ASC码
break;
case 2: L_shi--;
if(L_shi==-1) L_shi=9;
Write1602(0x80+12,0x30+L_shi); //将ASC码
break;
case 3:
Write1602(0x80+11,(0x2d)); //将ASC码
break;
case 4: H_ge--;
if(H_ge==-1) H_ge=9;
Write1602(0x80+5,0x30+H_ge); //将ASC码
break;
case 5: H_shi--;
if(H_shi==-1) H_shi=9;
Write1602(0x80+4,0x30+H_shi); //将ASC码
break;
case 6: H_bai--;
if(H_bai==-1) H_bai=9;
Write1602(0x80+3,0x30+H_bai); //将ASC码
break;
case 7:
Write1602(0x80+2,'-'); //将ASC码
default: break;
}
}
}
}
/*****************************主函数*****************************/
void main()
{
GND=0;
delay(100);
init_1602();
while(1)
{
key_scan();
if(keyflag==0)
{
L_ge_xs();
L_shi_xs();
H_ge_xs(); //低温度设定
H_shi_xs(); //低温度设定
H_bai_xs(); //低温度设定
ds1820disp();
compare();
}
}
} |