📄 spl10a_driver.asm
字号:
.include hardware.inc
.external _TimeCounter
.define SETCOMMAND 0x00
.define WRITECOMMAND 0x01
.define STB 0x20
.define ACK 0x40
.define BITDATA 0x80
.define TRUE 0x00
.define FALSE 0x01
.ram
.public _Result,_KeyValue,_DisplayBuffer
.var _Result,_KeyValue //_Result=1表示对SPL10A操作失败,_KeyValue保存1-8键值(0表示无键)
.var Page
_DisplayBuffer: .dw 11 dup(0) //显示缓冲区。第0-7单元为自左至右共8个数据。第8单元为增量条形标识。
//第9单元为文字(含小数点)标识。第10单元为电池、阀门标识。
LCDBuffer: .dw 10 dup(0) //段显示缓冲区,将显示缓冲区内的内容转变为段码后存入段显示缓冲区
.data
//SPL10A的总命令表
CommandTbl:
.dw 0x8100 //00:Tone off
.dw 0x8200 //01:Tone on
.dw 0x8400 //02:Set Tone 1K
.dw 0x8500 //03:Set Tone 2K
.dw 0x8600 //04:Set Tone 4K
.dw 0x8700 //05:Battery Level Detect
.dw 0x8300 //06:LCD 1/4duty 1/3bias
.dw 0x9000 //07:Key Mode0(5*4) no shift
.dw 0x9100 //08:Key Mode1(4*4) shift1
.dw 0x9200 //09:Key Mode2(3*4) shift1,2
.dw 0x9300 //0A:Key Mode3(3*4) rolling F/B
.dw 0x9800 //0B:Key continue refresh mode
.dw 0x9900 //0C:Key hold until read out
.dw 0xE000 //0D:Sleep mode
//数据长度表
//在Set Command操作中数据长度8位,在Write Command操作中数据长度为16位
SizeTbl:
.dw 8,16
//数字显示段码
SegTbl:
.dw 0x003F,0x0006,0x005B,0x004F,0x0066 //0,1,2,3,4
.dw 0x006D,0x007D,0x0007,0x007F,0x006F //5,6,7,8,9
.dw 0x0000 //全灭
//增量条形标识段码
StickTbl:
.dw 0x00,0x01,0x03,0x07,0x0F
.code
.public InitIO
//初始化IO口,其中A7接DATA(输出),A5接STB(输出),A6接ACK(输入)
//入口:无
//出口:无
InitIO: .proc
R1=0x00A0
[P_IOA_Dir]=R1 //A7(DATA)、A5(STB)输出,A6(ACK)输入
[P_IOA_Attrib]=R1
R1=0x00E0
[P_IOA_Data]=R1
RETF
.endp
.public _InitSPL10A
//SPL10A初始化,包括初始化IO口、向SPL10A写初始化命令
//入口:无
//出口:无
_InitSPL10A: .proc
CALL InitIO //初始化IO口
BP=_DisplayBuffer //显示缓冲区初始化
R1=0x0A //前8个单元写入0x0A则不显示
R2=8
CL1: [BP++]=R1
R2-=1
JNZ CL1
R1=0 //后3个单元写入0则不显示
R2=3
CL2: [BP++]=R1
R2-=1
JNZ CL2
R1=0x0B
CALL SetCommand //送Key初始化命令:Key continue refresh mode
RETF
.endp
.public SetCommand
//向SPL10A送命令
//入口:R1。R1内容不是真正的控制命令,而是实际命令在命令表中的存储偏移量,通过查表得出实际命令
//出口:无
SetCommand: .proc
BP=CommandTbl //BP指向命令表首地址
BP+=R1
R1=[BP] //取出实际命令
R2=SETCOMMAND //当前操作为Set Command
CALL SendData //送出
CALL Delay //让STB、DATA信号保持一段时间的高电平
RETF
.endp
.public SendData
//数据传送,完成061A向SPL10A的送数据过程。传送过程遵循Set Command、Write Command通讯时序
//入口:R1--数据,R2--操作模式(Set Command、Write Command)
//出口:无
SendData: .proc
BP=SizeTbl //确定不同操作模式下数据长度
BP+=R2
R2=[BP]
R3=[P_IOA_Data] //STB、DATA信号置高,准备发送同步信号
R3|=STB+BITDATA
[P_IOA_Data]=R3
R3=[P_IOA_Data] //DATA置低,送同步信号
R3^=BITDATA
[P_IOA_Data]=R3
R3=100 //启动100ms定时
[_TimeCounter]=R3
Wait1:
R3=[_TimeCounter]
JNZ OK1
GOTO Error //100ms内未收到ACK信号则传送失败
OK1: R3=[P_IOA_Data] //等待ACK信号为低
R3&=ACK
JNZ Wait1
R3=[P_IOA_Data] //DATA置高
R3|=BITDATA
[P_IOA_Data]=R3
R3=100 //启动100ms定时
[_TimeCounter]=R3
Wait2:
R3=[_TimeCounter]
JNZ OK2
GOTO Error
OK2: R3=[P_IOA_Data] //等待ACK信号为高
R3&=ACK
JZ Wait2 //只有ACK信号随DATA信号从高变低,又从低变高,则同步成功
R4=0x8000 //数据从最高位开始传送
Next: R3=R1
R3&=R4 //判断传送位为高还是低
JZ ResBit
R3=[P_IOA_Data] //传送位为高
R3|=BITDATA
JMP Send
ResBit: R3=[P_IOA_Data] //传送位为低
R3|=BITDATA
R3^=BITDATA
Send: [P_IOA_Data]=R3
NOP
NOP
NOP
NOP
R3=[P_IOA_Data] //STB信号置低
R3|=STB
R3^=STB
[P_IOA_Data]=R3
R3=100 //启动100ms定时
[_TimeCounter]=R3
Wait3:
R3=[_TimeCounter]
JZ Error
R3=[P_IOA_Data] //等待ACK信号置低
R3&=ACK
JNZ Wait3
R3=[P_IOA_Data] //STB信号置高
R3|=STB
[P_IOA_Data]=R3
R3=100 //启动100ms定时
[_TimeCounter]=R3
Wait4:
R3=[_TimeCounter]
JZ Error
R3=[P_IOA_Data] //等待ACK信号置高
R3&=ACK
JZ Wait4
R3=0x01 //清狗
[P_Watchdog_Clear]=R3
R4=R4 LSR 1 //R4右移一位,以便判断下一位数据
R2-=1
JNZ Next //继续,直至所有的数据位传送完毕
R3=TRUE
JMP Stop
Error: R3=FALSE
Stop: [_Result]=R3
R3=[P_IOA_Data] //传送完毕后STB、DATA信号置高
R3|=STB+BITDATA
[P_IOA_Data]=R3
RETF
.endp
.public Delay
Delay: .proc
R3=0x8000
Wait: R1=0x01 //清狗
[P_Watchdog_Clear]=R1
R3-=1
JNZ Wait
RETF
.endp
.public _CheckKeypad
//键盘读取程序。过程遵循Read Command时序。
//入口:无
//出口:_KeyValue。0表示无键按下,1-8对应8个按键
_CheckKeypad: .proc
R1=0xC000 //取出实际命令
R2=SETCOMMAND //当前操作为Set Command
CALL SendData //送出
R1=[_Result]
JZ ComeOn
R1=0
[_KeyValue]=R1
RETF
ComeOn: R1=0x0020 //变化端口方向
[P_IOA_Dir]=R1 //A7(DATA)输入、A5(STB)输出,A6(ACK)输入
[P_IOA_Attrib]=R1
R1=0x00E0
[P_IOA_Data]=R1
R1=8 //读入的数据是8位
R2=0 //读入的数据暂存处
R4=0x0080
RdNext: R3=100 //启动100ms定时
[_TimeCounter]=R3
Wait5: R3=[_TimeCounter]
JZ RdFail
R3=[P_IOA_Data] //等待ACK置高,表示SPL准备放置数据
R3&=ACK
JZ Wait5
R3=[P_IOA_Data] //STB置低表示SPCE准备接收数据
R3|=STB
R3^=STB
[P_IOA_Data]=R3
R3=100 //启动100ms定时
[_TimeCounter]=R3
Wait6: R3=[_TimeCounter]
JZ RdFail
R3=[P_IOA_Data] //等待ACK置低,表示SPL数据就绪
R3&=ACK
JNZ Wait6
R3=[P_IOA_Data] //读入位数据
R3&=BITDATA
JNZ SetBit
R2|=R4
R2^=R4 //读入的位为低
JMP Con
SetBit: R2|=R4 //读入的位为高
Con: R4=R4 LSR 1
R3=[P_IOA_Data] //STB置高,表示SPCE已完成读取
R3|=STB
[P_IOA_Data]=R3
R1-=1
JNZ RdNext
R1=TRUE
[_Result]=R1
JMP RdSuc
RdFail: R1=FALSE
[_Result]=R1
R2=0
RdSuc: [_KeyValue]=R2
CALL InitIO //恢复IO口原方向
R3=[P_IOA_Data] //读完毕后STB、DATA信号置高
R3|=STB+BITDATA
[P_IOA_Data]=R3
CALL Delay
R1=[_KeyValue] //返回值
RETF
.endp
.public Convert
//显示缓冲区内容到段显示缓冲区内容的转变,完成将显示缓冲区内的所有显示内容转换为要
//实际显示的段码送入段显示缓冲区功能
//入口:_DisplayBuffer
//出口:LCDBuffer
Convert: .proc
BP=LCDBuffer //首先清除段显示缓冲区
R1=0
R2=10 //段显示缓冲区有10个单元
Clr: [BP++]=R1
R2-=1
JNZ Clr
R1=9
[Page]=R1 //先从第9页到第0页写数据
R1=_DisplayBuffer //R1指向显示缓冲区
R2=8 //先处理8个数字
Lp1: BP=SegTbl //BP指向段码表
R3=[R1++] //取显示缓冲区内容
BP+=R3
R3=[BP] //取段码
PUSH R3 TO [SP] //段码的高4位与低4位要分开处理
R3&=0x0F
BP=LCDBuffer //BP指向段显示缓冲区
R4=[Page]
BP+=R4
R4=[BP]
R4|=R3
[BP]=R4 //存入低4位段码
POP R3 FROM [SP]
R3&=0xF0
BP=LCDBuffer
R4=[Page]
R4-=1
BP+=R4
R4=[BP]
R4|=R3
[BP]=R4 //存入高4位段码
R3=[Page]
R3-=1
[Page]=R3
R2-=1
JNZ Lp1 //8个数字未转换完毕
R3=[R1++] //增量条形标识显示数据范围1-10
PUSH R3 TO [SP]
CMP R3,5
JNAE Stick1
R3=4
Stick1: BP=StickTbl //BP指向条形标识段码
BP+=R3
R3=[BP]
R4=1 //第1页
BP=LCDBuffer
BP+=R4
R4=[BP]
R4|=R3
[BP]=R4
POP R3 FROM [SP]
PUSH R3 TO [SP]
CMP R3,5
JAE C10
POP R3 FROM [SP]
JMP Word
C10: CMP R3,8
JNAE C1
JMP C2
C1: R3-=4
JMP Stick2
C2: R3=3
Stick2: BP=StickTbl
BP+=R3
R3=[BP]
R3=R3 LSL 4
BP=LCDBuffer //第0页
R4=[BP]
R4|=R3
[BP]=R4
POP R3 FROM [SP]
CMP R3,8
JNAE Word
CMP R3,11
JNAE C3
JMP C4
C3: R3-=7
JMP Stick3
C4: R3=3
Stick3: BP=StickTbl
BP+=R3
R3=[BP]
BP=LCDBuffer //第0页
R4=[BP]
R4|=R3
[BP]=R4
Word: R2=1
R3=1
[Page]=R3
C6: R4=[R1] //取出文字标识显示内容
R4&=R3
JZ C5
BP=LCDBuffer
BP+=R2
R4=[BP]
R4|=0x80
[BP]=R4
C5: R3=R3 LSL 1
R2+=1
CMP R2,9
JNE C6
R1+=1
R2=[R1]
BP=LCDBuffer
R3=[BP]
PUSH R2 TO [SP]
R2&=0x01
JNZ C7
JMP C8
C7: R3|=0x08
C8: POP R2 FROM [SP]
R2&=0x02
JNZ C9
JMP C11
C9: R3|=0x80
C11: [BP]=R3
RETF
.endp
.public _RefreshLCD
//LCD刷新程序。主程序修改显示缓冲区后调用,完成LCD显示。
//入口:_DisplayBuffer
//出口:无
_RefreshLCD: .proc
CALL Convert //调转换程序,将显示缓冲区内容转换为段显示缓冲区内容
R1=0
[Page]=R1
R4=10 //共有10页的数据要传送
BP=LCDBuffer //BP指向段显示缓冲区
Lop: R1=0xA000 //LCD写命令
R2=[Page] //将页码移至D8-D11
R2=R2 LSL 4
R2=R2 LSL 4
R1|=R2
R2=[BP++] //取出段显示内容
R1|=R2 //这时完整包含LCD写命令、页码、段显示内容
R2=WRITECOMMAND //Write Command操作标识
PUSH BP TO [SP]
PUSH R4 TO [SP]
CALL SendData //向SPL10A送数据
POP R4 FROM [SP]
POP BP FROM [SP]
R2=[Page] //准备传送下一页数据
R2+=1
[Page]=R2
R4-=1
JNE Lop
RETF
.endp
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -