求大神帮忙说一下这个电子钟的程序详细说明解释(汇编语言的)

求大神帮忙说一下这个电子钟的程序详细说明解释(汇编语言的),第1张

ms50 DATA 31H50ms计数内存地址sec DATA 32H秒计数内存地址min DATA 33H 分计数内存地址hour DATA 34H 时计数内存地址buffer DATA 35H 显示十进制内存起始地址EXTRN CODE(Display8)外部显示子程序(跟硬件设计有关,原文未列出) ORG 0000H LJMP STAR转主程序 ORG 000BH LJMP INT_Timer0转50ms定时器中断处理程序ORG 0100HSTAR: MOV SP,#60H 主程序 MOV ms50,A50ms计数器初始化到0 MOV hour,#12小时初始化为12 MOV min,#59分钟初始化为59 MOV sec,#50秒初始化为50 MOV TH0,#60初始化定时器T0为50ms的数据(跟时钟频率和定时器模式有关) MOV TL0,#176 MOV TMOD,#1初始化定时器模式 MOV IE,#82H设定中断 SETB TR0 开定时器0STAR1: LCALL Display 调用显示转换程序(先将16进制转为BCD码再显示) JNB F0,$等待中断处理完成标志 CLR F0复位中断处理完成标志

SJMP STAR1循环显示中断服务程序INT_Timer0:

MOV TL0,#176-550ms定时器计数器初始值再装入(-5为微调,含响应中断用时) MOV TH0,#60 PUSH 01H压入堆栈 MOV R1,#ms50装入50ms计数内存地址数31H INC @R150ms计数内存加1

CJNE @R1,#20,ExitInt不够1秒,退出 MOV @R1,#050ms计数内存复位为0(31H)

INC R1转为秒内存地址(32H)

INC @R1秒计数内存加1 CJNE @R1,#60,ExitInt1不够60秒,退出 MOV @R1,#0够60秒,秒计数复位为0 INC R1转为分计数内存地址(33H)

INC @R1 分计数内存加1 CJNE @R1,#60,ExitInt1不够60分,退出 MOV @R1,#0够60分,分复位为0 INC R1转为时内存地址(34H) INC @R1 时计数内存加1 CJNE @R1,#24,ExitInt1不够24时,退出 MOV @R1,#0时计数内存复位为0ExitInt1:

SETB F0置位中断处理完成标志ExitInt:

POP 01H恢复现场 RETI 退出中断

HexToBCD:16进制转BCD码

MOV B,#10 DIV AB MOV @R0,B存余数(10进制个位) INC R0转伤地址 MOV @R0,A存伤(10进制十位) INC R0转下一次余数地址 RET

Display:显示转换与调用显示程序

MOV R0,#buffer10进制BCD秒显示缓存地址(35H) MOV A,sec ACALL HexToBCD十进制秒转换后存在(35H)、(36H) MOV @R0,#10H(37H)=#10H,秒与分之间的间隔,无实际意义,或与dispaly8有关

INC R010进制BCD分显示缓存地址(38H)

MOV A,min ACALL HexToBCD十进制分转换后存在(38H)、(39H)

MOV @R0,#10H(3AH)=#10H,分与时之间的间隔,无实际意义,或与dispaly8有关

INC R010进制BCD时显示缓存地址(3BH)

MOV A,hour ACALL HexToBCD十进制时转换后存在(3CH)、(3DH)

MOV R0,#buffer恢复显示缓存地址(35H),为dispaly8置初始显示地址 LCALL Display8调用实际显示程序 RET END

A方案

--------------------------

外加一颗时钟芯片DS1302(非常准确)。

按键为单片机中断。

--------------------------

1、上电时自动显示时、分、秒;

实现方式:上电时单片机去启动DS1202,然后读取里面的时间值,自动显示时、分、秒;

2、设置一个控制按键,按下按键,则时钟以秒为单位开始计时;

实现方式:将DS1302此时的值暂时保存,最为计时开始的时间。

然后不停地读取DS1302里的新的时间值,

并将新的时间值 - 计时开始的时间 = 已计时数值

3、运行状态下可通过控制按键使时钟暂停,同时显示已计时数值;

实现方式:显示步骤2里的已计时数值。

4、停止状态下(已上电),按下复位按钮,时钟复位(清零),并进入下一次计时状态。

实现方式:计时开始的时间换成当前时间。

B方案

--------------------------

采用单片机内部定时器计时(不准)。

按键为单片机中断。

--------------------------

步骤类似,不用去读DS1302的时间,读自己内部的时间。

-------------------------------------------------------------------------------------------------------------------------------------------------------分割线。--------------------------------------------------------------------------

楼上的方案是当前比较常见的方案了。

没有给出程序

先给出A 方案程序如下。。。。//C语言编写。

*头文件*/

#include <reg52.h>

#include <intrins.h>

#define uint unsigned int

#define uchar unsigned char

#define nop() _nop_()

sbit T_CLK = P1^4 /*实时时钟时钟线引脚 */

sbit T_IO = P1^5 /*实时时钟数据线引脚 */

sbit T_RST = P2^2 /*实时时钟复位线引脚 */

sbit ACC0 = ACC^0

sbit ACC7 = ACC^7

sbit time_en_port = P3^7/*时间控制通道寄存器LE控制脚*/

sbit sled_en_port = P3^6/*数码管控制通道寄存器LE控制脚*/

#define sled_dm_port P0 /*定义数码管段码的控制脚*/

#define sled_wm_port P2/*定义数码管位码的控制脚*/

/*定义数码管显示字符跟数字的对应数组关系*/

uchar code mun_to_char[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e}

/* 0123456789abcdef */

/*定义需要点亮的数码管*/

uchar code sled_bit_table[]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f}

uchar data sled_data[8]={0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}/*0-7号SLED缓冲值*/

uchar data led_lighten_bit=0 /*LED灯点亮标志位0-7*/

uchar data time_data[8]={0x00,0x57,0x16,0x00,0x00,0x00,0x00,0x00}/*格式为: 秒 分 时 日 月 星期 年 */

/*-----------------------------------------------

显示部分程序,采用定时器0产生中断,1MS更新一次

------------------------------------------------*/

void SLED_Disp() interrupt 1 using 3

{

TH0 = (65536-1000)/256

TL0 = (65536-1000)/256

time_en_port = 0/*关闭时钟控制通道*/

sled_wm_port = sled_bit_table[led_lighten_bit]/*输出位码数据到数码管*/

sled_dm_port = sled_data[led_lighten_bit]/*输出段码数据到数码管*/

sled_en_port = 1/*打开数码管控制通道*/

sled_en_port = 0/*关闭数码管控制通道*/

sled_wm_port = 0xdf/* 释放P2端口,同时关闭发光二极管显示*/

time_en_port = 1/*打开时钟控制通道*/

led_lighten_bit++

if(led_lighten_bit>=8) led_lighten_bit=0/*8位数码管全动态输出*/

}

void T0_valueSet() /*定义中断方式,中断时间*/

{

TMOD = 0x01 /*定时0,工作在方式1*/

TH0 = (65536-1000)/256

TL0 = (65536-1000)/256

TR0 = 1/*启动计数*/

EA = 1/*开总中断*/

ET0 = 1/*开定时器0中断*/

return

}

/********************************************************************

函 数 名:RTInputByte()

功能:实时时钟写入一字节

说明:往DS1302写入1Byte数据 (内部函数)

入口参数:d 写入的数据

返 回 值:无

设计:zhaojunjie 日期:2002-03-19

修改: 日期:

***********************************************************************/

void RTInputByte(uchar d)

{

uchar i

ACC = d

for(i=8i>0i--)

{

T_IO = ACC0 /*相当于汇编中的 RRC */

T_CLK = 1

T_CLK = 0

ACC = ACC >>1

}

}

/********************************************************************

函 数 名:RTOutputByte()

功能:实时时钟读取一字节

说明:从DS1302读取1Byte数据 (内部函数)

入口参数:无

返 回 值:ACC

设计:zhaojunjie 日期:2002-03-19

修改: 日期:

***********************************************************************/

uchar RTOutputByte(void)

{

uchar i

for(i=8i>0i--)

{

ACC = ACC >>1/*相当于汇编中的 RRC */

ACC7 = T_IO

T_CLK = 1

T_CLK = 0

}

return(ACC)

}

/********************************************************************

函 数 名:W1302()

功能:往DS1302写入数据

说明:先写地址,后写命令/数据 (内部函数)

调用:RTInputByte() , RTOutputByte()

入口参数:ucAddr: DS1302地址, ucData: 要写的数据

返 回 值:无

设计:zhaojunjie 日期:2002-03-19

修改: 日期:

***********************************************************************/

void W1302(uchar ucAddr, uchar ucDa)

{

T_RST = 0

T_CLK = 0

T_RST = 1

RTInputByte(ucAddr) /* 地址,命令 */

RTInputByte(ucDa) /* 写1Byte数据*/

T_CLK = 1

T_RST = 0

}

/********************************************************************

函 数 名:R1302()

功能:读取DS1302某地址的数据

说明:先写地址,后读命令/数据 (内部函数)

调用:RTInputByte() , RTOutputByte()

入口参数:ucAddr: DS1302地址

返 回 值:ucData :读取的数据

设计:zhaojunjie 日期:2002-03-19

修改: 日期:

***********************************************************************/

uchar R1302(uchar ucAddr)

{

uchar ucData

T_RST = 0

T_CLK = 0

T_RST = 1

RTInputByte(ucAddr)/* 地址,命令 */

ucData = RTOutputByte()/* 读1Byte数据 */

T_CLK = 1

T_RST = 0

return(ucData)

}

/********************************************************************

函 数 名:BurstW1302T()

功能:往DS1302写入时钟数据(多字节方式)

说明:先写地址,后写命令/数据

调用:RTInputByte()

入口参数:pWClock: 时钟数据地址 格式为: 秒 分 时 日 月 星期 年 控制

8Byte (BCD码)1B 1B 1B 1B 1B 1B 1B 1B

返 回 值:无

设计:zhaojunjie 日期:2002-03-19

修改: 日期:

***********************************************************************/

void BurstW1302T(uchar *pWClock)

{

uchar i

W1302(0x8e,0x00)/* 控制命令,WP=0,写 *** 作?*/

T_RST = 0

T_CLK = 0

T_RST = 1

RTInputByte(0xbe) /* 0xbe:时钟多字节写命令 */

for (i = 8i>0i--) /*8Byte = 7Byte 时钟数据 + 1Byte 控制*/

{

RTInputByte(*pWClock)/* 写1Byte数据*/

pWClock++

}

T_CLK = 1

T_RST = 0

}

/********************************************************************

函 数 名:BurstR1302T()

功能:读取DS1302时钟数据

说明:先写地址/命令,后读数据(时钟多字节方式)

调用:RTInputByte() , RTOutputByte()

入口参数:pRClock: 读取时钟数据地址 格式为: 秒 分 时 日 月 星期 年

7Byte (BCD码)1B 1B 1B 1B 1B 1B 1B

返 回 值:无

设计:zhaojunjie 日期:2002-03-19

修改: 日期:

***********************************************************************/

void BurstR1302T(uchar *pRClock)

{

uchar i

T_RST = 0

T_CLK = 0

T_RST = 1

RTInputByte(0xbf)/* 0xbf:时钟多字节读命令 */

for (i=8i>0i--)

{

*pRClock = RTOutputByte() /* 读1Byte数据 */

pRClock++

}

T_CLK = 1

T_RST = 0

}

/********************************************************************

函 数 名:Set1302()

功能:设置初始时间

说明:先写地址,后读命令/数据(寄存器多字节方式)

调用:W1302()

入口参数:pClock: 设置时钟数据地址 格式为: 秒 分 时 日 月 星期 年

7Byte (BCD码)1B 1B 1B 1B 1B 1B 1B

返 回 值:无

设计:zhaojunjie 日期:2002-03-19

修改: 日期:

***********************************************************************/

void Set1302(uchar *pClock)

{

uchar i

uchar ucAddr = 0x80

EA = 0

W1302(0x8e,0x00) /* 控制命令,WP=0,写 *** 作?*/

for(i =7i>0i--)

{

W1302(ucAddr,*pClock) /* 秒 分 时 日 月 星期 年 */

pClock++

ucAddr +=2

}

W1302(0x8e,0x80) /* 控制命令,WP=1,写保护?*/

EA = 1

}

/********************************************************************

函 数 名:Get1302()

功能:读取DS1302当前时间

说明:

调用:R1302()

入口参数:ucCurtime: 保存当前时间地址。当前时间格式为: 秒 分 时 日 月 星期 年

7Byte (BCD码) 1B 1B 1B 1B 1B 1B 1B

返 回 值:无

设计:zhaojunjie 日期:2002-03-19

修改: 日期:

***********************************************************************/

void Get1302(uchar ucCurtime[])

{

uchar i

uchar ucAddr = 0x81

EA = 0

for (i=0i<7i++)

{

ucCurtime[i] = R1302(ucAddr)/*格式为: 秒 分 时 日 月 星期 年 */

ucAddr += 2

}

EA = 1

}

void delay_1ms(uchar x)

/* 1MS为单位的延时程序 */

{

uchar j

while(x--){

for(j=0j<125j++)

{}

}

}

void main()

{

T0_valueSet()

Set1302(time_data)

while(1){

Get1302(time_data)

sled_data[0]=mun_to_char[time_data[2]/0x10]

sled_data[1]=mun_to_char[time_data[2]%0x10]

sled_data[3]=mun_to_char[time_data[1]/0x10]

sled_data[4]=mun_to_char[time_data[1]%0x10]

sled_data[6]=mun_to_char[time_data[0]/0x10]

sled_data[7]=mun_to_char[time_data[0]%0x10]

delay_1ms(200)

}

}

方案B.

#include<reg52.h>

#define uchar unsigned char

#define uint unsigned int

sbit dula=P2^6

sbit wela=P2^7

sbit rs=P3^5

sbit lcden=P3^4

sbit s1=P3^0

sbit s2=P3^1

sbit s3=P3^2

sbit rd=P3^7

uchar count,s1num

char miao,shi,fen

uchar code table[]=" 2007-7-30 MON"

uchar code table1[]="00:00:00"

void delay(uint z)

{

uint x,y

for(x=zx>0x--)

for(y=110y>0y--)

}

void write_com(uchar com)

{

rs=0

lcden=0

P0=com

delay(5)

lcden=1

delay(5)

lcden=0

}

void write_date(uchar date)

{

rs=1

lcden=0

P0=date

delay(5)

lcden=1

delay(5)

lcden=0

}

void init()

{

uchar num

dula=0

wela=0

lcden=0

// fen=59

// miao=53

// shi=23

write_com(0x38)

write_com(0x0c)

write_com(0x06)

write_com(0x01)

write_com(0x80)

for(num=0num<15num++)

{

write_date(table[num])

delay(5)

}

write_com(0x80+0x40)

for(num=0num<12num++)

{

write_date(table1[num])

delay(5)

}

TMOD=0x01

TH0=(65536-50000)/256

TL0=(65536-50000)%256

EA=1

ET0=1

TR0=1

}

void write_sfm(uchar add,uchar date)

{

uchar shi,ge

shi=date/10

ge=date%10

write_com(0x80+0x40+add)

write_date(0x30+shi)

write_date(0x30+ge)

}

void keyscan()

{

rd=0

if(s1==0)

{

delay(5)

if(s1==0)

{ s1num++

while(!s1)

if(s1num==1)

{

TR0=0

write_com(0x80+0x40+10)

write_com(0x0f)

}

}

if(s1num==2)

{

write_com(0x80+0x40+7)

}

if(s1num==3)

{

write_com(0x80+0x40+4)

}

if(s1num==4)

{

s1num=0

write_com(0x0c)

TR0=1

}

}

if(s1num!=0)

{

if(s2==0)

{

delay(5)

if(s2==0)

{

while(!s2)

if(s1num==1)

{

miao++

if(miao==60)

miao=0

write_sfm(10,miao)

write_com(0x80+0x40+10)

}

if(s1num==2)

{

fen++

if(fen==60)

fen=0

write_sfm(7,fen)

write_com(0x80+0x40+7)

}

if(s1num==3)

{

shi++

if(shi==24)

shi=0

write_sfm(4,shi)

write_com(0x80+0x40+4)

}

}

}

if(s3==0)

{

delay(5)

if(s3==0)

{

while(!s3)

if(s1num==1)

{

/* if(miao==0)

{

miao=59

write_sfm(10,miao)

write_com(0x80+0x40+10)

}*/

miao--

if(miao==-1)

miao=59

write_sfm(10,miao)

write_com(0x80+0x40+10)

}

if(s1num==2)

{

fen--

if(fen==-1)

fen=59

write_sfm(7,fen)

write_com(0x80+0x40+7)

}

if(s1num==3)

{

shi--

if(shi==-1)

shi=23

write_sfm(4,shi)

write_com(0x80+0x40+4)

}

}

}

}

}

void main()

{

init()

while(1)

{

keyscan()

}

// while(1)

}

void timer0() interrupt 1

{

TH0=(65536-50000)/256

TL0=(65536-50000)%256

count++

if(count==18)

{

count=0

miao++

if(miao==60)

{

miao=0

fen++

if(fen==60)

{

fen=0

shi++

if(shi==24)

{

shi=0

}

write_sfm(4,shi)

}

write_sfm(7,fen)

}

write_sfm(10,miao)

}

}

以上的程序都是用C编写 如果是初学还是直接用C编写吧 虽然汇编也很好用 但是C已经是时代的趋势了。。

如果以上能帮到你 请给分哦。。 有什么不懂得也可以问我。

这个电子钟程序已经基本符合你的要求。希望能对你有用。

程序说明:

显示的时间格式为:12-00-00,既,时-分-秒

按键说明:P3.2为时调节。P3.3为分调节。P3.4为秒调节。这三个按键均是每按一次加一。

晶振说明:12MHZ

数码管说明:共阳数码管。共8个数码管。共用了两个4连共阳数码管。

其中,P0口为数码管的段选,P2口为数码管的位选。

本程序已通过实践验证!!!

汇编源程序如下:

SECOND EQU 30H

MINITE EQU 31H

HOUREQU 32H

HOURK BIT P3.2

MINITEK BIT P3.3

SECONDK BIT P3.4

DISPBUF EQU 40H

DISPBIT EQU 48H

T2SCNTA EQU 49H

T2SCNTB EQU 4AH

TEMPEQU 4BH

ORG 00H

LJMP START

ORG 0BH

LJMP INT_T0

START:MOV SECOND,#00H

MOV MINITE,#00H

MOV HOUR,#12

MOV DISPBIT,#00H

MOV T2SCNTA,#00H

MOV T2SCNTB,#00H

MOV TEMP,#0FEH

LCALL DISP

MOV TMOD,#01H

MOV TH0,#(65536-2000) / 256

MOV TL0,#(65536-2000) MOD 256

SETB TR0

SETB ET0

SETB EA

WT:JB SECONDK,NK1

LCALL DELY10MS

JB SECONDK,NK1

INC SECOND

MOV A,SECOND

CJNE A,#60,NS60

MOV SECOND,#00H

NS60:LCALL DISP

JNB SECONDK,$

NK1:JB MINITEK,NK2

LCALL DELY10MS

JB MINITEK,NK2

INC MINITE

MOV A,MINITE

CJNE A,#60,NM60

MOV MINITE,#00H

NM60:LCALL DISP

JNB MINITEK,$

NK2:JB HOURK,NK3

LCALL DELY10MS

JB HOURK,NK3

INC HOUR

MOV A,HOUR

CJNE A,#24,NH24

MOV HOUR,#00H

NH24:LCALL DISP

JNB HOURK,$

NK3:LJMP WT

DELY10MS:MOV R6,#10

D1:MOV R7,#248

DJNZ R7,$

DJNZ R6,D1

RET

DISP:MOV A,#DISPBUF

ADD A,#8

DEC A

MOV R1,A

MOV A,HOUR

MOV B,#10

DIV AB

MOV @R1,A

DEC R1

MOV A,B

MOV @R1,A

DEC R1

MOV A,#10

MOV @R1,A

DEC R1

MOV A,MINITE

MOV B,#10

DIV AB

MOV @R1,A

DEC R1

MOV A,B

MOV @R1,A

DEC R1

MOV A,#10

MOV@R1,A

DEC R1

MOV A,SECOND

MOV B,#10

DIV AB

MOV @R1,A

DEC R1

MOV A,B

MOV @R1,A

DEC R1

RET

INT_T0:MOV TH0,#(65536-2000) / 256

MOV TL0,#(65536-2000) MOD 256

MOV A,#DISPBUF

ADD A,DISPBIT

MOV R0,A

MOV A,@R0

MOV DPTR,#TABLE

MOVC A,@A+DPTR

MOV P0,A

MOV A,DISPBIT

MOV DPTR,#TAB

MOVC A,@A+DPTR

MOV P2,A

INC DISPBIT

MOV A,DISPBIT

CJNE A,#08H,KNA

MOV DISPBIT,#00H

KNA:INC T2SCNTA

MOV A,T2SCNTA

CJNE A,#100,DONE

MOV T2SCNTA,#00H

INC T2SCNTB

MOV A,T2SCNTB

CJNE A,#05H,DONE

MOV T2SCNTB,#00H

INC SECOND

MOV A,SECOND

CJNE A,#60,NEXT

MOV SECOND,#00H

INC MINITE

MOV A,MINITE

CJNE A,#60,NEXT

MOV MINITE,#00H

INC HOUR

MOV A,HOUR

CJNE A,#24,NEXT

MOV HOUR,#00H

NEXT:LCALL DISP

DONE:RETI

TABLE:DB 0C0H,0F9H,0A4H,0B0H,99H,92H,82H,0F8H,80H,90H,0BFH

TAB:DB 0FEH,0FDH,0FBH,0F7H,0EFH,0DFH,0BFH,07FH

END


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/yw/7753100.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-04-09
下一篇 2023-04-09

发表评论

登录后才能评论

评论列表(0条)

保存