仲恺农业工程学院课程设计基于STC89C52RC单片机LCD1602液晶显示屏上的菜单系统机械电子工程102班XXX学号:XXXXXXXXXXXX指导老师XXX完成时间:2013年6月6日简介:8051单片机的程序虽然简单,但是在进行新的设计的时候,也必须重新编写系统的每一行代码,在每一个源程序中有很多代码都是重复的,比如说中断服务的程序框架,主函数的跳转,字模的数据,延迟函数的程序主体,字模数据等等。这个过程不但需要时间,而且有出错的可能,在编译的时候不能通过,不得不再花时间检查程序。如果有一个通用性强,包含各种常用函数,有统一的程序入口,并且有信息反馈(LCD屏幕菜单)的单片机系统的话就能简化以后的设计过程,本课程设计就是这样的一个菜单系统,它将配合单片机的实验板使用。界面设计:本菜单系统一共有4重,分别是欢迎界面,设备选择界面,功能选择界面,以及运行结果界面,在功能选择界面下,用”←””→”选中设备后按下enter即可执行,结果显示在屏幕上。欢迎界面我把该菜单系统命名为sunflower,第二行显示我的邮箱地址tamayura@sina.com设备选择界面首行显示编译版本的代号,由于位置不够写sunflowerOS,就用片假名代替。功能选择界面此界面下按下enter即可执行子程序运行结果显示电路设计:LCD1602液晶屏幕的并行端口为三态的I/O口,并且内置上拉电阻,与STC89C52RC单片机的P0三态I/O连接最合适不过了,相应的,STC89C52RC单片机与LCD1602液晶屏幕的通信将会以并行的方式进行。该系统的任务并不是单单与LCD1602液晶屏幕通信,还要与各种器件通信(常见的比如DS18B20,DHT11等传感器),因此预留P2口作为与其他器件通信的端口。Proteus仿真时的原理图为了实现控制功能,我在本设计中加入了4个按键,分别是:”←”,”enter”,”esc”,”→”这四个。要加快系统的反应速度,系统对键盘的反应的以中断的形式进行的,4个按键再分别与门电路74HC21(双四路与门)的四个输入端口相连,以及和P1端口的P1.4,P1.5,P1.6,P1.7相连,为什么选这四个呢?因为P1与外部中断靠的够近,接线的时候不用绕来绕去。中断方式是电平式(低电平有效)。以下是真值表的一部分,之所以用到与门是因为中断是低电平触发的。74hc21←enteresc→不按键11111按下←00111按下enter01011按下esc01101按下→00001同时按下←和enter01100显然,所用按键的另一端接的是地(低电平),74hc21的输出端接的是中断端口,为了实现不按键时出现第一行所述的情况,在系统启动复位以及在响应完中断之后向按键端口P1.4,P1.5,P1.6,P1.7发送高电平。下面是中断响应的程序段:当外部中断INT0有效时程序入栈后跳转至0003H。ORG0003HCLREALJMPOS_KEYSCAN以上段落的含义是在响应中断以后马上关闭中断,否则不放手就没反应,然后跳转到键盘的扫描程序,由于计算机程序是顺序执行的,就算几个按键一起按也只会响应一个,程序中最优先的一个。请看下面段落:ORG0200HOS_KEYSCAN:JNBKEY_en,OS_enJNBKEY_exit,OS_escJNBKEY_R,OS_RJNBKEY_L,OS_L以上段落是逐一扫描按键,从enter开始,检测到低电平的话执行响应程序OS_XX。下面分别介绍”enter”的响应程序和”→”的响应程序:OS_en:INCR_OS_DEEPCJNER_OS_DEEP,#03H,OS_en_BackOS_APP:MOVR_OS_DEEP,#02HMOVA,ITEMMOVB,#03HMULABMOVDPH,08HMOVDPL,00HJMP@A+DPTROS_en_Back:CJNER_OS_DEEP,#01H,OS_en_DEEP_2MOVITEM,#00HLCALLLCD1602_RenewRETIOS_en_DEEP_2:MOVFUNCTION,#00HLCALLLCD1602_RenewRET分析:在系统中,利用R_OS_DEEP记录当前菜单位置{欢迎界面=00H,设备选择=01H,功能选择=02H},利用ITEM记录当前设备编号,利用FUNCTION记录需要执行的功能编号,当R_OS_DEEP=02H时(也就是处于功能选择界面)再按下enter的话就会执行对应的子程序了。当处欢迎界面或者设备选择界面时,再按下enter就会进入下一级界面(设备选择和功能选择),而按下esc键则是后退,程序大同小异,不再详细说明。系统设计:上电启动后程序从0000H处开始执行:ORG0000HJMPMAINORG0080HMAIN:CLREAMOVSP,#60HMOVR_OS_DEEP,#00HMOVITEM,#00HMOVFUNCTION,#00HMOVP1,#0FFHSETBEX0LCALLLCD1602_RETSETLCALLLCD1602_RenewSTART:SETBEALJMPSTART上电复位之后,系统启动,先关闭中断源,然后把相关的寄存器进行初始化,然后调用LCD1602_RETSET这个函数复位显示器,然后调用LCALLLCD1602_Renew刷新内容,将会进入欢迎界面,在界面上将会显示本人的邮箱地址:tamayura@sina.com。然后进入一个等待中断的循环。并且在中断响应结束后返回到该循环,为了更直观地表示系统运行的方式,绘制了如下的框图。后面的说明围绕此框图进行说明。系统的运行方式关于显示:LCD1602液晶显示屏支持并口和串口的通信因为STC89C52RC单片机的并口够多,而且并口的程序比较容易写,所以利用并口的通信方式。LCD1602液晶显示屏的引脚功能如下表。从表格的第4到6行看出LCD1602液晶显示屏的通信时序是:E引脚的下降沿执行命令或者写入数据,并行通信时以字节为单位发送的。编写发送命令的方式如下:LCD1602_Command:CLRRS;R4是程序的参数,长度是一字节的命令CLRRWCLRE_1SETBE_1MOVP_DATA,R4CLRE_1MOVR_OS_Delay_250ms,#0FFH;Delay4msLCALLOS_Delay_250msRETLCD1602各引脚的功能原理是先把E引脚的电位拉到高电平,然后把要发送的命令发到P0,再把E引脚的电位拉低,在E引脚的下沿时执行命令。类似的,发送数据的方式也差不多,只不过是RS和RW引脚的电位不同而已LCD1602_WriteData:SETBRS;R4是程序的参数,长度是一字节的数据CLRRWSETBE_1MOVP_DATA,R4CLRE_1CLRRSMOVR_OS_Delay_1ms,#010H;Delay12usLCALLOS_Delay_1msRET由于液晶屏接受数据及命令执行的时候需要时间,所以在命令和数据发送是调用到延迟程序。否则发送的数据会丢失,另外一种方法是通过读取LCD16002的忙信号来确定是否继续发送下一条命令或者下一字节数据。在存储器分配方面,用如下的语句进行声明,在编写程序的过程中,用单词表示存储器更直观而且方便记忆,就像C语言中的声明语句一样,可以使程序更有可读性,R_OS_Delay_1msEQU30HR_OS_Delay_250msEQU31HR_OS_Delay_60sEQU32HR_OS_DEEPEQUR2ITEMEQUR6FUNCTIONEQUR7其中,R_OS_DEEP是记录当前系统界面的位置,R_OS_DEEP=00H时,显示欢迎界面;R_OS_DEEP=01H时,显示设备选择界面;R_OS_DEEP=02H时,显示功能选择界面。系统运行的时候,每当用户按下enter按键R_OS_DEEP就会增加01H,再刷新一下屏幕数据以显示下一层菜单,相对的,每当用户按下esc按键的时候R_OS_DEEP就会减少01H,再刷新一下屏幕数据就可以显示上一层菜单。特别的,当R_OS_DEEP=02H时,再按下enter按键就会执行子函数,返回时赋值R_OS_DEEP=02H,并且把运行结果显示在屏幕上。比如说,再DS18b20温度传感器设备的功能选择界面上用←和→按键选择到“读取温度”函数后按下enter就会执行“温度读取”的子程序段,并把结果显示在第二行。而ITEM则是记录选中的设备,R_OS_DEEP=01H,时按下→ITEM就会增加01H,由于设备定义了四个,所以设备的选中是以环移的形式进行的,也就是说ITEM=03H时按下→就会使ITEM=01H。按下←则把过程逆过来。选择设备时显示数据也是会更新的。为了方便程序的寻址,设备名字记录在固定的数据段中,在设计中加入新设备是修改该数据段上的数据。ORG1100HDB'ITEM01'ORG1110HDB'ITEM02'ORG1120HDB'ITEM03'ORG1130HDB'ITEM04'跟ITEM记录选中设备的原理相类似的FUNCTION记录选中设备的功能,按下→就会增加01H,环移形式,按下←则相反,每当ITEM改变时,重新赋值FUNCTION=0,这跟大家对很多有菜单的设备的使用习惯是相同的。设备功能的名称的存储方式是和设备名字类似的,在特定数据段中存储,引用时需要查表:(ITEM×4+FUNCTION)×16需要乘以16是因为一个功能名字固定长度为16字节,刚好是屏幕一行能显示的宽度,设备名太短就用空格补足。一下是第一个设备的前面两个功能名字的存放方式。ORG1200HDB'FUNTION-01'ORG1210HDB'FUNTION-02'子程序的加入:上文说到:当R_OS_DEEP=02H时,再按下enter按键就会执行子函数,返回时赋值R_OS_DEEP=02H,并且把运行结果显示在屏幕上。是利用以下语句实现的,中断响应后检测到enter被按下则跳转到OS_enOS_en:INCR_OS_DEEPCJNER_OS_DEEP,#03H,OS_en_BackOS_APP:MOVR_OS_DEEP,#02HMOVA,ITEMMOVB,#03HMULABMOVDPH,08HMOVDPL,00HJMP@A+DPTROS_en_Back:CJNER_OS_DEEP,#01H,OS_en_DEEP_2MOVITEM,#00HLCALLLCD1602_RenewRETIOS_en_DEEP_2:MOVFUNCTION,#00HLCALLLCD1602_RenewRETI加粗部分的语句是一个查表的的功能,他的目标是一个程序的跳转表。跳转表起始位置0800H+(ITEM×04H+FUNCTION)×10HORG0800HLJMPAP_1_1LJMPAP_1_2LJMPAP_1_3LJMPAP_1_4LJMPAP_2_1LJMPAP_2_2当指针指向这个跳转表时程序再一次跳转,跳转到子程序,子程序用标号“AP_?_?:”表示即可。一个空的子程序是这样的,一共就两行。AP_1_1:LCALLLCD1602_RenewRETI在想要加入新功能的时候只需要在首行插入目标子程序即可,要注意的是子程序不能用到系统占用的寄存器,比如前面提到的:R_OS_DEEPEQUR2ITEMEQUR6FUNCTIONEQUR7总结这是一个实现菜单系统的一种可能,存在纰漏。加入子程序的方式比较繁琐,先要把单片机取出来,并按照该系统的规范对三个地方(设备名的数据段,设备功能名的数据段,子程序的代码段)的代码进行修改,然后编译,再把程序烧录在单片机上并放回原来的地方。其次,代码用汇编语言编写,提高了运行效率的同时,通用性很差,不能移植到其他指令集的单片机上。由于课程设计时间短,源程序的代码没有完全优化好,比如说在声明的时候没有声明所用系统占用的寄存器,导致在程序中直接写出寄存的地址,可读性不够,在没有完全优化源程序代码时基本上只有我明白其中的含义