📄 clockc正式版.asm
字号:
;******************
;clockc正式版,LED,16F870,用于改进爱蓓儿 CA-100,张文耀,2003/11/15调试成功,12/2修改注释
;按秒键显示秒,不按秒键即回常态。 2005/12/28改
;******************
pointer equ 0h ;定义间接寻址寄存器地址
tmr0 equ 1h ;定义定时器/计数器0寄存器地址
pcl equ 2h ;定义程序计数器低字节寄存器地址
status equ 3h ;定义状态寄存器地址
fsr equ 4h ;定义文件选择寄存器地址
porta equ 5h ;定义端口a的数据寄存器地址
portb equ 6h ;定义端口b的数据寄存器地址
portc equ 7h ;定义端口C的数据寄存器地址
intcon equ 0bh ;定义中断控制寄存器地址
option_reg equ 81h ;定义选项寄存器地址
trisa equ 85h ;定义端口a的方向控制寄存器地址
trisb equ 86h ;定义端口b的方向控制寄存器地址
trisc equ 87h ;定义端口C的方向控制寄存器地址
z equ 2h ;define fsr bit2
rp0 equ 5h ;定义状态寄存器中的页选位RP0
sec equ 0h ;标志寄存器中的标志位用于交替刷新显示
min equ 1h ;标志寄存器中的标志位用于交替刷新显示
hrs equ 2h ;标志寄存器中的标志位用于交替刷新显示
chg equ 3h ;标志位用于标志SW被按或被显示的小时,分钟,秒进位时被置1
sw1 equ 4h ;标志寄存器中的标志位用于标志设定:switches that are on=1
sw2 equ 5h ;sw1 is seconds,sw2-minutes,
sw3 equ 6h ;sw3-hours
sw_on equ 7h ;有一个SW被按时就被置1
;*** 变量寄存器***
key equ 20h;定义按键状态变化数据寄存器地址指示哪个键被按:bit0-sw1
flags equ 21h;定义标志数据寄存器地址
;7-sw_on ,6-sw3, 5-sw2, 4-sw1, 3-chg, 2-hrs, 1-min,bit0-sec,
display equ 22h;变化的位置:指示哪个DIS.需刷新。
digit1 equ 23h;最右面的dis.有时将seconds送入,有时将minutes送入
digit2 equ 24h;最右面第2的dis,
digit3 equ 25h;
digit4 equ 26h;
;***在某个数量上滚动,例:seconds在196开始,进60就是1秒并产生0***
sec_nth equ 31h;定义秒倍乘因子(变化)数据寄存器地址
seconds equ 32h;定义秒数据寄存器地址
minutes equ 33h;定义分数据寄存器地址
hours equ 34h;定义小时数据寄存器地址
var equ 35h;定义综合计算变化数据寄存器地址
count equ 36h;定义循环变化计数数据寄存器地址
count2 equ 37h;定义第2循环变化计数数据寄存器地址
;***最初化所有输出脚,全暗显示***
org 000h ;定义程序存放区域的起始地址
start
nop ;设置一条ICD必需的空操作指令
bsf status,rp0 ;设置文件寄存器的体1
movlw 03h ;设置选项寄存器内容,分频器给TMR0,并使bit7为0,启动弱上拉
movwf option_reg ;分频比值设为“1:16”
movlw 00h ;将00h先送W
movwf trisa ;再转到方向寄存器a,RA全部设为输出
movwf trisc ;再转到方向寄存器c,RC全部设为输出
movlw 0ffh ;将00h先送W
movwf trisb ;再转到方向寄存器b,RB全部设为输入
bcf status,rp0 ;恢复到文件寄存器的体0
movlw 00h ;blank display
movwf portc ;
;***initilalize 设初始值***
bcf intcon,2 ;将TMR0溢出标志位清0
movlw 01h ;put 01 in TMR0,并启动计时
movwf tmr0
movlw 0feh ;put b'11111110' in w
movwf display ;最初选择显示第1个dis.
movlw 00h ;put all displays to blank
movwf digit1
movwf digit2
movwf digit3
movwf digit4
movlw d'12' ;256-12=244(256*16*244=1秒)
movwf sec_nth ;最初n=244,以后是变化的,用以修正时间
movlw d'196' ;
movwf seconds ;put 196 in,256-196=60
movlw d'196' ;
movwf minutes ;put 196 in,256-196=60
movlw d'255'
movwf hours ;小时最大在12:00开始,+1就溢出:256-255=1
movlw 00h
movwf flags ;将标志寄存器置0
main
;wait for tmr0 to roll-over
tmr0_fill
btfss intcon,2 ;是1跳一步
goto tmr0_fill ;如无溢出就回上继续检测
bcf intcon,2 ;将TMR0溢出标志位清0
incfsz sec_nth,1 ;是0跳,在初始是12的基础上加1,12+244=256,到0即满1秒
goto time_done ;如不满1秒,就去交替刷新显示
movlw d'12' ;
movwf sec_nth ;restore sec_nth variable for next round
check_sw ;根据SW状态设置时间,在后面cycle段落中根据SW状态
;完成了flags各标志位的设置
btfss flags,sw_on;是1(即有SW按下)就跳一步,
goto set_time ;不是1时(即无SW按下)就到set_time(走时进位),
;而不要改变时间
btfsc flags,sw1 ;是0(即无SW1按下)就跳一步
goto set_time ;是1,就照旧去走时进位,sw1被按的特操作在check_seconds段中完成
movlw d'196' ;是0表示SW1没按,必有SW2,3按下,而当设置时间时,需要重置秒到零,
movwf seconds ;
movwf 7fh ;127 in W,
movwf sec_nth ;提高秒计时器1/2秒,用以加速时间设置
btfss flags,sw2 ;是1(即有SW2按下)就跳一步
goto hourset ;是0,即一定是SW3按下
movlw 0afh ;是1,就加快秒计时器,原是256-12=244,现256-175=81
movwf sec_nth ;
incfsz minutes,1 ;在加快秒计时器基础上,分钟+1当然加快,为0跳
goto hourset ;
movlw d'196' ;分钟溢出时,重新给初始值,
movwf minutes ;
hourset
btfsc flags,sw2 ;(不是sw3!) 是0(即必有SW3按下)就跳一步
goto check_time;按下就不改变小时
incfsz hours,1 ;小时加1,结果为0跳一步
goto check_time;
movlw d'244'
movwf hours ;小时溢出时,重新给初始值
goto check_time
set_time ;走时进位及修正
bsf flags,sec ;将sec标志位置1
bsf flags,chg ;将chg标志位置1
incfsz seconds,1 ;add 1 to seconds,为0跳,结果为0即溢出
goto time_done ;不为0就去交替刷新显示
movlw d'196' ;
movwf seconds ;restore seconds variable for next round
bsf flags,min ;将min标志位置1
bsf flags,chg ;将chg标志位置1
movlw d'9'
subwf sec_nth,1 ;每分钟到这里一次,所以每分钟减慢256*16*9=36mS
incfsz minutes,1 ;分钟进位1,为0跳,即需要小时进位就跳
goto time_done ;不需要小时进位就转交替刷新显示
movlw d'196' ;
movwf minutes ;准备下一次
bsf flags,hrs ;将hrs标志位置1
bsf flags,chg ;将chg标志位置1
movlw d'34' ;
addwf sec_nth,1 ;每小时修正34
incfsz hours,1 ;小时+1,如溢出(结果为0)就跳一步
goto time_done ;去交替刷新当前时间显示
movlw d'244' ;小时溢出就转到这里,走时半天才到这里一次
movwf hours ;初始值送入,为下一步作准备
movlw d'3'
subwf sec_nth,1 ;半天修正3
time_done
btfss flags,chg ;是0即无sw被按或显示数进位,直接去读SW状态后送显示,
goto cycle ;是1就先去数制转换,再去读SW状态后送显示
check_seconde ;如果秒键被按而且不在显示秒的模式
btfss flags,sw1 ;是1跳一步
goto check_time;是0就这样
movlw 00h ;SW1被按就这样
movwf digit2
movwf digit3
movwf digit4
movlw d'196' ;
subwf seconds,0 ;秒寄存器的数据减初始值(即真实的数值)送W
movwf digit1 ;秒真实的数值送digit1,之后再分离十位数到digit2
goto split_hex
check_time ;完成十位数为0的小时,分钟送入digit3,1,如不是在下段分离
movlw 00h
movwf digit4 ;在这种情况下,十位数为0
movwf digit2
movlw d'243'
subwf hours,0 ;hours的数值减去243(?为真实数)进W
movwf digit3 ;小时送 digit3
movlw d'196' ;
subwf minutes,0 ;minutes的数值减去196为真实数进W
movwf digit1 ;分钟送 digit1
split_hex ;分离进2个16位变化显示器并写入,2种情况-1:0,秒,2:小时,分钟
movlw 02h ;在以下务必明白:pointer为地址为fsr的数据,fsr为地址
movwf count ;2次循环转换digit1,3
movlw digit1 ;把digit1的地址送入fsr
movwf fsr ;第一次通过,fsr-digit1,第二次,fsr-digit3
goto loop ;这个循环用来定义分钟/秒的放置地方
loop2 ;2种情况:当显示秒时,digit3=0,当不显示秒时,digit3是小时
movlw digit3
movwf fsr ;第二次,FSR=digit3,这个循环用来定义小时的放置地方
loop
movlw d'10'
subwf pointer,1 ;找出在数字中有几个十,减为零时c=0
btfsc status,0 ;c=0(减为零)就跳一步,是否已找完?
goto increment_10s;如果没减完,对10位上加1
addwf pointer,1 ;如果已减完,就不要增加10位上的数,而对已减十的加十以恢复原来的数
goto next_digit ;
increment_10s
incf fsr,1 ;fsr+1,地址+1使下一步能在十位上操作
incf pointer,1 ;由先前的减法确定对十位上加1
decf fsr,1 ;直接地址减1,使操作又回到个位来作减十
goto loop
next_digit
decfsz count,1 ;count-1,结果为0跳(之前被赋值2,所以2次就跳)
goto loop2
convert_hex_to_display;转换16进制的变化量到十进制显示码
movlw digit1 ;将digit1的地址送入fsr,以下用fsr+1的方法,完成digit2-4
movwf fsr ;
movlw 04h ;
movwf count ;为所有4位显示准备循环变化量
next_hex
movf pointer,0 ;由于以下fsr+1,所以是依次把digit1,2,3,4的数据送入W
call return_code;转到16进制数转10进制数的子程序
movwf pointer ;把返回的显示器码送入间接数据寄存器(作动态数字寄存器),
;即分4次完成digit1,2,3,4中16进制数转显示器码
incf fsr,1 ;将fsr+1,用于下一步的动态数字寄存器的地址
decfsz count,1 ;只允许4次循环
goto next_hex ;循环回去
fix_display ;以上已完成中16进制数转十进制显示器码
movlw 00h ;put 0 in w
subwf digit4,0 ;当digit4是0时,z就为1
btfss status,z ;z=1就跳一步
goto fix_sec
movlw 00h
movwf digit4
fix_sec
btfss flags,sw1 ;sw1被按就跳一步
goto clear_flags ;sw1未按就转到标志寄存器的低4位清0
movwf digit3
clear_flags
movlw 0f0h ;put 11110000 in w
andwf flags,1 ;把标志寄存器的低4位(sec,min,hrs,chg)清0,使显示在更新状态
cycle ;循环,用来测SW是否被按,由于换B口,所以关display,
;如有SW被按,则完成各标志位的设置,以在前面的check_sw中动作
movlw 0ffh ;turn off led displays(共阴关)
movwf porta
movlw 0fh ;屏蔽掉高4位
andwf flags,1 ;标志寄存器flags的高4位(SW1-3,SW_on)置0
nop
nop
nop
movf portb,0 ;读B口输入,是“0”即SW被按
movwf var ;转到var寄存器,
btfsc var,1 ;(秒)是0(即SW1被按)跳一步
goto switch2 ;未按就检测SW2
bsf flags,chg ;SW1按下,就将CHG标志位置1
bsf flags,sw1 ;SW1按下,就将SW1标志位置1
bsf flags,sw_on ;SW1按下,就将SW_ON标志位置1
switch2 ;(分)检测SW2是否按下
btfsc var,2 ;是0(即SW2被按)跳一步
goto switch3 ;未按就检测SW3
bsf flags,chg ;SW2按下,就将CHG标志位置1
bsf flags,sw2 ;SW2按下,就将SW1标志位置1
bsf flags,sw_on ;SW2按下,就将SW_ON标志位置1
switch3 ;(小时)检测SW3是否按下
btfsc var,0 ;是0(即SW3被按)跳一步
goto setport ;未按就set display black
bsf flags,chg ;SW3按下,就将CHG标志位置1
bsf flags,sw3 ;SW3按下,就将SW3标志位置1
bsf flags,sw_on ;SW3按下,就将SW_ON标志位置1
setport
movlw 00h
movwf portc ;set display black
;***确定哪个显示器需要刷新,循环点亮它。因哪个亮靠display控制晶体管,
;***因脚都是并联,所以都靠一个通道传输,有效的亮,无效的不亮***
btfss display,0 ;display的0位是1跳一步
movf digit4,0 ;是0就让dispay1亮
btfss display,1 ;display的1位是1跳一步
movf digit3,0 ;是0就让dispay2亮
btfss display,2 ;display的2位是1跳一步
movf digit2,0 ;是0就让dispay3亮
btfss display,3 ;display的3位是1跳一步
movf digit1,0 ;是0就让dispay4亮
movwf portc ;c put the number out to display
btfsc sec_nth,7 ;sec_nth的7位是1跳一步 ??
bsf portc,0 ;将portb的0位(控制显示器的点)置1
movf display,0 ;让需要
movwf porta ;将display的数据送A口,用以交替显示
movwf display ;不是已在display?
rlf display,1 ;数据带C左移
bsf display,0 ;将0位置1
btfss display,4 ;4位是1就跳一步
bcf display,0 ;在4位是0条件下,将0清零
goto main
;***读取显示信息的查表子程序***
return_code
addwf pcl,1 ;地址偏移量加当前PC值
retlw 07eh ;显示信息码:0 ,读取数据后返回。
retlw 0ch ;显示信息码:1
retlw 0b6h ;显示信息码:2
retlw 9eh ;显示信息码:3
retlw 0cch ;显示信息码:4
retlw 0dah ;显示信息码:5
retlw 0fah ;显示信息码:6
retlw 0eh ;显示信息码:7
retlw 0feh ;显示信息码:8
retlw 0ceh ;显示信息码:9
end
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -