;kernel: sys51 r0.99
;project name: doudou's up & down
;designer: ut
;version: 1.0
;date: 2016/11/1
;=============================================================================================
; TIME-SHARING SYSTEM FOR MCS51 RELEASE 0.99
; UT.ZUZU
; COPYRIGHT(2012/5/10-2016/11/--)
;=============================================================================================
;詳細(xì)請查看手冊
;硬件要求
;1、52系列兼容的51單片機(jī),內(nèi)存256字節(jié)或以上。本程序在AT89S52運(yùn)行,24.576MHZ晶振,改變晶振需調(diào)整計(jì)數(shù)器值。晶振頻率越高,控制器性能越好。
;2、256字節(jié)內(nèi)存中,系統(tǒng)使用了大部分高地址部分,0-47由用戶支配,具體請看內(nèi)存分配說明。
;3、一共8個(gè)線程:TASK0到TASK2為3個(gè)主線程,其余為次線程;主線程對9個(gè)寄存器和PSW、AB、DPTR進(jìn)行保護(hù),并預(yù)留堆棧最大嵌套調(diào)用為7級;次線程僅保護(hù)PSW,AB,R0-R3,最大嵌套調(diào)用為2級。
;4、系統(tǒng)可以在調(diào)度程序中喂看門狗,時(shí)間片不可過大,超過4MS不喂狗看門狗發(fā)出系統(tǒng)復(fù)位信號?撮T狗功能可以在配置定義中取消。
;5、分時(shí)過程通過定時(shí)器0進(jìn)行,其初值定義在T0_VALUE中,目前設(shè)置的是5MS時(shí)間片。
;6、系統(tǒng)時(shí)間記錄在SYS_TIME變量中,通過定時(shí)器2進(jìn)行,目前設(shè)置是10MS加1.
;任務(wù)操作說明
;0、任務(wù)的邊界應(yīng)該是循環(huán)。不建議跳出邊界。盡可能的使用系統(tǒng)提供的調(diào)用。
;1、不同任務(wù)可以調(diào)用同一個(gè)子程序,注意子程序內(nèi)受保護(hù)的范圍。
;2、主任務(wù)擁有獨(dú)立的R0-R7、ACC、B、PSW寄存器、DPTR指針。次任務(wù)僅保護(hù)7個(gè)寄存器。
;3、任務(wù)之間可以通過內(nèi)存變量來傳遞信息,注意在寫內(nèi)存時(shí)必須占用系統(tǒng),寫完后再釋放系統(tǒng),建議使用加鎖和解鎖調(diào)用。
;4、系統(tǒng)初始化后所有任務(wù)都是睡眠的,系統(tǒng)會(huì)喚醒任務(wù)0和任務(wù)7,其他任務(wù)的喚醒由用戶操作。任務(wù)7為伺服任務(wù),不建議休眠它或在該任務(wù)中使用系統(tǒng)延時(shí)調(diào)用。(有一種風(fēng)險(xiǎn):所有任務(wù)處于休眠態(tài),會(huì)進(jìn)入待機(jī))
;5、系統(tǒng)的性能與晶振頻率、喚醒的任務(wù)數(shù)量、任務(wù)占用的時(shí)間片有關(guān)系。
;6、任務(wù)有權(quán)殺死或休眠任何任務(wù),如果系統(tǒng)所有任務(wù)都被殺死或休眠,系統(tǒng)會(huì)進(jìn)入節(jié)電POWER_DOWN模式,等待復(fù)位激活。
;7、系統(tǒng)提供10MS刻度的16位系統(tǒng)時(shí)間,由TIMER2來完成。任務(wù)可以根據(jù)自己需要來完成延時(shí)功能,其性能優(yōu)于普通的空等待DELAY子程序。
;8、任務(wù)不可以操作TIMER0和TIMER2這兩個(gè)定時(shí)器,需要時(shí),可以使用TIMER1. 建議不要設(shè)置為高優(yōu)先級,可能導(dǎo)致系統(tǒng)時(shí)間停走。
;注:殺死和休眠的區(qū)別:任務(wù)被殺死后再次喚醒從頭開始運(yùn)行,任務(wù)被休眠后再次喚醒是從原來休眠的地方繼續(xù)運(yùn)行(就像暫停)。
;用戶使用注意:
;1.總計(jì)8個(gè)任務(wù),單個(gè)線程是死循環(huán),所有線程并發(fā)執(zhí)行,可以有限調(diào)整每個(gè)線程的時(shí)間片,默認(rèn)5MS時(shí)間片,合理使用可以滿足實(shí)時(shí)要求。
;2.任務(wù)0到2是主線程,線程內(nèi)寄存器A和B,R0-R7,DPTR都受保護(hù),子程序嵌套調(diào)用最大達(dá)8級。
;3.任務(wù)3到7是次線程,線程內(nèi)寄存器A和B,R0-R3受保護(hù),子程序嵌套調(diào)用最大2級。注意這個(gè)限制條件。嵌套調(diào)用超限將導(dǎo)致堆棧過界破壞,使系統(tǒng)崩潰。
;4.用戶只能使用0-59之間的內(nèi)存空間。
;5.用戶無需考慮堆棧的分配,禁止任務(wù)程序修改堆棧指針SP。
;6.中斷響應(yīng)程序中要注意保護(hù)現(xiàn)場和恢復(fù)現(xiàn)場。
;2012-5-22 R0.91 占用系統(tǒng)和釋放系統(tǒng)改用停止和開啟計(jì)時(shí)器的方式實(shí)現(xiàn)。UNDEBUG
;2012-5-23 R0.92 喂狗簡化到CPL指令 UNDEBUG
;使用時(shí)注意:所有中斷程序內(nèi)要用到PSW,A,B,R0~R7,DPTR,必須事先暫存,返回前恢復(fù),注意它們不受保護(hù)
;2016-11-08 確認(rèn)BUG和注釋?梢宰鳛榉(wěn)定版。
;2016-11-08 R0.99
;為了增強(qiáng)實(shí)用性,擬重新布局內(nèi)存,改用堆棧方式保護(hù)現(xiàn)場,保證3個(gè)主線程,每個(gè)線程分配29字節(jié),增加對DPTR的保護(hù),;增加對PSW的保護(hù)
;可以最大嵌套29-2(PC)-2(DPTR)-10(AB,RG)-1(PSW)=7個(gè)CALL;閹割剩余5個(gè)次線程,每個(gè)線程分配13字節(jié):AB,R0-R3,PC,PSW,最大嵌套2個(gè)CALL。
;總體256字節(jié)的內(nèi)存:3個(gè)主線程:29*3=87;5個(gè)次線程:13*5=65;8個(gè)線程狀態(tài)(優(yōu)先級、SP、鬧鈴H、鬧鈴L)=32;
;系統(tǒng)變量:10;系統(tǒng)堆棧:14;R0-R7:8個(gè)除去。 剩余用戶可用的內(nèi)存區(qū):40字節(jié)
;真可謂:螺螄殼里做道場。
;20161110
;備忘:調(diào)度程序要增加加鎖功能(不切換,好處是總是能進(jìn)系統(tǒng)區(qū)做一些系統(tǒng)要做的事,比如喂狗)
;延時(shí)誤差太大,最大誤差是一個(gè)單位(不累計(jì)),考慮系統(tǒng)(放在時(shí)鐘程序內(nèi))來負(fù)責(zé)高精度大跨度的計(jì)時(shí),和喚醒服務(wù),需要額外16字節(jié)用于8個(gè)線程的鬧鐘記錄。
;看門狗使用指南:時(shí)間片調(diào)節(jié)的太大就會(huì)觸發(fā)看門狗,應(yīng)能根據(jù)需要關(guān)閉看門狗。13位,每一個(gè)機(jī)器周期+1
;時(shí)鐘要方便配置
;注意中斷嵌套的影響 ;注意測量 系統(tǒng)服務(wù)的時(shí)間,及其與中斷時(shí)間的比重,比重和效率成正比 ;中斷響應(yīng)前后次序的關(guān)系分析,用戶怎么用中斷
;喚醒服務(wù)要注意的是:必須留一個(gè)伺服線程,該線程始終保持就緒(不能使用系統(tǒng)延時(shí))。否則有一種風(fēng)險(xiǎn):所有任務(wù)同時(shí)調(diào)用系統(tǒng)延時(shí)而休眠,調(diào)度程序?qū)⑥D(zhuǎn)入節(jié)電模式。要復(fù)位或外部中斷才能恢復(fù)。
;20161111 r0.99基本調(diào)試完成
;0.99版本比較0.92版本特點(diǎn)如下:
;1、充分利用堆棧的特點(diǎn)布局內(nèi)存,使得保護(hù)內(nèi)容的調(diào)整變的靈活。
;2、不改變8個(gè)任務(wù)的總數(shù),但集中資源到3個(gè)主任務(wù)上,增加對psw、dptr寄存器的保護(hù)(原來沒考慮周全,如psw是必須保護(hù)的)。使主任務(wù)不再有束縛。
;3、取消原有的延時(shí)服務(wù),增加系統(tǒng)時(shí)鐘的定時(shí)喚醒服務(wù)功能,每個(gè)任務(wù)可以設(shè)置自己的延時(shí)時(shí)間,然后進(jìn)入休眠態(tài)等待,時(shí)間到了系統(tǒng)時(shí)鐘會(huì)喚醒你。
;4、改變了殺、休眠、喚醒的方式,采用位表示殺死信號、就緒態(tài)、喚醒服務(wù),可以用邏輯的方法快速操作。
;5、增加了調(diào)度程序的加鎖功能,加鎖狀態(tài)下,調(diào)度程序不進(jìn)行任務(wù)切換,但繼續(xù)執(zhí)行其他系統(tǒng)功能。
;6、看門狗、初始時(shí)間片可配置。
;7、任務(wù)7作為伺服線程,可以做一些簡單的脈搏動(dòng)作。伺服線程必須始終就緒,否則有任務(wù)全部休眠的風(fēng)險(xiǎn)。
;0.99的篇幅反而比0.92下降了7%,除了更加實(shí)用以外,顯得更加優(yōu)美。
;實(shí)際應(yīng)用達(dá)到3個(gè)以上時(shí),修復(fù)一些潛在的bug之后,可以升為r1.0版本,并出一份《51多任務(wù)內(nèi)核的應(yīng)用手冊》
;內(nèi)存地圖規(guī)劃
;0-47 用戶
;48-63 鬧鐘數(shù)組-每個(gè)任務(wù)2個(gè)字節(jié),用于指示鬧鐘時(shí)間 /30H
;64-73 系統(tǒng)變量 /40H
;74-87 系統(tǒng)堆棧 7個(gè)CALL 包括中斷 SP_SYS:73 /49H 再壓縮至6個(gè)call
;88-95 任務(wù)優(yōu)先狀態(tài)字節(jié) /58H
;96-103 任務(wù)SP指針 /60H
;104-132 任務(wù)0堆棧 SP0:103 /67H
;133-161 任務(wù)1堆棧 SP1:132 /84H
;162-190 任務(wù)2堆棧 SP2:161 /A1H
;191-203 任務(wù)3堆棧 SP3:190 /BEH
;204-216 任務(wù)4堆棧 SP4:203 /CBH
;217-229 任務(wù)5堆棧 SP5:216 /D8H
;230-242 任務(wù)6堆棧 SP6:229 /E5H
;243-255 任務(wù)7堆棧 SP7:242 /F2H
;NOTE:OPRATING SFR OR RAM WHERE HAVE THE SAME ADDRESS WITH EACH OTHER WILL BE ATTENTED! CARE <DATASHEET OF AT89S52>
;-------------------------------------------------------------------------------
;標(biāo)號定義
PRI_BYTE EQU 0D8H ;INIT PRIORITY OF EVERY TASK ;時(shí)間片;0.5MS:0FCH,1MS:0F8H,2MS:0F0H,5MS:D8H,10MS:B0H,20MS:60H 這里是參考值,初始化時(shí)間片請定義在PRI_BYTE
SYS_SP EQU 4bH ;SYSTEM STACK HEAD
START_TASK_SP EQU 67H
TAB_PRI EQU 58H ;基址 見內(nèi)存分配規(guī)劃
TAB_SP EQU 60H ;基址
TAB_CLK EQU 30H ;BASE
WDT_PIE EQU 00H ;設(shè)置為1E,看門狗開啟,其他值則關(guān)閉看門狗 NO TEST 13位計(jì)時(shí)器1FFF復(fù)位,合計(jì)4MS :意味著啟用看門狗時(shí),時(shí)間片必須小于4MS,占用系統(tǒng)時(shí)也要注意這個(gè)問題,建議用加鎖功能代替占用系統(tǒng)
;系統(tǒng)全局變量定義
sys_bit_byte equ 2fh ;留給系統(tǒng)的8個(gè)標(biāo)志位 位地址78-7fh
TMP_A EQU 40H
TASK_CURT_P EQU 41H ;當(dāng)前的任務(wù)指針
task_sch_p equ 4ah ;調(diào)度任務(wù)指針
CLK_ALARM EQU 42H ;鬧鐘字節(jié) 從左到右每一位依次標(biāo)志任務(wù)0到7的鬧鈴請求,1為有鬧鈴請求
DEAD_SIG EQU 43H ;從左到右每一位依次標(biāo)志任務(wù)0到7的殺死請求,1為有殺死請求
READY_BYTE EQU 44H ;從左到右每一位依次標(biāo)志任務(wù)0到7的就緒狀態(tài),1為就緒
LOCK_BYTE EQU 45H ;5A表示加鎖,其他值表示解鎖
TMP_SP EQU 46H
WDT_BYTE EQU 47H ;狗盆子
SYS_TIME_H EQU 48H ;系統(tǒng)時(shí)鐘高8位
SYS_TIME_L EQU 49H ;系統(tǒng)時(shí)鐘低8位
nouse equ 4bh ;預(yù)留
preempt_bit bit 78h ;是否搶占
delay_sv_bit bit 79h ;定時(shí)器1中斷服務(wù) 標(biāo)志 用于小刻度的延時(shí)需求
preempt_task EQU 2eh ;搶占任務(wù)號 僅0-7有效,搶占后作廢,用于調(diào)度程序切換到指定的任務(wù)去。
delay_times equ 2dh ;用于timer1計(jì)時(shí)刻度的次數(shù)
;系統(tǒng)晶振:24.576MHZ
T0_VALUE_H EQU 0D8H ;時(shí)間片;0.5MS:0FCH,1MS:0F8H,2MS:0F0H,5MS:D8H,10MS:B0H,20MS:60H 這里是初始賦值,初始化時(shí)間片請定義在PRI_BYTE
T0_VALUE_L EQU 00H
T2_VALUE_H EQU 0B0H ;時(shí)鐘刻度 參考上面
T2_VALUE_L EQU 00H
T1_VALUE_H EQU 0fcH ;時(shí)鐘刻度 參考上面 500us
T1_VALUE_L EQU 00h ;
;------------------------------規(guī)劃程序入口
ORG 00H
JMP SYS_START
ORG 03H
;LJMP INT_INT0 ;(INT0)
RETI
ORG 0BH
;LJMP INT_T0 ;(IF0)
LJMP SHARE_SYS
RETI
ORG 13H
;LJMP INT_INT1 ;(INT1)
RETI
ORG 1BH
;LJMP INT_T1 ;(IF1)
JMP sys_ms_svrs
RETI
ORG 23H
;LJMP INT_RTX ;(RI,TI)
RETI
ORG 2BH
;LJMP INT_T2 ;(IF2)
JMP SYS_TIME_RUN
RETI
;標(biāo)記中斷返回:如果意外中斷,直接返回,不至于跳飛;-)
;以下是任務(wù)的入口,應(yīng)和表格中定義一致
ORG 30H
LJMP TASK_0
ORG 38H
LJMP TASK_1
ORG 40H
LJMP TASK_2
ORG 48H
LJMP TASK_3
ORG 50H
LJMP TASK_4
ORG 58H
LJMP TASK_5
ORG 60H
LJMP TASK_6
ORG 68H
LJMP TASK_7
;;開機(jī),從00H跳過來*******************************************
SYS_START:
MOV SP,#SYS_SP ;SYSTEM STACK
MOV WDT_BYTE,#WDT_PIE ;準(zhǔn)備好狗糧
clr preempt_bit
clr delay_sv_bit
mov preempt_task,#0
CALL INIT_RAM ;初始化系統(tǒng)內(nèi)存
CALL INIT_TIMER ;初始化定時(shí)器
CALL USER_INIT ;用戶初始化程序
CALL SYS_TIMER_START ;啟動(dòng)系統(tǒng)定時(shí)器
MOV DEAD_SIG,#0 ;清空殺手信號
MOV R1,#0F8H;
MOV R0,#7;
CALL SET_PRIBYTE ;任務(wù)7時(shí)間片設(shè)置為1MS
MOV READY_BYTE,#10000001B ;任務(wù)0就緒,任務(wù)7當(dāng)作伺服線程,如果沒有一個(gè)線程就緒,會(huì)進(jìn)待機(jī)
MOV TASK_CURT_P,#0
MOV TASK_sch_P,#0
MOV TAB_PRI,#PRI_BYTE ;任務(wù)正常運(yùn)行的要素:不被殺,就緒,優(yōu)先級(時(shí)間片)不要太長(看門狗會(huì)叫),SP狀態(tài)
MOV SP,#START_TASK_SP
LJMP TASK_0 ;進(jìn)入任務(wù)0,啟動(dòng)分時(shí),START SHARE
;;上面用到的子程序:任務(wù)1到7依次初始化各自內(nèi)存空間-----------------------------
INIT_RAM:
MOV R0,#7 ;以此對各任務(wù)進(jìn)行內(nèi)存初始化賦值
ITR0:
CALL TASKRAM_INIT
DJNZ R0,ITR0 ;TASK0任務(wù)作為系統(tǒng)啟動(dòng)的入口,可以不用初始,其內(nèi)容會(huì)在第一個(gè)時(shí)間片中斷后調(diào)度程序會(huì)給予。
;CALL TASKRAM_INIT ;JUST FOR TEST TASK0 RAM INIT
RET
;以下表格用于初始化內(nèi)存用
TAB_1:
DB 067H,084H,0A1H,0BEH,0CBH,0D8H,0E5H,0F2H,00H ;任務(wù)棧頂?shù)刂?br />
TAB_2:
DB 030H,038H,040H,048H,050H,058H,060H,068H,00H ;任務(wù)入口地址 和ORG 30H.. 對應(yīng)
;上面用到的子程序:開機(jī)初始化任務(wù)內(nèi)存操作:1、根據(jù)任務(wù)號查表得棧頂位置、入口位置;2、在棧頂壓入:入口、現(xiàn)場;3、將SP存到SP_I; 4、清就緒態(tài)
;初始化任務(wù)內(nèi)存分主次 ;任務(wù)號先存R0
TASKRAM_INIT:
MOV A,R0
MOV DPTR,#TAB_1
MOVC A,@A+DPTR ;查表得初始SP
MOV TMP_SP,SP
MOV SP,A ;開始壓棧
MOV A,R0
MOV DPTR,#TAB_2
MOVC A,@A+DPTR ;查表得初始PC
MOV 02H,A
PUSH 02H ;PUSH PC_L
MOV 02H,#0
PUSH 02H ;PUSH PC_H PC是16位的
PUSH 02H ;PSW,AB,R0-R7,DPTR
PUSH 02H
PUSH 02H
PUSH 02H
PUSH 02H
PUSH 02H
PUSH 02H
;區(qū)分主次任務(wù)
;任務(wù)號大于2則跳過以下步驟
CLR C
MOV A,#2
SUBB A,R0
JC TKI00
PUSH 02H ;R4 R5 R6 R7 DPL DPH
PUSH 02H
PUSH 02H
PUSH 02H
PUSH 02H
PUSH 02H
TKI00:
;保存SP到數(shù)組,SP--> SP_I
MOV A,#TAB_SP
ADD A,R0
MOV R1,A ;這個(gè)是指針變量,指向當(dāng)前SP的存放地址
MOV @R1,SP ;記錄SP
MOV SP,TMP_SP ;壓棧完成,恢復(fù)SP
;優(yōu)先級字節(jié)賦值初始值
MOV A,#TAB_PRI
ADD A,R0
MOV R1,A
MOV @R1,#PRI_BYTE
;清就緒態(tài)
CALL CLR_READY_BIT
RET
;子程序:以下初始化系統(tǒng)定時(shí)器 TIMER2 DEBUGED 120516 --------------------------
INIT_TIMER:
;TIMER2 SETUP
MOV 0C8H,#00H ;MOV T2CON,#00H
MOV 0C9H,#00H ;MOV T2MOD,#00H
MOV 0CCH,#T2_VALUE_L ;MOV TL2,#T2_VALUE_L
MOV 0CDH,#T2_VALUE_H ;MOV TH2,#T2_VALUE_H
MOV 0CAH,0CCH ;MOV RCAP2L,TL2
MOV 0CBH,0CDH ;MOV RCAP2H,TH2
;TIMER0 SETUP
ANL 88H,#11101111B;TCON CLR TR0 : STOP TIMER0
ANL 89H,#11110000B ;TMOD(SET TIMER0)
ORL 89H,#00000001B ;TMOD(SET TIMER0) MODE:01 16BIT COUNT UP
MOV 8AH,#T0_VALUE_L ;TL0
MOV 8CH,#T0_VALUE_H ;TH0
;TIMER1 SETUP
ANL 88H,#10111111B;TCON CLR TR0 : STOP TIMER1
ANL 89H,#00001111B ;TMOD(SET TIMER0)
ORL 89H,#00010000B ;TMOD(SET TIMER0)MODE:01 16BIT COUNT UP MODE:02 8BIT autoCOUNT UP
MOV 8bH,#T1_VALUE_L ;TL0
MOV 8dH,#T1_VALUE_H ;TH0
RET
;子程序:啟動(dòng)TIMER0和TIMER2 ;DEBUGED 120516---------------------------------
SYS_TIMER_START:
MOV SYS_TIME_H,#00
MOV SYS_TIME_L,#00
MOV IP,#00000000B ;SET PRIORITY
MOV IE,#10101010B ;SETB EA ;SETB ET2 ;SETB ET0 ET1 TO ENABLE INTERUPT OF TIMER2 AND TIMER0 AND TIMER1
ORL 88H,#01010000B ;TCON SETB TR0,TR1 START TIMER0 TIMER1
ORL 0C8H,#00000100B ;ORL T2CON,#00000100B ;SETB TR2 TO START TIMER2
RET
;;系統(tǒng)時(shí)間處理,在TIMER2中斷后跳進(jìn)來
;系統(tǒng)時(shí)間處理有2大內(nèi)容:1、比較各鬧鐘的目標(biāo)時(shí)間是否到達(dá),到達(dá)并且該任務(wù)有喚醒服務(wù),就執(zhí)行喚醒;2、時(shí)鐘刻度加一。
SYS_TIME_RUN:
CLR EA
MOV TMP_SP,SP ;保存A 保護(hù)現(xiàn)場
MOV SP,#SYS_SP ;--------------------------------界面,以下系統(tǒng)區(qū)
MOV TMP_A,PSW
PUSH TMP_A
MOV TMP_A,A ;PUSH A
PUSH TMP_A
MOV TMP_A,B ;PUSH B
PUSH TMP_A
PUSH 00H ;PUSH R0
PUSH 01H ;PUSH R1
PUSH 02H ;PUSH R2
PUSH 03H ;PUSH R3
;處理CLK_ALARM字節(jié)、TAB_CLK數(shù)組
MOV A,CLK_ALARM
JZ STR00 ;沒有服務(wù)時(shí)跳過
MOV R0,#TAB_CLK
MOV R3,SYS_TIME_L
CALL PROC_CMP_BYTE ;低8位比較
MOV R1,A
MOV R0,#TAB_CLK
DEC R0
MOV R3,SYS_TIME_H
CALL PROC_CMP_BYTE ;高8位比較,對比結(jié)果保存到A 1表示相等 0表示不等
ANL A,R1 ;H和L的比較結(jié)果合并
MOV R1,A
MOV A,CLK_ALARM
ANL A,R1 ;與喚醒服務(wù)合并
ORL READY_BYTE,A ;執(zhí)行喚醒
MOV A,R1
CPL A
ANL CLK_ALARM,A ;清喚醒標(biāo)志,表示完成喚醒
STR00:
;16位系統(tǒng)時(shí)鐘+1 放在后面處理,延時(shí)00時(shí)可立即生效
MOV A,SYS_TIME_L
INC SYS_TIME_L
INC A
JNZ $+4
INC SYS_TIME_H
ANL 0C8H,#01111111B ;ANL T2CON,#01111111B ;CLEAR TF2 清TIMER2中斷標(biāo)志
POP 03H ;POP R3
POP 02H ;POP R2
POP 01H ;POP R1
POP 00H ;POP R0
POP TMP_A
MOV B,TMP_A ;POP B
POP TMP_A
MOV A,TMP_A ;POP A ;恢復(fù)現(xiàn)場
POP TMP_A
MOV PSW,TMP_A
MOV SP,TMP_SP ;---------------------------------------------界面,以上系統(tǒng)區(qū)
SETB EA
RETI
;;;;;;;中斷返回
;用于刻度為500us,次數(shù)255的等待服務(wù)。只提供一個(gè)線程使用,出于系統(tǒng)消耗的考慮,500us中斷必須篇幅足夠小。
;定時(shí)器1中斷服務(wù):500us中斷一次,無服務(wù)直接返回。有服務(wù):次數(shù)(time_us字節(jié))為0則讓waiting_task_p任務(wù)搶占(標(biāo)志完成)。不為0時(shí),減一。
;系統(tǒng)需要用一個(gè)字節(jié)的標(biāo)志位2fh,用戶要避開。
;preempt_bit bit 78h ;是否搶占
;delay_sv_bit bit 79h ;定時(shí)器1中斷服務(wù) 標(biāo)志 用于小刻度的延時(shí)需求
;preempt_task EQU 3fh ;搶占任務(wù)號 僅0-7有效,搶占后作廢,用于調(diào)度程序切換到指定的任務(wù)去。
;delay_times equ 3eh ;用于timer1計(jì)時(shí)刻度的次數(shù)
sys_ms_svrs:
jb delay_sv_bit,smsv0 ;無服務(wù)直接返回
MOV 8bH,#T1_VALUE_L ;TL1
MOV 8dH,#T1_VALUE_H ;TH1
reti
smsv0:
;保護(hù)現(xiàn)場
mov tmp_a,a
;查delay_times次數(shù):等于0時(shí),置搶占任務(wù)preempt_bit
mov a,delay_times
jnz smsv1
setb preempt_bit ;置搶占位
clr delay_sv_bit ;清服務(wù)位
ORL 88H,#00100000B ;SETB TF0 ;SOFT INTERUPT TIMER0 TCON-->:TF1:TR1:TF0:TR0:IE1:IT1:IE0:IT0:
;中斷不嵌套,本次中斷返回后進(jìn)入系統(tǒng)中斷
MOV 8bH,#T1_VALUE_L ;TL1
MOV 8dH,#T1_VALUE_H ;TH1
mov tmp_a,a
reti
;次數(shù)減一
smsv1: dec delay_times
;恢復(fù)現(xiàn)場
mov a,tmp_a
MOV 8bH,#T1_VALUE_L ;TL1
MOV 8dH,#T1_VALUE_H ;TH1
reti
;;上面要用到
;;子程序:基地址存R0(間隔1個(gè)字節(jié)的8個(gè)數(shù)組),與系統(tǒng)時(shí)鐘(H或L字節(jié))R3進(jìn)行比較,8次,結(jié)果存放在ACC對應(yīng)的位里面,1表示相等
PROC_CMP_BYTE:
MOV B,#0
MOV R2,#8
MOV A,#15
ADD A,R0
MOV R0,A
PCB00:
MOV A,@R0
CJNE A,03H,PCB01
MOV A,B
SETB C
RRC A
JMP PCB02
PCB01:
MOV A,B
CLR C
RRC A
PCB02: MOV B,A
DEC R0
DEC R0 ;間隔1字節(jié)的指針,從右到左
DJNZ R2,PCB00
MOV A,B
RET
;;調(diào)度程序,在timer0中斷后跳過來。
;;調(diào)度程序的內(nèi)容:1、保護(hù)現(xiàn)場;2、存sp;3、喂狗、執(zhí)行任務(wù)死刑、判斷加鎖;4、切換下一個(gè)就緒的任務(wù)指針;5、調(diào)取新任務(wù)的時(shí)間片設(shè)置到定時(shí)器;6、調(diào)取新sp;7、恢復(fù)現(xiàn)場;8、返回到新任務(wù)。
SHARE_SYS: ;保護(hù)現(xiàn)場先
MOV TMP_A,PSW ;PUSH PSW
PUSH TMP_A
MOV TMP_A,A ;PUSH A
PUSH TMP_A
MOV TMP_A,B ;PUSH B
PUSH TMP_A
PUSH 00H ;PUSH R0
PUSH 01H ;PUSH R1
PUSH 02H ;PUSH R2
PUSH 03H ;PUSH R3
;區(qū)分主次任務(wù)
;TASK_CURT_P 大于2則跳過以下步驟
CLR C
MOV A,#2
SUBB A,TASK_CURT_P
JC SS00
PUSH 04H ;PUSH R4
PUSH 05H ;PUSH R5
PUSH 06H ;PUSH R6
PUSH 07H ;PUSH R7
PUSH DPL
PUSH DPH
SS00: ;存SP到數(shù)組SP
MOV A,#TAB_SP
ADD A,TASK_CURT_P
MOV R0,A ;這個(gè)是指針變量,指向當(dāng)前SP的存放地址
MOV @R0,SP ;記錄SP
;切換SP,以下進(jìn)入系統(tǒng)區(qū)----------------------------------------------------------------INTERFACE
MOV SP,#SYS_SP ;SP指向系統(tǒng)SP
CALL WDT ;喂狗
CALL KILL_TASK ;根據(jù)DEAD_SIG字節(jié),執(zhí)行任務(wù)的死刑 ;-*
;是否上鎖,如果上鎖 LOCK_BYTE= 5AH 則不執(zhí)行任務(wù)切換
MOV A,LOCK_BYTE
CJNE A,#5AH,SS04
JMP SS05
SS04:
mov r1,task_sch_p ;暫存
MOV R6,#10
SELECT_P: ;選擇下一個(gè)任務(wù)
DJNZ R6,SS01 ;選擇次數(shù)計(jì)時(shí),如果連續(xù)選擇超10次就得進(jìn)節(jié)電模式了
MOV P1,#0FFH
ORL 87H,#02H ;INTO POWER-DOWN MODE
LJMP SYS_START ;醒來的話就重新開機(jī)咯
;切換任務(wù)指針(0-7) 全局變量TASK_sch_P 任務(wù)指針,僅此進(jìn)行寫操作
SS01:
INC TASK_sch_P
MOV R0,TASK_sch_P
CJNE R0,#8,SS02 ;超限
MOV TASK_sch_P,#0
;判就緒位,不在就緒態(tài)就跳回 SELECT_P,重復(fù)以上步驟
SS02:
MOV R0,TASK_sch_P
CALL GET_READY_BIT
JNC SELECT_P
;調(diào)度結(jié)束,新的指針在task_sch_p
;是否有搶占信號
jnb preempt_bit,ss06
mov a,preempt_task
clr c
subb a,#8
jnc ss06 ;搶占任務(wù)號無效(大于7)
mov a,preempt_task
cjne a,task_sch_p,ss07 ;如果搶占任務(wù)和本次應(yīng)該調(diào)度的任務(wù)相同,則下一次不要再調(diào)這個(gè)任務(wù)了。(本次調(diào)度生效,否則退回上一次調(diào)度指針)。
jmp ss08
ss07:
mov task_sch_p,r1 ;恢復(fù)調(diào)度指針
ss08:
mov r0,preempt_task
call set_ready_bit ;搶占任務(wù)就緒位
mov task_curt_p,preempt_task ;直接指定任務(wù)號,切換
clr preempt_bit
jmp ss05
ss06: mov task_curt_p,task_sch_p ;調(diào)度盤指針 確定調(diào)度指針和實(shí)際任務(wù)指針分離,解決搶占后調(diào)度不公平問題
SS05:
;取優(yōu)先字節(jié)地址
MOV A,#TAB_PRI
ADD A,TASK_CURT_P
MOV R0,A
;時(shí)間片賦值 ;RESET THE TIMER0
MOV 8AH,#T0_VALUE_L ;TL0
MOV 8CH,@R0 ;TH0 ;MOV TH0,@R0;選中后,優(yōu)先級設(shè)置到時(shí)間片
;取SP_I --> SP
MOV A,#TAB_SP
ADD A,TASK_CURT_P
MOV R0,A
MOV SP,@R0
;以下退出系統(tǒng)態(tài),回到新的任務(wù)態(tài),恢復(fù)現(xiàn)場-------------------------------------------INTERFACE
;區(qū)分主次任務(wù)
;TASK_CURT_P 大于2則跳過以下步驟
CLR C
MOV A,#2
SUBB A,TASK_CURT_P
JC SS03
POP DPH
POP DPL
POP 07H ;POP R7
POP 06H ;POP R6
POP 05H ;POP R5
POP 04H ;POP R4
SS03:
POP 03H ;POP R3
POP 02H ;POP R2
POP 01H ;POP R1
POP 00H ;POP R0
POP TMP_A
MOV B,TMP_A ;POP B
POP TMP_A
MOV A,TMP_A ;POP A
POP TMP_A
MOV PSW,TMP_A
;此時(shí)堆棧內(nèi)當(dāng)前應(yīng)是中斷返回時(shí)的PC值,RETI可以返回。
;ANL 88H,#11011111B ;CLR TF0 ;SOFT INTERUPT TIMER0 TCON-->:TF1:TR1:TF0:TR0:IE1:IT1:IE0:IT0:
RETI
;;子程序:根據(jù)被殺任務(wù)信號字節(jié)8位,從左到右每一位代表任務(wù)0-7是否要?dú)⒌簦?為殺死,0為不殺 來執(zhí)行死刑
;執(zhí)行內(nèi)容:將該任務(wù)的內(nèi)存區(qū)重新初始化(初始化后為休眠態(tài)),下次再輪到時(shí),從頭開始。
KILL_TASK:
MOV R3,#8
KTA00:
MOV A,DEAD_SIG
RRC A
MOV DEAD_SIG,A
JNC KTA01
MOV a,R3
DEC a
mov r0,a
CALL TASKRAM_INIT
KTA01:
DJNZ R3,KTA00
MOV DEAD_SIG,#0 ;清掉所有DEAD信息
RET
;;喂狗子程序
WDT:
MOV 0A6H,WDT_BYTE ;MOV WDTRST,WDT_BYTE WDT_BYTE= 1EH OR E1H
MOV A,WDT_BYTE
CPL A ;取反
MOV WDT_BYTE,A
RET
;;獲取就緒位:在調(diào)度程序中用到
GET_READY_BIT: ;任務(wù)號R0, 執(zhí)行結(jié)束后,結(jié)果的位在C
MOV B,R0
INC B
MOV A,READY_BYTE
GRB00: RLC A
DJNZ B,GRB00
RET
;提供的系統(tǒng)調(diào)用
;-----------------------------------------------------------------------------------------------
;子程序:修改任務(wù)的時(shí)間片,任務(wù)號在R0,優(yōu)先字節(jié)(時(shí)間片)在R1,將優(yōu)先字節(jié)寫入到數(shù)組
SET_PRIBYTE:
MOV A,#TAB_PRI
ADD A,R0
MOV R0,A
MOV A,R1
MOV @R0,A
RET
;子程序:回到調(diào)度程序 DEBUGED 120516
WAITING:
NOP ;留給中斷響應(yīng)的間隙
ORL 88H,#00100000B ;SETB TF0 ;SOFT INTERUPT TIMER0 TCON-->:TF1:TR1:TF0:TR0:IE1:IT1:IE0:IT0:
RET
;子程序:占用系統(tǒng),任務(wù)在讀寫的時(shí)候不允許系統(tǒng)中斷,和frees配套使用
OCCUPY:
;ORL IE,#00000010B ;ENABLE INTERRUPT OF TIMER0 方法1:關(guān)閉timer0的中斷
ANL 88H,#11101111B ;TCON CLR TR0, STOP TIMER0 方法2:關(guān)閉timer0的計(jì)時(shí)
RET
;子程序:釋放系統(tǒng) 和occupy配套使用,任務(wù)占用系統(tǒng)后應(yīng)及時(shí)釋放
FREES:
;ANL IE,#11111101B ;DISABLE INTERUPT OF TIMER0
ORL 88H,#00010000B ;TCON SETB TR0, START TIMER0
RET
;注意:occupy和free要配套用,他們之間就是臨界區(qū),然而occupy會(huì)導(dǎo)致不進(jìn)調(diào)度程序,不建議使用。建議用加鎖和解鎖來實(shí)現(xiàn)臨界區(qū)的操作。
LOCK_SYS:
MOV LOCK_BYTE,#5AH
RET
UNLOCK_SYS:
MOV LOCK_BYTE,#0EEH
RET
;精確的系統(tǒng)延時(shí)-將16位的延時(shí)數(shù),每一位為一個(gè)時(shí)刻,存放在DPTR,計(jì)算目標(biāo)時(shí)間,設(shè)置喚醒任務(wù),休眠自己。等待系統(tǒng)時(shí)鐘在時(shí)間到了再喚醒你,誤差為一個(gè)調(diào)度周期。
;任務(wù)號為全局變量指針TASK_CURT_P
;延時(shí)步驟:1、將dptr個(gè)刻度和當(dāng)前時(shí)間相加得到目標(biāo)時(shí)間,存入到鬧鈴數(shù)組當(dāng)前任務(wù)位置;2、設(shè)置本任務(wù)的喚醒服務(wù)位,當(dāng)目標(biāo)時(shí)間到達(dá),系統(tǒng)時(shí)鐘會(huì)喚醒你;3、進(jìn)入休眠態(tài);
DELAY_SYS:
;計(jì)算目標(biāo)16位目標(biāo)值,存放在TAB_CLK對應(yīng)的位置
MOV A,SYS_TIME_L
ADD A,DPL
MOV DPL,A
MOV A,SYS_TIME_H
ADDC A,DPH ;帶進(jìn)位
MOV DPH,A
MOV A,#TAB_CLK
MOV R0,TASK_CURT_P
ADD A,R0
ADD A,R0
;雙字節(jié)指針
MOV R0,A
MOV @R0,DPH
INC R0
MOV @R0,DPL
;設(shè)置喚醒位,在CLK_ALARM字節(jié),8個(gè)位標(biāo)志8個(gè)任務(wù)的喚醒服務(wù),1為有服務(wù)。
MOV R0,TASK_CURT_P
CALL SET_ALARM_BIT
;清就緒位,在READY_BYTE
MOV R0,TASK_CURT_P
CALL CLR_READY_BIT
;回調(diào)度
ORL 88H,#00100000B
RET
;上面用到的子程序:設(shè)置喚醒服務(wù)的位,任務(wù)號預(yù)先放在R0
SET_ALARM_BIT:
MOV B,R0
MOV A,#10000000B
INC B ;最小任務(wù)號為1
SAB00: DJNZ B,SAB01 ;循環(huán)左移
ORL CLK_ALARM,A
JMP SAB02
SAB01: RR A
JMP SAB00
SAB02:
RET
;子程序:任務(wù)自殺
KILL_SELF:
MOV B,TASK_CURT_P
MOV A,#10000000B
INC B ;最小任務(wù)號為1
KSF00: DJNZ B,KSF01 ;循環(huán)左移
ORL DEAD_SIG,A
JMP KSF02
KSF01: RR A
JMP KSF00
KSF02:
RET
;子程序:殺死,任務(wù)號存R0
KILL_TASK_CALL:
MOV B,R0
MOV A,#10000000B
INC B ;最小任務(wù)號為1
KTSK00: DJNZ B,KTSK01 ;循環(huán)左移
ORL DEAD_SIG,A
JMP KTSK02
KTSK01: RR A
JMP KTSK00
KTSK02:
RET
;子程序:清就緒位,就緒態(tài)字節(jié) 8位 從左到右每一位分別代表任務(wù)0-7是否就緒,1為就緒,0為休眠
;任務(wù)號存在R0
CLR_READY_BIT:
MOV B,R0
MOV A,#01111111B
INC B ;最小任務(wù)號為1
CRB00: DJNZ B,CRB01 ;循環(huán)左移
ANL READY_BYTE,A
JMP CRB02
CRB01: RR A
JMP CRB00
CRB02:
RET
;子程序:置就緒位,上面的相反操作 ;任務(wù)號存在R0
SET_READY_BIT:
MOV B,R0
MOV A,#10000000B
INC B ;最小任務(wù)號為1
SRB00: DJNZ B,SRB01 ;循環(huán)左移
ORL READY_BYTE,A
JMP SRB02
SRB01: RR A
JMP SRB00
SRB02:
RET
;子程序:小刻度的延時(shí)功能(通過定時(shí)器1和搶占機(jī)制完成),次數(shù)放在r0
delay_sys_us:
mov delay_times,r0
mov preempt_task,task_curt_p ;占用的任務(wù)號預(yù)存
mov r0,task_curt_p
call clr_ready_bit ;延時(shí)期間要休眠
setb delay_sv_bit ;開啟延時(shí)服務(wù)
ORL 88H,#00100000B ;SETB TF0 ;SOFT INTERUPT TIMER0 TCON-->:TF1:TR1:TF0:TR0:IE1:IT1:IE0:IT0:
nop
nop ;中斷響應(yīng)
ret
;;;;;;;;;;;;;;;;;;伺服線程:任務(wù)7
task_7:
mov r2,#77h
mov r3,#77h
tk700:
mov r0,#01h
mov r1,#0eh
call delay16b
setb p1.7 ;led 熄滅100ms
mov r0,#0dh
mov r1,#0bdh
call delay16b
clr p1.7 ;led 點(diǎn)亮900ms
jmp tk700
jmp task_7
;r0:h r1:l 16位數(shù)的nop延時(shí) 一個(gè)周期為10.25us(全速) ,高8位放在r0,低8位放在r1
delay16b:
dll00:
mov a,r1
clr c
subb a,#1
mov r1,a
mov a,r0
subb a,#0 ;進(jìn)位 16位數(shù)減一
mov r0,a
div ab ;純粹為了延時(shí)
div ab
nop
nop
mov a,r0
orl a,r1
jnz dll00
ret
;注意:以上僅做了關(guān)于殺死、休眠、喚醒任務(wù)的調(diào)用,僅為了使用方便,實(shí)際使用時(shí)推薦使用更高效的邏輯方法:
;比如:要?dú)⑷蝿?wù)3和6,可以將dead_sig ORL 00010010 即可
;要休眠任務(wù)2和4,可以將ready_byte ANL 11010111 即可
;要喚醒任務(wù)1和7,可以將ready_byte ORL 10000001 即可
;SYSTEM END==============================================================line number of r0.92 is 750
;User's code
;*********************************************************************
;project name: 360度指示器 豆豆的打開關(guān)上
;designer: ut
;version: 1.0
;date: 16-11-16
;*********************************************************************
;用戶在此定義自己的變量地址 及 標(biāo)號 0-46d 0-2cH :一共45個(gè)字節(jié),除去0-7,可以用8-2cH這37個(gè)字節(jié)
;需求:
;1\ 16位數(shù)字鍵,0-9 abcd * #
; 2\ 3位段碼LCD顯示
; 3\ 按下數(shù)字,插入到LCD的左側(cè)。
; 4\ 按下D(回車),LCD的數(shù)字作為角度值,電機(jī)轉(zhuǎn)動(dòng)到指定角度,三位數(shù)字范圍0-999,對360取模,執(zhí)行完畢后再輸入數(shù)字時(shí)LCD清零再插入。
; 5\ 按下A電機(jī)向上微調(diào),按下B電機(jī)向下微調(diào)
; 6\ 按下C,LCD清零。
; 7\ 關(guān)機(jī)時(shí),壁板歸位至270度位置,再切斷電源
; 8\ 開機(jī)時(shí),壁板開啟到0度位置。
;task0: 主線程,開機(jī)初始化,啟動(dòng)其他任務(wù),主循環(huán)是不停的取鍵、取鍵值成功后處理鍵值。
;task1: 電機(jī)移動(dòng),始終試圖將當(dāng)前位置靠近目標(biāo)位置,直到達(dá)到為止。
;task2: 按鍵掃描,轉(zhuǎn)換為鍵值存入到緩沖區(qū)。
;處理鍵值:0-9,執(zhí)行循環(huán)插入 BCD 數(shù)組,如果有清屏標(biāo)志,則先清屏再插入。
;處理鍵值:A-B, 執(zhí)行電機(jī)走12拍,約1度,A為正方向,B為反方向。
;處理鍵值:C, 將BCD全部設(shè)置為0
;處理鍵值:D,將BCD轉(zhuǎn)成一個(gè)16位數(shù),再mod360運(yùn)算,將結(jié)果寫到電機(jī)目標(biāo)值。設(shè)置清屏標(biāo)志。
;關(guān)于顯示:在主線程的循環(huán)中,涉及到BCD變化時(shí),才會(huì)觸發(fā)顯示,顯示過程:將BCD碼轉(zhuǎn)換成段碼,將段碼輸出到HT1621驅(qū)動(dòng)器。
WR_1621 BIT P3.6
;RD_1621 BIT P3.7
DATA_1621 BIT P3.5
CS_1621 BIT P3.7
BIAS EQU 52H; //0B1000 0101 0010 1/3DUTY 4COM
SYSDIS EQU 0; //0B1000 0000 0000 關(guān)振系統(tǒng)蕩器和LCD偏壓發(fā)生器
SYSEN EQU 02H; //0B1000 0000 0010 打開系統(tǒng)振蕩器
LCDOFF EQU 04H; //0B1000 0000 0100 關(guān)LCD偏壓
LCDON EQU 06H; //0B1000 0000 0110 打開LCD偏壓
XTAL EQU 28H; //0B1000 0010 1000 外部接時(shí)鐘
RC256 EQU 30H; //0B1000 0011 0000 內(nèi)部時(shí)鐘
TONEON EQU 12H; //0B1000 0001 0010 打開聲音輸出
TONEOFF EQU 10H; //0B1000 0001 0000 關(guān)閉聲音輸出
WDTDIS EQU 0AH; //0B1000 0000 1010 禁止看門狗
;;;內(nèi)存變量,范圍(8-2cH)
nouse1 equ 20h ;預(yù)留給可尋址的位
nouse2 equ 21h
pool_key equ 21h ;22,23,24;類似堆棧指針,前推一位
p_key equ 25h
pool_bcd equ 26h ;26,27,28;存放bcd碼 循環(huán)覆蓋
p_bcd equ 29h ;存放bcd指針,0-2 循環(huán)
pool_print equ 8h ;8 9 10 存放3位數(shù)碼管的段碼
key_value equ 0bh
p_moto_H equ 0ch
p_moto_L equ 0dh
targ_moto_H equ 0eh
targ_moto_L equ 0fh
p_step equ 10h ;表的指針
p_deg equ 11h
;定義位
key_catched bit 00h ;獲取到一個(gè)按鍵后置位
bcd_ready bit 01h ;bcd插入新值時(shí)置位
moto_dir bit 02h ;電機(jī)方向
tmp_dir bit 03h
reset_bcd bit 04h ;重置bcd
;;用戶在這里寫初始化程序,在系統(tǒng)開機(jī)初始化時(shí),被調(diào)用,注意:此處不可進(jìn)行系統(tǒng)功能的調(diào)用
user_init:
mov p1,#0f0h ;關(guān)電機(jī)
mov 08h,#0 ;段碼區(qū)
mov 09h,#0
mov 0ah,#0
mov 26h,#0 ;bcd區(qū)
mov 27h,#0
mov 28h,#0
mov p_key,#0 ;表示無按鍵
mov p_bcd,#0
mov p_step,#0
mov p_deg,#0
mov p_moto_h,#0
mov p_moto_l,#0
mov targ_moto_h,#0
mov targ_moto_l,#0
clr reset_BCD
clr p2.2 ;開啟關(guān)機(jī)繼電器
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;任務(wù)0 主線程 ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;主線程,1、從鍵盤緩沖池取一個(gè)按鍵; 2、處理該按鍵(數(shù)字鍵插入bcd區(qū))其他鍵(步數(shù)增減、清零、回車)3、bcd轉(zhuǎn)換為段碼,隱去尾部0
;4、段碼輸出
;;;其他按鍵處理:步數(shù)增加一個(gè)幅度,不改變參數(shù),步數(shù)減少一個(gè)幅度,不改變參數(shù),bcd歸零,bcd轉(zhuǎn)換為目標(biāo)值;;;;;;;;;;
;;-----------------------------------任務(wù)0
task_0:
CALL Ht1621_Init;() ; 上電初始化LCD驅(qū)動(dòng)芯片
mov dptr,#tab_ht1621
mov r3,#0
mov r5,#16
call Ht1621WrAllData;(0,Ht1621Tab,16) ;清除1621寄存器數(shù)據(jù),清屏
mov dptr,#tab_ht1621_dou
mov r3,#0
mov r5,#3
call Ht1621WrAllData;(0,Ht1621Tab,3);顯示 ;logo
;LCD的掃描是不需要延時(shí)的
orl ready_byte,#01100000b ;開啟任務(wù)2:鍵盤掃描程序 ;開啟任務(wù)1:電機(jī)驅(qū)動(dòng):實(shí)際值逼近目標(biāo)值
;臂板垂直向下270度為初始態(tài)(壓縮狀態(tài),方便包裝和移動(dòng))在電氣驅(qū)動(dòng)里面初始化。
tsk0tv0:
jb p2.1,tsk04 ;關(guān)機(jī)信號判斷
clr key_catched
call catch_a_key
jnb key_catched,tsk0tv0 ;沒有獲取到鍵值
clr bcd_ready
call key_proc
jnb bcd_ready,tsk0tv0 ;不涉及到bcd變化
call bcd2print ;bcd 轉(zhuǎn)換為段碼
call hide_zero ;消隱尾部的0
mov r3,#0
mov r4,#pool_print
mov r5,#3
; mov lock_byte,#5ah ;加鎖
call print ;輸出到LCD
; mov lock_byte,#11h
jmp tsk0tv0
;;關(guān)機(jī)流程,回到270度位置
tsk04:
mov dptr,#tab_ht1621_off
mov r3,#0
mov r5,#3
call Ht1621WrAllData;(0,Ht1621Tab,3);顯示off
mov targ_moto_l,#0eh
mov targ_moto_h,#01h ;電機(jī)目標(biāo)為270
;等待電機(jī)到點(diǎn)
tsk040: mov a,P_moto_l
cjne a,targ_moto_l,tsk040
mov a,p_moto_h
cjne a,targ_moto_h,tsk040
jnb p2.1,tsk0tv0 ;最后確認(rèn)是否關(guān)機(jī)
setb p2.2 ;關(guān)機(jī)
ORL 87H,#02H ;INTO POWER-DOWN MODE
LJMP SYS_START ;醒來的話就重新開機(jī)咯
;步驟:1、指針為0則無按鍵值,2、取鍵值,指針-1,(臨界區(qū));3處理鍵值;
;print_LCD: 函數(shù) 將3個(gè)字節(jié)的內(nèi)容顯示到LCD 0-f 都能顯示 步奏:1、字節(jié)數(shù)轉(zhuǎn)換到 段碼字節(jié) 2發(fā)送給ht1621
;如何循環(huán)顯示,三個(gè)字節(jié)要構(gòu)成單向環(huán),abcabcabc,始終顯示指針后3位數(shù)字,加入新的字節(jié)時(shí)指針往前推。
;將上面的三個(gè)字節(jié),轉(zhuǎn)為一個(gè)整數(shù)<=999,占2個(gè)字節(jié)。
;設(shè)為目標(biāo)值
;當(dāng)前值與目標(biāo)值比較,不等于則靠近,等于則關(guān)閉。
;關(guān)機(jī)線程
;正或反,步數(shù)n個(gè)。函數(shù)
jmp task_0
;--------task0 end----------
;任務(wù)0子程序:從pool_key,p_key取一個(gè)鍵值,存放在key_value,并置位key_catched
catch_a_key:
;clr key_catched
mov a,p_key
jnz cak00
ret ;p_key 為0表示鍵值池空
cak00:
;臨界區(qū):取一個(gè)鍵值
mov lock_byte,#5ah
mov a,#pool_key
add a,p_key
mov r0,a
mov a,@r0
dec p_key
mov lock_byte,#11;臨界區(qū)
mov key_value,a ;鍵值
setb key_catched
ret
;任務(wù)0子程序:處理當(dāng)前鍵值,小于10放到循環(huán)的bcd池里(pool_bcd,p_bcd),大于10則調(diào)用相關(guān)功能
key_proc:
mov a,key_value
clr c
subb a,#10
jc kpc00
mov a,key_value
cjne a,#0ah,kpc01
;0a鍵功能
call up_a_bit
kpc01: cjne a,#0bh,kpc02
;0b鍵功能
call down_a_bit
kpc02: cjne a,#0ch,kpc03
;0c鍵功能
call clr_bcd
kpc03: cjne a,#0dh,kpc04
;0d鍵功能
setb reset_BCD ;回車后前面的數(shù)據(jù)在下次按鍵輸入后,清掉
call set_target
ret
kpc00: call keyv2bcd
kpc04:
ret
;;;;;;第二層子程序
clr_bcd:
mov r0,#pool_bcd
mov @r0,#0
inc r0
mov @r0,#0
inc r0
mov @r0,#0
setb bcd_ready
ret
set_target: ;將bcd里的3位數(shù)字轉(zhuǎn)換16位數(shù)字,并存入到targ_moto_L, targ_moto_H 中
mov r1,p_bcd ;0-2范圍
mov r3,#0
mov r4,#0
;;個(gè)位數(shù)
mov a,#pool_bcd
add a,r1
mov r0,a
mov a,@r0 ; 取到bcd值 從個(gè)位數(shù)查起
mov r4,a ;r3存H,r4存L 100* + 10* + L
;;;重復(fù)
dec r1
mov a,r1
cjne a,#0ffh,ste00;
mov r1,#2 ;過界處理
ste00:
mov a,#pool_bcd
add a,r1
mov r0,a
mov a,@r0
mov b,#10
mul ab ;十位數(shù)
clr c ;16位加法
addc a,r4
mov r4,a
mov a,b
addc a,r3
mov r3,a
;;;重復(fù)以上
dec r1
mov a,r1
cjne a,#0ffh,ste01;
mov r1,#2 ;過界處理
ste01:
mov a,#pool_bcd
add a,r1
mov r0,a
mov a,@r0
mov b,#100
mul ab ;百位數(shù)
clr c ;16位加法
addc a,r4
mov r4,a
mov a,b
addc a,r3
mov r3,a
call targ_mod360
mov lock_byte,#5ah
mov targ_moto_L,r4
mov targ_moto_H,r3
mov lock_byte,#11h
ret
;目標(biāo)值在r3,r4(HL),結(jié)果調(diào)整后還是在R3 R4
targ_mod360: ;輸入的bcd值(0-999)轉(zhuǎn)換為0-360度范圍,與360取模:求余
mov dph,r3 ;暫存
mov dpl,r4
mov a,r4 ;360d=0168h
clr c
subb a,#68h
mov r4,a
mov a,r3
subb a,#01h
mov r3,a
jc tmd00;表示過頭了
jmp targ_mod360
tmd00:
mov r3,dph
mov r4,dpl
ret
up_a_bit: ;電機(jī)向上微調(diào)一個(gè)距離 ;臨界區(qū)處理,禁止其他控制電機(jī)的操作
anl ready_byte,#10111111b ;休眠電機(jī)任務(wù)(task1)
mov r3,#12 ;走12拍
uab00:
dec p_step
mov a,p_step
cpl a
jnz uab03 ;過0則回到7
mov p_step,#7
uab03:
mov a,p_step
mov dptr,#tab_step
MOVC A,@a+dptr
anl P1,#11110000b ;驅(qū)動(dòng)電機(jī)
orl P1,a
call waiting
djnz r3,uab00
anl p1,#11110000b ;關(guān)電機(jī)
orl ready_byte,#01000000b ;喚醒電機(jī)任務(wù)
ret
down_a_bit: ;電機(jī)向下微調(diào)一個(gè)距離 ;臨界區(qū)處理,禁止其他控制電機(jī)的操作
anl ready_byte,#10111111b ;休眠電機(jī)任務(wù)(task1)
mov r3,#12 ;走12拍
dab00:
inc p_step
mov a,p_step
cjne a,#8,dab03 ;過7則回到0
mov p_step,#0
dab03:
mov a,p_step
mov dptr,#tab_step
MOVC A,@a+dptr
anl P1,#11110000b ;驅(qū)動(dòng)電機(jī)
orl P1,a
call waiting
djnz r3,dab00
anl p1,#11110000b ;關(guān)電機(jī)
orl ready_byte,#01000000b ;喚醒電機(jī)任務(wù)
ret
;任務(wù)0子程序:鍵值key_value放到循環(huán)的bcd池里(pool_bcd,p_bcd),置位bcd_ready *****orig
keyv2bcd:
jnb reset_bcd,k2b10
call clr_bcd
clr reset_bcd
k2b10: mov b,key_value ;鍵值
;存放在pool_bcd
mov a,p_bcd ;容錯(cuò)處理:p_bcd只能0-2,超范圍就置0
clr c
subb a,#3
jnc k2b01
;先推指針
inc p_bcd
mov a,p_bcd
cjne a,#3,k2b02 ;0-2循環(huán)處理
k2b01: mov p_bcd,#0
k2b02:
mov a,#pool_bcd
add a,p_bcd
mov r0,a
mov @r0,b ;再存鍵值
setb bcd_ready
ret
;任務(wù)0子程序:從循環(huán)的bcd池里取最近3個(gè)值(pool_bcd,p_bcd),查表轉(zhuǎn)換成段碼,存放到段碼數(shù)組(pool_print);
bcd2print:
mov r1,p_bcd ;0-2范圍
mov r2,#3 ;依次取3個(gè)數(shù)
b2p00: mov a,#pool_bcd
add a,r1
mov r0,a
mov a,@r0 ; 取到bcd值然后 查表獲取段碼
mov dptr,#tab_ht1621_seg
movc a,@a+dptr
mov r3,a
mov a,r2
dec a
add a,#pool_print
mov r0,a
mov a,r3
mov @r0,a
dec r1
mov a,r1
cpl a
jnz b2p01
mov r1,#2
b2p01:
djnz r2,b2p00
ret
;任務(wù)0子程序:將段碼數(shù)組pool_print的3個(gè)字節(jié)前面的0隱去
hide_zero:
mov r3,#2 ;2次,個(gè)位數(shù)不管
mov r0,#pool_print
hzo00:
mov a,@r0
cjne a,#5fh,hzo01 ; 5f 為0的段碼
mov @r0,#0
inc r0
djnz r3,hzo00
hzo01:
ret
;任務(wù)0子程序:將段碼數(shù)組pool_print的3個(gè)字節(jié)輸出到ht1621
print: ;(uchar Addr,uchar *p,uchar cnt) R3:ADDR r4:P R5:CNT
CLR CS_1621;
MOV A,#0A0H
MOV R0,#3
CALL Ht1621Wr_Data ;(0xa0,3); // - - 寫入數(shù)據(jù)標(biāo)志101
MOV A,R3
RLC A
RLC A ;Ht1621Wr_Data(Addr<<2,6); // - - 寫入地址數(shù)據(jù)
MOV R0,#6
CALL Ht1621Wr_Data
prt00:
mov a,r4
mov r0,a
MOV A,@r0 ;取段碼
MOV R0,#8
CALL Ht1621Wr_Data ;Ht1621Wr_Data(*p,8); // - - 寫入數(shù)據(jù)
INC r4
DJNZ R5,prt00
SETB CS_1621
CALL delay_a_while
RET
;任務(wù)0清零表
TAB_HT1621:
DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0;
TAB_HT1621_off:
DB 033h,078h,078h,055h,055h,055h,000h,05h,05h,05h,0,0,0,0,0,0;
TAB_HT1621_dou:
DB 0b7h,0b3h,093h,055h,055h,055h,000h,05h,05h,05h,0,0,0,0,0,0;
;任務(wù)0段碼表,依據(jù)硬件線序確定
tab_ht1621_seg:
db 5fh; 0
db 06h; 1
db 3dh; 2
db 2fh; 3
db 66h; 4
db 6bh; 5
db 7bh; 6
db 0eh; 7
db 7fh; 8
db 6fh; 9
db 7eh; A
db 73h; b
db 31h; c
db 37h; d
db 79h; E
db 78h; F
db 33h; o
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;任務(wù)1:電機(jī)驅(qū)動(dòng),實(shí)際值逼近目標(biāo)值 ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;實(shí)際值:p_moto_L、p_moto_H、目標(biāo)值targ_moto_L、targ_moto_H 最大360度
;步驟:目標(biāo)值-實(shí)際值,記錄符號(正負(fù))到moto_dir, 結(jié)果等于0時(shí),關(guān)閉電機(jī),返回;結(jié)果小于180時(shí),moto_dir反置(尋找最短路徑)
;讓電機(jī)逼近一步,實(shí)際值+1或-1。返回。
;;------------------------------------------任務(wù)1
task_1:
mov p_moto_L,#0eh
mov p_moto_H,#01h ; 0-359范圍
mov targ_moto_L,#0
mov targ_moto_H,#0 ; 0-999范圍 ;要mod360處理,變?yōu)?-359范圍
;臂板垂直向下270度為初始態(tài)(壓縮狀態(tài),方便包裝和移動(dòng))在電氣驅(qū)動(dòng)里面初始化。
tsk100:
;16位減法 目標(biāo)值-當(dāng)前值,默認(rèn)為+
clr moto_dir ;默認(rèn)電機(jī)方向
clr c
mov a,targ_moto_L
subb a,P_moto_L
mov b,a
mov a,targ_moto_H
subb a,P_moto_H ;結(jié)果高位在a,低位在b
jnc tsk105 ;結(jié)果為負(fù)數(shù)的話 被減數(shù)+360,再減
clr c
mov a,targ_moto_L
addc a,#68h
mov r0,a
mov a,#01h
addc a,targ_moto_h
mov r1,a
clr c ;重新算一次
mov a,r0
subb a,P_moto_L
mov b,a
mov a,r1
subb a,P_moto_H ;結(jié)果高位在a,低位在b
tsk105:
mov r1,a ;H
mov r0,b ;L 暫存結(jié)果(正偏差:0-359)
jnz tsk104
mov a,b
jnz tsk104
;結(jié)果為0 關(guān)閉電機(jī) 并返回
anl p1,#11110000b ;驅(qū)動(dòng)電機(jī)
orl ready_byte,#11100001b ;開啟其他任務(wù)
jmp tsk100
tsk104: ;偏差如果大于180,電機(jī)方向反向
anl ready_byte,#11011111b ;暫停鍵盤線程
clr c
mov a,r0
subb a,#180
mov b,a
mov a,r1
subb a,#0 ;16位減去180
jc tsk101 ;
cpl moto_dir
tsk101:
call moto_move
;實(shí)際位置指針調(diào)整一位
jb moto_dir,tsk102
clr c
mov a,p_moto_L
addc a,#1
mov p_moto_L,a
clr a
addc a,p_moto_H
mov p_moto_H,a
cjne a,#01h,tsk100 ;如果等于360則歸零
mov a,p_moto_L
cjne a,#68h,tsk100
mov p_moto_L,#0
mov p_moto_H,#0
jmp tsk100
tsk102:
clr c
mov a,p_moto_L
subb a,#1
mov p_moto_L,a
mov a,p_moto_H
subb a,#0
mov p_moto_H,a
cpl a ;如果等于ffff,則改為359
jnz tsk100
mov a,p_moto_L
cpl a
jnz tsk100
mov p_moto_L,#67h
mov p_moto_H,#01h
jmp tsk100
jmp task_1
;----------task1 end-------}}}}--
;任務(wù)1子程序:電機(jī)走一度,方向在moto_dir,
;涉及2張表:表1,45度折合512拍表,tab_deg,p_deg(0-44), 表2,8拍表tab_step,p_step(0-7)
;步驟:1根據(jù)方向調(diào)整度數(shù)指針,取一個(gè)度數(shù)拍數(shù) 2根據(jù)方向走N拍并更新拍數(shù)指針;
moto_move:
mov c,moto_dir ;防止過程中改變方向
mov tmp_dir,c
mmv00:
jb tmp_dir,mmv01 ;正方向
dec p_deg
mov a,p_deg
cpl a
jnz mmv03 ;過0則回到44
mov p_deg,#44
mmv03:
mov a,p_deg
mov dptr,#tab_deg
movc a,@a+dptr
jmp mmv02
mmv01:
inc p_deg ;反方向
mov a,p_deg
cjne a,#45,mmv04 ;過44則回到0
mov p_deg,#0
mmv04:
mov a,p_deg
mov dptr,#tab_deg
movc a,@a+dptr
mmv02:
mov r3,a
call move_n_step
ret
move_n_step:;方向在tmp_dir,步數(shù)在r3, 表2,8拍表tab_step,p_step(0-7)
mns00:
jb tmp_dir,msn01 ;正方向
dec p_step
mov a,p_step
cpl a
jnz msn03 ;過0則回到7
mov p_step,#7
msn03:
mov a,p_step
mov dptr,#tab_step
MOVC A,@a+dptr
jmp msn02
msn01:
inc p_step ;反方向
mov a,p_step
cjne a,#8,msn04 ;過7則回到0
mov p_step,#0
msn04:
mov a,p_step
mov dptr,#tab_step
MOVC A,@a+dptr
msn02:
anl p1,#11110000b ;驅(qū)動(dòng)電機(jī)
orl p1,a
;至此,電機(jī)走動(dòng)了一拍,下面是延時(shí):需要2ms,采用不可重入的delay_sys_us完成
;CALL delay_a_step
;call waiting
;mov dptr,#10
;call delay_sys
mov r0,#3
call delay_sys_us
djnz r3,mns00 ;走r3步數(shù)
ret
tab_step: ;步進(jìn)電機(jī)8拍表,循環(huán)使用
DB 1001B,0001B,0011B,0010B,0110B,0100B,1100B,1000B
tab_deg: ;45度折合512拍表,循環(huán)使用
db 11,11,12,11,11,12,11,11,12,11,12,12,11,11,12
db 11,11,12,11,11,12,11,11,12,11,11,12,11,11,12
db 11,11,12,12,11,12,11,11,12,11,11,12,11,11,12
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; ;
;;;;;任務(wù)2:按鍵掃描 ;
;;標(biāo)準(zhǔn)的4*4按鍵掃描程序,鍵值為0-fh,設(shè)置3個(gè)字節(jié)的緩沖pool_key,設(shè)置一個(gè)緩沖指針p_key(0-3),當(dāng)緩沖區(qū)滿,丟棄新的按鍵
task_2:
;初始化
mov p_key,#0 ;0表示緩沖區(qū)空,3表示滿了,類似堆棧指針,注意定義時(shí)往前推一格
scan_key:
mov a,p_key
cjne a,#3,tk301 ;緩沖區(qū)滿了
jmp scan_key
tk301:
anl p0,#00001111b ;p0.7 p0.6 p0.5 p0.4 為豎線 從左到右
mov a,p2 ;p2.4 p2.5 p2.6 p2.7 為橫線 從上到下
orl a,#00001111b
cpl a
jz scan_key ;快速判斷,無任何按鍵時(shí)不要去挨個(gè)掃了,這樣響應(yīng)更快
mov r3,#4 ;豎線循環(huán)4次
mov a,#01111111b
tk300:
orl p0,#11110000b
anl p0,a
mov r2,a ;暫存
jb p2.4,tk303
mov r0,#0
call take_keyv
tk303:
jb p2.5,tk304
mov r0,#1
call take_keyv
tk304:
jb p2.6,tk305
mov r0,#2
call take_keyv
tk305:
jb p2.7,tk302
mov r0,#3
call take_keyv
tk302:
mov a,r2
rr a ;下一個(gè)豎線
djnz r3,tk300
jmp scan_key
jmp task_2
;----------------------------task2 end---}}}}}-----
;
tab_key16: ;二位數(shù)組的4*4鍵值表
db 0ah,0bh,0ch,0dh
db 03,06,09,0fh
db 02,05,08,0
db 01,04,07,0eh
;子程序:查表取鍵值,r3:行號,r0:列號
take_keyv:
mov a,r3 ;1-4 轉(zhuǎn)為 0-3
dec a
mov dptr,#tab_key16
mov b,#4
mul ab ;調(diào)整基地址
add a,dpl
mov dpl,a
clr a
addc a,dph ;進(jìn)位考慮
mov dph,a
mov a,r0
movc a,@a+dptr ;查表取到對應(yīng)的鍵值 在b
mov b,a
;存到緩沖池
mov a,p_key
cjne a,#3,tkv00 ;緩沖區(qū)滿了
ret
tkv00:
mov lock_byte,#5ah ;;臨界區(qū),加鎖
inc p_key
mov a,p_key
add a,#pool_key
mov r1,a
mov @r1,b ;存緩沖
mov lock_byte,#11h ;;;;退臨界區(qū),解鎖
mov a,#30
add a,sys_time_l ;設(shè)置300ms時(shí)限
mov r1,a
tkv01: ;按鍵釋放時(shí)立即返回,連續(xù)按住時(shí)要間隔延時(shí)
;超時(shí)退出
mov a,sys_time_l
clr c
subb a,r1
clr c
subb a,#5 ;時(shí)間模糊處理,只要接近目標(biāo)時(shí)間50ms以內(nèi),就算超時(shí),擔(dān)心有錯(cuò)過時(shí)鐘刻度的考慮
jc tkv02
;anl p0,#00001111b ;p0.7 p0.6 p0.5 p0.4 為豎線 改變p0可能會(huì)擾亂豎線掃描
mov a,p2 ;p2.4 p2.5 p2.6 p2.7 為橫線 從上到下
orl a,#00001111b
cpl a
jnz tkv01 ;判斷是否釋放(范圍為本行)
tkv02:
ret
;;--------------任務(wù)3-----次任務(wù),注意保護(hù)范圍:psw\a\b\r0-r3 以及最大嵌套2個(gè)call
;;-----------------------------------任務(wù)3
;;步進(jìn)電機(jī)每走一步的延時(shí)喚醒線程
task_3:
jmp task_3
;-----------------------------------------------task3 end--------------
;
;;-----------------------------------任務(wù)4
task_4:
jmp task_4
;-----------------------------------------------task5 end--------------
;
;;-----------------------------------任務(wù)5
task_5:
jmp task_5
;-----------------------------------------------task5 end--------------
;
;;-----------------------------------任務(wù)6
task_6:
jmp task_6
;-----------------------------------------------task6 end--------------
;
;
;--------------------------------------------------------------------------------------
;以下用戶子程序區(qū)
;;ht1621b driver RD WR DATA CS
;/********************************************************
;函數(shù)名稱:void Ht1621_Init(void)
;功能描述: HT1621初始化
Ht1621_Init:
SETB CS_1621;
SETB WR_1621;
SETB DATA_1621;
MOV dptr,#5;
CALL delay_sys; // - - 延時(shí)使LCD工作電壓穩(wěn)定
MOV R1,#BIAS
CALL Ht1621WrCmd;
MOV R1,#RC256
CALL Ht1621WrCmd; // - - 使用內(nèi)部振蕩器
MOV R1,#SYSDIS
CALL Ht1621WrCmd; // - - 關(guān)振系統(tǒng)蕩器和LCD偏壓發(fā)生器
MOV R1,#WDTDIS
CALL Ht1621WrCmd;; // - - 禁止看門狗
MOV R1,#SYSEN; // - - 打開系統(tǒng)振蕩器
CALL Ht1621WrCmd;
MOV R1,#LCDON; // - - 打開聲音輸出
CALL Ht1621WrCmd;
ret
;**寫數(shù)據(jù)到ht1621,數(shù)據(jù)存A,發(fā)送位數(shù)存R0*****************************************************/
Ht1621Wr_Data:;(uchar Data,uchar cnt) A:DATA R0:number of send-bit
CLR WR_1621;
CALL delay_a_while
RLC A;
MOV DATA_1621,C;
CALL delay_a_while
SETB WR_1621;
CALL delay_a_while
DJNZ R0,Ht1621Wr_Data
ret
;****寫命令給HT1621****************************************************
Ht1621WrCmd: ;(uchar Cmd) cmd byte store in R1
CLR CS_1621
CALL delay_a_while
MOV A,#80H
MOV R0,#4
CALL Ht1621Wr_Data; // - - 寫入命令標(biāo)志1000
MOV A,R1
MOV R0,#8
CALL Ht1621Wr_Data; // - - 寫入命令數(shù)據(jù)
SETB CS_1621
CALL delay_a_while
RET
;*******************************************************
;函數(shù)名稱:void Ht1621WrOneData(uchar Addr,uchar Data)
;功能描述: HT1621在指定地址寫入數(shù)據(jù)函數(shù)
;全局變量:無
;參數(shù)說明:Addr為寫入初始地址,Data為寫入數(shù)據(jù)
;返回說明:無
;說 明:因?yàn)镠T1621的數(shù)據(jù)位4位,所以實(shí)際寫入數(shù)據(jù)為參數(shù)的后4位
;********************************************************/
Ht1621WrOneData:;(uchar Addr,uchar Data) R2,R3
CLR CS_1621;
MOV A,#0A0H
MOV R0,#3
CALL Ht1621Wr_Data;(0xa0,3); // - - 寫入數(shù)據(jù)標(biāo)志101
MOV A,R2
RLC A
RLC A
MOV R0,#6
CALL Ht1621Wr_Data;(Addr<<2,6); // - - 寫入地址數(shù)據(jù)
MOV A,R3
RLC A
RLC A
RLC A
RLC A
MOV R0,#4
CALL Ht1621Wr_Data;(Data<<4,4); // - - 寫入數(shù)據(jù)
SETB CS_1621
CALL delay_a_while
RET
;*********函數(shù)名稱:void Ht1621WrAllData(uchar Addr,uchar *p,uchar cnt)
;功能描述: HT1621連續(xù)寫入方式函數(shù)
;參數(shù)說明:Addr為寫入初始地址,*p為連續(xù)寫入數(shù)據(jù)指針,
;cnt為寫入數(shù)據(jù)總數(shù)
;返回說明:無
;說 明:HT1621的數(shù)據(jù)位4位,此處每次數(shù)據(jù)為8位,寫入數(shù)據(jù)
;總數(shù)按8位計(jì)算
;********************************************************/
Ht1621WrAllData:;(uchar Addr,uchar *p,uchar cnt) R3:ADDR DPTR:P R5:CNT
CLR CS_1621;
MOV A,#0A0H
MOV R0,#3
CALL Ht1621Wr_Data ;(0xa0,3); // - - 寫入數(shù)據(jù)標(biāo)志101
MOV A,R3
RLC A
RLC A ;Ht1621Wr_Data(Addr<<2,6); // - - 寫入地址數(shù)據(jù)
MOV R0,#6
CALL Ht1621Wr_Data
hwd00:
CLR A
MOVC A,@A+DPTR
MOV R0,#8
CALL Ht1621Wr_Data ;Ht1621Wr_Data(*p,8); // - - 寫入數(shù)據(jù)
INC DPTR
DJNZ R5,hwd00
SETB CS_1621
CALL delay_a_while
RET
;;;----------------
delay_a_while:
mov r3,#50
daw00:
nop
djnz r3,daw00
ret
delay_a_step:
mov r6,#0ffh
dast00:
nop
nop
nop
djnz r6,dast00
ret
;---------------------------------------以下用戶數(shù)據(jù)表區(qū)------------------
;用戶可以在此定義所需要的數(shù)據(jù)表
end
;*******************************************the end**********************
|