微波EDA网,见证研发工程师的成长!
首页 > 研发问答 > 嵌入式设计讨论 > FPGA,CPLD和ASIC > FPGA实验之1602字符液晶设计

FPGA实验之1602字符液晶设计

时间:10-02 整理:3721RD 点击:

FPGA实验之1602字符液晶设计
1.     实验目的:
通过本次实验,掌握使用 HDL语言操作1602字符液晶的方法。
2.     实验原理:
(1) 1602字符液晶简介
上一课我们学会了LED数码管的原理及使用,下面,我们再来学习字符型液晶模块的使用。液晶屏显示模块与数码管相比,它显得更为与业、漂亮。液晶显示屏以其微功耗、体积小、显示内容丰富、超薄轻巧、使用方便等诸多优点,在通讯、仪器仪表、电子设备、家用电器等低功耗应用系统中得到越来越广泛的应用,使这些电子设备的人机界面变得越来越直观形象,目前已广泛应用与电子表、计算器、IC卡电话机、液晶电视机、便携式电脑、掌上型电子玩具、复印机、传真机等许多方面……

1602字符液晶在实际的产品中运用的也比较多了。而且对于FPGA的学习而言,掌握最常见的液晶屏 1602的驱动与用法是每一个学习者必然要经历的过程。所谓 1602是指显示的内容为 16*2,即可以显示两行,每行 16个字符。目前市面上字符液晶绝大多数是基于SPLC780C液晶芯片的,控制原理是完全相同的,因此基于SPLC780C 写的控制程序可以很方便地应用于市面上大部分的字符型液晶。  

目前市面上最常见的1602液晶背光主要有两种,一种是普通的黄绿色背光,黑色的文字。另一种显示屏是蓝色背光白色字体,如下图所示。前者使用更加广泛,成本低廉。后者显示的效果更加美观,但是价格也相对较高。此外还分别有单芯片与双芯片的版本。LCD背面的黑块内部就封装了控制芯片,市面上许多低廉的1602都是单芯片驱动,性能不稳定,双芯片的价格要上高一些,但是稳定性要远远好于单芯片的1602。本实验板采用了深圳亚斌电子有限公司生产的蓝色背光的双芯片YB1602A 液晶模块。YB1602A采用COB工艺制作,结构稳定,使用寿命长,可以应用于智能仦器仦表,通讯,办公自动化以及军工领域。



1602液晶的正面(绿色背光,黑色字体)


1602液晶的背面(绿色背光,黑色字体)  


YB1602A主要特性如下:

◆8位并行数据接口,适配M6800系列时序;

◆可选4位并行数据方式;

◆具有字符发生器ROM,含10880位;

◆192 种5×8 点字体字符;

◆64 种5×10 点字体字符;

◆具有字符发生器RAM,含512位;

◆8 种5×8 点字体字符;

◆4 种5×10 点字体字符;

◆低功耗,高可靠性。

字符型LCD1602通常有14条引脚线或者16条引脚线的LCD,多出来的2条线是背光电源线VCC(15脚)和地线GND(16脚),其控制原理与14脚的LCD完全一样,引脚定义如下表所示:  


  根据上述引脚定义可知,实验板上的1602原理图部分如下连接。其中电位器是用来调节LCD的对比度。  VCC-VEE的点位差在4.5V以上,显示字符清晰。


(2)控制器的操作时序说明

ZRtech的教材1602的控制器为SPLC780C,

自己使用的是长沙太阳人的1602液晶,控制器名字叫HD44780,功能都是一样的。

HD44780控制时序表如下图所示:


E=高脉冲,在E的时序下降沿的时候出发


对于液晶屏来说,主要的功能还是作为一种输出设备,所以我们主要掌握的应该是写时序:R/W=L,向液晶写入数据



在进行写操作的时候,RW要置为0,RS根据写的内容不同(指令或数据)置为1或0,同时,大家注意C和D两根红线,我们在将E置为1之前,要先将数据送到数据口上,然后,在C位置,将E置为1,经过tPW延时后,再将E置为0,在这个时间段内必须保证数据口上的数据稳定不变,为有效的数据。同理,由于tPW这些延时相对较短(ns级),所以在程序里也不必考虑延时问题。

