文章目录
- main.asm
- STC15_init
- LCD1602
- juzheng
- delay
- usart(应该是uart,下面的文件写错了,另行修改)
main.asm
/*----------------------------------------------------------------------------------
;实验名称: 串口双机通信实验
;功 能: 1.上电初始化LCD1602,显示指针在第二行;
; 2.第一行是从外界接收到的字符显示,第二行是本机通过矩阵键盘输入的字符字符显示;
; 3.通过矩阵键盘的功能键,可以设置数字符号、大小写模式切换,并使的对应的指示灯点亮;
; 例如:按下“数字符号切换”按键,“数字符号切换指示灯”点亮,此时输入的字符是按键对应的数字和字符;
; 再按下“数字符号切换”按键,“数字符号切换指示灯”熄灭,退出数字字符模式。
; 当“数字符号切换指示灯”和“大小写切换指示灯”熄灭时,此时输入的是小写的英文字符;
; 当同时设置数字字符模式,和大小写模式,优先级:数字字符 > 大写 > 小写;
; 4.设置了删除,清屏,发送功能键;
; (1)“删除”是删除一位字符;
; (2)输入完成,按下“发送”按键,才串口发送给所连接的单片机;
; 发送的字符串以 0A 0D 作为结束标志符号,在“发送”的服务程序中有单独的代码,按下“发送”自动添加
; 5.设置了避免连续按“发送”按键误操作程序;
; 6.可以同一单片机多次发送字符串到另一单片机。
;算法说明: 1.所有的工作寄存器R0~R7作为局部变量,不存储静态变量或全局变量;
; 2.所有的静态变量和全局变量都通过自定义地址来存储,所有变量总览如下:
; LCD中的变量 LCD_RS BIT P2.5 ;1602数据命令选择端口
; LCD_RW BIT P2.6 ;1602读写选择端口
; LCD_EN BIT P2.7 ;1602使能端口
; LCD_OverLineSize_Light BIT P3.4 ;1602一行显示越界指示灯
; LCD_DATA EQU P0 ;1602数据端口
; LCD_ALL_FLAG DATA 20H ;标志位
; LCD_FLAG BIT LCD_ALL_FLAG.0 ;1602读忙标志位
; LCD_Line_BIT BIT LCD_ALL_FLAG.1 ;换行标志位
; LCD_DAT DATA 21H ;1602数据命令字
; LCD_DELAYED DATA 22H ;延时字
; LCD_LineSP DATA 23H ;LCD堆栈指针(最大为一行16个字符)
; LCD_StackAddress DATA 0A0H ;LCD堆栈首地址
; LCD_StackSize EQU 20 ;LCD堆栈大小
; juzheng中的变量 KEY DATA 24H ;用于存储按键的编号:0~F
; JZ_ALL_FLAG DATA 25H ;矩阵键盘的所有标志位
; Shift_number_BIT BIT JZ_ALL_FLAG.0 ;切换数字标志位
; Shift_LH_BIT BIT JZ_ALL_FLAG.1 ;切换大小写标志位
; Shift_number_Light BIT P3.2 ;切换数字指示灯
; Shift_LH_Light BIT P3.3 ;切换大小写指示灯
; usart中的变量 Usart_Buffer DATA 27H ;串口缓存器
; Usart_StackSP DATA 28H ;串口堆栈指针
; Usart_StackAddress DATA 80H ;串口堆栈首地址
; Usart_StackSize EQU 20 ;串口堆栈大小
; 3.不足之处:
; (1)函数块冗杂,一些函数块重复出现,但是这些重复出现的函数块所输入的参数不同,
; 此时还需要再通过设置新的变量来获得输入的值,再调用函数块,这样的话,定义的变量会较多,
; 这是一个需要改进的地方。
; (2)关于LCD,串口堆栈的设置和处理,感觉冗杂,需要简化处理,此时就需要重新更改堆栈的处理方式
;设计者:
;设计时间:2020.4.24
;设计版本:V1.0 */
/**************头文件包含*********************/
$INCLUDE(LCD1602.INC)
$INCLUDE(JUZHENG.INC)
$INCLUDE(USART.INC)
ORG 0000H
LJMP MAIN
ORG 0023H
LJMP Usart_ISR
ORG 0100H
/******************主函数********************/
MAIN:
MOV SP,
CLR Shift_number_BIT ;清除切换标志位
CLR Shift_LH_BIT
CLR Shift_number_Light ;熄灭所有指示灯
CLR Shift_LH_Light
LCALL LCD_INIT ;LCD初始化
LCALL Usart_Init ;串口初始化
MAINLOOP:
LCALL KEYSCAN ;扫描矩阵按键
LJMP MAINLOOP ;死循环
/*******************结束********************/
END
STC15_init
;以下是变量及函数的声明
PUBLIC STC15_INIT
;***************************************************
;定义程序区块,编译时动态分配程序地址,此段代码可以不要
_STC15_INIT_ASM SEGMENT CODE
RSEG _STC15_INIT_ASM
;***************************************************
P0M1 DATA 0x93 ; P0M1.n,P0M0.n =00--->Standard, 01--->push-pull
P0M0 DATA 0x94 ; =10--->pure input, 11--->open drain
P1M1 DATA 0x91 ; P1M1.n,P1M0.n =00--->Standard, 01--->push-pull
P1M0 DATA 0x92 ; =10--->pure input, 11--->open drain
P2M1 DATA 0x95 ; P2M1.n,P2M0.n =00--->Standard, 01--->push-pull
P2M0 DATA 0x96 ; =10--->pure input, 11--->open drain
P3M1 DATA 0xB1 ; P3M1.n,P3M0.n =00--->Standard, 01--->push-pull
P3M0 DATA 0xB2 ; =10--->pure input, 11--->open drain
P4M1 DATA 0xB3 ; P4M1.n,P4M0.n =00--->Standard, 01--->push-pull
P4M0 DATA 0xB4 ; =10--->pure input, 11--->open drain
P5M1 DATA 0xC9 ; P5M1.n,P5M0.n =00--->Standard, 01--->push-pull
P5M0 DATA 0xCA ; =10--->pure input, 11--->open drain
P6M1 DATA 0xCB ; P6M1.n,P6M0.n =00--->Standard, 01--->push-pull
P6M0 DATA 0xCC ; =10--->pure input, 11--->open drain
P7M1 DATA 0xE1 ;
P7M0 DATA 0xE2 ;
P4 DATA 0C0H
P5 DATA 0C8H
STC15_INIT:
// 端口初始化
CLR A
MOV P0M1, A ;设置为准双向口
MOV P0M0, A
MOV P1M1, A ;设置为准双向口
MOV P1M0, A
MOV P2M1, A ;设置为准双向口
MOV P2M0, A
MOV P3M1, A ;设置为准双向口
MOV P3M0, A
MOV P4M1, A ;设置为准双向口
MOV P4M0, A
MOV P5M1, A ;设置为准双向口
MOV P5M0, A
MOV P6M1, A ;设置为准双向口
MOV P6M0, A
MOV P7M1, A ;设置为准双向口
MOV P7M0, A
RET
;*****************结束*******************
END
LCD1602
;程序名称: LCD1602.asm
;程序说明: 1602汇编程序,51单片机汇编程序,仅需修改引脚定义即可。晶振大小12M,
; 程序测试完全正确。内部包含写数据、写命令(包括读忙和不读忙)、初始化等子函数。
; 调用时先给LCD_DAT赋值,给出需要写入的数据或命令,然后调用。
; eg: 写数据: MOV LCD_DAT,
; LCALL LCD_W_DATA
; 写命令: MOV LCD_DAT,
; LCALL LCD_W_CMD ;(或者LCD_CMD)
;***********************命令字******************************************************************
;RS=0、RW=0——表示向LCM写入指令
;RS=0、RW=1——表示读取Busy标志
;RS=1、RW=0——表示向LCM写入数据
;RS=1、RW=1——表示从LCM读取数据
;01H:清除DDRAM的所有单元,光标被移动到屏幕左上角。
;02H:DDRAM所有单元的内容不变,光标移至左上角。
;04H:写入DDRAM后,地址指针减一,比如第一个字符写入8FH,则下一个字符会写入8EH;屏幕上的内容不滚动。
;05H:写入DDRAM后,地址指针减一,同上一种情况;每一个字符写入以后,屏幕上的内容向右滚动一个字符位。
;06H:写入DDRAM后,地址指针加一,比如第一个字符写入80H,则下一个字符会写入81H;屏幕上的内容也是不滚动。这应该是最常用的一种显示方式。
;07H:写入DDRAM后,地址指针加一,同上一种情况;每一个字符写入以后,屏幕上的内容向左滚动一个字符位。
;08H、09H、0AH、0BH:关闭显示屏,对DDRAM的操作还是在进行的,接着执行下面的某条指令,就能看到刚才屏幕关闭期间,对DDRAM操作的效果了。
;0cH:打开显示屏,不显示光标,光标所在位置的字符不闪烁。
;0dH:打开显示屏,不显示光标,光标所在位置的字符闪烁。
;0eH:打开显示屏,显示光标,光标所在位置的字符不闪烁。
;0fH:打开显示屏,显示光标,光标所在位置的字符闪烁。
; 关于光标的位置:光标所在的位置指示了下一个被写入的字符所处的位置,
; 加入在写入下一个字符前没有通过指令设置DDRAM的地址,那么这个字符就应该显示在光标指定的地方。
;10H:每输入一次该指令,AC就减一,对应了光标向左移动一格。整体的画面不滚动。
;14H:每输入一次该指令,AC就加一,对应了光标向右移动一格。整体的画面不滚动。
;18H:每输入一次该指令,整体的画面就向左滚动一个字符位。
;1CH:每输入一次该指令,整体的画面就向右滚动一个字符位。
; 画面在滚动的时候,每行的首尾是连在一起的,也就是每行的第一个字符,若左移25次,就会显示在该行的最后一格。
; 在画面滚动的过程中,AC的值也是变化的。
;20H:4位总线,单行显示,显示5×7的点阵字符。
;24H:4位总线,单行显示,显示5×10的点阵字符。
;28H:4位总线,双行显示,显示5×7的点阵字符。
;2CH:4位总线,双行显示,显示5×10的点阵字符。
;30H:8位总线,单行显示,显示5×7的点阵字符。
;34H:8位总线,单行显示,显示5×10的点阵字符。
;38H:8位总线,双行显示,显示5×7的点阵字符。这是最常用的一种模式。3CH:8位总线,双行显示,显示5×10的点阵字符。
;80H:第一行
;0C0H:第二行
;*********************************************************************************************************
/*********以下是变量及函数的声明**************/
PUBLIC LCD_R_DATA
PUBLIC LCD_W_DATA
PUBLIC LCD_W_CMD
PUBLIC LCD_CMD
PUBLIC LCD_INIT
PUBLIC LCD_DAT
PUBLIC LCD_FLAG
PUBLIC LCD_Line_BIT
PUBLIC LCD_LineSP
PUBLIC LCD_StackAddress
PUBLIC LCD_Save2Stack
PUBLIC LCD_OverLineSize_Light
;***************************************************
;定义程序区块,编译时动态分配程序地址,此段代码可以不要
_LCD1602_ASM SEGMENT CODE
RSEG _LCD1602_ASM
;***************************************************
/***************变量声明区****************/
LCD_RS BIT P2.5 ;1602数据命令选择端口
LCD_RW BIT P2.6 ;1602读写选择端口
LCD_EN BIT P2.7 ;1602使能端口
LCD_OverLineSize_Light BIT P3.4 ;1602一行显示越界指示灯
LCD_DATA EQU P0 ;1602数据端口
LCD_ALL_FLAG DATA 20H ;标志位
LCD_FLAG BIT LCD_ALL_FLAG.0 ;1602读忙标志位
LCD_Line_BIT BIT LCD_ALL_FLAG.1 ;换行标志位
LCD_DAT DATA 21H ;1602数据命令字
LCD_DELAYED DATA 22H ;延时字
LCD_LineSP DATA 23H ;LCD堆栈指针(最大为一行16个字符)
LCD_StackAddress DATA 0A0H ;LCD堆栈首地址
LCD_StackSize EQU 20 ;LCD堆栈大小
/***************************************************
函数名称:LCD_R_DATA
函数功能:1602读命令函数
输 入:LCD_DATA(P0口)
输 出:高位存至LCD_LAG中
***************************************************/
LCD_R_DATA:
MOV LCD_DATA,
LCD_BUSY: CLR LCD_RS
SETB LCD_RW
NOP
SETB LCD_EN
NOP
MOV Acc,LCD_DATA
MOV C,Acc.7
MOV LCD_FLAG,C
CLR LCD_EN
NOP
JB LCD_FLAG,LCD_BUSY
RET
/***************************************************
函数名称:LCD_W_DATA
函数功能:1602写数据函数
输 入:数据存在LCD_DAT
输 出:LCD_DATA(P0口)
***************************************************/
LCD_W_DATA:
LCALL LCD_R_DATA
SETB LCD_RS
CLR LCD_RW
NOP
MOV LCD_DATA,LCD_DAT
SETB LCD_EN
NOP
CLR LCD_EN
RET
/***************************************************
函数名称:LCD_W_CMD
函数功能:1602写命令函数,检测忙信号
输 入:命令存在LCD_DAT
输 出:LCD_DATA(P0口)
***************************************************/
LCD_W_CMD:
LCALL LCD_R_DATA
CLR LCD_RS
CLR LCD_RW
NOP
MOV LCD_DATA,LCD_DAT
SETB LCD_EN
NOP
CLR LCD_EN
RET
/***************************************************
函数名称:LCD_CMD
函数功能:1602写命令函数,不检测忙信号
输 入:命令存在LCD_DAT
输 出:LCD_DATA(P0口)
***************************************************/
LCD_CMD:
CLR LCD_RS
CLR LCD_RW
NOP
MOV LCD_DATA,LCD_DAT
SETB LCD_EN
NOP
CLR LCD_EN
RET
/***************************************************
函数名称:LCD_INIT
函数功能:1602初始化函数
输 入:无
输 出:无
***************************************************/
LCD_INIT:
MOV LCD_LineSP,
CLR LCD_OverLineSize_Light
SETB LCD_Line_BIT ;第二行
MOV LCD_DELAYED,
LCALL LCD_DELAY_MS
MOV LCD_DAT,
LCALL LCD_CMD
MOV LCD_DELAYED,
LCALL LCD_DELAY_MS
MOV LCD_DAT,
LCALL LCD_CMD
MOV LCD_DELAYED,
LCALL LCD_DELAY_MS
MOV LCD_DAT,
LCALL LCD_CMD
MOV LCD_DELAYED,
LCALL LCD_DELAY_MS
MOV LCD_DAT,
LCALL LCD_W_CMD
MOV LCD_DAT,
LCALL LCD_W_CMD
MOV LCD_DAT,
LCALL LCD_W_CMD
MOV LCD_DAT,
LCALL LCD_W_CMD
MOV LCD_DAT,
LCALL LCD_W_CMD
MOV LCD_DAT,
LCALL LCD_W_CMD
RET
/***************************************************
函数名称:LCD_Save2Stack
函数功能:存储LCD_DAT的内容到堆栈
输 入:LCD_StackAddress,LCD_LineSP
输 出:无
***************************************************/
LCD_Save2Stack:
MOV A,
ADD A, LCD_LineSP
MOV R0, A
MOV @R0, LCD_DAT
INC LCD_LineSP
RET
/*****************************************
延时函数,延时时间为LCD_DELAYED*0.5毫秒 0~100毫秒的延时
*****************************************/
LCD_DELAY_MS:
MOV R7, LCD_DELAYED
D1: MOV R6,
D2: DJNZ R6, D2
DJNZ R7, D1
RET
/*****************************************
延时函数,延时时间为LCD_DELAYED*2微秒 0~500微秒的延时
*****************************************/
LED_DELAY_US:
MOV R7, A
DU1:
DJNZ R7, DU1
RET
END
juzheng
;程序名称: juzheng.asm
;程序说明: 矩阵按键4行*8列,占用P1口和P2的低四位
;按键表示符号含义:
; ;Y P1.0 P1.1 P1.2 P1.3 P1.4 P1.5 P1.6 P1.7
;| | | | | | | |
;X | | | | | | | |
;P2.0 ---- A/1 ---- B/2 ---- C/3 ---- D/4 ---- E/5 ---- F/6 ---- G/7 ---- 换行 ----
;| | | | | | | |
;P2.1 ---- H/8 ---- I/9 ---- J/0 ---- K/" ---- L/= ---- M/@ ---- N/# ---- 清除 ----
;| | | | | | | |
;P2.2 ---- O/$ ---- P/% ---- Q/& ---- R/, ---- S/. ---- T/( ---- U/) ---- 确定 ----
;| | | | | | | |
;P2.3 ---- V/+ ---- W/- ---- X/* ---- Y/ /---- Z/? ----空格/!----数字----大小写切换 ----
;| | | | | | 符号切换 |
;按键数字标号:
;Y P1.0 P1.1 P1.2 P1.3 P1.4 P1.5 P1.6 P1.7
;| | | | | | | |
;X | | | | | | | |
;P2.0 ---- 0 ------ 1 ------ 2 ------ 3 ------ 4 ------ 5 ------ 6 ------ 7 ----
;| | | | | | | |
;P2.1 ---- 8 ------ 9 ------ 10 ----- 11 ----- 12 ----- 13 ----- 14 ----- 15 ----
;| | | | | | | |
;P2.2 ---- 16 ----- 17 ----- 18 ----- 19 ----- 20 ----- 21 ----- 22 ----- 23 ----
;| | | | | | | |
;P2.3 ---- 24 ----- 25 ----- 26 ----- 27 ----- 28 ----- 29 ----- 30 ----- 31 ----
;| | | | | | | |
;以下是变量及函数的声明
PUBLIC KEYSCAN
PUBLIC KEY
PUBLIC Shift_number_BIT, Shift_LH_BIT, Shift_number_Light, Shift_LH_Light
;***************************************************
;定义程序区块,编译时动态分配程序地址,此段代码可以不要
_JUZHENG_ASM SEGMENT CODE
RSEG _JUZHENG_ASM
;***************************************************
;****************头文件包含****************
$INCLUDE(DELAY.INC)
$INCLUDE(LCD1602.INC)
$INCLUDE(USART.INC)
;*****************自定义*********************************************
KEY DATA 24H ;用于存储按键的编号:0~F
JZ_ALL_FLAG DATA 25H ;矩阵键盘的所有标志位
Shift_number_BIT BIT JZ_ALL_FLAG.0 ;切换数字标志位
Shift_LH_BIT BIT JZ_ALL_FLAG.1 ;切换大小写标志位
Shift_number_Light BIT P3.2 ;切换数字指示灯
Shift_LH_Light BIT P3.3 ;切换大小写指示灯
/******************************************************************
函数名称:KEYSCAN
函数说明:按键扫描子程序:反转法识别按键,并将按键编码压入显示缓冲区
;行列键扫描程序
;使用XY查找4x8键的方法,只能单键,速度快
;****************************************************************/
KEYSCAN:
ANL P2, #0F0H
MOV P1, #0FFH ;置列(P1)为输入模式,行(P2低四位)为输出模式
MOV A, P1 ;读入P1口状态,判断是否有键按下
CJNE A, #0FFH, KEYCODE ;不相等说明有键按下,转按下键的处理
MOV KEY, #0xFF
RETURN:
RET ;相等说明没有键按下,返回
KEYCODE:
LCALL DELAY4ms ;延时消除抖动
MOV A, P1 ;
CJNE A, #0FFH, KEYID ;延时后读入P1口状态,不相等说明确实有键按下,转入键识别处理过程
LJMP RETURN ; 相等则说明是干扰引起,不予处理
KEYID:
MOV R4, A ; 此时的P1口状态已经读入R4中,对应按下的行为0,将行状态咱存于R4
ORL P2, #0FH
MOV P1, #00H ;行列反转置列为输入模式,列为输出模式全为0
NOP
NOP ; 适当短延时,待端口电平稳定
MOV A, P2 ;读入P2口状态,有键按下的话,则对应的行会被拉低,将列状态存入A中,
ANL A, #0FH ;去除高四位,保留低四位
MOV R3, A ;按键扫描码暂存于R3中
//下面等待键释放
KEYUP:
MOV A, P2 ;读入P2口状态
ANL A, #0FH
CJNE A, #0FH, KEYUP ; 不相等说明按键没有松开,继续等待
LCALL DELAY4ms ;相等说明按键松开,延时消除抖动
MOV A, P2 ;读入P2口状态
ANL A, #0FH
CJNE A, #0FH, KEYUP ; 不相等说明按键没有真正松开,干扰造成,继续等待
; 相等说明按键真正松开了,开始根据存储于R3,R4中的按键扫描码做按键编码处理
KEYCODE1:MOV DPTR, #JBKEY ;DPTR指向显示码存储区
MOV R2, #20H ;32个按键,循环32次
MOV R5, #00H ;顺序读取按键的数字标号
KEYCODELOOP:
MOV A, R5
ADD A, R5
MOVC A, @A+DPTR ;
SUBB A, R3 ;
JNZ KEYCODEi
MOV A, R5
ADD A, R5
INC A
MOVC A, @A+DPTR ;
SUBB A, R4
JNZ KEYCODEi ;
MOV DPTR, #SEGCODE ;DPTR指向显示码存储区
MOV A, R5
MOV KEY, A ;保存到KEY
MOV A, R5
CLR C
SUBB A, #7
JZ JMP_KEY_7 ;跳转到下方JMP_KEY_7
MOV A, R5
CLR C
SUBB A, #15
JZ JMP_KEY_15 ;跳转到下方JMP_KEY_15
MOV A, R5
CLR C
SUBB A, #23
JZ JMP_KEY_23 ;跳转到下方JMP_KEY_23
MOV A, R5
CLR C
SUBB A, #30
JZ JMP_KEY_30 ;跳转到下方JMP_KEY_30
MOV A, R5
CLR C
SUBB A, #31
JZ JMP_KEY_31 ;跳转到下方JMP_KEY_31
MOV A, LCD_LineSP
JNZ Character_Show_Normal ;判断LCD_LineSP是否为0,否,正常显示
MOV LCD_DAT, #01H ;是,则进行LCD清屏
LCALL LCD_W_CMD
//显示串口堆栈里的内容
;MOV R0, #Usart_StackAddress
;MOV R1, #16 ;LCD一行显示16个字符,不采取滚动模式
;Show_UsartStask:
;MOV LCD_DAT, @R0 ;30H为LCD_DAT
;LCALL LCD_W_DATA ;显示串口堆栈中的内容到LCD显示
;INC R0
;DJNZ R1, Show_UsartStask ;显示串口堆栈中的前16位
MOV R0, #Usart_StackAddress ;获取堆栈首地址
MOV R1, #16 ;获取堆栈指针
LCALL ShowStask
MOV LCD_DAT, #0C0H ;切换到LCD的第二行
LCALL LCD_W_CMD
Character_Show_Normal:
MOV A, LCD_LineSP
CJNE A ,#16, Character_Show_Normali ;判断输入是否超过16个字符越界,越界则不保存
SETB LCD_OverLineSize_Light ;越界指示灯点亮
LJMP RETURN ; 返回
Character_Show_Normali:
CLR LCD_OverLineSize_Light ;没有越界,越界指示灯熄灭
LCALL Character_Show ;正常显示
LJMP RETURN ;退出本次按键扫描
KEYCODEi:
INC R5 ;
DJNZ R2, KEYCODELOOP
RET
JMP_KEY_7:
LJMP KEY_7 ;删除(删除一位字符)
RET
JMP_KEY_15:
LJMP KEY_15 ;清屏
RET
JMP_KEY_23:
LJMP KEY_23 ;确定发送
RET
JMP_KEY_30:
LJMP KEY_30 ;切换成数字
RET
JMP_KEY_31:
LJMP KEY_31 ;切换大小写
RET
//键7:删除(删除一位字符)
KEY_7:
MOV LCD_DAT, #01H ;LCD清屏
LCALL LCD_W_CMD
MOV R0, #Usart_StackAddress ;获取堆栈首地址
MOV R1, #16 ;获取堆栈指针
LCALL ShowStask
MOV LCD_DAT, #0C0H ;切换到LCD第二行
LCALL LCD_W_CMD
DEC LCD_LineSP
MOV R0, #LCD_StackAddress ;获取堆栈首地址
MOV R1, LCD_LineSP ;获取堆栈指针
LCALL ShowStask
LJMP RETURN ;退出本次按键扫描
RET
//键15:清屏
KEY_15:
MOV LCD_LineSP, #00H ;LCD堆栈指针归零
CLR LCD_OverLineSize_Light ;越界指示灯熄灭
MOV LCD_DAT, #01H ;LCD清屏
LCALL LCD_W_CMD
MOV LCD_DAT, #0C0H ;切换到LCD第二行
LCALL LCD_W_CMD
LJMP RETURN ;退出本次按键扫描
RET
//键23:确定发送
KEY_23:
LCALL SendNByte ;发送LCD堆栈中的字符
MOV Usart_Buffer, #0AH ;结束标志字符 0A 0D
LCALL Send0neByte
MOV Usart_Buffer, #0DH
LCALL Send0neByte
//如果想在发送后本机LCD上显示刚刚发送的字符串,只有把下面的代码注释即可
;*******************************************************************
MOV LCD_DAT, #01H ;LCD清屏
LCALL LCD_W_CMD
MOV R0, #Usart_StackAddress ;获取堆栈首地址
MOV R1, #16 ;获取堆栈指针
LCALL ShowStask
MOV LCD_DAT, #0C0H ;切换到LCD第二行
LCALL LCD_W_CMD
;*********************************************************************
MOV LCD_LineSP, #00H ;LCD堆栈指针归零
CLR LCD_OverLineSize_Light ;越界指示灯熄灭
LJMP RETURN ;退出本次按键扫描
RET
//键30:切换成数字
KEY_30:
CPL Shift_number_BIT ;翻转数字符号切换标志位
CPL Shift_number_Light ;翻转数字符号切换指示灯
LJMP RETURN ;退出本次按键扫描
RET
//键31:切换大小写
KEY_31:
CPL Shift_LH_BIT ;翻转切换大小写标志位
CPL Shift_LH_Light ;切换大小写标志位指示灯
LJMP RETURN ;退出本次按键扫描
RET
Character_Show: ;优先级:数字 > 大写 > 小写
JB Shift_number_BIT, Shift_number ;数字的优先级高
JB Shift_LH_BIT, Shift_upper ;其次是大写
LCALL Shift_lower ;最后是小写
RET
Shift_number:
MOV DPTR, #SEGCODE ;设置DPTR到标准字库
MOV A, KEY ;获取按键数字标号
ADD A, #64 ;数字符号区
MOVC A, @A+DPTR ;
MOV LCD_DAT, A ;
LCALL LCD_Save2Stack ;保存到LCD堆栈
LCALL LCD_W_DATA ;LCD显示字符
LJMP RETURN ;退出本次按键扫描
RET
Shift_upper:
MOV DPTR, #SEGCODE ;设置DPTR到标准字库
MOV A, KEY ;获取按键数字标号
ADD A, #32 ;大写英文区
MOVC A, @A+DPTR ;
MOV LCD_DAT, A
LCALL LCD_Save2Stack ;保存到LCD堆栈
LCALL LCD_W_DATA ;LCD显示字符
LJMP RETURN ;退出本次按键扫描
RET
Shift_lower:
MOV DPTR, #SEGCODE ;设置DPTR到标准字库
MOV A, KEY ;获取按键数字标号
MOVC A, @A+DPTR ; ;小写英文区
MOV LCD_DAT, A
LCALL LCD_Save2Stack ;保存到LCD堆栈
LCALL LCD_W_DATA ;LCD显示字符
LJMP RETURN ;退出本次按键扫描
RET
/***************************************************
函数名称:SendNByte
函数功能:发送N个字节
输 入:Usart_Buffer
输 出:无
***************************************************/
SendNByte:
MOV R0, #LCD_StackAddress ;获取LCD堆栈首地址
MOV R1, LCD_LineSP ;获取LCD堆栈指针
CJNE R1, #00H, SendNByteLOOP ;R1不为0,串口发送LCD_LineSP个字符
RET ;R1为0,返回
SendNByteLOOP:
MOV Usart_Buffer, @R0
LCALL Send0neByte ;
INC R0
DJNZ R1, SendNByteLOOP ;串口发送LCD_LineSP个字符
RET
JBKEY: ;判断按键对应的标号
; 0 1 2 3 4 5 6 7
DB 0EH,0FEH, 0EH,0FDH, 0EH,0FBH, 0EH,0F7H, 0EH,0EFH, 0EH,0DFH, 0EH,0BFH, 0EH,07FH
; 8 9 10 11 12 13 14 15
DB 0DH,0FEH, 0DH,0FDH, 0DH,0FBH, 0DH,0F7H, 0DH,0EFH, 0DH,0DFH, 0DH,0BFH, 0DH,07FH
; 16 17 18 19 20 21 22 23
DB 0BH,0FEH, 0BH,0FDH, 0BH,0FBH, 0BH,0F7H, 0BH,0EFH, 0BH,0DFH, 0BH,0BFH, 0BH,07FH
; 24 25 26 27 28 29 30 31
DB 07H,0FEH, 07H,0FDH, 07H,0FBH, 07H,0F7H, 07H,0EFH, 07H,0DFH, 07H,0BFH, 07H,07FH
SEGCODE: ;标准字库
DB 'a','b','c','d','e','f','g',' '
DB 'h','i','j','k','l','m','n',' '
DB 'o','p','q','r','s','t','u',' '
DB 'v','w','x','y','z',' ',' ',' '
DB 'A','B','C','D','E','F','G',' '
DB 'H','I','J','K','L','M','N',' '
DB 'O','P','Q','R','S','T','U',' '
DB 'V','W','X','Y','Z',' ',' ',' '
DB '1','2','3','4','5','6','7',' '
DB '8','9','0','"','=','@','
DB '$','%','&',',','.','(',')',' '
DB '+','-','*','/','?','!'
;*****************结束*******************
END ;
delay
;以下是变量及函数的声明
PUBLIC DELAY400MS
PUBLIC DELAY1ms
PUBLIC DELAY4ms
;***************************************************
;定义程序区块,编译时动态分配程序地址,此段代码可以不要
_DELAY_ASM SEGMENT CODE
RSEG _DELAY_ASM
;***************************************************
//延时400ms子程序,用于数码管闪烁显示报警
//延时400ms子程序,用于数码管闪烁显示报警
DELAY400MS: ;@12.000MHz
NOP
NOP
NOP
PUSH 60H
PUSH 61H
PUSH 62H
MOV 60H,
MOV 61H,
MOV 62H,
NEXT0:
DJNZ 62H, NEXT0
DJNZ 61H, NEXT0
DJNZ 60H, NEXT0
POP 62H
POP 61H
POP 60H
RET
//延时1ms子程序:修改R7可以改变延时时间的长短,控制扫描速度,12MHz时钟,延时约1ms
DELAY1ms:
MOV R7,
DEL2:
MOV R6,
NOP
DEL3:
DJNZ R6, DEL3
DJNZ R7, DEL2
RET ; 子程序返回
//延时4ms子程序:用于按键消除抖动,实际应用时可以根据按键灵敏度修改
DELAY4ms: ;@12.000MHz
MOV 70H,
MOV 71H,
NEXT:
DJNZ 71H, NEXT
DJNZ 70H, NEXT
RET
;*****************结束*******************
END
usart(应该是uart,下面的文件写错了,另行修改)
;以下是变量及函数的声明
PUBLIC Usart_Init
PUBLIC Usart_ISR
PUBLIC Send0neByte
PUBLIC Usart_Buffer
PUBLIC Usart_StackSP
PUBLIC Usart_StackAddress
PUBLIC ShowStask
;***************************************************
;定义程序区块,编译时动态分配程序地址,此段代码可以不要
_USART_ASM SEGMENT CODE
RSEG _USART_ASM
;***************************************************
$INCLUDE(LCD1602.INC)
Usart_Buffer DATA 27H ;串口缓存器
Usart_StackSP DATA 28H ;串口堆栈指针
Usart_StackAddress DATA 80H ;串口堆栈首地址
Usart_StackSize EQU 20 ;串口堆栈大小
;AT89C52定时器有4种工作方式,与STC15的定时器工作方式不同
;有四种工作方式:
;方式0,13位定时/计数方式。
;方式1,16位的定时/计数方式。
;方式2,自动重装载8位工作方式
;方式3,定时/计数器0被拆成2个独立的定时/计数器来用。
;其中,TL0可以构成8位的定时器或计数器的工作方式,而TH0则只能作为定时器来用。
/***************************************************
函数名称:Usart_Init
函数功能:串口初始化
输 入:无
输 出:无
***************************************************/
Usart_Init:
MOV TMOD,
MOV SCON,
MOV TH1,
MOV TL1,
MOV PCON,
SETB ES
SETB EA
SETB TR1
MOV Usart_Buffer,
MOV Usart_StackSP,
RET
/***************************************************
函数名称:Usart_ISR
函数功能:串口中断服务程序
输 入:无
输 出:Usart_Buffer
***************************************************/
Usart_ISR:
PUSH ACC
JB RI, Usart_Receive ;判断是否在接收数据
Usart_Transmit:
CLR TI ;清除发送标志位
RETI
Usart_Receive:
CLR RI ;清除接收标志位
MOV A, SBUF
CJNE A,
MOV Usart_Buffer, SBUF ;是 0A ,存放到串口缓存器
JMP Usart_Receive_RET ;退出串口中断服务函数
JReceiveEND1:
MOV A, Usart_Buffer
CJNE A,
MOV A, SBUF ;是 0A,将SBUF中的内容放到累加器A
CJNE A,
;是 0D,串口接收字符串结束
MOV A, Usart_StackSP ;
JZ JReceiveEND1i ;Usart_StackSP为0,则跳转,归零串口缓存器,和串口指针
;避免了避免连续按“发送”按键误操作
//接收完成后进行数据处理
//此次接收,堆栈没有存内容的地址里的内容清除,即 Usart_StackSP ~ Usart_StackSize的内容清除
MOV A,
ADD A, Usart_StackSP ;获取堆栈指针
MOV R0, A
MOV A,
SUBB A, Usart_StackSP
MOV R1, A
CLR_LOOP:
MOV @R0,
INC R0
DJNZ R1, CLR_LOOP ;循环
//接收到的字符串显示到LCD
MOV LCD_DAT,
LCALL LCD_W_CMD
MOV R0,
MOV R1, Usart_StackSP ;获取堆栈指针
LCALL ShowStask
MOV LCD_DAT,
LCALL LCD_W_CMD
JReceiveEND1i:
MOV Usart_Buffer,
MOV Usart_StackSP,
JMP Usart_Receive_RET
JReceiveEND2:
MOV Usart_Buffer,
MOV A,
ADD A, Usart_StackSP
MOV R0, A
MOV @R0, Usart_Buffer
INC Usart_StackSP
Usart_Receive_Normal:
MOV Usart_Buffer, SBUF ;获取接收到的数据到累加器A
MOV A,
ADD A, Usart_StackSP
MOV R0, A
MOV @R0, Usart_Buffer
INC Usart_StackSP
Usart_Receive_RET:
POP ACC
RETI
/***************************************************
函数名称:ShowStask
函数功能:显示堆栈里的内容
输 入:R0(堆栈首地址),R1(获取堆栈指针)
输 出:无
调用举例:例如:
MOV R0,
MOV R1, Usart_StackSP ;获取堆栈指针
LCALL ShowStask
***************************************************/
ShowStask:
MOV LCD_DAT, @R0 ;30H为LCD_DAT
LCALL LCD_W_DATA ;显示堆栈里的内容
INC R0
DJNZ R1, ShowStask ;循环
RET
/***************************************************
函数名称:Send0neByte
函数功能:发送一个字节
输 入:Usart_Buffer
输 出:无
***************************************************/
Send0neByte:
CLR ES ;关闭串口中断
CLR TI ;清除发送标志位
MOV SBUF, Usart_Buffer;将数据Buffer里的数据发送出去
SendFinish:
JNB TI, SendFinish ;判断是否发送完毕
CLR TI ;是,则清除发送标志位
SETB ES ;开启串口中断
RET
END