#include<reg52.h>
#include <intrins.h>
#define uchar unsigned char
#define uint unsigned int
sbit lcdrs=P1^0; //lcd数据命令选择控制
sbit lcdrw=P1^1; //lcd读/写选择控制
sbit lcden=P1^2; //lcd使能信号
sbit DS=P3^3; //DS18B20数据总线
sbit SCLK=P1^3; //DS1302SCLK
sbit DIO=P1^4; //DS1302I/O口
sbit RST=P1^5; //DS1302片选
uchar n; //键盘扫描程序返回值
uchar flag=0; //停走标志初始化为0
uchar p=0; //光标移动指示计数值
uchar code distable1[]="0123456789:- "; //利用一个数字表解决显示乱码
uchar distable2[3]; //星期英文显示的数据暂存
uchar timedate[8]={0x00,0x00,0x09,0x014,0x07,0x04,0x011,0}; //时间数据暂存,顺序为:秒分时日月星期年
uchar display1[16]; //第一行显示数据暂存
uchar display2[16]; //第二行显示数据暂存
uchar code wr_rtc_addr[7]={0x80,0x82,0x84,0x86,0x88,0x8a,0x8c}; //DS1302写寄存器地址,顺序为:秒分时日月星期年
uchar code rd_rtc_addr[7]={0x81,0x83,0x85,0x87,0x89,0x8b,0x8d}; //DS1302写寄存器地址,顺序同上
void delay(uchar z); //函数声明
void init_lcd(); //lcd相关
void write_com(uchar com);
void write_date(uchar date);
void tmpDelay(int num); //DS18B20相关
void Init_DS18B20();
uchar ReadOneChar();
void WriteOneChar(uchar dat);
uint Readtemp();
void display_tem();
void convert_time(); //DS1302相关
void convert_week();
void display_time();
void Write_Ds1302_byte(uchar temp);
void Write_Ds1302(uchar addr,dat);
uchar Read_Ds1302 (uchar addr);
void Read_RTC();
void Set_RTC();
uchar scan_keys(); //键盘控制相关
void key0_ctrl();
void key1_ctrl();
uchar key2_ctrl();
uchar key3_ctrl();
void Set_time();
void anticonvert_time();
void delay1(uchar x);
void main()
{
init_lcd(); //初始化lcd
Set_RTC(); //DS1302写入时间初始数据
while(1)
{
key0_ctrl(); //扫描键0
if(flag==1) //标志位为1则暂停计时
{
key1_ctrl(); //扫描键1
if(p==0) //若时间未被调整,继续计时,不显示
Read_RTC(); //DS1302读取时间数据
else
{
Set_time(); //设置时间
anticonvert_time(); //反转换格式
Set_RTC(); //DS1302写入时间数据
}
}
else //标志位为0则继续计时并显示
{
p=0;
Read_RTC(); //DS1302读取时间数据
convert_time(); //转换格式
display_time(); //显示时间
}
display_tem(); //显示温度
}
}
void delay(uchar z) //延时函数
{
uchar x,y;
for(x=20;x>1;x--)
for(y=z;y>1;y--);
}
void write_com(uchar com) //lcd写命令
{
lcdrs=0; //rs置低
P2=com; //数据口送数
delay(15);
lcden=1; //en高脉冲
delay(15);
lcden=0;
}
void write_date(uchar date) //lcd写数据
{
lcdrs=1; //rs置高
P2=date;
delay(15);
lcden=1;
delay(15);
lcden=0;
}
void init_lcd() //初始化lcd
{
lcden=0;
lcdrw=0;
write_com(0x38);
write_com(0x01);
write_com(0x0c);
write_com(0x06);
}
/*************************DS18B20温度读取显示****************************/
void tmpDelay(int num) //延时函数
{
while(num--) ;
}
void Init_DS18B20() //初始化ds1820
{
uchar x=0;
DS = 1; //DS复位
tmpDelay(8); //稍做延时
DS = 0; //单片机将DS拉低
tmpDelay(80); //精确延时 大于 480us
DS = 1; //拉高总线
tmpDelay(14);
x=DS; //稍做延时后 如果x=0则初始化成功 x=1则初始化失败
tmpDelay(20);
}
uchar ReadOneChar() //读一个字节
{
uchar i=0;
uchar dat = 0;
for (i=8;i>0;i--)
{
DS = 0; // 给脉冲信号
dat>>=1;
DS = 1; // 给脉冲信号
if(DS)
dat|=0x80;
tmpDelay(4);
}
return(dat);
}
void WriteOneChar(uchar dat) //写一个字节
{
uchar i=0;
for (i=8; i>0; i--)
{
DS = 0;
DS = dat&0x01;
tmpDelay(5);
DS = 1;
dat>>=1;
}
}
uint Readtemp() //读取温度
{
uchar a=0;
uchar b=0;
uint t=0;
float tt=0;
Init_DS18B20();
WriteOneChar(0xCC); // 跳过读序号列号的操作
WriteOneChar(0x44); // 启动温度转换
Init_DS18B20();
WriteOneChar(0xCC); //跳过读序号列号的操作
WriteOneChar(0xBE); //读取温度寄存器
a=ReadOneChar(); //连续读两个字节数据 //读低8位
b=ReadOneChar(); //读高8位
t=b;
t<<=8;
t=t|a; //两字节合成一个整型变量。
tt=t*0.0625; //得到真实十进制温度值,因为DS18B20可以精确到0.0625度,所以读回数据的最低位代表的是0.0625度
t= tt*10+0.5; //放大十倍,这样做的目的将小数点后第一位也转换为可显示数字,同时进行一个四舍五入操作。
return(t);
}
void display_tem() //显示温度
{
uint num;
uint shi,ge,xiaoshu; //这里的num,shi,ge,xiaoshu 必须用uint无符号整数来表示,用uchar字符型则显示错误
num=Readtemp();
shi=num/100; //显示数据拆分为十位、个位和小数位
ge=num/10%10;
xiaoshu=num%10;
write_com(0x80+0x40+8); //从第二行第九位显示,如T=25.9℃
write_date('T');
delay(1);
write_com(0x80+0x40+9);
write_date('=');
delay(1);
write_com(0x80+0x40+10);
write_date(distable1[shi]);
delay(1);
write_com(0x80+0x40+11);
write_date(distable1[ge]);
delay(1);
write_com(0x80+0x40+12);
write_date(0x2e);
delay(1);
write_com(0x80+0x40+13);
write_date(distable1[xiaoshu]);
delay(1);
write_com(0x80+0x40+14);
write_date(0xa1);
delay(1);
write_com(0x80+0x40+15);
write_date('C');
delay(1);
}
/*************************DS1302时间数据存取及显示***********************/
void Write_Ds1302_Byte(uchar temp) //写一字节数据
{
uchar i;
for (i=0;i<8;i++) //循环8次 写入数据
{
SCLK=0;
DIO=temp&0x01; //每次传输低字节
temp>>=1; //右移一位
SCLK=1;
}
}
void Write_Ds1302( uchar addr,dat ) //写DS1302
{
RST=0;
_nop_();
SCLK=0;
_nop_();
RST=1;
_nop_(); //启动
Write_Ds1302_Byte(addr); //发送地址
Write_Ds1302_Byte(dat); //发送数据
RST=0; //恢复
}
uchar Read_Ds1302 ( uchar addr ) //读DS1302
{
uchar i,temp=0x00;
RST=0;
_nop_();
SCLK=0;
_nop_();
RST=1;
_nop_();
Write_Ds1302_Byte(addr);
for (i=0;i<8;i++) //循环8次 读取数据
{
if(DIO)
temp|=0x80; //每次传输低字节
SCLK=0;
temp>>=1; //右移一位
SCLK=1;
}
RST=0;
_nop_(); //以下为DS1302复位的稳定时间
RST=0;
SCLK=0;
_nop_();
SCLK=1;
_nop_();
DIO=0;
_nop_();
DIO=1;
_nop_();
return (temp); //返回
}
void Set_RTC() //设置DS1302寄存器
{
uchar i,*p;
Write_Ds1302(0x8E,0X00); //禁止写保护
p=wr_rtc_addr; //写寄存器列表地址传递
for(i=0;i<7;i++) //7次写入 秒分时日月星期年
{
Write_Ds1302(*p,timedate[i]);
p++;
}
Write_Ds1302(0x8E,0x80); //允许写保护
}
void Read_RTC() //读出DS1302寄存器
{
uchar i,*p;
p=rd_rtc_addr; //读寄存器列表地址传递
for(i=0;i<7;i++) //分7次读取 年月日时分秒星期
{
timedate[i]=Read_Ds1302(*p);
p++;
}
}
void convert_time() //读出的BCD值转换为两位十进制数字并放入显示缓存
{
display1[0]=2;
display1[1]=0;
display1[2]=timedate[6]/16; //年
display1[3]=timedate[6]&0x0f;
display1[4]=11;
display1[5]=timedate[4]/16; //月
display1[6]=timedate[4]&0x0f;
display1[7]=11;
display1[8]=timedate[3]/16; //日
display1[9]=timedate[3]&0x0f;
display1[10]=12;
display1[11]=timedate[5]/16; //星期
display1[12]=timedate[5]&0x0f;
display2[0]=timedate[2]/16; //时
display2[1]=timedate[2]&0x0f;
display2[2]=10;
display2[3]=timedate[1]/16; //分
display2[4]=timedate[1]&0x0f;
display2[5]=10;
display2[6]=timedate[0]/16; //秒
display2[7]=timedate[0]&0x0f;
}
void convert_week() //星期转换为英文
{
switch(display1[12])
{
case 1: distable2[0]='M';distable2[1]='o';distable2[2]='n';break;
case 2: distable2[0]='T';distable2[1]='u';distable2[2]='e';break;
case 3: distable2[0]='W';distable2[1]='e';distable2[2]='d';break;