主要看写操作,在整个程序里LCD_E控制了整个液晶屏的E端,这就意味着如果LCD_E在高电平的时候,那么上一个时钟下降沿送入的数据就被送到了LED屏,LCD_E在低电平的时候才显示出来。


   

                     

时序参数

由以上时序可以看到,如果要写入指令或者数据,首先要使RS与 R/W线的电平变化,RS的高低分别表示即将写入的是数据还是指令。R/W 分别控制是读写,对于写,则 R/W 应该保持为低电平。然后在确保 RS、RW 稳定后送入使能信号E使之为高电平,在使能信号稳定后,就可以在数据线D0-D7上送入需要写入的命令或者数据了。对于一次读写操作,最短的周期在500-1000ns,也就是不到 1 微秒,这个时间是足够短了。实际使用时,可以适当放慢写入的速度,也可以足够时间显示了,并可以达到理想的效果。

(3)控制器的控制方式

控制器SPLC780内置了DDRAM(显示数据存储器)、CGROM(自定义字符存储器)和AC(地址指针计数器) 。 CGROM的功能主要是存储用户自定义的字符,在这里我们主要介绍AC和DDRAM:

地址指针计数器AC是可读可写计数器。他是DDRAM和CGRAM共用的地址指针计数器,由当前的最近写入的地址设置指令的标识码来确定。可设置成加一计数器和减一计数器,当读/写操作后地址指针计数器会自动进行修正。AC 还作为光标和闪烁的位置地址指针,指示当前光标和闪烁的位置地址。

DDRAM就是显示数据RAM,用来寄存待显示的字符代码。共80个字节,其地址和屏幕的对应关系如下表:  


  也就是说想要在LCD1602屏幕的第一行第一列显示一个"A"字,就要向DDRAM的00H地址写入“A”字的代码就行了。

但具体的写入是要按LCD模块的指令格式来进行的,后面我们会说到的。那么一行可有40个地址呀?是的,在1602中我们就用前16个就行了。第二行也一样用前16个地址。对应如上图。

事实上往DDRAM里的00H地址处送一个数据,譬如0x31(数字1的代码)并不能显示1出来。这是一个令初学者很容易出错的地方,原因就是如果你要想在DDRAM的00H地址处显示数据,则必须将00H加上80H,即80H,若要在DDRAM的01H处显示数据,则必须将01H加上80H即81H。依次类推。大家看一下控制指令的8条:DDRAM地址的设定,即可以明白是怎么样的一回事了。

1602液晶模块内部的字符发生存储器(CGROM)已经存储了160个不同的点阵字符图形,如下表所示,这些字符有:阿拉伯数字、英文字母的大小写、常用的符号、和日文假名等,每一个字符都有一个固定的代码,比如大写的英文字母“A”的代码是01000001B(41H),显示时模块把地址41H中的点阵字符图形显示出来,就能看到字母“A” 。


字符代码0x00~0x0F为用户自定义的字符图形RAM(对与5X8点阵的字符, 可以存放8组, 5X10点阵的字符,存放4组),就是CGRAM了。后面我会详细说的。

0x20~0x7F为标准的ASCII码,0xA0~0xFF为日文字符和希腊文字符,其余字符码(0x10~0x1F及0x80~0x9F)没有定义。   

那么如何对DDRAM的内容和地址进行具体操作呢,下面会详细介绍SPLC780C的指令集。


(4)控制器的指令集

下面来介绍SPLC780C的指令集及其设置说明,请浏览该指令集,并找出对DDRAM的内容和地址进行操作的指令。共11条指令:


下面逐一进行说明:

1. 清屏指令(Clear Display,代码 01H)

功能: <1> 清除液晶显示器,即将DDRAM的内容全部填入"空白"的 ASCII码 20H;  

      <2> 光标归位,即将光标撤回液晶显示屏的左上方;  

      <3> 将地址计数器(AC)的值设为0。  

该指令多用于上电时或者更新全屏显示内容时。

2. 光标归HOME位指令(Return Home,代码 02H)

功能: <1> 把光标撤回到显示器的左上方;将光标或闪烁位返回到显示屏的左上第一字符位上,即 DDRAM 地址00H 单元位置;这是因为光标和闪烁位都是以地址指针计数器 AC 当前值定位的。如果画面已滚动,则撤销滚动效果,将画面拉回到 Home位。

      <2> 把地址计数器(AC)的值设置为 0;  

      <3> 保持DDRAM的内容不变  

3. 进入模式设置指令,输入方式设置(Enter Mode Set,代码 04H~07H)

该指令的功能在于设置显示字符的输入方式,即在 CPU 读/写 DDRAM 或 CGRAM 后,地址指针计数器 AC 的修改方式,反应在显示效果上,当写入一个字符后画面或光标的移动。该指令的两个参数I/D (N)和 S 确定四种字符的输入方式,如下表所示:

注意:画面滚动方式在 CPU 读DDRAM 数据时,或在读/写 CGRAM 时无效,也就是说该指令主要应用在 CPU 写入 DDRAM 数据的操作时。

4. 显示开关控制指令(Display on/off Control,代码 08H~0FH)

   该指令控制着画面,光标与闪烁的开与关。该指令有三个状态位 D、C、B,这三个状态位分别控制这画面,光标和闪烁的显示状态。

闪烁出现在有字符或光标显示的字符位时,正常显示态为当前字符或光标的显示,全亮显示态为该字符位所以点全部显示。若出现在无字符或光标显示的字符位时,正常显示态为无显示,全亮显示态为该字符位所有点全部显示。这种闪烁方式可以设计成块状光标,如同计算机显示器上块状光标闪烁提示符的效果。

该指令实现 5 种状态如下表所示:

5. 设定显示屏和光标移动方向指令(Cursor or Display Shift,代码 10H、14H、18H、1CH)

执行该指令将产生画面或光标向左或右滚动一个字符位。如果定时间隔地执行该指令将关闭画面或光标的平滑滚动。画面滚动是在一行内循环进行的,也就是说一行的第一个单元和最后一个人连接起来,形成闭环式滚动。画面滚动的显示效果如下所示:

功能:使光标移位或使整个显示屏幕移位。参数设定的情况如下:  

6. 功能设定指令,工作方式设置(Function Set,代码 30H)

该指令设置了控制器的工作方式,包括控制器与 CPU 的接口形式和控制器显示驱动器的占空比系数等。该指令有 3 个参数,组合功能如下表所示:

7. 设定 CGRAM地址指令(40H~7FH)

该指令将 6 位的 CGRAM 地址写入地址指针计数器 AC 内, 随后计算机对数据的操作是对 CGRAM 的读/写。

8. 设定DDRAM地址指令(80H~FFH)

该指令将 7 位的 DDRAM 地址写入地址指针计数器 AC 内, 随后计算机对数据的操作是对DDRAM 的读/写。

(注意这里我们送地址的时候应该是0x80+Address,这也是前面说到写地址命令的时候要加上 0x80的原因)  

9. 读取忙信号或者 AC地址指令  

计算机对指令寄存器通道读操作即 RS 为 0、R/W 为 1 时,将读出此格式的忙标志BF 值和 7 位地址指针计数器 AC 的值。

读取忙碌信号 BF的内容,BF=1表示液晶显示器忙,暂时无法接收单片机送来的数据或者指令;                        当 BF=0时,液晶显示器可以接收单片机送来的数据或指令;

10. 数据写入 DDRAM或者CGRAM指令一览(WriterData to CG or DDRAM)  

CPU 向数据寄存器通道写入数据,SPLC780根据当前地址指针计数器 AC 值的属性及数值将该数据送入相应的存储器的 AC 所指的单元里。如果 AC 值为DDRAM地址指针,则认为写入的数据是字符代码并送入 DDRAM 的 AC 所指单元里。如果 AC 值为CGRAM的地址指针,则认为写入的数据是自定义字符的字模数据并送入 CGRAM 内 AC所指的单元里。所以 CPU 在写数据之前需要设置地址指针或人为的确认地址指针的属性及数值。在写入数据后地址指针计数器 AC 将根据最近设置的输入方式最大修改。由此可知,CPU 在在写数据操作之前要做两项工作,其一是设置或确认地址指针计数器 AC 值的属性及数值,以确保所写数据能够正确到位,其二是设置或确认输入方式,以确保连续写入数据时 AC 值的修改方式符合要求。

11. 从 CGRAM或者DDRAM读出数据的指令一览(Read Data From CG or DDRAM)

在 SPLC780 的内部运行时序操作下,地址指针计数器 AC 值的每一次修改,包括新的 AC 值的写入,光标滚动位移所引起的 AC 值的修改或由 CPU 读写数据操作后所产生的 AC 值的修改,SPLC780 都会把当前 AC 所指单元的内容送到数据输出寄存器内,供 CPU 读取。如果 AC 值为 DDRAM 地址指针,则认为读取的是 DDRAM 内 AC 所指的单元的字符代码,如果 AC 值为 CGRAM 的地址指针,则认为读取的是 CGRAM 内 AC所指单元的自定义字符的字模数据。


(5)总结一下基本操作时序:  

读状态           输入:RS=L,RW=H,E=H                     

                       输出:DB0~DB7=状态字  


写指令           输入:RS=L,RW=L,E=下降沿脉冲,DB0~DB7=指令码  

                       输出:无  


读数据           输入:RS=H,RW=H,E=H                                 

                       输出:DB0~DB7=数据  


写数据           输入:RS=H,RW=L,E=下降沿脉冲

(E为高电平的时候,进行数据的写入),DB0~DB7=数据  

                       输出:无


呵呵,看到这么多的控制指令希望你没有头晕。其实这么多的指令刚开始的时候没有必要全部掌握,随着学习的深入可以再尝试去用更复杂的控制指令。下面让我们一起插上 1602 的液晶吧。当我们硬件连接错误,或者程序错误时就会出现情况:就是上排显示 16的白色的块,别急!我们还没写程序呢,一起往下看吧。







3.     实验结果:
LCD1602显示如下字符。

4.     具体实现:
由于实验代码太长,详见程序代码。此程序用了状态机,对照以上的指令应该不难理解吧。主要就是开机等待后,
进行清屏指令;
然后进行功能设置,包括数据位,行,点阵模式。
接着设置显示状态开关,包括显示开关;光标开关;闪烁开关。
然后设置输入方式,滚动方式等等。设置完毕后就可以写DDRAM了,写完一行后要注意换行。

这里要注意的是:
比如第二行第一个字符的地址是40H,那么是否直接写入40H就可以将光标定位在第二行第一个字符的位置呢?这样不行,因为写入显示地址时要求最高位D7恒定为高电平1所以实际写入的数据应该是 01000000B(40H)+10000000B(80H)=11000000B(C0H)
具体实现代码:稳定复位版本:
[plain] view plaincopyprint?
/*************************************************  
//Module:       lcd1602  
//File Name:    lcd1602.v  
//Version:      2.0  
//Date:         2011.12.14   
//Author:       wang li  
//Code Type:    RTL  
//Description:  LCD1602液晶显示  
//              clk——时钟输入(1位)  
//              rst——复位信号输入(1位)  
//                          输入看模块  
**************************************************/  
module lcd1602(clk,rst,LCD_E,LCD_RW,LCD_RS,LCD_DATA);  
input clk;              //时钟信号,50Mhz  
input rst;              //复位信号,低电平进行复位  
output LCD_E;           //1602使能引脚,1时读取信息,1->0(下降沿)执行命令  
output LCD_RS;          //1602数据——H/命令——L  选择端  
output LCD_RW;          //1602写——L/读——H  选择端  
output [7:0] LCD_DATA;  //1602数据传输端口  
wire LCD_E;  
reg [8:0] count;  
reg clk_div1;       //500个clk的周期,20ns*500=10us  
reg clk_div2;       //1000个,20us  
reg [7:0] count1;   //250个clk_div2的周期,20us*250=5000u=5ms  
reg clk_buf;  
//******************  
//-----分频模块-----  
//******************  
always @(posedge clk or negedge rst)  
begin  
    if(!rst)    //rst=0  
        count =500-1)        //5000  
                count =250-1)       //5000  
                count1 ";  
        Data_First[9] =  " ";  
        Data_First[10]=  "Z";  
        Data_First[11]=  "R";  
        Data_First[12]=  "t";  
        Data_First[13]=  "e";  
        Data_First[14]=  "c";  
        Data_First[15]=  "h";  
         
        Data_Second[0] =   "w";  
        Data_Second[1] =   "w";  
        Data_Second[2] =   "w";  
        Data_Second[3] =   ".";  
        Data_Second[4] =   "Z";  
        Data_Second[5] =   "R";  
        Data_Second[6] =   "-";  
        Data_Second[7] =   "t";  
        Data_Second[8] =   "e";  
        Data_Second[9] =   "c";  
        Data_Second[10]=   "h";  
        Data_Second[11]=   ".";  
        Data_Second[12]=   "n";  
        Data_Second[13]=   " ";  
        Data_Second[14]=   " ";  
        Data_Second[15]=   " ";  
  
//      Data_First[0] =  "a";  
//      Data_First[1] =  "b";  
//      Data_First[2] =  "c";  
//      Data_First[3] =  "d";  
//      Data_First[4] =  "e";  
//      Data_First[5] =  "f";  
//      Data_First[6] =  "g";  
//      Data_First[7] =  "h";  
//      Data_First[8] =  "i";  
//      Data_First[9] =  "j";  
//      Data_First[10]=  "k";  
//      Data_First[11]=  "l";  
//      Data_First[12]=  "n";  
//      Data_First[13]=  "m";  
//      Data_First[14]=  "o";  
//      Data_First[15]=  "p";  
//        
//      Data_Second[0] =   "Q";  
//      Data_Second[1] =   "W";  
//      Data_Second[2] =   "E";  
//      Data_Second[3] =   "R";  
//      Data_Second[4] =   "T";  
//      Data_Second[5] =   "Y";  
//      Data_Second[6] =   "U";  
//      Data_Second[7] =   "A";  
//      Data_Second[8] =   "S";  
//      Data_Second[9] =   "D";  
//      Data_Second[10]=   "F";  
//      Data_Second[11]=   "G";  
//      Data_Second[12]=   "Z";  
//      Data_Second[13]=   "X";  
//      Data_Second[14]=   "C";  
//      Data_Second[15]=   "V";  
    end  
//-----状态控制-----  
always @(posedge clk_buf or negedge rst)        // clk_div1 clk_buf  
begin  
    if(!rst)  
        begin  
            state   
      
  

310640505
点击打开链接
5.     实验总结:
通过以上的讲解,相信各位已经可以熟练驱动LCD1602了吧,在今后的使用中,可以试着将一些采集的数据用1602显示出来显示,比如传感器温度啊,时间啊,AD采集的电压值啊…等等。

6.     课后作业:
使用LCD1602显示并实现如下的简易电子钟:
显示格式:
The time is:
XX (小时): XX(分钟)  : XX(秒)
按reset按键 初始时间为,12:00:00。
7.     问题反思:

顶起 ! 小编好人 。

这也太好了吧?!谢谢小编

这个必须顶的,学习了

标记、、

很不错!

时钟设计要动态显示?小编是否可以分享些参考资料?

多谢  讲的很详细!

这个必须顶的

好资料

好长好长好长

不错不错,就是看不懂

小编威武啊

小编不是一般的帅。

有没有数字钟的程序啊?

写得不错

好详细的资料啊 ,,,谢谢

早点看到就好了

静态的字符显示不难,关键是能实时显示的数据怎么实现?

不错,很详细.

不错的资料,感谢小编                    

这个程序编译有错啊,小编确定可靠没啊?

驱动是一回事,数据实时显示就是另外一回事了!

入门菜鸟必须学习

必须顶呀  太给类呀  初学者很有用

很充实,而且寄存器那些都弄出来了,注释的很清楚,我验证了下没有问题,可以说是大师之作!

早点看到就省很多麻烦事了!

DUOXIE 小编帮助。

很详细  谢谢分享

很详细的资料,谢谢分享

这个必须顶的,学习了

小编神武!

FPGA实验之1602字符液晶设计

谢谢,正在学习fpga各个外围模块程序的编写,顶一个

上一节数码管在哪里找呢,有哪位大哥知道吗

再次感谢,的确是好贴。

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top