ds1302实时时钟程序流程图(利用ds1302和74ls244实现12位LED的实时电子时钟,分别显示年月日时分,求大佬给C程序)
- 利用ds1302和74ls244实现12位LED的实时电子时钟,分别显示年月日时分,求大佬给C程序
- DS1302的介绍和引脚图
- 51单片机控制DS1302,时间显示在数码管上
- 求ds1302和at89c51+LCD1602实时日历时钟带闹铃可调节的程序和电路图 851968194@qq.com
- 求一个DS1302的闹钟程序,显示当前时间,用LED显示的程序
- 基于DS1302与AT89C51的实时日历时钟的LCD显示程序你还有么还有图的
- 求教这个DS1302实时时钟电路图是如何工作的,各个引脚的作用
void Transmit_Byte(u8 dat)
{
u8 mask;
for(mask = 0x01;mask != 0;mask 《《= 1)
{
if(dat & mask)
DS1302_IO = 1;
else
DS1302_IO = 0; // Transmit bit
DS1302_SCLK = 0;
DS1302_SCLK = 1; // raising edge
}
}
u8 Receive_Byte()
{
u8 mask, dat=0;
for(mask = 0x01;mask != 0;mask 《《= 1)
{
DS1302_SCLK = 1;
DS1302_SCLK = 0; // falling edge
if(DS1302_IO)
dat |= mask; // Receive bit
}
return dat;
}
void Reset_CE()
{
DS1302_CE = 0;
DS1302_SCLK = 0;
}
DS1302是由美国DALLAS公司推出的具有涓细电流充电能力的低功耗实时时钟芯片。它可以对年、月、日、周、时、分、秒进行计时,且具有闰年补偿等多种功能。
串行时钟电路很多,如DS1302、DS1307、PCF8485等。这些电路的接口简单、价格低廉、使用方便,被广泛地采用。本文介绍的实时时钟电路DS1302是DALLAS公司的一种具有涓细电流充电能力的电路,主要特点是采用串行数据传输,可为掉电保护电源提供可编程的充电功能,并且可以关闭充电功能。采用普通32.768kHz晶振。
1302.c
#include《DS1302.h》
#include《key.h》
uchar?bit_ser={0xfe,0xfd,0xfb,0xf7,0xef,0xdf};?
uchar?seven_seg?=?{0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};
/***********************时间显示*****************/
void?timer0_init(void)?//T0初始化函数,用于时间的动态显示
{
TMOD?=?0x21;
TL0?=?(65536-5000)?%?256;
TH0?=?(65536-5000)?/?256;
EA?=?1;
ET0?=?1;
TR0?=?1;
}
void?timer0_isr(void)?interrupt?1?//T0中断处理函数
{
char?flag;??//flag用于表示调整时闪烁的亮或灭
TR0?=?0;
TL0?=?(65536-5000)?%?256;
TH0?=?(65536-5000)?/?256;
TR0?=?1;
flag?=?x?/?100?*?0xff;//设置闪烁标志,如果x大于100则flag为0xff,小于100则为0x00
x++;
if(x?》?200)
x?=?0;
switch(i)
{
case?0:
P2?=?bit_ser;
if(setflag?==?3)?//根据setflag的值判断当前位是否需要闪烁
P0?=?flag?|?seven_seg;
else
P0?=?seven_seg;
break;
case?1:
P2?=?bit_ser;
if(setflag?==?3)
P0?=flag?|?seven_seg;
else
P0?=seven_seg;
break;
case?2:
P2?=?bit_ser;
if(setflag?==?2)
P0?=flag?|?seven_seg;
else
P0?=seven_seg;
break;
case?3:
P2?=?bit_ser;
if(setflag?==?2)
P0?=flag?|?seven_seg;
else
P0?=seven_seg;
break;
case?4:
P2?=?bit_ser;
if(setflag?==?1)
P0?=flag?|?seven_seg;
else
P0?=seven_seg;
break;
case?5:
P2?=?bit_ser;
if(setflag?==?1)
P0?=flag?|?seven_seg;
else
P0?=seven_seg;
break;
}?
i++;
if(i?》=?6)?
{
i?=?0;
if(j?==?10)
{
j?=?0;
if(setflag?==?0)
DS1302_GetTime(&Time);//如果setflag是0,就从1302中读出时间,因为setflag不是0时,说明处于调整状态,不需要读时间
dis_buffer?=?Time.Second?%?10;//把当前时间放入显示缓冲区
dis_buffer?=?Time.Second?/?10;
dis_buffer?=?Time.Minute?%?10;
dis_buffer?=?Time.Minute?/?10;
dis_buffer?=?Time.Hour?%?10;
dis_buffer?=?Time.Hour?/?10;
}
j++;
}
}
void?main()
{
Initial_DS1302(Time);
timer0_init();
while(1)
{
set_down();
timer_down();
up_down();
down_down();
beepflag_down();
if(setflag?==?0?&&?Time.Hour?==?romhour?&&?Time.Minute?==?romminute?&&?Beepflag?==?1)//判断蜂鸣器是否要响
Beep?=?!Beep;?
}
}
//key.c
#include《reg51.h》
#define?uchar?unsigned?char
#define?uint?unsigned?int
uchar?i?=?0,j?=?0,x?=?0,setflag,flag_set,flag_timer;???//setflag用来表示调整的位置,flag_set和flag_timer分别表示当前处于调整状态还是定时状态
SYSTEMTIME?Time={0,20,15,3,30,6,10};???//系统时间的初始值2010年6月30日星期三,15时20分0秒
char?dis_buffer;???//存放显示数据的缓冲区
sbit?Beep_flag?=?P3^2;???//蜂鸣器的接口
sbit?key_timer?=?P3^4;???//定时按钮
sbit?key_set?=?P3^5;???//调整按钮
sbit?key_up?=?P3^6;???//增加按钮
sbit?key_down?=?P3^7;???//减小按钮
char?romhour,romminute,romsec;???//分别存放定时的时,分,秒
bit?Beepflag;???//标记闹钟是否开启
//延时函数
void?delays(uchar?x)
{
while(x)?x--;
}
//设置键的处理函数
void?set()
{
setflag?++;
flag_set?=?1;
if(setflag?》=?4)
{
setflag?=?0;
flag_set?=?0;
Initial_DS1302(Time);
}
}
//定时间的处理函数
void?timer()
{
setflag?++;
flag_timer?=?1;
if(setflag?==?1)
{
Time.Hour?=?romhour;
Time.Minute?=?romminute;
Time.Second?=?romsec;
}
else?if(setflag?》=?4)
{
setflag?=?0;
flag_timer?=?0;
romhour?=?Time.Hour;
romminute?=?Time.Minute;
romsec?=?Time.Second;
}
}
//增加键的处理函数
void?up()
{
switch(setflag)
{
case?0:
break;
case?1:
Time.Second?++;
if(Time.Second?》=?60)
Time.Second?=?0;
break;
case?2:
Time.Minute?++;
if(Time.Minute?》=?60)
Time.Minute?=?0;
break;
case?3:
Time.Hour?++;
if(Time.Hour?》=?24)
Time.Hour?=?0;
break;
}
}
//减小键的处理函数
void?down()
{
switch(setflag)
{
case?0:
break;
case?1:
Time.Second?--;
if(Time.Second?《?0)
Time.Second?=?59;
break;
case?2:
Time.Minute?--;
if(Time.Minute?《?0)
Time.Minute?=?59;
break;
case?3:
Time.Hour?--;
if(Time.Hour?《?0)
Time.Hour?=?23;
break;
}
}
//设置键的扫描函数
void?set_down()
{
if(key_set?==?0?&&?flag_timer?==?0)
{
delays(100);
if(key_set?==?0)
{
set();
}
while(!key_set);
}
}
//定时键的扫描函数
void?timer_down()
{
if(key_timer?==?0?&&?flag_set?==?0)
{
delays(100);
if(key_timer?==?0)
{
timer();
}
while(!key_timer);
}
}
//增加键的扫描函数
void?up_down()
{
if(key_up?==?0?&&?setflag?!=?0)
{
delays(100);
if(key_up?==?0)
{
up();
while(!key_up);
}
}
}
//减少键的处理函数
void?down_down()
{
if(key_down?==?0?&&?setflag?!=?0)
{
delays(100);
if(key_down?==?0)
{
down();
while(!key_down);
}
}
}
//定时开关的扫描处理函数
void?beepflag_down()
{
if(Beep_flag?==?0)
{
delays(100);
{
Beepflag?=?!Beepflag;
while(!Beep_flag);
}
}
}
//ds1302.h
#ifndef?_REAL_TIMER_DS1302
#define?_REAL_TIMER_DS1302
#include?《REG51.h》
sbit??DS1302_CLK?=?P1^1;??????????????//实时时钟时钟线引脚?
sbit??DS1302_IO??=?P1^2;??????????????//实时时钟数据线引脚?
sbit??DS1302_RST?=?P1^3;??????????????//实时时钟复位线引脚
sbit??ACC0?=?ACC^0;
sbit??ACC7?=?ACC^7;
sbit??Beep?=?P2^7;
typedef?struct?__SYSTEMTIME__
{??char?Second;
char?Minute;
char?Hour;
char?Week;
char?Day;
char?Month;
char?Year;
}SYSTEMTIME;//定义的时间类型
#define?AM(X)X
#define?PM(X)(X+12)??????????????//?转成24小时制
#define?DS1302_SECOND0x80??????????//秒寄存器??????
#define?DS1302_MINUTE0x82??????????//分寄存器
#define?DS1302_HOUR0x84?
#define?DS1302_WEEK0x8A??????
#define?DS1302_DAY0x86
#define?DS1302_MONTH0x88
#define?DS1302_YEAR0x8C
#define?DS1302_RAM(X)(0xC0+(X)*2)???//用于计算?DS1302_RAM?地址的宏?
void?DS1302InputByte(unsigned?char?d)?//实时时钟写入一字节(内部函数)
{???unsigned?char?i;
????ACC?=?d;
????for(i=8;?i》0;?i--)
????{DS1302_IO??=?ACC0;???????????//相当于汇编中的?RRC
????????DS1302_CLK?=?1;
????????DS1302_CLK?=?0;?????????????????//发一个高跳变到低的脉冲
????????ACC?=?ACC?》》?1;?
????}?
}
unsigned?char?DS1302OutputByte(void)?//实时时钟读取一字节(内部函数)
{?unsigned?char?i;
????for(i=8;?i》0;?i--)
????{ACC?=?ACC?》》1;?????????//相当于汇编中的?RRC?
????????ACC7?=?DS1302_IO;
????????DS1302_CLK?=?1;
????????DS1302_CLK?=?0;?????????????????//发一个高跳变到低的脉冲
????}?
????return(ACC);?
}
void?Write1302(unsigned?char?ucAddr,?unsigned?char?ucDa)//ucAddr:?DS1302地址,?ucData:?要写的数据
{DS1302_RST?=?0;
????DS1302_CLK?=?0;
????DS1302_RST?=?1;?
????DS1302InputByte(ucAddr);???????//?地址,命令?
????DS1302InputByte(ucDa);???????//?写1Byte数据
????DS1302_CLK?=?1;
????DS1302_RST?=?0;??????????????????//RST?0-》1-》0,CLK?0-》1
}?
unsigned?char?Read1302(unsigned?char?ucAddr)//读取DS1302某地址的数据
{unsigned?char?ucData;
????DS1302_RST?=?0;
????DS1302_CLK?=?0;
????DS1302_RST?=?1;??????????????????????//enable
????DS1302InputByte(ucAddr|0x01);????????//?地址,命令?
????ucData?=?DS1302OutputByte();?????????//?读1Byte数据
????DS1302_CLK?=?1;??????????????????????//RST?0-》1-》0,CLK?0-》1
????DS1302_RST?=?0;????????????????????
????return(ucData);
}
void?DS1302_SetProtect(bit?flag)????????//是否写保护
{if(flag)
Write1302(0x8E,0x80);?//WP=1,不能写入
else
Write1302(0x8E,0x00);//WP=0,可以写入?
}
void?DS1302_SetTime(unsigned?char?Address,?unsigned?char?Value)????????//?设置时间函数
{DS1302_SetProtect(0);
Write1302(Address,?((Value/10)《《4?|?(Value%10)));?//高4位为十位,低4位为个位
DS1302_SetProtect(1);
}
//获取时间函数,从DS1302内读取时间然后存入Time内
void?DS1302_GetTime(SYSTEMTIME?*Time)
{unsigned?char?ReadValue;
ReadValue?=?Read1302(DS1302_SECOND);
Time-》Second?=?((ReadValue&0x70)》》4)*10?+?(ReadValue&0x0F);//转换成10进制的秒
ReadValue?=?Read1302(DS1302_MINUTE);
Time-》Minute?=?((ReadValue&0x70)》》4)*10?+?(ReadValue&0x0F);
ReadValue?=?Read1302(DS1302_HOUR);
Time-》Hour?=?((ReadValue&0x70)》》4)*10?+?(ReadValue&0x0F);
ReadValue?=?Read1302(DS1302_DAY);
Time-》Day?=?((ReadValue&0x70)》》4)*10?+?(ReadValue&0x0F);
ReadValue?=?Read1302(DS1302_WEEK);
Time-》Week?=?((ReadValue&0x70)》》4)*10?+?(ReadValue&0x0F);
ReadValue?=?Read1302(DS1302_MONTH);
Time-》Month?=?((ReadValue&0x70)》》4)*10?+?(ReadValue&0x0F);
ReadValue?=?Read1302(DS1302_YEAR);
Time-》Year?=?((ReadValue&0x70)》》4)*10?+?(ReadValue&0x0F);
}
//利用STime初始化DS1302
void?Initial_DS1302(SYSTEMTIME?STime)
{unsigned?char?Second=Read1302(DS1302_SECOND);
if(Second&0x80)??DS1302_SetTime(DS1302_SECOND,0);??//如果第七为1(表明没有启动),?则启动时钟??
DS1302_SetTime(DS1302_SECOND,STime.Second);?//设定起始时间
DS1302_SetTime(DS1302_MINUTE,STime.Minute);
DS1302_SetTime(DS1302_HOUR,STime.Hour);
DS1302_SetTime(DS1302_DAY,STime.Day);
DS1302_SetTime(DS1302_MONTH,STime.Month);
DS1302_SetTime(DS1302_YEAR,STime.Year);
DS1302_SetTime(DS1302_WEEK,STime.Week);
}
#endif
;=====液晶屏通信引脚定义=====
RS BIT P2.6
RW BIT P2.5
E BIT P2.7
DB0_DB7 EQU P0
;=====DS1302通信引脚定义=====
RST BIT P3.5
SCLK BIT P3.6
IO BIT P3.4
;=====数据设定引脚定义========
MODE BIT P3.1
JIA BIT P3.2
JIAN BIT P3.3
;=====定义数据存储地址========
DS1302_ADDR DATA 30H ;地址寄存器
DS1302_DATA DATA 31H ;数据寄存器
TIME_YEAR DATA 32H ;年寄存器
TIME_MONT DATA 33H ;月寄存器
TIME_DAY DATA 34H ;天寄存器
WEEK_DATA DATA 35H ;星期寄存器
HOUR DATA 36H ;小时寄存器
MINTUE DATA 37H ;分钟寄存器
SECOND DATA 38H ;秒钟寄存器
;=========显示数据缓冲地址============
YEAR_HBUF DATA 40H
YEAR_LBUF DATA 41H
MONT_HBUF DATA 42H
MONT_LBUF DATA 43H
DAY_HBUF DATA 44H
DAY_LBUF DATA 45H
WEEK_HBUF DATA 46H
WEEK_LBUF DATA 47H
HOUR_HBUF DATA 48H
HOUR_LBUF DATA 49H
MINTUE_HBUF DATA 4AH
MINTUE_LBUF DATA 4BH
SECOND_HBUF DATA 4CH
SECOND_LBUF DATA 4DH
;============程序开始==============
ORG 00H
AJMP START
;==================================
ORG 0050H
START:
MOV SP,#70H
LCALL INITIALZE ;调用初始化液晶屏幕
LCALL INIT_P ;调用初始画面
MOV A, #00000001B ;清液晶屏,写成空白
LCALL WRITE_COM
;============主程序================
MAIN:
LCALL RD_DS1302
LCALL DATA_BUF
LCALL DISPLAY
AJMP MAIN
;==========读1302子程序=================
RD_DS1302:
MOV DS1302_ADDR,#8DH ;读DS1302中的年
LCALL READ ;调用读DS1302子程序
MOV TIME_YEAR, DS1302_DATA ;把读出的年数据存入年寄存器中
MOV DS1302_ADDR,#8BH ;读DS1302中的星期
LCALL READ
MOV WEEK_DATA, DS1302_DATA ;把读出的星期数据存入星期寄存器中
MOV DS1302_ADDR,#89H ;读DS1302中的月
LCALL READ
MOV TIME_MONT, DS1302_DATA ;把读出的月数据存入月寄存器中
MOV DS1302_ADDR,#87H ;读DS1302中的天
LCALL READ
MOV TIME_DAY, DS1302_DATA ;把读出的天数据存入天寄存器中
MOV DS1302_ADDR,#85H ;读DS1302中的小时
LCALL READ
MOV HOUR, DS1302_DATA ;把读出的天数据存入小时寄存器中
MOV DS1302_ADDR,#83H ;读DS1302中的分钟
LCALL READ
MOV MINTUE, DS1302_DATA ;把读出的天数据存入分钟寄存器中
MOV DS1302_ADDR,#81H ;读DS1302中的秒钟
LCALL READ
MOV SECOND, DS1302_DATA ;把读出的天数据存入秒钟寄存器中
RET
;===========按键子程序=================
;=========数据分离后送显示缓存==================
DATA_BUF:
MOV R0,TIME_YEAR ;年数据分离,送显示缓存
LCALL DIVIDE
MOV YEAR_HBUF,R1
MOV YEAR_LBUF,R2
MOV R0,TIME_MONT ;月数据分离,送显示缓存
LCALL DIVIDE
MOV MONT_HBUF,R1
MOV MONT_LBUF,R2
MOV R0,TIME_DAY ;日数据分离,送显示缓存
LCALL DIVIDE
MOV DAY_HBUF,R1
MOV DAY_LBUF,R2
MOV R0,WEEK_DATA ;星期数据分离,送显示缓存
LCALL DIVIDE
MOV WEEK_HBUF,R1
MOV WEEK_LBUF,R2
MOV R0,HOUR ;小时数据分离,送显示缓存
LCALL DIVIDE
MOV HOUR_HBUF,R1
MOV HOUR_LBUF,R2
MOV R0,MINTUE ;分钟数据分离,送显示缓存
LCALL DIVIDE
MOV MINTUE_HBUF,R1
MOV MINTUE_LBUF,R2
MOV R0,SECOND ;秒钟数据分离,送显示缓存
LCALL DIVIDE
MOV SECOND_HBUF,R1
MOV SECOND_LBUF,R2
RET
;=========日历显示子程序==========
DISPLAY:
MOV A,#10000001B ;设定年第1位的显示地址为第1行,第1列
LCALL WRITE_COM
MOV A, #32H ;数字2的ASCII码
LCALL WRITE_DATA
MOV A,#10000010B ;设定年第2位的显示地址为第1行,第2列
LCALL WRITE_COM
MOV A, #30H ;数字0的ASCII码
LCALL WRITE_DATA
MOV A,#10000011B ;设定年第3位的显示地址为第1行,第3列
LCALL WRITE_COM
MOV A, YEAR_LBUF ;年的底位缓存数据
ADD A,#30H ;加30H修正取ASCII码
LCALL WRITE_DATA
MOV A,#10000100B ;设定年第4位的显示地址为第1行,第4列
LCALL WRITE_COM
MOV A, YEAR_HBUF ;年的高位缓存数据
ADD A,#30H ;加30H修正取ASCII码
LCALL WRITE_DATA
MOV A,#10000101B ;设定斜线的显示地址为第1行,第5列
LCALL WRITE_COM
MOV A,#2FH ;斜线的ASCII码
LCALL WRITE_DATA
MOV A,#10000110B ;设定月第1位的显示地址为第1行,第6列
LCALL WRITE_COM
MOV A, MONT_LBUF ;月的低位缓存数据
ADD A,#30H ;加30H修正取ASCII码
LCALL WRITE_DATA
MOV A,#10000111B ;设定月第2位的显示地址为第1行,第7列
LCALL WRITE_COM
MOV A, MONT_HBUF ;月的高位缓存数据
ADD A,#30H ;加30H修正取ASCII码
LCALL WRITE_DATA
MOV A,#10001000B ;设定斜线的显示地址为第1行,第8列
LCALL WRITE_COM
MOV A,#2FH ;斜线的ASCII码
LCALL WRITE_DATA
MOV A,#10001001B ;设定天第1位的显示地址为第1行,第9列
LCALL WRITE_COM
MOV A, DAY_LBUF ;天的低位缓存数据
ADD A,#30H ;加30H修正取ASCII码
LCALL WRITE_DATA
MOV A,#10001010B ;设定天第2位的显示地址为第1行,第10列
LCALL WRITE_COM
MOV A, DAY_HBUF ;天的高位缓存数据
ADD A,#30H ;加30H修正取ASCII码
LCALL WRITE_DATA
MOV A,#10001101B ;设定星期第2位的显示地址为第1行,第13列
LCALL WRITE_COM
MOV A, WEEK_DATA ;星期的高位缓存数据
SUBB A,#1
ADD A,#30H ;加30H修正取ASCII码
LCALL WRITE_DATA
MOV A,#11000000B ;设定小时第1位的显示地址为第2行,第0列
LCALL WRITE_COM
MOV A, HOUR_LBUF ;小时的低位缓存数据
ADD A,#30H ;加30H修正取ASCII码
LCALL WRITE_DATA
MOV A,#11000001B ;设定小时第2位的显示地址为第2行,第1列
LCALL WRITE_COM
MOV A, HOUR_HBUF ;小时的高位缓存数据
ADD A,#30H ;加30H修正取ASCII码
LCALL WRITE_DATA
MOV A,#11000010B ;设定冒号的显示地址为第2行,第2列
LCALL WRITE_COM
MOV A, #3AH ;冒号的ASCII码
LCALL WRITE_DATA
MOV A,#11000011B ;设定分钟第1位的显示地址为第2行,第3列
LCALL WRITE_COM
MOV A, MINTUE_LBUF ;分钟的低位缓存数据
ADD A,#30H ;加30H修正取ASCII码
LCALL WRITE_DATA
MOV A,#11000100B ;设定分钟第2位的显示地址为第2行,第4列
LCALL WRITE_COM
MOV A, MINTUE_HBUF ;分钟的高位缓存数据
ADD A,#30H ;加30H修正取ASCII码
LCALL WRITE_DATA
MOV A,#11000101B ;设定冒号的显示地址为第2行,第5列
LCALL WRITE_COM
MOV A, #3AH ;冒号的ASCII码
LCALL WRITE_DATA
MOV A,#11000110B ;设定秒钟第1位的显示地址为第2行,第6列
LCALL WRITE_COM
MOV A, SECOND_LBUF ;秒钟的低位缓存数据
ADD A,#30H ;加30H修正取ASCII码
LCALL WRITE_DATA
MOV A,#11000111B ;设定秒钟第2位的显示地址为第2行,第7列
LCALL WRITE_COM
MOV A, SECOND_HBUF ;秒钟的高位缓存数据
ADD A,#30H ;加30H修正取ASCII码
LCALL WRITE_DATA
RET
;=========初始画面==============
INIT_P:
MOV A,#10000000B ;设定显示地址1000为第1行,1010为第0列
LCALL WRITE_COM ;调用写液晶指令子程序
MOV DPTR,#LINE1
LCALL DISP
MOV A,#11000000B ;设定显示地址1100为第2行,1010为第0列
LCALL WRITE_COM ;调用写液晶指令子程序
MOV DPTR,#LINE2
LCALL DISP
LCALL DELAY2 ;调用延时2秒程序
RET
;=========显示的字符串============
LINE1: DB ’ Welcome Use ’
LINE2: DB ’ wan nian li’
;========液晶初始化===============
INITIALZE:
MOV A, #00111000B ;8位数据,双行显示,5-7字型
LCALL WRITE_COM ;调用写液晶指令
MOV A, #00001100B ;显示屏开启,光标出现在地址计数器位置,光标不闪烁
LCALL WRITE_COM ;调用写液晶指令
MOV A, #00000110B ;光标右移一格,AC值加一,字符全部不动
LCALL WRITE_COM ;调用写液晶指令
CLR A
;========DS1302初始化===========
MOV DS1302_ADDR, #8EH ;写DS1302控制指令
MOV DS1302_DATA, #00H ;写数据到DS1302的8E控制寄存器中,允许对其进行写操作
LCALL WRITE ;调用写DS1302子程序
MOV DS1302_ADDR, #90H ;写DS1302控制指令
MOV DS1302_DATA,#0A6H ;写数据到DS1302的90控制寄存器中,对电池涓流充电,充电电流为1.1mA
LCALL WRITE ;调用写DS1302子程序
RET
;=========查询忙碌标志============
CHECK_BUSY:
PUSH ACC
BUSY_LOOP:
CLR E
SETB RW
CLR RS
SETB E
MOV A, DB0_DB7
JB p0.7,BUSY_LOOP
POP ACC
LCALL DEL
RET
;=========写指令到液晶=============
WRITE_COM:
LCALL CHECK_BUSY
CLR E
CLR RS
CLR RW
SETB E
MOV DB0_DB7,A
CLR E
RET
;==========写数据到液晶==============
WRITE_DATA:
LCALL CHECK_BUSY
CLR E
SETB RS
CLR RW
SETB E
MOV DB0_DB7,A
CLR E
RET
;===========延时程序===================
DEL:
MOV R6,#5
L1:
MOV R7,#248
DJNZ R7,$
DJNZ R6,L1
RET
;===========显示字符串到LCM==============
DISP:
PUSH ACC
DISP_LOOP:
CLR A
MOVC A,@A+DPTR
JZ END_DISP ;若A的内容为0.则终止查表
LCALL WRITE_DATA
INC DPTR
SJMP DISP_LOOP
END_DISP:
POP ACC
RET
;***********写1302程序*************
WRITE:
CLR SCLK
NOP
SETB RST
NOP
MOV A,DS1302_ADDR
MOV R4,#8
WRITE1:
RRC A ;送地址给1302
NOP
NOP
CLR SCLK
NOP
NOP
NOP
MOV IO,C
SETB SCLK ;送入地址在时钟上升沿有效
NOP
NOP
NOP
NOP
DJNZ R4,WRITE1
CLR SCLK
NOP
MOV A,DS1302_DATA
MOV R4,#8
WRITE2:
RRC A
NOP ;送数据给1302,时钟上升沿,数据输入
CLR SCLK
NOP
NOP
MOV IO,C
NOP
NOP
NOP
SETB SCLK
NOP
NOP
DJNZ R4,WRITE2
CLR RST
CLR A
RET
;**********读1302程序************
READ:
CLR SCLK
NOP
NOP
SETB RST
NOP
MOV A,DS1302_ADDR
MOV R4,#8
READ1:
RRC A
NOP
MOV IO,C
NOP
NOP
NOP
SETB SCLK ;送入地址在时钟上升沿有效
NOP
NOP
NOP
CLR SCLK
NOP
NOP
DJNZ R4,READ1 ;判断8位数据是否传送完?
MOV R4,#8
READ2:
CLR SCLK
NOP
NOP
NOP
MOV C,IO
NOP
NOP
NOP
NOP
NOP ;从ds1302中读取数据,时钟下降沿有效
RRC A
NOP
NOP
NOP
NOP
SETB SCLK
NOP
DJNZ R4,READ2 ;判断8位数据是否传送完?
MOV DS1302_DATA,A
CLR RST
RET
;==========分离数据子程序=========
DIVIDE:
MOV A,R0
ANL A,#0FH ;屏蔽掉低4位,留下高4位
MOV R1,A
MOV A,R0
SWAP A ;A中数据高4位与低4位互换
ANL A,#0FH ;实际上是屏蔽掉了高4位,留下低4位
MOV R2,A
RET
;========延时2秒子程序=============
DELAY2:
MOV R5,#20
D3:
MOV R6,#200
D2:
MOV R7,#250
DJNZ R7,$
DJNZ R6,D2
DJNZ R5,D3
RET
END
DS1302程序:
#include?“ds1302.h“
unsigned?char?time_buf1?=?{20,9,3,13,18,51,00,6};//空年月日时分秒周
unsigned?char?time_buf?;?????????????????????????//空年月日时分秒周
/*------------------------------------------------
???????????向DS1302写入一字节数据
------------------------------------------------*/
void?Ds1302_Write_Byte(unsigned?char?addr,?unsigned?char?d)
{
?unsigned?char?i;
?RST_SET;?
?
?//写入目标地址:addr
?addr?=?addr?&?0xFE;?????//最低位置零
?for?(i?=?0;?i?《?8;?i?++)?
?????{?
??if?(addr?&?0x01)?
??????{
???IO_SET;
???}
??else?
??????{
???IO_CLR;
???}
??SCK_SET;
??SCK_CLR;
??addr?=?addr?》》?1;
??}
?
?//写入数据:d
?for?(i?=?0;?i?《?8;?i?++)?
????{
??if?(d?&?0x01)?
??????{
???IO_SET;
???}
??else?
??????{
???IO_CLR;
???}
??SCK_SET;
??SCK_CLR;
??d?=?d?》》?1;
??}
?RST_CLR;?????//停止DS1302总线
}
/*------------------------------------------------
???????????从DS1302读出一字节数据
------------------------------------------------*/
unsigned?char?Ds1302_Read_Byte(unsigned?char?addr)?
{
?unsigned?char?i;
?unsigned?char?temp;
?RST_SET;?
?//写入目标地址:addr
?addr?=?addr?|?0x01;//最低位置高
?for?(i?=?0;?i?《?8;?i?++)?
?????{
??????
??if?(addr?&?0x01)?
?????{
???IO_SET;
???}
??else?
??????{
???IO_CLR;
???}
??SCK_SET;
??SCK_CLR;
??addr?=?addr?》》?1;
??}
?
?//输出数据:temp
?for?(i?=?0;?i?《?8;?i?++)?
?????{
??temp?=?temp?》》?1;
??if?(IO_R)?
?????{
???temp?|=?0x80;
???}
??else?
?????{
???temp?&=?0x7F;
???}
??SCK_SET;
??SCK_CLR;
??}
?
?RST_CLR;?//停止DS1302总线
?return?temp;
}
/*------------------------------------------------
???????????向DS1302写入时钟数据
------------------------------------------------*/
void?Ds1302_Write_Time(void)?
{
?????
????unsigned?char?i,tmp;
?for(i=0;i《8;i++)
?????{??????????????????//BCD处理
??tmp=time_buf1/10;
??time_buf%10;
??time_buf+tmp*16;
?????}
?Ds1302_Write_Byte(ds1302_control_add,0x00);???//关闭写保护?
?Ds1302_Write_Byte(ds1302_sec_add,0x80);????//暂停?
?//Ds1302_Write_Byte(ds1302_charger_add,0xa9);???//涓流充电?
?Ds1302_Write_Byte(ds1302_year_add,time_buf);??//年?
?Ds1302_Write_Byte(ds1302_month_add,time_buf);?//月?
?Ds1302_Write_Byte(ds1302_date_add,time_buf);??//日?
?Ds1302_Write_Byte(ds1302_day_add,time_buf);??//周?
?Ds1302_Write_Byte(ds1302_hr_add,time_buf);??//时?
?Ds1302_Write_Byte(ds1302_min_add,time_buf);??//分
?Ds1302_Write_Byte(ds1302_sec_add,time_buf);??//秒
?Ds1302_Write_Byte(ds1302_day_add,time_buf);??//周?
?Ds1302_Write_Byte(ds1302_control_add,0x80);???//打开写保护?
}
/*------------------------------------------------
???????????从DS1302读出时钟数据
------------------------------------------------*/
void?Ds1302_Read_Time(void)??
{?
????????unsigned?char?i,tmp;
?time_buf=Ds1302_Read_Byte(ds1302_year_add);??//年?
?time_buf=Ds1302_Read_Byte(ds1302_month_add);??//月?
?time_buf=Ds1302_Read_Byte(ds1302_date_add);??//日?
?time_buf=Ds1302_Read_Byte(ds1302_hr_add);??//时?
?time_buf=Ds1302_Read_Byte(ds1302_min_add);??//分?
?time_buf=(Ds1302_Read_Byte(ds1302_sec_add))&0x7F;//秒?
?time_buf=Ds1302_Read_Byte(ds1302_day_add);??//周?
?for(i=0;i《8;i++)
????{???????????//BCD处理
??tmp=time_buf/16;
??time_buf1%16;
??time_buf1+tmp*10;
????}
}
/*------------------------------------------------
????????????????DS1302初始化
------------------------------------------------*/
void?Ds1302_Init(void)
{
?
?RST_CLR;???//RST脚置低
?SCK_CLR;???//SCK脚置低
????Ds1302_Write_Byte(ds1302_sec_add,0x00);?????
}
主程序MAIN:
/*-----------------------------------------------
??名称:DS1302时钟数码管显示
??论坛:www.doflye.net
??编写:shifang
??日期:2009.5
??修改:无
??内容:DS1302实时时钟数码管显示,只显示时间。并通过4个按键加减小时、分钟,其他参数调节自行添加
????????
------------------------------------------------*/
#include《reg52.h》?//包含头文件,一般情况不需要改动,头文件包含特殊功能寄存器的定义
#include?“ds1302.h“
#define?KeyPort?P3?//定义按键端口
#define?DataPort?P0?//定义数据端口?程序中遇到DataPort?则用P0?替换
sbit?LATCH1=P2^2;//定义锁存使能端口?段锁存
sbit?LATCH2=P2^3;//?????????????????位锁存
bit?ReadTimeFlag;//定义读时间标志
unsigned?char?code?dofly_DuanMa={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};//?显示段码值0~9
unsigned?char?code?dofly_WeiMa={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};//分别对应相应的数码管点亮,即位码
unsigned?char?TempData;?//存储显示值的全局变量
void?DelayUs2x(unsigned?char?t);//us级延时函数声明?
void?DelayMs(unsigned?char?t);?//ms级延时
void?Display(unsigned?char?FirstBit,unsigned?char?Num);//数码管显示函数
unsigned?char?KeyScan(void);//键盘扫描
void?Init_Timer0(void);//定时器初始化
/*------------------------------------------------
????????????????????主函数
------------------------------------------------*/
void?main?(void)
{
unsigned?char?num;??????????????????
Init_Timer0();
Ds1302_Init();
while?(1)?????????//主循环
??{
?num=KeyScan();
?switch(num)
???????{
?????case?1:time_buf1=0;????
??????????????Ds1302_Write_Time();break;?//正常时间?小时?加1
??case?2:time_buf1=23;??
???????????Ds1302_Write_Time();break;?//正常时间?小时减1
??case?3:time_buf1=0;?????
???????????Ds1302_Write_Time();break;//分加1
??case?4:time_buf1=59;?
???????????Ds1302_Write_Time();break;?//分减1
??default:break;
????}
if(ReadTimeFlag==1)
{
??ReadTimeFlag=0;
??Ds1302_Read_Time();
?//数据的转换,因我们采用数码管0~9的显示,将数据分开
?TempData;?//时??
?TempData;
?TempData=0x40;??????????????????//加入“-“
?TempData;?//分
?TempData;
?TempData=0x40;
?TempData;?//秒
?TempData;?
?}?
??}
}
/*------------------------------------------------
?uS延时函数,含有输入参数?unsigned?char?t,无返回值
?unsigned?char?是定义无符号字符变量,其值的范围是
?0~255?这里使用晶振12M,精确延时请使用汇编,大致延时
?长度如下?T=tx2+5?uS?
------------------------------------------------*/
void?DelayUs2x(unsigned?char?t)
{???
?while(--t);
}
/*------------------------------------------------
?mS延时函数,含有输入参数?unsigned?char?t,无返回值
?unsigned?char?是定义无符号字符变量,其值的范围是
?0~255?这里使用晶振12M,精确延时请使用汇编
------------------------------------------------*/
void?DelayMs(unsigned?char?t)
{
?????
?while(t--)
?{
?????//大致延时1mS
?????DelayUs2x(245);
??DelayUs2x(245);
?}
}
/*------------------------------------------------
?显示函数,用于动态扫描数码管
?输入参数?FirstBit?表示需要显示的第一位,如赋值2表示从第三个数码管开始显示
?如输入0表示从第一个显示。
?Num表示需要显示的位数,如需要显示99两位数值则该值输入2
------------------------------------------------*/
void?Display(unsigned?char?FirstBit,unsigned?char?Num)
{
??????static?unsigned?char?i=0;
???
????DataPort=0;???//清空数据,防止有交替重影
???????LATCH1=1;?????//段锁存
???????LATCH1=0;
???????DataPort=dofly_WeiMa;?//取位码?
???????LATCH2=1;?????//位锁存
???????LATCH2=0;
???????DataPort=TempData;?//取显示数据,段码
???????LATCH1=1;?????//段锁存
???????LATCH1=0;
???????
????i++;
???????if(i==Num)
???????i=0;
}
/*------------------------------------------------
????????????????????定时器初始化子程序
------------------------------------------------*/
void?Init_Timer0(void)
{
?TMOD?|=?0x01;???//使用模式1,16位定时器,使用“|“符号可以在使用多个定时器时不受影响???????
?//TH0=0x00;???????//给定初值
?//TL0=0x00;
?EA=1;????????????//总中断打开
?ET0=1;???????????//定时器中断打开
?TR0=1;???????????//定时器开关打开
}
/*------------------------------------------------
?????????????????定时器中断子程序
------------------------------------------------*/
void?Timer0_isr(void)?interrupt?1?
{
?static?unsigned?int?num;
?TH0=(65536-2000)/256;????//重新赋值?2ms
?TL0=(65536-2000)%256;
?
?Display(0,8);???????//?调用数码管扫描
?num++;
?if(num==50)????????//大致100ms
???{
????num=0;
????ReadTimeFlag=1;?//读标志位置1
?}
}
/*------------------------------------------------
按键扫描函数,返回扫描键值
------------------------------------------------*/
unsigned?char?KeyScan(void)
{
?unsigned?char?keyvalue;
?if(KeyPort!=0xff)
???{
????DelayMs(10);
????if(KeyPort!=0xff)
????{
?????keyvalue=KeyPort;
?????while(KeyPort!=0xff);
??switch(keyvalue)
??{
???case?0xfe:return?1;break;
???case?0xfd:return?2;break;
???case?0xfb:return?3;break;
???case?0xf7:return?4;break;
???case?0xef:return?5;break;
???case?0xdf:return?6;break;
???case?0xbf:return?7;break;
???case?0x7f:return?8;break;
???default:return?0;break;
??}
???}
???}
???return?0;
}
2.3.6 显示模块的设计
本设计中由于要对时间、温度进行显示,所以选择液晶显示屏1602模块作为输出。1602字符型LCD通常有14条引脚线或16条引脚线的LCD,多出来的2条线是背光电源线。它可以显示两行,每行16个字符,采用单+5V电源供电,外围电路配置简单,价格便宜,具有很高的性价比。1602液晶模块内部的字符发生存储器(CGROM)已经存储了160个不同的点阵字符图形,这些字符有:阿拉伯数字、英文字母的大小写、常用的符号、和日文假名等,每一个字符都有一个固定的代码,比如大写的英文字母“A”的代码是01000001B(41H),显示时模块把地址41H中的点阵字符图形显示出来,我们就能看到字母“A”。管脚功能如表2-1所示。
表2-1 LCD1602引脚功能
引脚符号功能说明
1VSS一般接地
2VDD接电源(+5V)
3V0液晶显示器对比度调整端。
4RSRS为寄存器选择。
5R/WR/W为读写信号线。
6EE(或EN)端为使能(enable)端,下降沿使能。
7DB0低4位三态、 双向数据总线 0位(最低位)
8DB1低4位三态、 双向数据总线 1位
9DB2低4位三态、 双向数据总线 2位
10DB3低4位三态、 双向数据总线 3位
11DB4高4位三态、 双向数据总线 4位
12DB5高4位三态、 双向数据总线 5位
13DB6高4位三态、 双向数据总线 6位
14DB7高4位三态、 双向数据总线 7位(最高位)
LCD1602主要管脚介绍:V0为液晶显示器对比度调整端,接正电源时对比度最弱,接地电源时对比度最高,对比度过高时会产生鬼影使用时可以通过一个10K的电位器调整对比度。RS为寄存器选择端,高电平时选择数据寄存器,低电平时选择指令寄存器。R/W为读写信号线端,高电平时进行读操作,低电平时进行写操作。当RS和R/W共同为低电平时可以写入指令或者显示地址;当RS为高电平R/W 为低电平时可以写入数据。E为使能端,当E端由高电平跳变成低电平时,液晶模块执行命令。
将LCD1602的RS端和P2.0,R/W端和P2.1, E 端和P2.2相连,当RS=0时,对LCD1602写入指令;当RS=1时,对LCD1602写入数据。当R/W端接高电平时芯片处于读数据状态,反之处于写数据状态,E端为使能信号端。当R/W为高电平,E端也为高电平,RS为低电平时,液晶显示屏显示需要显示的示数。图2.11为1602液晶显示屏与单片机的硬件连接图。
图2.11 LCD液晶显示与单片机硬件连线图
附录二 部分程序说明
void delay(uint xms) //*******延时函数,有参函数*****//
{ uint x,y;
for(x=xms;x》0;x--)
for(y=110;y》0;y--);
}
//******ds18b20芯片有关子程序******/
void DS18B20_init() //****初始化
{ uint i; tem_ds=0;
i=160; while(i》0) //给DS18B20单总线至少480uS的低电平信号
i--; tem_ds=1; //拉高15~60uS
i=8; while(i》0) i--;
}
void temwritebit(bit instruc_data) //*****写一位*******//
{ int time;
if(instruc_data)
{ tem_ds=0;
time=3; //延时14us
while(time》0)
time--;
tem_ds=1; //写“1“
time=8; //延时35us
while(time》0)
time--;
}
else
{
tem_ds=0; //写0
time=14; //延时62us
while(time》0)
time--;
}
tem_ds=1; //释放数据线
time++;time++;
}
bit temreadbit() //*********读一位*********//
{ uint i;
bit datbit;
tem_ds=0;
i++;
tem_ds=1;
i++;i++;
datbit=tem_ds; //读数据
i=10; //延时45
while(i》0)
i--;
tem_ds=1;
return(datbit);
}
uchar temreadbyte() //********读字节*********//
{ uchar i,j,dat;
dat=0;
for(i=0;i《8;i++)
{ j=temreadbit() ;
dat=(j《《7)|(dat》》1);
}
return(dat);
}
void temwritebyte(uchar instru) //********写字节*********//
{ int i;
for(i=0;i《8;i++)
{temwritebit(instru&01);
instru》》=1;
}
}
uint get_tem() //********获取温度*******//
{ uchar tem_L,tem_H;
DS18B20_init();
delay(1);
temwritebyte(0xcc); //写跳过ROM指令;
temwritebyte(0xbe); //读数据
tem_L=temreadbyte();
tem_H=temreadbyte();
tem=tem_H《《8|tem_L;
f_tem=tem*0.0625;
tem=f_tem ;
return (tem);
}
//******液晶相关程序******/
write_1602com(uchar com) //****液晶写入指令函数****//
{ rs=0; //数据/指令选择置为指令
rw=0; //读写选择置为写
P0=com; //送入数据
delay(1);
en=1; //拉高使能端,为制造有效的下降沿做准备
delay(1);
en=0; //en由高变低,产生下降沿,液晶执行命令
}
write_1602dat(uchar dat) //***液晶写入数据函数****//
{ rs=1; //数据指令选择置为数据
rw=0; //读写选择置为写
P0=dat; //送入数据
delay(1);
en=1; //en置高电平,为制造下降沿做准备
delay(1);
en=0; //en由高变低,产生下降沿,液晶执行命令
}
lcd_init() //***液晶初始化函数****//
{ write_1602com(0x38); //设置液晶工作模式 意思:16*2行显示,5*7点阵,8位数据
write_1602com(0x01); //清显示
write_1602com(0x06); //整屏不移动,光标自动右移
write_1602com(yh+1); //日历显示固定符号从第一行第1个位置之后开始显示
write_1602com(0x0c); //开显示不显示光标
for(a=0;a《14;a++)
{ write_1602dat(tab1); //向液晶屏写日历显示的固定符号部分
delay(3);
}
write_1602com(er+2); //时间显示固定符号写入位置,从第2个位置后开始显示
for(a=0;a《8;a++)
{write_1602dat(tab2); //写显示时间固定符号,两个冒号
delay(3);
}
}
/***************DS1302有关子函数********************/
void write_byte(uchar dat) //*******写一个字节*****//
{ ACC=dat;
RST=1;
for(a=8;a》0;a--)
{ IO=ACC0;
SCLK=0; /*在控制指令字输入后的下一个SCLK时钟的上升沿时*/
SCLK=1; /*数据被写入DS1302*/
ACC=ACC》》1;
}
}
uchar read_byte() //******读一个字节******//
{ RST=1;
for(a=8;a》0;a--)
{ ACC7=IO;
SCLK=1;
SCLK=0;
ACC=ACC》》1;
}
return (ACC);
}
void write_1302(uchar add,uchar dat) //****向1302芯片写函数,指定写入地址,数据**//
{ RST=0;
SCLK=0;
RST=1;
write_byte(add);
write_byte(dat);
SCLK=1;
RST=0;
}
uchar read_1302(uchar add) //****从1302读数据函数,指定读取数据来源地址***//
{ uchar temp;
RST=0;
SCLK=0;
RST=1;
write_byte(add);
temp=read_byte();
SCLK=1;
RST=0;
return(temp);
}
uchar BCD_Decimal(uchar bcd) //*****BCD码转十进制函数****//
{ uchar Decimal;
Decimal=bcd》》4; //BCD高四位表示十位,低四位个位,8421码;
return(Decimal=Decimal*10+(bcd&=0x0F));
}
void ds1302_init() //***1302芯片初始化子函数(2010-01-07,12:00:00,week4)***//
{ RST=0;
SCLK=0;
write_1302(0x8e,0x00); //允许写,禁止写保护
write_1302(0x80,0x00); //向DS1302内写秒寄存器80H写入初始秒数据00
write_1302(0x82,0x00); //向DS1302内写分寄存器82H写入初始分数据00
write_1302(0x84,0x12); //向DS1302内写小时寄存器84H写入初始小时数据12
write_1302(0x8a,0x04); //向DS1302内写周寄存器8aH写入初始周数据4
write_1302(0x86,0x07); //向DS1302内写日期寄存器86H写入初始日期数据07
write_1302(0x88,0x01); //向DS1302内写月份寄存器88H写入初始月份数据01
write_1302(0x8c,0x10); //向DS1302内写年份寄存器8cH写入初始年份数据10
write_1302(0x8e,0x80); //打开写保护
}
void write_temp(uchar add,uchar dat) //****向LCD写温度数据,并指定显示位置****//
{ uchar gw,sw;
gw=dat%10; //取得个位数字
sw=dat/10; //取得十位数字
write_1602com(er+add); //er是头文件规定的值0x80+0x40
write_1602dat(0x30+sw); //数字+30得到该数字的LCD1602显示码
write_1602dat(0x30+gw); //数字+30得到该数字的LCD1602显示码
write_1602dat(0xdf); //显示温度的小圆圈符号,0xdf是液晶屏字符库的该符号地址码
write_1602dat(0x43); //显示“C“符号,0x43是液晶屏字符库里大写C的地址码
}
void write_sfm(uchar add,uchar dat) //向LCD写时分秒,有显示位置加显示数据,两个参数
{uchar gw,sw;
gw=dat%10; //取得个位数字
sw=dat/10; //取得十位数字
write_1602com(er+add); //er是头文件规定的值0x80+0x40//年月日显示将er改为yh即可,其他相同;
write_1602dat(0x30+sw); //数字+30得到该数字的LCD1602显示码
write_1602dat(0x30+gw); //数字+30得到该数字的LCD1602显示码
}
void write_week(uchar week) //****写星期函数*****//
{ write_1602com(yh+0x0c); //星期字符的显示位置
switch(week)
{ case 1:write_1602dat(’M’); //星期数为1时,显示
write_1602dat(’O’);
write_1602dat(’N’);
break; //下面六种选择形式相同将括号中的字符相应修改就行了
}
}
void keyscan() //****************键盘扫描有关函数**********************
{ if(key1==0) //key1为功能键(设置键)
{delay(9); //延时,用于消抖动
if(key1==0) //延时后再次确认按键按下
{buzzer=0; //蜂鸣器短响一次
delay(20);
buzzer=1;
while(!key1); //按键等待释放
key1n++;
if(key1n==9)
key1n=1; //设置按键共有秒、分、时、星期、日、月、年、返回,8个功能循环
switch(key1n)
{ case 1: TR0=0; //关闭定时器
write_1602com(er+0x09); //设置按键按动一次,秒位置显示光标
write_1602com(0x0f); //设置光标为闪烁
temp=(miao)/10*16+(miao)%10; //秒数据写入DS1302
write_1302(0x8e,0x00);
write_1302(0x80,0x80|temp); //miao
write_1302(0x8e,0x80);
break;
case 2: write_1602com(er+6); //按2次fen位置显示光标
write_1602com(0x0f); //下面case3~case7基本相同,改变地址就行了
case 8: write_1602com(0x0c); //按动到第8次,设置光标不闪烁
TR0=1;//打开定时器
temp=(miao)/10*16+(miao)%10;
write_1302(0x8e,0x00);
write_1302(0x80,0x00|temp);//miao数据写入DS1302
write_1302(0x8e,0x80);
break;
}
}
}
//------------------------------加键key2----------------------------
if(key1n!=0) //当key1按下以下。再按以下键才有效(按键次数不等于零)
{if(key2==0) //上调键
{delay(10);
if(key2==0)
{buzzer=0; //蜂鸣器短响一次
delay(20);
buzzer=1;
while(!key2);
switch(key1n)
{ case 1:miao++; //设置键按动1次,调秒
if(miao==60)
miao=0;
write_sfm(0x08,miao);
temp=(miao)/10*16+(miao)%10; //十进制转换成DS1302要求的BCD码
write_1302(0x8e,0x00); //允许写,禁止写保护
write_1302(0x80,temp); ;//向DS1302内写秒寄存器80H写入调整后的数据BCD码
write_1302(0x8e,0x80); //打开写保护
write_1602com(er+0x09); //因为设置液晶的模式是写入数据后,指针自动加一,所以需要光标回位
break;
//下面case2~case7和case1相同将相应的地址改一下就行了。
}
}
}
下面的key3与加键key2形式基本相同;
}
}
void init() //定时器、计数器设置函数
{ TMOD=0x01; //指定定时/计数器的工作方式为1
TH0=0; //定时器T0的高四位=0
TL0=0; //定时器T0的低四位=0
EA=1; //系统允许有开放的中断
ET0=1; //允许T0中断
TR0=1; //开启中断,启动定时器
}
void main() //*********主函数********
{ lcd_init(); //调用液晶屏初始化子函数
ds1302_init(); //调用DS1302时钟的初始化子函数
init(); //调用定时计数器的设置子函数
buzzer=0; //蜂鸣器长响一次
delay(80);
buzzer=1;
while(1) //无限循环下面的语句:
{keyscan();} //调用键盘扫描子函数
}
Void timer0() interrupt 1 //取得并显示日历和时间
{ TH0=0; //重复初始值
TL0=0;
DS18B20_init();
delay(1);
temwritebyte(0xcc); //写跳过ROM指令;
temwritebyte(0x44); //启动温度转换;
flag=get_tem(); //将18b20运行返回的函数结果送到变量flag中,用于显示
//读取秒时分周日月年七个数据(DS1302的读寄存器与写寄存器不一样):
miao = BCD_Decimal(read_1302(0x81));//下面分秒年月日形式相同,改变地址就可以了
//显示温度、秒、时、分数据:
write_temp(12,flag);//显示温度,从第二行第12个字符后开始显示
write_sfm(8,miao);//秒,从第二行第8个字后开始显示(调用时分秒显示子函数)
write_sfm(5,fen);//分,从第二行第5个字符后开始显示
write_sfm(2,shi);//小时,从第二行第2个字符后开始显示
//显示日、月、年数据:
write_nyr(9,ri);//日期,从第二行第9个字符后开始显示
write_nyr(6,yue);//月份,从第二行第6个字符后开始显示
write_nyr(3,nian);//年,从第二行第3个字符后开始显示
write_week(week);
}
主是要3个引脚,SCLK串行时钟脉冲输入端,I/O串行数据输入/输出端,即同双向的,能输入串行数据,也能输出串行数据。RST复位端。它的工作必须要由单片机来控制,写入控制字和初始时间后就可以自动计时了。这完全是要由程序来完成的,硬件工作原理很简单,上电后就能工作了,主要是对32768Hz的时钟脉冲信号计数,得到秒,分,小时,日,月,年,星期的。最根本的是要有单片机用程序来控制,即串行写入控制字,串行读出串行时间。
标签:?? me 显示 数据