一直想做一个万年历,看了一下硬件电路还是蛮简单的(AT89S52+12864+DS18B20+DS1302就这么几个芯片),主要还是程序难一点,因为没有一点思路,但那几个芯片的模块程序我以前研究过的,所以网上找了几个程序研究了下,编出了一个最简单的,没有农历,闹钟,这种东西,以后再加嘛,(*^__^*)
。
C语言代码如下(因为太大,部分代码再另一篇文章中)
//头文件
#include<AT89X52.h>
#include<intrins.h>
#include<string.h> //字符串操作函数
//宏定义
#define uchar unsigned char
#define uint unsigned char
#define lcddata
P0 //液晶8位并口数据
//定义全局变量
uchar
hide_sec,hide_min,hide_hour,hide_day,hide_week,hide_month,hide_year;
//秒,分,时到日,月,年位闪的计数
uchar count,temp,up_flag,down_flag,done;
uchar flag;
//负温度标志
uchar
tltemp;
//临时暂存变量
uchar
temp_value,temp1_value;
//temp_value温度值正数部分 temp1_value温度值小数部分
uchar week_value[3];
uchar TempBuffer[6];
uchar week_value[3];
void show_all();
//定义特殊位
sbit
lcd_rs=P2^0; //H=data;L=command
sbit
lcd_rw=P2^1; //H=read;L=write
sbit lcd_e=P2^2; //input
enable
sbit lcd_psw=P2^3; //H=Parallel
Mode;L=Serial Mode
sbit lcd_rst=P2^4; //Reset
Signal,Low effective
sbit
lcd_bf=P0^7;
//LCD Busy bit
sbit fmq=P3^6;
sbit
DQ=P3^3;
//DS18B20 Data input/output Pin
sbit
DS1302_SCLK=P1^0;
//实时时钟时钟引脚
sbit DS1302_DATA=P1^1;
//实时时钟数据引脚
sbit DS1302_RST=P1^2;
//实时时钟复位引脚
sbit Set=P1^4;
sbit Up=P1^5;
sbit Down=P1^6;
//sbit KEY_4=P1^7;
void delaynms(uint aa)
{
uchar bb;
while(aa--)
{
for(bb=0;bb<115;bb++)
//1ms基准延时程序
{
;
}
}
}
/
void chkbusy_lcd(void)
{
lcddata=0xff;
//把忙碌标志位BF置1
lcd_rs=0;
//指令操作
lcd_rw=1;
//读操作
lcd_e=1;
//拉高使能,读取数据
while(lcd_bf==1);
//判断忙碌位是否为0,若果为1,液晶忙,一直等待(BF=1,状态忙)
lcd_e=0;
//拉低使能
}
void wr_lcd(uchar dat_comm,uchar
content)
{
chkbusy_lcd();
if(dat_comm==1)
{
lcd_rs=1;
//data
lcd_rw=0;
//write
}
else
{
lcd_rs=0;
//command
lcd_rw=0;
//write
}
lcd_e=1;
//拉高使能
lcddata=content;//放上数据
_nop_();
//等待
lcd_e=0;
//拉低使能,使数据写入
}
void init_lcd(void)
{
wr_lcd(0,0x30); //基本指令集
delaynms(1); //等待
wr_lcd(0,0x30); //再设置一次为基本指令集,因为ST7920中有2个寄存器用来设置使用哪个指令集
delaynms(1); //等待
wr_lcd(0,0x0c); //开显示,关游标,关游标位置
delaynms(1); //等待
wr_lcd(0,0x01); //清屏,地址指针指向00H
delaynms(20); //等待>10ms
wr_lcd(0,0x06); //光标右移,整体不移
}
void lcd_clr(void)
{
wr_lcd(0,0x30);
//基本指令集
wr_lcd(0,0x01); //清除显示
delaynms(1);
}
void gotoxy(unsigned char y, unsigned char
x)
{
if(y==1)
wr_lcd(0,0x80|x);
//Line 1
if(y==2)
wr_lcd(0,0x90|x);
//Line 2
if(y==3)
wr_lcd(0,((0x80|x)+8));
//Line 3
if(y==4)
wr_lcd(0,((0x90|x)+8)); //Line
4
}
void print(uchar *str)
{
while(*str!='\0')
//检查是否到字符串尾
{
wr_lcd(1,*str++);
//输入*str后str++
}
}
/
bit Init_DS18B20(void)
{
bit flag;
DQ=1;
_nop_();
DQ=0; //拉低,
for(t=0;t<200;t++); //产生一个约600us低电平脉冲
DQ=1; //释放总线为高电平
for(t=0;t<15;t++); //延时约45us
flag=DQ; //对总线检测
for(t=0;t<200;t++);
return flag;
}
uchar ReadOneChar(void)
{
uchar dat;
uchar i=0;
for(i=0;i<8;i++)
{
DQ=1;
_nop_();
DQ=0;
//DQ拉低1us以后,
_nop_(); //
DQ=1;
//释放单总线为高电平,以让DS18B20把数据传到单总线上
for(t=0;t<3;t++);
//延时9微妙
dat>>=1;
//
if(DQ==1)
//
{
dat|=0x80;
//数据采集
}
else
dat|=0x00;
for(t=0;t<1;t++);
//延时3us,两个读时序间至少需要1us的恢复期
}
return dat;
}
void WriteOneChar(uchar dat)
{
uchar i;
for(i=0;i<8;i++)
{
DQ=1;
_nop_();
DQ=0;
//主机把总线拉低1us,表示写周期开始
_nop_();
//
DQ=dat&0x01;
for(t=0;t<15;t++); //延时约45秒,
for(t=0;t<10;t++); //????
DQ=1;
//释放总线
for(t=0;t<1;t++);
//延时3us,两个写时序间至少需要1us的恢复期???
dat>>=1;
}
for(t=0;t<4;t++); //????
}
void ReadTemperature(void)
{
uchar TH=0; //
uchar TL=0; //
flag=0;
Init_DS18B20();
WriteOneChar(0xCC); // 跳过读序号列号的操作
WriteOneChar(0x44); // 启动温度转换
//
delaynms(1000);
//千万不能延时,(!!!!)
Init_DS18B20();
WriteOneChar(0xCC); //跳过读序号列号的操作
WriteOneChar(0xBE); //读取温度寄存器
//
delaynms(500);
// 不延时(!!!!)
TL=ReadOneChar(); //读低8位
TH=ReadOneChar(); //读高8位
if((TH&0xf8)!=0x00)
//是负温度
{
flag=1;
TH=~TH;
TL=~TL;
tltemp=TL+1;
if(tltemp>255)
TH++;
} //25.125
temp_value=TH*16+TL/16; //整数
25
temp1_value=(TL%16)*10/16; //小数部分 1250
}
void Temp2Str(void)
{
TempBuffer[0]=':';
if(flag==1)
//是负温度
{
TempBuffer[1]='-';
}
else
{
TempBuffer[1]=temp_value/100+'0';
if(TempBuffer[1]=='0')
{
TempBuffer[1]=' ';
}
else
TempBuffer[1]='1';
}
TempBuffer[2]=temp_value%100/10+'0';
TempBuffer[3]=temp_value%10+'0';
TempBuffer[4]='.';
TempBuffer[5]=temp1_value+'0';
TempBuffer[6]='\0';
}
/
void DS1302InputByte(uchar d)
{
uchar
i;
DS1302_SCLK=0; //拉低SCLK,为上升沿写入数据做好准备
for(i=0;i<8;i++) //连续写入8个二进制数据
{
DS1302_DATA=d&0x01; //取出d的第0位,写入1302,
低位在前,高位在后
_nop_(); //等待
DS1302_SCLK=1; //
拉高SCLK,上升沿写入数据
_nop_(); //
等待
DS1302_SCLK=0; //拉低SCLK形成脉冲
d>>=1; //将d的数据向右移一位,准备写入下一个二进制数据
}
}
uchar DS1302OutputByte(void)
{
uchar i;
uchar dat;
for(i=0;i<8;i++) //连续读出8个二进制数
{
dat>>=1; //向右移一位
if(DS1302_DATA==1) //如果读出数据是1,(上一个写入控制字结束后,保存一个读出数据)
{
dat|=0x80;
}
DS1302_SCLK=1; //拉高SCLK
_nop_();
DS1302_SCLK=0; //拉低SCLK,读取数据
}
return
dat;
//将读出的数据返回
}
void Write1302(uchar ADDRorCOMM,uchar
DATA)
{
DS1302_RST=0;
//禁止数据传输
DS1302_SCLK=0;
//确保写写之前SCLK被拉低
DS1302_RST=1; //启动数据传输
DS1302InputByte(ADDRorCOMM); //写入命令或地址
DS1302InputByte(DATA); //
DS1302_SCLK=1;
//将时钟电平置于高电平状态 $$$$$$ 置高是为了让下次写的时候 能准确的被拉低 保证电平
状态的正确性
DS1302_RST=0;
//禁止数据传输
}
uchar Read1302(uchar ADDRorCOMM)
{
uchar
dat;
DS1302_RST=0;
//禁止数据传输
DS1302_SCLK=0;
//确保写写之前SCLK被拉低
DS1302_RST=1; //启动数据传输
DS1302InputByte(ADDRorCOMM); //写入命令或地址
dat=DS1302OutputByte(); //
读出数据
DS1302_SCLK=1;
//将时钟电平置于高电平状态 $$$$$$ 置高是为了让下次写的时候 能准确的被拉低 保证电平
状态的正确性
DS1302_RST=0;
//禁止数据传输
return(dat);
}
void
Init_1302(void)
//(2008年7月12日12时00分00秒星期六)
{
uchar flag;
flag=Read1302(0x81);
//读秒寄存器
if(flag&0x80)
//CH为0(flag最高位是0),时钟走动,不用初始化 。
{
Write1302(0x8e,0x00);
//允许写操作
Write1302(0x8c,((8/10)<<4|(8%10)));
//YEAR
Write1302(0x8a,0x01);
//DAY
Write1302(0x88,((3/10)<<4|(3%10)));
//MONTH
Write1302(0x86,((14/10)<<4|(14%10)));
//DATE
Write1302(0x84,((12/10)<<4|(12%10)));
//HR
Write1302(0x82,((0/10)<<4|(0%10)));
//MIN
Write1302(0x80,((0/10)<<4|(0%10)));
//SEC
Write1302(0x90,0xa5);
//打开充电功能
Write1302(0x8e,0x80);
//禁止写操作
}
}
typedef struct _SYSTEMTIME_
{
uchar Second;
uchar Minute;
uchar Hour;
uchar Week;
uchar Day;
uchar Month;
uchar Year;
uchar DateString[11];
uchar TimeString[9];
}SYSTEMTIME;
SYSTEMTIME CurrentTime;
void DS1302_GetTime(SYSTEMTIME *Time)
{
uchar ReadValue;
ReadValue=Read1302(0x81);
//从秒寄存器里读数据
Time->Second=((ReadValue&0x70)>>4)*10+(ReadValue&0x0f);
//把读出的数据转换成BCD码
ReadValue=Read1302(0x83);
//从分寄存器里读数据
Time->Minute=((ReadValue&0x70)>>4)*10+(ReadValue&0x0f);
//把读出的数据转换成BCD码
ReadValue=Read1302(0x85);
//从小时寄存器里读数据
Time->Hour=((ReadValue&0x70)>>4)*10+(ReadValue&0x0f);
//把读出的数据转换成BCD码
ReadValue=Read1302(0x8b);
//从星期寄存器里读数据
Time->Week=((ReadValue&0x70)>>4)*10+(ReadValue&0x0f);
//把读出的数据转换成BCD码
ReadValue=Read1302(0x87);
//从日寄存器里读数据
Time->Day=((ReadValue&0x70)>>4)*10+(ReadValue&0x0f);
//把读出的数据转换成BCD码
ReadValue=Read1302(0x89);
//从月寄存器里读数据
Time->Month=((ReadValue&0x70)>>4)*10+(ReadValue&0x0f);
//把读出的数据转换成BCD码
ReadValue=Read1302(0x8d);
//从年寄存器里读数据
Time->Year=((ReadValue&0xf0)>>4)*10+(ReadValue&0x0f);
//把读出的数据转换成BCD码 //注意是0xF0
}
void Date2Str(SYSTEMTIME *Time)
{
uchar
tab[]={0xd2,0xbb,0xbb6,0xfe,0xc8,0xfd,0xcb,0xc4,0xce,0xe5,0xc1,0xf9,0xc8,0xd5};//?????
// uchar tab[]={"一二三四五六日"};
if(hide_year<2) ////这里的if,else语句都是判断位闪烁,<2显示数据,>2就不显示,
{
Time->DateString[0]='2';
Time->DateString[1]='0';
Time->DateString[2]=Time->Year/10+'0';
Time->DateString[3]=Time->Year%10+'0';
}
else
{
Time->DateString[0]=' ';
Time->DateString[1]=' ';
Time->DateString[2]=' ';
Time->DateString[3]=' ';
}
Time->DateString[4]='-';
if(hide_month<2)
{
Time->DateString[5]=Time->Month/10+'0';
Time->DateString[6]=Time->Month%10+'0';
}
else
{
Time->DateString[5]=' ';
Time->DateString[6]=' ';
}
Time->DateString[7]='-';
if(hide_day<2)
{
Time->DateString[8]=Time->Day/10+'0';
Time->DateString[9]=Time->Day%10+'0';
}
else
{
Time->DateString[8]=' ';
Time->DateString[9]=' ';
}
if(hide_week<2)
{
week_value[0]=tab[2*(Time->Week%10)-2];
//星期的数据另外放到 week_value[]数组里,跟年,月,日的分开存
放,因为等一下要在最后显示
week_value[1]=tab[2*(Time->Week%10)-1];
}
else
{
week_value[0]=' ';
week_value[1]=' ';
}
week_value[2]='\0';
Time->DateString[10]='\0';
//字符串末尾加 '\0' ,判断结束字符
}
void Time2Str(SYSTEMTIME *Time)
{
if(hide_hour<2)
{
Time->TimeString[0]=Time->Hour/10+'0';
Time->TimeString[1]=Time->Hour%10+'0';
}
else
{
Time->TimeString[0]=' ';
Time->TimeString[1]=' ';
}
Time->TimeString[2]=':';
if(hide_min<2)
{
Time->TimeString[3]=Time->Minute/10+'0';
Time->TimeString[4]=Time->Minute%10+'0';
}
else
{
Time->TimeString[3]=' ';
Time->TimeString[4]=' ';
}
Time->TimeString[5]=':';
if(hide_sec<2)
{
Time->TimeString[6]=Time->Second/10+'0';
Time->TimeString[7]=Time->Second%10+'0';
}
else
{
Time->TimeString[6]=' ';
Time->TimeString[7]=' ';
}
Time->TimeString[8]='\0';
}
加载中,请稍候......