⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 clockc正式版.asm

📁 51单片机汇编语言编程
💻 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 + -