高分求基于51单片机和ds12887的电子万年历,要有电路图和程序

最好用1602液晶显示,谢谢

第1个回答  2008-11-19
//==========直接上代码吧

//===============LCD12887_1.C 主文件
/*--------------------------------------------------------------*/
//包含头文件
#include<AT89X52.H>
#include"LCD1602_8.H"
#include"DS12887_1.H"

/*--------------------------------------------------------------*/
unsigned char k; //键值
unsigned char Set; //调整值

/*--------------------------------------------------------------*/
//延时200ms 函数定义
void delay200ms(void)
{
unsigned char i,j,k;
for(i=201;i>0;i--)
for(j=32;j>0;j--)
for(k=14;k>0;k--);
}

/*--------------------------------------------------------------*/
//延时5000+0us 函数定义
void delay5ms(void)
{
unsigned char i,j;
for(i=185;i>0;i--)
for(j=12;j>0;j--);
}

/*--------------------------------------------------------------*/
//键盘扫描
void Keysan(void) //P0_0切换键,P0_1数值加,P0_1数值减
{
if(P0_0 == 0)
{
delay5ms();
if(P0_0 == 0) k++;
if(k == 7) k = 0;
}
if(P0_1 == 0) {delay5ms(); if(P0_1 == 0) Set++;}
if(P0_2 == 0) {delay5ms(); if(P0_2 == 0) Set--;}
switch(k)
{
case 0: DS12887_SetTime(DS12887_Second, Set); if(Set > 59 || Set < 0) Set = 0; break;
case 1: DS12887_SetTime(DS12887_Minute, Set); if(Set > 59 || Set < 0) Set = 0; break;
case 2: DS12887_SetTime(DS12887_Hour , Set); if(Set > 24 || Set < 0) Set = 0; break;
case 3: DS12887_SetTime(DS12887_Day , Set); if(Set > 31 || Set < 0) Set = 0; break;
case 4: DS12887_SetTime(DS12887_Month , Set); if(Set > 12 || Set < 0) Set = 0; break;
case 5: DS12887_SetTime(DS12887_Year , Set);break;
default: break;
}
}

/*--------------------------------------------------------------*/
//主函数
void main(void)
{

SYSTEMTIME CurrentTime;
lcd_init();
DS12887_Init();

lcd_pos(0,0);
prints("Date:");
lcd_pos(0,1);
prints("Time:");
k = 6; //不改变时间
while(1)
{
DS12887_GetTime(&CurrentTime);
DateToStr(&CurrentTime);
TimeToStr(&CurrentTime);
lcd_pos(6,0);
prints(CurrentTime.DateString);
lcd_pos(6,1);
prints(CurrentTime.TimeString);
delay200ms();
Keysan();
}
}

//=======================包含文件1 LCD1602_8.H
/*--------------------------------------------------------------*/
//包含头文件
#include<AT89X52.H>
#include"LCD1602_8.H"
#include"DS12887_1.H"

/*--------------------------------------------------------------*/
unsigned char k; //键值
unsigned char Set; //调整值

/*--------------------------------------------------------------*/
//延时200ms 函数定义
void delay200ms(void)
{
unsigned char i,j,k;
for(i=201;i>0;i--)
for(j=32;j>0;j--)
for(k=14;k>0;k--);
}

/*--------------------------------------------------------------*/
//延时5000+0us 函数定义
void delay5ms(void)
{
unsigned char i,j;
for(i=185;i>0;i--)
for(j=12;j>0;j--);
}

/*--------------------------------------------------------------*/
//键盘扫描
void Keysan(void) //P0_0切换键,P0_1数值加,P0_1数值减
{
if(P0_0 == 0)
{
delay5ms();
if(P0_0 == 0) k++;
if(k == 7) k = 0;
}
if(P0_1 == 0) {delay5ms(); if(P0_1 == 0) Set++;}
if(P0_2 == 0) {delay5ms(); if(P0_2 == 0) Set--;}
switch(k)
{
case 0: DS12887_SetTime(DS12887_Second, Set); if(Set > 59 || Set < 0) Set = 0; break;
case 1: DS12887_SetTime(DS12887_Minute, Set); if(Set > 59 || Set < 0) Set = 0; break;
case 2: DS12887_SetTime(DS12887_Hour , Set); if(Set > 24 || Set < 0) Set = 0; break;
case 3: DS12887_SetTime(DS12887_Day , Set); if(Set > 31 || Set < 0) Set = 0; break;
case 4: DS12887_SetTime(DS12887_Month , Set); if(Set > 12 || Set < 0) Set = 0; break;
case 5: DS12887_SetTime(DS12887_Year , Set);break;
default: break;
}
}

/*--------------------------------------------------------------*/
//主函数
void main(void)
{

SYSTEMTIME CurrentTime;
lcd_init();
DS12887_Init();

lcd_pos(0,0);
prints("Date:");
lcd_pos(0,1);
prints("Time:");
k = 6; //不改变时间
while(1)
{
DS12887_GetTime(&CurrentTime);
DateToStr(&CurrentTime);
TimeToStr(&CurrentTime);
lcd_pos(6,0);
prints(CurrentTime.DateString);
lcd_pos(6,1);
prints(CurrentTime.TimeString);
delay200ms();
Keysan();
}
}

//================================ 包含文件2 DS12887_1.H
/*--------------------------------------------------------------*/
//File: DS12887驱动程序
//Date: 08-10-20 ~ 10-23
//Time: 21:20 ~ 16:53
//Source: Web

/*--------------------------------------------------------------*/
#ifndef __DS12887_1_H__
#define __DS12887_1_H__

/*--------------------------------------------------------------*/
//接口定义
sbit DS_AS = P3^0; //地址选择
sbit DS_RW = P3^1; //读写选择
sbit DS_DS = P3^2; //数据选择
sbit DS_IRQ = P3^3; //中断,低电平有效,通过读出0x0c来清除信号
sfr DS_DAT = 0x90; //8位数据线P1口

/*--------------------------------------------------------------*/
//数据地址定义
#define DS12887_Second 0x00 //秒
#define DS12887_Minute 0x02 //分
#define DS12887_Hour 0x04 //时
#define DS12887_Week 0x06 //星期
#define DS12887_Day 0x07 //日
#define DS12887_Month 0x08 //月
#define DS12887_Year 0x09 //年

/*--------------------------------------------------------------*/
//定义时间类型
typedef struct _SYSTEMTIME_
{
unsigned char Second;
unsigned char Minute;
unsigned char Hour;
unsigned char Week;
unsigned char Day;
unsigned char Month;
unsigned char Year;
unsigned char DateString[9];
unsigned char TimeString[9];
}SYSTEMTIME;

/*--------------------------------------------------------------*/
//函数声明
void DS12887_Init(void); //DS12887初始化
void DS12887_Write(unsigned char Address, unsigned char Value); //DS12887指定地址写入数据
unsigned char DS12887_Read(unsigned char Address); //DS12887指定地址中读出数据
void DS12887_SetTime(unsigned char Address, unsigned char Value); //设置时间函数
void DS12887_GetTime(SYSTEMTIME *Time); //读出时间
void DateToStr(SYSTEMTIME *Time); //日期转化成字符
void TimeToStr(SYSTEMTIME *Time); //时间转化成字符

/*--------------------------------------------------------------*/
//DS12887指定地址写入数据
void DS12887_Write(unsigned char Address, unsigned char Value)
{
DS_AS = 0;
DS_DS = 1;
DS_RW = 1;
DS_AS = 1;
DS_DAT= Address;
DS_AS = 0;
DS_RW = 0;
DS_DAT= Value;
DS_RW = 1;
DS_AS = 1;
}

/*--------------------------------------------------------------*/
//DS12887指定地址中读出数据
unsigned char DS12887_Read(unsigned char Address)
{
unsigned char DS_RDAT;
DS_AS = 0;
DS_DS = 1;
DS_RW = 1;
DS_AS = 1;
DS_DAT= Address;
DS_AS = 0;
DS_DS = 0;
DS_DAT=0xff;
DS_RDAT = DS_DAT;
DS_DS = 1;
DS_AS = 1;
return (DS_RDAT);
}

/*--------------------------------------------------------------*/
//DS12887初始化
void DS12887_Init(void)
{
DS12887_Write(0x0a, 0x20); //启动DS12887
DS12887_Write(0x0b, 0x86); //禁止更新,接下来初始化数据,即写入时间,日期等
DS12887_Write(0x0b, 0x06); //正常更新,二进制格式,24进制小时
}

/*--------------------------------------------------------------*/
//设置时间函数
void DS12887_SetTime(unsigned char Address, unsigned char Value)
{
DS12887_Write(0x0b, 0x86); //禁止更新,接下来初始化数据,即写入时间,日期等
DS12887_Write(Address,Value);
DS12887_Write(0x0b, 0x06); //正常更新,二进制格式,24进制小时
}

/*--------------------------------------------------------------*/
//读出时间
void DS12887_GetTime(SYSTEMTIME *Time)
{
Time->Second = DS12887_Read(DS12887_Second);
Time->Minute = DS12887_Read(DS12887_Minute);
Time->Hour = DS12887_Read(DS12887_Hour );
Time->Day = DS12887_Read(DS12887_Day );
Time->Week = DS12887_Read(DS12887_Week );
Time->Month = DS12887_Read(DS12887_Month );
Time->Year = DS12887_Read(DS12887_Year );
}

/*--------------------------------------------------------------*/
//日期转化成字符
void DateToStr(SYSTEMTIME *Time)
{
Time->DateString[0] = Time->Year/10 + '0';
Time->DateString[1] = Time->Year%10 + '0';
Time->DateString[2] = '-';
Time->DateString[3] = Time->Month/10 + '0';
Time->DateString[4] = Time->Month%10 + '0';
Time->DateString[5] = '-';
Time->DateString[6] = Time->Day/10 + '0';
Time->DateString[7] = Time->Day%10 + '0';
Time->DateString[8] = '\0';
}

/*--------------------------------------------------------------*/
//时间转化成字符
void TimeToStr(SYSTEMTIME *Time)
{
Time->TimeString[0] = Time->Hour/10 + '0';
Time->TimeString[1] = Time->Hour%10 + '0';
Time->TimeString[2] = ':';
Time->TimeString[3] = Time->Minute/10 + '0';
Time->TimeString[4] = Time->Minute%10 + '0';
Time->TimeString[5] = ':';
Time->TimeString[6] = Time->Second/10 + '0';
Time->TimeString[7] = Time->Second%10 + '0';
Time->TimeString[8] = '\0';
}

/*--------------------------------------------------------------*/
#endif

/*--------------------------------------------------------------*/
//File: LCD1602_8.H
//Date: 08-7-29
//Time: 16:09
//Note: LCD1602 Mini Driver.

/*--------------------------------------------------------------*/
#ifndef __LCD1602_8_H__
#define __LCD1602_8_H__
#include <intrins.h>

/*--------------------------------------------------------------*/
//LCD接口定义
sfr io = 0xA0; //P0-0x80,P1-0x90,P2-0xA0,P3-0xB0;
sbit rs = P3^4; //LCD数据/命令选择端(H/L)
sbit rw = P3^5; //LCD读/写选择端(H/L)
sbit ep = P3^6; //LCD使能控制
sbit bz = io^7; //LCD忙标志位

/*--------------------------------------------------------------*/
//函数声明
void lcd_busy(void); //测试LCD忙碌状态程序
void lcd_wcmd(unsigned char cmd); //写入指令到LCD程序
void lcd_wdat(unsigned char dat); //写入数据到LCD程序
void lcd_pos (unsigned char x, bit y); //LCD数据指针位置程序
//void printc(unsigned char CHAR); //显示字符
void prints(unsigned char *string); //显示字符串
void lcd_init(void); //LCD初始化设定程序

/*--------------------------------------------------------------*/
//测试LCD忙碌状态
void lcd_busy(void)
{
do{
ep = 0;
rs = 0; //指令
rw = 1; //读出
io = 0xff;
ep = 1;
_nop_(); //高电平读出 1us
}while(bz); //bz=1表示忙,bz=0表示空闲
ep = 0;
}

/*--------------------------------------------------------------*/
//写入指令到LCD
void lcd_wcmd(unsigned char cmd)
{
lcd_busy(); //检测忙
rs = 0; //指令
rw = 0; //写入
ep = 1;
io = cmd; //指令
ep = 0; //下降沿有效
}

/*--------------------------------------------------------------*/
//写入数据函数
void lcd_wdat(unsigned char Data)
{
lcd_busy(); //检测忙
rs = 1; //数据
rw = 0; //写入
ep = 1;
io = Data; //数据
ep = 0; //下降沿有效
}

/*--------------------------------------------------------------*/
//LCD数据指针位置程序
void lcd_pos(unsigned char x, bit y)
{
if(y)lcd_wcmd(x|0xc0); //y=1,第二行显示;y=0,第一行显示 0<=x<16
else lcd_wcmd(x|0x80); //数据指针=80+地址码(00H~27H,40H~67H)
}

/*--------------------------------------------------------------*/
//显示字符
/*
void printc(unsigned char CHAR)
{
lcd_wdat(CHAR);
}
*/

/*--------------------------------------------------------------*/
//显示字符串
void prints(unsigned char *string)
{
while(*string) {lcd_wdat(*string);string++;}
}

/*--------------------------------------------------------------*/
//LCD初始化设定
void lcd_init()
{
lcd_wcmd(0x38); //设置LCD为16X2显示,5X7点阵,八位数据接口
lcd_wcmd(0x06); //LCD显示光标移动设置(光标地址指针加1,整屏显示不移动)
lcd_wcmd(0x0c); //LCD开显示及光标设置(光标不闪烁,不显示"_")
lcd_wcmd(0x01); //清除LCD的显示内容
}

/*--------------------------------------------------------------*/
#endif

以下是相应的说明:
8根并行数据线+三根控制信号线~就可以咯~

按键接法(按键的另一条腿接到GND上):
P0_0切换键,
P0_1数值加,
P0_1数值减

时钟日历管脚接法:
sbit DS_AS = P3^0; //地址选择
sbit DS_RW = P3^1; //读写选择
sbit DS_DS = P3^2; //数据选择
sbit DS_IRQ = P3^3; //中断,低电平有效,通过读出0x0c来清除信号
sfr DS_DAT = 0x90; //8位数据线P1口

液晶管脚接法:
sfr io = 0xA0; //液晶数据口 P2-0xA0; --D0-D7
sbit rs = P3^4; //LCD数据/命令选择端(H/L) --RS / DI
sbit rw = P3^5; //LCD读/写选择端(H/L) --RW
sbit ep = P3^6; //LCD使能控制 --EN
sbit bz = io^7; //LCD忙标志位(不用再接)

DS12887的RST接在VCC, CS接在GND, IRQ不用管, MOT悬空即可~也即选择默认的Intel 工作方式。

提供的资料够详细了吧?!
以前找到的,嘿嘿本回答被提问者采纳
第2个回答  2008-11-13
这个我不会``` 不过也说两句,可以得两分耶``
相似回答