/***********************************************************************************/
/************使用LCD1602、DS1302时钟芯片、DS18B20温度传感器完成该日历**************/
#include<reg52.h>
#define uint unsigned int
#define uchar unsigned char
sbit rs="P2"^0; // 数据/命令选择端
sbit rw="P2"^1; //读写选择端
sbit e="P2"^2; //使能信号
sbit rst="P2"^5; //时钟芯片复位端
sbit sck="P2"^6; // 时钟信号
sbit io="P2"^7; // 输入/输出端
sbit ds="P2"^3; //温度传感器信号线
sbit led="P2"^4; //小灯位定义
uint temp; // 整型温度值
float f_temp; //浮点型温度值
void init(); // 初始化函数
void delay(uchar z); //延时函数
void write_com(uchar com); //LCD写命令
void write_date(uchar date); //LCD写数据
uint get_temp(); //获得温度
void tempchange(void); //转换温度
void dsreset(void); //DS18B20复位
bit tempreadbit(void); //读DS118B20一位
uchar tempreadbyte(void); //读DS18B20一个字节
void tempwritebyte(uchar dat);
void deal(); //温度处理函数
void Write_Ds1302_Byte(uchar temp);//写入一个字节
void Write_Ds1302(uchar address,uchar dat);//写入
uchar Read_Ds1302 ( uchar address ); //读取时间
void Read_RTC(void); //读取 日历
void Set_RTC(void); //设定 日历
void time_date(); //时间数据处理
void display(uchar *lp,uchar lc); //显示时间
void Temp_Display(); //温度显示
uchar table[]="0123456789.C";
uchar table0[]="0123456789-";
uchar table1[]="MONTUEWEDTHUFRISATSUN";
uchar table2[]="0123456789:!";
uchar l_tmpdate[7]={21,59,23,28,10,2,8};
/*初始化时钟芯片,依次是秒分时日月星期年,用十六进制表示十进制,如0x1c表示
1*16+12即28,所以显示出来的就是28*/
uchar l_tmpdisplay[18];
code uchar write_rtc_address[7]={0x80,0x82,0x84,0x86,0x88,0x8a,0x8c};
//以上是写入时钟芯片的地址,顺序同上
code uchar read_rtc_address[7]={0x81,0x83,0x85,0x87,0x89,0x8b,0x8d};
//读出数据的地址
/******************************日历主函数************************************/
void main()
{
init(); //初始化LCD
Set_RTC();//初始化时钟芯片
while(1)
{
tempchange();//温度转换命令
time_date();//显示时间
Temp_Display(); //显示温度
deal(); //温度处理
P1=0xf0;
IT0=1; // 选择外部中断0为电平触发方式(1为跳变沿触发方式)
EX0=1;
EA="1";
}
}
void inter0() interrupt 0 //外部中断0
{
P1=0xfe;
if(P1!=0xfe)
delay(10);
if(P1==0xee)
{ led=~led;
write_com(0x1c);
}
if(P1==0xde)
{ led=~led;
write_com(0x18);
}
}
/***************************以下为温度传感器相关程序************************/
void dsreset(void) //DS18B20复位,初始化函数
{
uint i;
ds=0;
i=103;
while(i>0)i--;
ds=1;
i=4;
while(i>0)i--;
}
bit tempreadbit(void) //读一位数据函数
{
uint i;
bit dat;
ds=0;i++; //i++起延时的作用
ds=1;i++;i++;
dat=ds;
i=8;while(i>0)i--;
return(dat);
}
uchar tempreadbyte(void) //读一个字节数据函数
{
uchar i,j,dat;
dat=0;
for(i=1;i<=8;i++)
{
j=tempreadbit();
dat=(j<<7)|(dat>>1); //读出的数据最低位在最前面
}
return(dat);
}
void tempwritebyte(uchar dat)
{ //写一个字节数据函数
uint i;
char j;
bit testb;
for(j=1;j<=8;j++)
{
testb=dat&0x01;
dat=dat>>1;
if(testb) //写1
{
ds=0;
i++;i++;
ds=1;
i=8;while(i>0)i--;
}
else //写0
{
ds=0;
i=8;while(i>0)i--;
ds=1;
i++;i++;
}
}
}
void tempchange(void) //DS18B20开始获取温度并转换
{
dsreset();
delay(1);
tempwritebyte(0xcc); //写跳过读ROM指令
tempwritebyte(0x44); //写温度转换指令
}
uint get_temp() //读取寄存器中存储的温度数据
{
uchar a,b;
dsreset();
delay(1);
tempwritebyte(0xcc);
tempwritebyte(0xbe); //读RAM内部9字节的温度数据
a=tempreadbyte(); //读低8位
b=tempreadbyte(); //读高8位
temp=b;
temp<<=8;
temp=temp|a; //两个字节组合为一个字节
f_temp=temp*0.0625; // 温度在寄存器中为12位,分辨率为0.0625
temp=f_temp*10+0.5; //乘以10表示小数点后面只取1位,加0.5时四舍五入
f_temp=f_temp+0.05;
return temp;
}
void Temp_Display() //温度显示函数
{
write_com(0x80+0x40+0x0b);
write_date(table[get_temp()/100]);
write_com(0x80+0x40+0x0c);
write_date(table[get_temp()%100/10]);
write_com(0x80+0x40+0x0d);
write_date(table[10]);
write_com(0x80+0x40+0x0e);
write_date(table[get_temp()%10]);
write_com(0x80+0x40+0x0f);
write_date(table[11]);
}
void deal() //温度处理函数
{
uint i;
i=get_temp();
if(i>300||i<200) //当温度低于20度或大于30度时小灯闪烁
{
led=0;
delay(100);
led=1;
// write_com(0x80+12);
// write_date(table2[11]);
}
// else led="1";
}
/***********************以上为温度传感器相关程序***********************/
/***********************以下为时钟芯片相关程序***********************/
void Write_Ds1302_Byte(uchar temp) //写入一字节数据
{
uchar i;
for (i=0;i<8;i++) //循环8次 写入数据 ,上升沿写入
{
sck="0";
io="temp"&0x01; //每次传输低字节
temp>>=1; //右移一位
sck="1";
}
}
void Write_Ds1302(uchar address,uchar dat)//写入
{
rst=0;
delay(1);
sck=0;
delay(1);
rst=1;
delay(1); //启动
Write_Ds1302_Byte(address); //发送地址
Write_Ds1302_Byte(dat); //发送数据
rst=0; //恢复
}
uchar Read_Ds1302 (uchar address) //读取时间
{
uchar i,time=0x00;
rst=0;
delay(1);
sck=0;
delay(1);
rst=1;
delay(1);
Write_Ds1302_Byte(address);
for (i=0;i<8;i++) //循环8次 读取数据
{
if(io)
time|=0x80; //每次传输低字节
sck=1; //时钟下降沿读入数据?????????
time>>=1; //右移一位
sck=0;
}
rst=0;
delay(1); //以下为DS1302复位的稳定时间
rst=0;
sck=0;
delay(1);
sck=1;
delay(1);
io=0;
delay(1);
io=1;
delay(1);
return (time);
}
void Read_RTC() //读取 日历
{
uchar i,*p;
p=read_rtc_address; //地址传递
for(i=0;i<7;i++) //分7次读取 年月日时分秒星期
{
l_tmpdate=Read_Ds1302(*p);
p++;
}
}
void Set_RTC(void) //设定 日历
{
uchar i,*p,tmp;
for(i=0;i<7;i++)
{
tmp=l_tmpdate/10;
l_tmpdate=l_tmpdate%10;
l_tmpdate=l_tmpdate+tmp*16;
}
Write_Ds1302(0x8E,0X00); //允许写入
p=write_rtc_address; //传地址
for(i=0;i<7;i++) //7次写入 年月日时分秒星期
{
Write_Ds1302(*p,l_tmpdate);
p++;
}
Write_Ds1302(0x8E,0x80); //禁止写入
}
void time_date() //时间数据处理
{
Read_RTC();
l_tmpdisplay[0]=l_tmpdate[2]/16;//时
l_tmpdisplay[1]=l_tmpdate[2]&0x0f;
l_tmpdisplay[2]=10; //加入":"
l_tmpdisplay[3]=l_tmpdate[1]/16;//分
l_tmpdisplay[4]=l_tmpdate[1]&0x0f;
l_tmpdisplay[5]=10;
l_tmpdisplay[6]=l_tmpdate[0]/16;//秒
l_tmpdisplay[7]=l_tmpdate[0]&0x0f;
l_tmpdisplay[8]=2; //显示2008的2
l_tmpdisplay[9]=0; //显示2008的第一个0
l_tmpdisplay[10]=l_tmpdate[6]/16; //年
l_tmpdisplay[11]=l_tmpdate[6]&0x0f;
l_tmpdisplay[12]=10; //加入“-”
l_tmpdisplay[13]=l_tmpdate[4]/16;//月
l_tmpdisplay[14]=l_tmpdate[4]&0x0f;
l_tmpdisplay[15]=10;
l_tmpdisplay[16]=l_tmpdate[3]/16;//日
l_tmpdisplay[17]=l_tmpdate[3]&0x0f;
display(l_tmpdisplay,8);
}
void display(uchar *lp,uchar lc) //显示时间
{
unsigned char i; //定义变量
write_com(0x80); //液晶第一行显示时间和星期
for(i=0;i<lc;i++)
{
write_date(table2[lp]);
delay(1);
}
write_com(0x80+0x09);
switch(l_tmpdate[5]) //用英文缩写显示星期
{
case 0: write_date(table1[0]);
write_date(table1[1]);
write_date(table1[2]);
break;
case 1: write_date(table1[3]);
write_date(table1[4]);
write_date(table1[5]);
break;
case 2: write_date(table1[6]);
write_date(table1[7]);
write_date(table1[8]);
break;
case 3: write_date(table1[9]);
write_date(table1[10]);
write_date(table1[11]);
break;
case 4: write_date(table1[12]);
write_date(table1[13]);
write_date(table1[14]);
break;
case 5: write_date(table1[15]);
write_date(table1[16]);
write_date(table1[17]);
break;
case 6: write_date(table1[18]);
write_date(table1[19]);
write_date(table1[20]);
break;
}
write_com(0x80+0x40); //第二行显示年
for(i=8;i<lc+10;i++)
{
write_date(table0[lp]);
delay(1);
}
}
/********************以上为时钟芯片相关程序***************************/
void init() //LCD初始化函数
{
e=0;
write_com(0x38);//显示模式的设置
delay(1);
write_com(0x0c);//开显示,光标显示
delay(1);
write_com(0x06);//光标位置
delay(1);
write_com(0x01); //清显示
delay(1);
}
void write_com(uchar com) //LCD写命令
{
rs=0;
rw=0;
P0=com;
delay(1);
e=1;
delay(1);
e=0;
}
void write_date(uchar date) //LCD写数据
{
rs=1;
rw=0;
P0=date;
delay(1);
e=1;
delay(1);
e=0;
}
void delay(uchar z) //延时函数
{
uchar x,y;
for(x=0;x<z;x++)
for(y=0;y<110;y++);
}
/***************END***********END******************************/
用户1545666 2009-6-28 17:08