本帖依旧是使用AT89C2051、汇编语言实现的一个小程序。应用时,与计算机相连,从串口收到可显示的字符时,显示到LCD1602上。LCD1602基本上也算是被淘汰的LCD了,但作为初学者,学习相关的通讯处理,个人觉得依旧有存在的意义。这个汇编程序,对于学习、理解51单片机在中断上的处理方式上,希望能对51单片机初学者有所帮助。
电路图:
P1.0和 P1.1作为IO使用的时候,必须要加上拉电阻。串口没有做特殊处理,连接计算机的串口时,需要使用TTL转换电路,这一点要特别注意。串口的通讯波特率为2400,n,8,1模式。
程序如下:
;显示缓冲区1---第一行数据,总共16字节 08H-17H LineBuf1 equ 08H ;显示缓冲区1---第二行数据,总共16字节 18H-27H LineBuf2 equ 18H ;寄存器选择 RS equ P3.4 ;R/W为读写信号线,高电平时进行读操作,低电平时进行写操作。 ;当RS和RW共同为低电平时可以写入指令或者显示地址, ;当RS为低电平RW为高电平时可以读忙信号, ;当RS为高电平RW为低电平时可以写入数据; RW equ P3.5 ;E端为使能端,当E端由高电平跳变成低电平时,液晶模块执行命令; EN equ P3.7 ;;串口接收完整数据标志单元 ;DatOK equ 28H ;串口数据接收缓冲区,收到03时,缓冲区单元重新指向30H,并建立标志,启动显示 ComDatBuf equ 2AH ;标号==============指令================================地址===机器码======= ORG 0000H LJMP Startup ORG 0023H LJMP ComInt Startup: ;初始化所有单元为0 MOV R0,#7FH CLR A initmem: MOV @R0,A DJNZ R0,initmem ;设置堆栈地址 MOV SP,#40H ;初始化LCD1602 LCALL InitLcd ;初始化串口:2400,N,8,1 Lcall InitCom Main: NOP ;建立串口缓冲区接收地址 MOV R0, #ComDatBuf MOV R7,#0AH MOV R6,#00H LCALL _DELAY ;清除显示 ;LCALL ClearDisp ;显示第一行字符串 CLR A MOV R7,A LCALL LCD_POS DispLine1: MOV A,R6 MOV DPTR,#LineStr1 MOVC A,@A+DPTR MOV R7,A JZ Line2Start LCALL LCD_WDAT INC R6 LJMP DispLine1 ;显示第二行字符串 Line2Start: MOV R7,#41H LCALL LCD_POS CLR A MOV R6,A DispLine2: MOV A,R6 MOV DPTR,#LineStr2 MOVC A,@A+DPTR MOV R7,A JZ LoopEnd LCALL LCD_WDAT INC R6 LJMP DispLine2 LoopEnd: LJMP LoopEnd ;========================================================================== InitLcd: MOV R7,#38H LCALL LCD_WCMD MOV R7,#01H MOV R6,#00H LCALL _DELAY ;MOV R7,#0CH MOV R7,#0FH LCALL LCD_WCMD MOV R7,#01H LCALL _DELAY MOV R7,#06H LCALL LCD_WCMD MOV R7,#01H LCALL _DELAY LCALL LCD_WCMD LJMP _DELAY ;========================================================================== LCD_WCMD: LCALL LCD_Busy JC LCD_WCMD CLR RS CLR RW CLR EN NOP NOP MOV P1,R7 NOP NOP NOP NOP SETB EN NOP NOP NOP NOP CLR EN RET ;========================================================================== LCD_WDAT: LCALL LCD_Busy JC LCD_WDAT SETB RS CLR RW CLR EN NOP NOP MOV P1,R7 NOP NOP NOP NOP SETB EN NOP NOP NOP NOP CLR EN RET ;========================================================================== ;延时 _DELAY: CLR A MOV R5,A Delay1: MOV A,R5 CLR C SUBB A,R7 MOV A,R6 XRL A,#80H MOV R3,A MOV A,#80H SUBB A,R3 JNC DelayEnd CLR A MOV R4,A Delay2: INC R4 CJNE R4,#0FDH,Delay2 INC R5 SJMP Delay1 DelayEnd: RET ;========================================================================== ;检查LCD是否忙中 LCD_Busy: CLR RS SETB RW SETB EN NOP NOP NOP NOP MOV A,P1 RLC A CLR EN RET ;========================================================================== ;设置LCD显示位置 LCD_POS: MOV A,R7 ORL A,#80H MOV R7,A LJMP LCD_WCMD ;清除所有显示 ClearDisp: NOP CLR A MOV R7,A LCALL LCD_POS DispSpc1: MOV A,R6 MOV DPTR,#LineSpace MOVC A,@A+DPTR MOV R7,A JZ LineSpc2Start LCALL LCD_WDAT INC R6 LJMP DispSpc1 LineSpc2Start: MOV R7,#41H LCALL LCD_POS CLR A MOV R6,A DispSpc2: MOV A,R6 MOV DPTR,#LineSpace MOVC A,@A+DPTR MOV R7,A JZ ClearEnd LCALL LCD_WDAT INC R6 LJMP DispSpc2 ClearEnd: RET ;初始化串口工作为2400,N,8,1模式,为了和HC-06匹配波特率 InitCom: NOP ;清除显示 LCALL ClearDisp MOV TMOD, #20H ;设置T1的工作模式:2、自动装载,8位计数器 MOV TH1, #0FAH ;6M晶振, 2400波特率 MOV TL1, #0FAH SETB TR1 ;允许T1开始工作 MOVSCON, #50H;设定串行口工作模式=1,8位UART,软件控制允许串口接收数据。REN=1,允许接收;REN=0:禁止接收 ;MOV PCON, #00H ;波特率不加倍.6M晶振场合,2400波特率/4800波特率 SETBES;允许串口中断 SETBEA;开中断 RET ;串口中断处理程序,接收来自HC-06的数据,并保存到缓冲区, ;收到结束标志时,建立允许显示标志DatOK,并准备转送。 ;未收到结束标志,但已经超过10个字符了,重新初始化接收缓冲区标志 ;******************************串口中断处理程序,接收字符直到收到0x03或者超过了16个字符时 ComInt: CLR ES ;禁止中断 PUSH ACC ;保存现场 PUSH PSW PUSHB JNB RI, ComEnd ;收到数据? CLRRI ;取得串口数据 MOV A, SBUF ;保存到缓冲区 MOV @R0, A ;是否收到结束标志03H? XRL A, #03H JNZReadNext0 ;显示串口数据到液晶上 LCALl DispComDat ;重新指向串口缓冲区首地址 MOV R0, #ComDatBuf LJMP ComEnd ReadNext0: NOP ;没有收到结束标志,但已经超过了16个字符? MOV A, #ComDatBuf ADD A, #16 XRL A, R0 JNZ ReadNext ;显示串口数据到液晶上 LCALl DispComDat ;重新指向串口缓冲区首地址 MOV R0, #ComDatBuf LJMP ComEnd ReadNext: INC R0;指向下一个缓冲区 ComEnd: POPB POP PSW POP ACC ComEnd1: SETB ES ;开放串口中断,允许下次接受 RETI ;显示串口接收到的数据(结束标志03H,不能被显示) DispComDat: NOP MOV R2, #0 ;计数显示字符数目 MOV R1, #ComDatBuf ;显示在第一行上 CLR A MOV R7, A LCALL LCD_POS ;循环接收缓冲区数据 DispComDat1: MOV A, @R1 MOV B, A ;是否为结束标志,是则不显示并退出 XRL A, #03H JZ DispComDatEnd ;不是结束标志,正常数据,发给液晶显示 MOV R7, B LCALL LCD_WDAT INC R2 ;是否已经显示了16个字符? MOV A, #16 XRL A, R2 JZ DispComDatEnd ;没有。指向下一个数据,继续显示 INC R1 LJMP DispComDat1 ;恢复缓冲区首地址 DispComDatEnd: MOV R0, #ComDatBuf RET ;========================================================================== ;数据定义区 ;========================================================================== LineSpace: DB ' ' DB 00H ;LineStr1: DB 20H, 20H, 57H, 61H, 6EH, 67H, 48H, 65H, 6AH, 75H, 6EH, 20H, 20H, 00H; LineStr1: DB '2016-12-12 12:00:00' DB 00H LineStr2: DB 20H, 31H, 38H, 36H, 32H, 34H, 32H, 30H, 31H, 38H, 35H, 32H, 20H, 00H; END
程序中都有注释,很容易理解。