?? 19264avr-asm.asm
字號:
; TG19264A接口程序(AVR模擬方式)
;************************************************************************
;連線圖: *
;*LCM------S8515* *LCM----S8515* *LCM-------S8515* *LCM------S8515* *
;*DB0-------PA0* *DB4-----PA4* *D/I--------PC6* *CS1-------PC5* *
;*DB1-------PA1* *DB5-----PA5* *R/W--------PC7* *CS2-------PC4* *
;*DB2-------PA2* *DB6-----PA6* */RST-------VCC* *CS3-------PD2* *
;*DB3-------PA3* *DB7-----PA7* *E----------PC3* *
;注:AT90S8515的晶振頻率為8MHz *
;************************************************************************
.include"8515def.inc" ;器件配置文件
;接口引腳定義:
.equ DI =PC6 ;數據/命令
.equ RW =PC7 ;讀/寫
.equ ELCM =PC3 ;操作允許,高電平有效(允許)
.equ CS1 =PC4 ;左區選中,低電平有效
.equ CS2 =PC5 ;中區選中,低電平有效
.equ CS3 =PD2 ;右區選中,低電平有效
.equ Colend = 0x40 ;每一個分區寬64點
.def status = r1
.def eeaddrl = r5 ;eeprom地址低8位
.def eeaddrh = r6 ;eeprom地址高8位
.def temp = r3
.def temp1 = r4
.def rxpos = r9 ;X坐標備份
.def rypos = r10 ;X坐標備份
.def mode = r15
.def cbyte = r16 ;通用寄存器,主要在液晶顯示數據
.def count = r17
.def ioreg = r18
.def baud = r20
.def maxcol = r21 ;字符點陣寬度(8或16)
.def col = r22 ;X坐標
.def row = r23 ;Y坐標
.def lbyte = r24
.def hbyte = r25
.macro Dptrinc ;AVR沒有帶進位立即數的加法,沒辦法
subi r30,low(-0x0001) ;才出此下策
sbci r31,high(-0x0001)
.endmacro
;主程序開始
.cseg
.org $000
rjmp RESET
.org URXCaddr
;*****************************************
;* Program starts here after power up. *
;*****************************************
.org 10 ;保留空間給應用程序(中斷向量區)
RESET: cli ;關全局中斷允許位(SREG.7)=I
ldi cbyte,low(RAMEND) ;堆棧頂部設定
out SPL,cbyte ;
ldi cbyte,high(RAMEND) ;
out SPH,cbyte ;
clr eeaddrl ;內部 EEPROM 指針清零
clr eeaddrh ;指向起始點
clr mode ;顯示模式清零
clr cbyte ;顯示內容清零
out GIMSK,cbyte ;通用屏蔽寄存器清零
out timsk,cbyte ;定時/計數器中斷屏蔽寄存器清零
out wdtcr,cbyte ;看門狗定時控制寄存器清零
clr count ;程序軟件計數器(R17)清零
out MCUCR,count ;MCU通用控制寄存器清零
ser ioreg ;置FF. (R18=0xFF)
out DDRD,ioreg ;定義端口D為輸出
out DDRC,ioreg ;定義端口C為輸出
out portb,ioreg ;端口B置FF
out portd,ioreg ;端口D置FF
rjmp Main ;初始化結束,進入主程序
;****************************************************************
; 主程序
;****************************************************************
Main: ldi cbyte, low(ramend) ;堆棧頂部設定
out SPL, cbyte ;keep our stack healthy!!!
ldi cbyte, high(ramend) ;確認堆棧指針正確
out SPH,cbyte
rcall delay ;延時等待LCM復位好
rcall delay
rcall Initlcd ;液晶模塊初始化
ldi col,0x00 ; X = 0
ldi row,0x00 ; Y = 0 (第一行)
ldi r30,low(STRING1*2) ; Z 指針指向第一個字符串
ldi r31,high(STRING1*2)
rcall Putstr ;顯示輸出這個字符串
ldi col,0x00 ; X = 0
ldi row,0x02 ; Y = 2 (第二行)
ldi r30,low(STRING2*2) ; Z 指針指向第二個字符串
ldi r31,high(STRING2*2)
rcall Putstr ;顯示輸出這個字符串
Main1: wdr
rjmp Main1 ;程序死循環,到此為止。
;****************************************************************
; LCM系統復位
;****************************************************************
InitLcd:
ldi cbyte,0x3e ;關顯示
rcall WrCmd1
rcall WrCmd2
rcall WrCmd3
ldi cbyte,0x3F ;開顯示
rcall WrCmd1
rcall WrCmd2
rcall WrCmd3
ldi cbyte,0xC0 ;設定起始地址
rcall WrCmd1
rcall WrCmd2
rcall WrCmd3
rcall Cls ;清屏
ret
;****************************************************************
; 延時程序
;****************************************************************
Delay: push temp
push temp1
clr temp
dt11: clr temp1
dt21: nop
dec temp1
brne dt21
dec temp
brne dt11
pop temp1
pop temp
ret
;****************************************************************
;獲取字串內字符編碼,C=0 顯示結束,字符串以0FFH結尾作為結束標志
;以兩字節組成一個字符:前一字節表示是全角(>=80H)還是半角(<80H)
; 后一字節字符點陣表內偏移量“內碼”
;****************************************************************
Getstrchar:
Gsc_pa:
lpm ;先讀取字頭(字符屬性或結束標志)
mov cbyte,r0 ;保存字符屬性
Dptrinc ; Z++
inc r0
clc ;置程序出口標志(表示已經結束)
breq Gsc_px ;如果是結束碼(0ffh+1=00h)
lpm ;真正讀取“內碼”
Dptrinc
sec ;編碼有效標志
Gsc_px:
ret
;************************************************************************
;一個長字符串數據輸出,字符串以 0xFF 作結尾標志,入口 Z 指向該字符串
;顯示位置的 XY 坐標由調用方確定
;************************************************************************
Putstr: rcall delay ;演示加上的延時,實際應用時去掉
rcall Getstrchar ;從字符串中取一個字
push r30 ;push Z
push r31
brcc Psr_ax ; if c=0 輸出結束
sbrc cbyte,0x07 ; if cbyte^7=0 半角字符
rjmp Psr_pb
; 半角字符
Psr_pa: ldi Maxcol,0x08 ; 每字8列
mov cbyte,r0 ; 取字符編碼(內部碼)
rcall Edotpos ; 字庫實際指針換算,結果置入Z
rjmp Psr_pbx
;Chinese ; 全角字符
Psr_pb: ldi Maxcol,0x10 ; 每字16列
mov cbyte,r0 ; 取字符編碼(內部碼)
rcall Cdotpos ; 字庫實際指針換算,結果置入Z
Psr_pbx:
rcall Putchardot ; 點陣碼輸出
pop r31
pop r30
rjmp Putstr ; 繼續下一個字
Psr_ax:
pop r31
pop r30
ret ; return
;****************************************************************
;半(全)角字符數據輸出,Maxcol*16 點陣, Maxcol = 8 0r 16
;****************************************************************
Putchardot:
push col ;暫時保護X坐標,留給下半個字符用
mov count,Maxcol ;共Maxcol列
Pat_pa:
lpm ;讀取點陣碼,放在r0
mov cbyte,r0 ;給輸出器存器
rcall Wrdata ;輸出
Dptrinc ;指針加1,指向下一位
inc col ;X=X+1
dec count ;計數器減1
brne Pat_pa ;判斷如果未完成則繼續
inc row ;Y=Y+1 指向下半個字符
pop col ;對齊左邊起點
mov count,Maxcol ;也是Maxcol列
Pat_pb:
lpm ;讀取點陣碼,放在r0
mov cbyte,r0 ;給輸出器存器
rcall Wrdata ;輸出
Dptrinc ;指針加1,指向下一位
inc col ;X=X+1
dec count ;計數器減1
brne Pat_pb ;判斷如果未完成則繼續
dec col ;回退1列
rcall Cusornext ;做邊界判斷
cpi col,0x01 ;判斷是否換行?
brsh Pat_pc ;沒有換行,返回
inc row ;加一行(每個字符占用兩行)
Pat_pc:
dec row ;指向上半部分
ret ; return
;****************************************************************
;按給定的XY坐標定位,并寫數據子程序
;****************************************************************
Wrdata:
rcall Locate
rcall LcdWd
ret
;****************************************************************
;一字節數據輸出,并根據坐標自動定位寫入區域
;****************************************************************
LcdWd: cpi col,Colend ;分區判斷,是否左區?
brsh LW1 ;col>=Colend是中區或右區
rcall Wrdata1 ;輸出該(數據)字節
rjmp LW3 ;返回
LW1: cpi col,Colend*2 ;在中與右間區分
brsh LW2 ;col>=2Colend 則為右區
rcall Wrdata2 ;中區數據輸出
rjmp LW3 ;返回
LW2: rcall Wrdata3 ;右區數據輸出
LW3: ret ;返回
;****************************************************************
;清屏,全屏幕清零
;****************************************************************
Cls: ldi row,0x00 ;Y坐標起點
ldi cbyte,0x00 ;填充數據 0x00
lflpb: ldi col,0x00 ;X坐標起點
lflpa: rcall WrData ;數據寫輸出(分區自動判別)
rcall Cusornext ;計算下一個該填充位置
cpi col,0x00 ;有否產生換行?
brne lflpa ;還未完成本行處理,繼續
cpi row,0x00 ;是否已結束?
brne lflpb ;沒有結束,繼續下一行處理
ret
;****************************************************************
; 連續輸出時的坐標指針換算,自動指向下一個可寫入地址
;****************************************************************
Cusornext:
andi row,0x07 ; 防止意外,確認只保留低3位
inc col ; X=X+1
cpi col,Colend*3 ; 是否出界(右邊界=3Colend)
brlo Cusret ; 未出界(col<Colend*3)
clr col ; 出界了,X=0x00 重新指向左邊起點
inc row ; Y=Y+1 換行
sbrc row,0x03 ; 行出界了嗎?if (~row^3)
clr row ; 已出界,回到第0行
Cusret: ret ; return
;****************************************************************
; BUSY狀態等待,出口片選信號保持有效,elcm已關閉
;****************************************************************
StatusCS1:
cbi portc,CS1 ; CS1 = 0
sbi portc,CS2 ; CS2 = 1
sbi portd,CS3 ; CS3 = 1
rjmp Statuscom ; 程序的公共部分
StatusCS2:
sbi portc,CS1 ; CS1 = 1
cbi portc,CS2 ; CS2 = 0
sbi portd,CS3 ; CS3 = 1
rjmp Statuscom ; 程序的公共部分
StatusCS3:
sbi portc,CS1 ; CS1 = 1
sbi portc,CS2 ; CS2 = 1
cbi portd,CS3 ; CS3 = 0
Statuscom:
sbi portc,RW ; R/W = 1
cbi portc,DI ; D/I = 0
sbi portc,elcm ; ELCM = 1 (ENABLE)
Stchk1:
clr ioreg ;清零
out DDRA,ioreg ;定義A口作為輸入
ser ioreg ;置FF
out porta,ioreg ;使A口成高阻狀態
nop ;等待書出到端口線上(一個指令周期)
in status,PINA ; 讀a口數據給status
sbrc status,0x07 ; 如果忙,再讀狀態,直到不忙為止(跳行)
rjmp Stchk1
cbi portc,elcm ; 關 Elcm
ser ioreg ; 置FF
out DDRA,ioreg ; 恢復A口為輸出
ret ;狀態已允許,返回
;
;****************************************************************
;數據寫輸出(分為左中右3個程序)
;****************************************************************
WrData1:
rcall StatusCS1 ;等待允許(片選保持)
rjmp Wrdatac
WrData2:
rcall StatusCS2 ;等待允許(片選保持)
rjmp Wrdatac
WrData3:
rcall StatusCS3 ;等待允許(片選保持)
Wrdatac:
; ldi cbyte,0x55 ;
sbi portc,DI ;D/I=1 R/W=0
cbi portc,RW
out porta,cbyte
sbi portc,elcm
wdr ;看門狗復位
cbi portc,elcm
ret
;
;****************************************************************
; 控制命令輸出
;****************************************************************
WrCmd1:
rcall StatusCS1 ; 等待允許(片選保持)
rjmp Wrcmdc
WrCmd2:
rcall StatusCS2 ; 等待允許(片選保持)
rjmp Wrcmdc
WrCmd3:
rcall StatusCS3 ; 等待允許(片選保持)
Wrcmdc: ; E=1 D/I=0 R/W=0 為指向命令口
cbi portc,DI ; D/I = 0
cbi portc,RW ; R/W = 0
out porta,cbyte ; 將控制指令放到數據線上
sbi portc,Elcm ; Elcm = 1
wdr ; 看門狗復位(借以延時)
cbi portc,Elcm ; Elcm = 0
ret
;****************************************************************
; 漢字庫實際指針換算,結果置入Z(r31r30)
;****************************************************************
Cdotpos:
ldi count,0x05 ;每個全角字符占用32字節
ldi r31,high(HZKDOT*2) ;Z的高8位(指向漢字點陣碼表)
ldi r30,low(HZKDOT*2) ;Z的低8位
rjmp Eps0 ;轉到公共程序入口
;
;****************************************************************
; 半角字符實際指針換算,結果置入 Z(r31r30)
;****************************************************************
Edotpos:
ldi count,0x04 ;每個半角字符占用16字節
ldi r31,high(EZKDOT*2) ;Z的高8位(指向半角點陣碼表)
ldi r30,low(EZKDOT*2) ;Z的低8位
Eps0: mov temp,cbyte ;取字符編碼
clr temp1 ;高8位清零
clc ;請進位標志C
Eps1: rol temp ;帶進位位的左循環
rol temp1 ;將標志移入高8位內
dec count ;計數器減1
brne Eps1 ;如果計數器不為零繼續
add r30,temp
adc r31,temp1 ;指向表內制定字符
ret ;return
;****************************************************************
; X,Y坐標定位處理 ,光標Y方向定位指令0xB8,X方向定位指令0x40
;****************************************************************
Locate: push cbyte
mov cbyte,row ; 取Y坐標
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -