📄 192x64液晶屏用avr驱动的汇编语言.asm.txt
字号:
; TG19264A接口程序(AVR模拟方式)
;液晶模块供应商:广州市盛宝电子有限公司 Tel:020-87592491 Fax:87541571
;Email: tinsharp@public.guangzhou.gd.cn
;这个连线图是因为原先的51试验电路改的,有些脚是将就着用的。
;************************************************************************
;连线图: *
;*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
;****************************************************************
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -