51单片机入门实战 (stc15单片机实战指南连载)

实时时钟及数据闪存本实例应用的MCU(32P脚)没有副时钟功能,实时时钟只能用纯软件编写。

实时时钟计数器就采用8位。

秒是0~59十进制的值表示,通过毫秒计数器上溢进行递增计数。

分是0~59十进制的值表示,通过秒计数器上溢进行递增计数。

小时是0~23十进制的值表示,通过分计数器上溢进行递增计数。

日是取1~31十进制的值表示,通过小时计数器的上溢进行递增计数。

计数器进行以下的计数。

• 01~31 (1、 3、 5、 7、 8、 10、 12月)

• 01~30 (4、 6、 9、 11月)

• 01~29 (2月 闰年)

• 01~28 (2月 平年)

月是取1~12十进制的值表示,通过日计数器的上溢进行递增计数。

年是取0~99十进制的值表示,通过月计数器的上溢进行递增计数。

其中能被4整除的是闰年。

实时时钟处理子程序:

DATE_CONT:

MOVA,#0

MOVX,!YEARREG ; 年计数寄存器

XCHA,X

MOV!MDUC,#0X80

MOVWMDAH,#0X0

MOVWMDAL,AX

MOVWMDBH,#0X0

MOVWMDBL,#0X4 ; 年计数寄存器能被4整除是闰年 SET1!DIVST

DATE_LOP:

NOP

NOP

MOVA,!MDUC

BT A.0,$DATE_LOP ; 除运算结束

MOVWAX,!MDCL

CMPWAX,#0

BNZ$DATE_CNTA

SET1!YEAR_BIT ; 置闰年标志

BR $MONTH_STAR

DATE_CNTA:

CLR1!YEAR_BIT ; 清闰年标志

MONTH_STAR:

CMP!MONTHREG,#1 ; 月计数寄存器是1月

BZ $DAY31_CON

CMP!MONTHREG,#3 ; 月计数寄存器是3月

BZ $DAY31_CON

CMP!MONTHREG,#5 ; 月计数寄存器是5月

BZ $DAY31_CON

CMP!MONTHREG,#7 ; 月计数寄存器是7月

BZ $DAY31_CON

CMP!MONTHREG,#8 ; 月计数寄存器是8月

BZ $DAY31_CON

CMP!MONTHREG,#10 ; 月计数寄存器是10月

BZ $DAY31_CON

CMP!MONTHREG,#12 ; 月计数寄存器是12月

BZ $DAY31_CON

CMP!MONTHREG,#4 ; 月计数寄存器是4月

BZ $DAY30_CON

CMP!MONTHREG,#6 ; 月计数寄存器是6月

BZ $DAY30_CON

CMP!MONTHREG,#9 ; 月计数寄存器是9月

BZ $DAY30_CON

CMP!MONTHREG,#11 ; 月计数寄存器是11月

BZ $DAY30_CON

MOVA,!FLASHRG

BT A.7,$DAY29_CON

CMP!DAYREG,#28 ; 日计数寄存器=28天

BNC$MONTH_SET

RET

DAY29_CON:

CMP!DAYREG,#29 ; 日计数寄存器=29天

BNC$MONTH_SET

RET

DAY30_CON:

CMP!DAYREG,#30 ; 日计数寄存器=30天

BNC$MONTH_SET

RET

DAY31_CON:

CMP!DAYREG,#31 ; 日计数寄存器=31天

BNC$MONTH_SET

RET

MONTH_SET:

CMP!MONTHREG,#12 ; 月计数寄存器=12

BNC$YEAR_STRA

INC!MONTHREG ; 月计数寄存器+1

CLRB!DAYREG ; 日计数寄存器归零

RET

YEAR_STRA:

INC!YEARREG ; 年计数寄存器+1

CLRB!MONTHREG ; 月计数寄存器归零

RET

数据闪存的读写是通过一个《Data Flash Library Type04 CC-RL》库文件来完成的。

改文件中包含了一下程序:

_R_FDL_Init

_R_FDL_Read

_PFDL_Close

_R_FDL_ExecuteWrite

_R_FDL_ClearDataFlash

读数据程序在主程序MAIN中,以下是写数据子程序。

写数据到Flash处理子程序:

DAFW_CONT:

MOVA,!FLASHRG

BT A.0,$DAFW_STAR ; 允许写FLASH TO DAFW_STAR

RET

DAFW_STAR:

BT A.1,$DAFW_BLOCK ; 允许块清楚 TO DAFW_BLOCK

MOVWAX,!_g_write_address

CMPWAX,#0X1FFF ; 判断是否所有数据块都已写完

BC $DAFW_WINTS ; _g_write_address < 0X1FFF TO DAFW_WINTS

SET1!ERASES_BT ; 置块清楚标志

RET

DAFW_WINTS:

MOVWDTE,#0XAC

MOVWAX,!_g_write_address

NOP

CALL!_R_FDL_Init

NOP

CALL!_R_FDL_Write

NOP

CALL!_PFDL_Close

MOVWAX,!_g_write_address

ADDWAX,#2

MOVW!_g_write_address,AX

CLR1!FLASH_EN

RET

DAFW_BLOCK:

MOVWDTE,#0XAC

MOV!_g_block_valeu,#0

NOP

CALL!_R_FDL_Init

NOP

CALL!_R_FDL_Erase

CLRB!BLOCK_TIM

MOVWDTE,#0XAC

DAFW_BLOCK_S:

NOP

INC!BLOCK_TIM

CMP!BLOCK_TIM,#100

BC $DAFW_BLOCK_S

MOVWDTE,#0XAC

MOV!_g_block_valeu,#1

NOP

CALL!_R_FDL_Erase

NOP

CALL!_PFDL_Close

MOVWAX,#0

MOVW!_g_write_address,AX

CLR1!ERASES_BT ; 清块清楚标志

RET

好了,基本的子程序模块已分析完了,下篇开始介绍编译器的应用,并介绍初始化文件及主程序的文件。