您的位置 首页 > 资讯

ds1302实时时钟程序流程图(利用ds1302和74ls244实现12位LED的实时电子时钟,分别显示年月日时分,求大佬给C程序)

[本站 ds1302实时时钟程序流程图(利用ds1302和74ls244实现12位LED的实时电子时钟,分别显示年月日时分,求大佬给C程序)利用ds1302和74ls244实现12位LED的实时电子时钟,分别显示年月日时分,求大佬给C程序DS…

ds1302实时时钟程序流程图(利用ds1302和74ls244实现12位LED的实时电子时钟,分别显示年月日时分,求大佬给C程序)

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的时钟脉冲信号计数,得到秒,分,小时,日,月,年,星期的。最根本的是要有单片机用程序来控制,即串行写入控制字,串行读出串行时间。

ds1302实时时钟程序流程图(利用ds1302和74ls244实现12位LED的实时电子时钟,分别显示年月日时分,求大佬给C程序)

标签:??   me   显示   数据

本文来自网络,不代表94汽车车网立场,所有(图文、音视频)均由用户自行上传分享,仅供网友学习交流,版权归原作者。若您的权利被侵害,请联系 56325386@qq.com 删除。转载请注明出处:https://94che.com/qc/157846.html

发表回复

您的电子邮箱地址不会被公开。

返回顶部