?? 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 + -