fpga培训

更新时间:2022-12-27 11:51:06 阅读: 评论:0


2022年12月27日发(作者:白宫国家安全顾问确诊新冠)

FPGA培训模块资料应用物理系

1

英文字符液晶模块1602的FPGA控制

液晶模块1602

所谓1602是指显示的内容为16*2,即可以显示两行,每行16个字符。目前

市面上字符液晶绝大多数是基于HD44780液晶芯片的,控制原理是完全相同的,

因此基于HD44780写的控制程序可以很方便地应用于市面上大部分的字符型液

晶。

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

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

FPGA培训模块资料应用物理系

2

另一种1602液晶模块,显示屏是蓝色背光白色字体

字符型LCD1602通常有14条引脚线或16条引脚线的LCD,多出来的2条

线是背光电源线VCC(15脚)和地线GND(16脚),其控制原理与14脚的LCD完

全一样,引脚定义如下表所示:

HD44780内置了DDRAM、CGROM和CGRAM。

DDRAM就是显示数据RAM,用来寄存待显示的字符代码。共80个字节,

其地址和屏幕的对应关系如下表:

FPGA培训模块资料应用物理系

3

也就是说想要在LCD1602屏幕的第一行第一列显示一个"A"字,就要向

DDRAM的00H地址写入“A”字的代码就行了。但具体的写入是要按LCD模块

的指令格式来进行的,后面我会说到的。那么一行可有40个地址呀?是的,在

1602中我们就用前16个就行了。第二行也一样用前16个地址。对应如下:

DDRAM地址与显示位置的对应关系

(事实上我们往DDRAM里的00H地址处送一个数据,譬如0x31(数字1

的代码)并不能显示1出来。这是一个令初学者很容易出错的地方,原因就是如

果你要想在DDRAM的00H地址处显示数据,则必须将00H加上80H,即80H,

若要在DDRAM的01H处显示数据,则必须将01H加上80H即81H。依次类推。

大家看一下控制指令的的8条:DDRAM地址的设定,即可以明白是怎么样的一

回事了)

FPGA培训模块资料应用物理系

4

1602液晶模块内部的字符发生存储器(CGROM)已经存储了160个不同的

点阵字符图形,如下表所示,这些字符有:阿拉伯数字、英文字母的大小写、常

用的符号、和日文假名等,每一个字符都有一个固定的代码,比如大写的英文字

母“A”的代码是01000001B(41H),显示时模块把地址41H中的点阵字符图形显

示出来,我们就能看到字母“A”

上表中的字符代码与我们PC中的字符代码是基本一致的。因此我们在向

DDRAM写C51字符代码程序时甚至可以直接用P1='A'这样的方法。PC在编译

时就把“A”先转为41H代码了。

字符代码0x00~0x0F为用户自定义的字符图形RAM(对于5X8点阵的字

符,可以存放8组,5X10点阵的字符,存放4组),就是CGRAM了。后面我会

详细说的。

0x20~0x7F为标准的ASCII码,0xA0~0xFF为日文字符和希腊文字符,

其余字符码(0x10~0x1F及0x80~0x9F)没有定义。

那么如何对DDRAM的内容和地址进行具体操作呢,下面先说说HD44780

的指令集及其设置说明,请浏览该指令集,并找出对DDRAM的内容和地址进

行操作的指令。共11条指令:

1.清屏指令

FPGA培训模块资料应用物理系

5

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

20H;

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

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

2.光标归位指令

功能:<1>把光标撤回到显示器的左上方;

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

<3>保持DDRAM的内容不变

3.进入模式设置指令

FPGA培训模块资料应用物理系

6

功能:设定每次定入1位数据后光标的移位方向,并且设定每次写入的一个字符

是否移动。参数设定的情况如下所示:

位名设置

I/D0=写入新数据后光标左移

1=写入新数据后光标右移

S0=写入新数据后显示屏不移动

1=写入新数据后显示屏整体右移1个字

4.显示开关控制指令

功能:控制显示器开/关、光标显示/关闭以及光标是否闪烁。参数设定的情况如

下:

位名设置

D0=显示功能关1=显示功能开

C0=无光标1=有光标

FPGA培训模块资料应用物理系

7

B0=光标闪烁1=光标不闪烁

5.设定显示屏或光标移动方向指令

功能:使光标移位或使整个显示屏幕

移位。参数设定的情况如下:

S/CR/L设定情况

00光标左移1格,且AC值减1

01光标右移1格,且AC值加1

10显示器上字符全部左移一格,但光标不动

11显示器上字符全部右移一格,但光标不动

6.功能设定指令

功能:设定数据总线位数、显示的行

数及字型。参数设定的情况如下:

FPGA培训模块资料应用物理系

8

位名设置

DL0=数据总线为4位

1=数据总线为8位

N0=显示1行

1=显示2行

F0=5×7点阵/每字符

1=5×10点阵/每字符

7.设定CGRAM地址指令

功能:设定下一个要存入数据的

CGRAM的地址。

8.设定DDRAM地址指令

功能:设定下一个要存入数据的

FPGA培训模块资料应用物理系

9

CGRAM的地址。

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

的时候要加上0x80的原因)

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

功能:<1>读取忙碌信号BF的内容,

BF=1表示液晶显示器忙,暂时无法接收单片机送来的数据或指令;当BF=0时,

液晶显示器可以接收单片机送来的数据或指令;

<2>读取地址计数器(AC)的内容。

10.数据写入DDRAM或CGRAM指令一览

功能:<1>将字符码写入DDRAM,

以使液晶显示屏显示出相对应的字符;

<2>将使用者自己设计的图形存入CGRAM。

FPGA培训模块资料应用物理系

10

11.从CGRAM或DDRAM读出数据的指令一览

功能:读取DDRAM或CGRAM中的

内容。

基本操作时序:

读状态输入: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=下降沿脉冲,DB0~DB7=数据

输出:无

例1VHDL控制1602液晶显示英文字符,第一行显示,从A~P,学习体会如

何写入控制指令,写入数据指令,学习如何在指定位置显示字符。

libraryIEEE;

_LOGIC_;

_LOGIC_;

_LOGIC_;

entityLCD1602is

Port(CLK:instd_logic;

Ret:instd_logic;

LCD_RS:outstd_logic;--寄存器选择信号

LCD_RW:outstd_logic;--液晶读写信号

LCD_EN:outstd_logic;--液晶时钟信号

FPGA培训模块资料应用物理系

11

LCD_Data:outstd_logic_vector(7downto0));--液晶数据信号

endLCD1602;

architectureBehavioralofLCD1602is

typestateis

(t_dlnf,t_cursor,t_dcb,t_cgram,write_cgram,t_ddram,writ

e_LCD_Data);

signalCurrent_State:state;

signalClk_Out:std_logic;

signalLCD_Clk:std_logic;

begin

process(CLK)--分频进程,CLK输入,CLK_Out输出,50MHz输入,125Hz输出,8ms

variablen1:integerrange0to199999;

begin

ifrising_edge(CLK)then

ifn1<199999thenn1:=n1+1;

eln1:=0;

Clk_Out<=notClk_Out;

endif;

endif;

endprocess;

LCD_RW<='0';--RW='0';写入设置

LCD_EN<=Clk_Out;--用125Hz作为LCD的使能,也作为LCD的时钟

LCD_Clk<=Clk_Out;--用125Hz作为LCD的时钟

process(LCD_Clk,Ret,Current_State)--状态机控制显示

variablecnt1:std_logic_vector(4downto0):="00000";

begin

ifRet='0'thenCurrent_State<=t_dlnf;--Ret就清屏,Ret接

出用一个按钮作为复位按键即可,按下就为'0'复位。

cnt1:="11110";

LCD_RS<='0';

elsifrising_edge(LCD_Clk)thenCurrent_State<=Current_State;

LCD_RS<='0';

caCurrent_Stateis

whent_dlnf=>cnt1:="00000";

LCD_Data<="00000001";--/*清除显示*/清屏指令

Current_State<=t_cursor;

FPGA培训模块资料应用物理系

12

whent_cursor=>LCD_Data<="00110000";--/*设置8位格式,2

行,5*7*/

Current_State<=t_dcb;

whent_dcb=>LCD_Data<="00001100";--/*整体显示,关光标,不闪

烁*/

Current_State<=t_cgram;

whent_cgram=>LCD_Data<="00000110";--/*显示移动格式,看最后

两位,10表示光标右移

Current_State<=write_cgram;

whenwrite_cgram=>LCD_RS<='1';--主体显示,写显示内容

LCD_Data<="01000001"+CNT1;

Current_State<=t_ddram;

whent_ddram=>IFCNT1<"01111"THENCNT1:=CNT1+1;--

主体显示,写显示地址DDRam(RS='0')

ELSECNT1:="00000";

ENDIF;

IFCNT1<="01111"THENLCD_Data

<="10000000"+CNT1;

ENDIF;

Current_State<=write_LCD_Data;

whenwrite_LCD_Data=>LCD_Data<="00000000";

Current_State<=t_cursor;

whenothers=>null;

endca;

endif;

endprocess;

endBehavioral;

例2VHDL控制显示1602字符液晶,分屏分时显示,

COLLEGEOFSCIENCE,SouthChinaofAgriculturalUnivers等字符。

libraryIEEE;

_LOGIC_;

_LOGIC_;

FPGA培训模块资料应用物理系

13

_LOGIC_;

entityLCD1602is

Port(CLK:instd_logic;--状态机时钟信号,同时也是液晶时钟信号,其周期

应该满足液晶数据的建立时间

Ret:instd_logic;

LCD_RS:outstd_logic;--寄存器选择信号

LCD_RW:outstd_logic;--液晶读写信号

LCD_EN:outstd_logic;--液晶时钟信号

LCD_Data:outstd_logic_vector(7downto0));--液晶数据信号

endLCD1602;

architectureBehavioralofLCD1602is

typestateis

(t_dlnf,t_cursor,t_dcb,t_cgram,write_cgram,t_ddram,writ

e_LCD_Data);

signalCurrent_State:state;

typeram1isarray(0to31)ofstd_logic_vector(7downto0);

typeram2isarray(0to31)ofstd_logic_vector(7downto0);

typeram3isarray(0to31)ofstd_logic_vector(7downto0);

constantcgram1:ram1:=

(x"57",x"57",x"57",x"2e",x"53",x"43",x"41",x"55",x"2e",x"45",x"44

",x"55",x"2e",x"43",x"4e",x"20",x"30",x"31"

,x"32",x"33",x"34",x"35",x"36",x"37",x"38",x"39",x"20",x"20",x"20

",x"20",x"20",x"20");

--分行显示[]和[]

constantcgram3:

ram3:=(x"53",x"6F",x"75",x"74",x"68",x"20",x"43",x"68",x"69",x"6

E",x"61",x"20",x"41",x"67",x"72",x"69",x"63",x"75",x"6C"

,x"74",x"75",x"72",x"61",x"6C",x"20",x"55",x"6E",x"69",x"76",x"65

",x"72",x"73");

--显示[SouthChinaofAgriculturalUnivers]

constantcgram2:

ram2:=(x"43",x"4f",x"4c",x"4c",x"45",x"47",x"45",x"20",x"4f",x"4

6",x"20",x"53",x"43",x"49",x"45",x"4e",x"43",x"45"

,x"20",x"20",x"20",x"20",x"20",x"20",x"20",x"20",x"20",x"20",x"20

",x"20",x"20",x"20");

--显示[COLLEGEOFSCIENCE]

signalCLK1:std_logic;

signalClk_Out:std_logic;

signalLCD_Clk:std_logic;

signalm:std_logic_vector(1downto0);

FPGA培训模块资料应用物理系

14

begin

process(CLK)--分频进程,CLK输入,CLK_Out

输出,50MHz输入,1250Hz输出,0.8ms

variablen1:integerrange0to19999;

begin

ifrising_edge(CLK)then

ifn1<19999thenn1:=n1+1;

eln1:=0;

Clk_Out<=notClk_Out;

endif;

endif;

endprocess;

LCD_RW<='0';--RW='0';写入设置

LCD_EN<=Clk_Out;--用1250Hz作为LCD的使能,也作为LCD的时钟

LCD_Clk<=Clk_Out;--用1250Hz作为LCD的时钟

process(Clk_Out)--再分频,1250/1000=1.25Hz,0.8s的周

期输出,CLK1输出周期1.25Hz

variablen2:integerrange0to499;

begin

ifrising_edge(Clk_Out)then

ifn2<499thenn2:=n2+1;

eln2:=0;Clk1<=notClk1;

endif;

endif;

endprocess;

process(Clk1)--设置m的值,m分别=0,1,2;5个CLK1

周期内,m为'00';再5个周期,m为'01';再5个周期,m为'10',m应为时间控制字

variablen3:integerrange0to14;

begin

ifrising_edge(Clk1)thenn3:=n3+1;

ifn3<=4thenm<="00";

elsifn3<=9andn3>4thenm<="01";

elm<="10";

endif;

endif;

endprocess;

process(LCD_Clk,Ret,Current_State)--状态机控制显示

variablecnt1:std_logic_vector(4downto0);

begin

FPGA培训模块资料应用物理系

15

ifRet='0'thenCurrent_State<=t_dlnf;--Ret就清屏,Ret接

出用一个按钮作为复位按键即可,按下就为'0'复位。

cnt1:="11110";

LCD_RS<='0';

elsifrising_edge(LCD_Clk)thenCurrent_State<=Current_State;

LCD_RS<='0';

caCurrent_Stateis

whent_dlnf=>cnt1:="00000";

LCD_Data<="00000001";--/*清除显示*/清屏指令

Current_State<=t_cursor;

whent_cursor=>LCD_Data<="00111000";--/*设置8位格式,2

行,5*7*/

Current_State<=t_dcb;

whent_dcb=>LCD_Data<="00001100";--/*整体显示,关光标,不闪

烁*/

Current_State<=t_cgram;

whent_cgram=>LCD_Data<="00000110";

Current_State<=write_cgram;

whenwrite_cgram=>LCD_RS<='1';

ifm="00"then

LCD_Data<=cgram1(conv_integer(cnt1));

elsifm="01"then

LCD_Data<=cgram2(conv_integer(cnt1));

elLCD_Data<=cgram3(conv_integer(cnt1));

endif;

Current_State<=t_ddram;

whent_ddram=>ifcnt1<"11111"thencnt1:=cnt1+1;

elcnt1:="00000";

endif;

ifcnt1<="01111"then

LCD_Data<="10000000"+cnt1;--80H--显示数据,

elLCD_Data<="11000000"+cnt1-"10000";--C0H

endif;

Current_State<=write_LCD_Data;

whenwrite_LCD_Data=>LCD_Data<="00000000";

Current_State<=t_cursor;

FPGA培训模块资料应用物理系

16

whenothers=>null;

endca;

endif;

endprocess;

endBehavioral;

思考题

1阅读下列液晶1602的显示程序,掌握调用函数进行字符ASCII码转换的程序,

掌握使用WHEN_ELSE并行赋值语句的状态机输出赋值特点,自行修改程序,

设置合适的显示流程。

显示流程参考:初始化=>清屏=>SETFUNCTION=>屏开关=>设置光标=>写显示

内容=>写显示地址=>SETFUNCTION

libraryIEEE;

_LOGIC_;

_LOGIC_;

_LOGIC_;

entitylcdis

Port(clk:instd_logic;--50MHZ

Ret:instd_logic;--复位输入

lcd_rs:outstd_logic;--液晶RS位

lcd_rw:outstd_logic;--液晶读写RW位

lcd_e:bufferstd_logic;--液晶使能

data:outstd_logic_vector(7downto0);--数据/指令输出

--stateout:outstd_logic_vector(10downto0);

clk_out:outstd_logic);--CLK_out输出

endlcd;

architectureBehavioraloflcdis

constantIDLE:std_logic_vector(10downto0):="";

--使用1位热码编码的状态机,状态共12种

constantCLEAR:std_logic_vector(10downto0):="";

constantRETURNCURSOR:std_logic_vector(10downto

FPGA培训模块资料应用物理系

17

0):="";

constantSETMODE:std_logic_vector(10downto

0):="";

constantSWITCHMODE:std_logic_vector(10downto

0):="";

constantSHIFT:std_logic_vector(10downto0):="";

constantSETFUNCTION:std_logic_vector(10downto

0):="";

constantSETCGRAM:std_logic_vector(10downto

0):="";

constantSETDDRAM:std_logic_vector(10downto

0):="";

constantREADFLAG:std_logic_vector(10downto

0):="";

constantWRITERAM:std_logic_vector(10downto

0):="";

constantREADRAM:std_logic_vector(10downto

0):="1";

constantcur_inc:std_logic:='1';--液晶指令中的控制字,用语言符

号表示数字信号控制字,方便程序体中调用

constantcur_dec:std_logic:='0';

constantcur_shift:std_logic:='1';

constantcur_noshift:std_logic:='0';

constantopen_display:std_logic:='1';

constantopen_cur:std_logic:='0';

constantblank_cur:std_logic:='0';

constantshift_display:std_logic:='1';

constantshift_cur:std_logic:='0';

constantright_shift:std_logic:='1';

constantleft_shift:std_logic:='0';

constantdatawidth8:std_logic:='1';

constantdatawidth4:std_logic:='0';

constanttwoline:std_logic:='1';

constantoneline:std_logic:='0';

constantfont5x10:std_logic:='1';

constantfont5x7:std_logic:='0';

signalstate:std_logic_vector(10downto0);

signalcounter:integerrange0to127;

signaldiv_counter:integerrange0to15;

FPGA培训模块资料应用物理系

18

signalflag:std_logic;

constantDIVSS:integer:=15;

signalchar_addr:std_logic_vector(5downto0);

signaldata_in:std_logic_vector(7downto0);

componentchar_ram

port(address:instd_logic_vector(5downto0);

data:outstd_logic_vector(7downto0)

);

endcomponent;

signalclk_int:std_logic;

signalclkcnt:std_logic_vector(18downto0);

constantdivcnt:std_logic_vector(18downto

0):="1111000";--498752*2=997504分频

signalclkdiv:std_logic;

signaltc_clkcnt:std_logic;

begin

process(clk,ret)--做一个clkcnt的累加,在Ret来的时候清零,

在等于divcnt时也清零

begin

if(ret='0')thenclkcnt<="0000000";--Ret清零

elsif(clk'eventandclk='1')then

if(clkcnt=divcnt)thenclkcnt<="0000000";--等于

divcnt也清零

elclkcnt<=clkcnt+1;

endif;

endif;

endprocess;

tc_clkcnt<='1'whenclkcnt=divcntel--当等于divcnt的时候

给一个上升沿tc_clkcnt

'0';

process(tc_clkcnt,ret)--对clkdiv进行取反,每次tc_clkcnt上升沿来

信时进行clkdiv的取反,做一个997504的分频,50.125Hz,0.02s

begin

if(ret='0')thenclkdiv<='0';

elsif(tc_clkcnt'eventandtc_clkcnt='1')thenclkdiv<=notclkdiv;

FPGA培训模块资料应用物理系

19

endif;

endprocess;

process(clkdiv,ret)--对clkdiv再分频,clk_int输出2分频,

25Hz,0.04s

begin

if(ret='0')thenclk_int<='0';

elsif(clkdiv'eventandclkdiv='1')thenclk_int<=notclk_int;

endif;

endprocess;

clk_out<=clk_int;--输出clk_int到clk_out中

process(clkdiv,ret)--使用clkdiv作为敏感信号,Ret复位

begin

if(ret='0')thenlcd_e<='0';

elsif(clkdiv'eventandclkdiv='0')thenlcd_e<=notlcd_e;

--clkdiv下降沿的时候,lcd_e2分频

endif;

endprocess;

aa:char_ramportmap(address=>char_addr,data=>data_in);--例化调用

char_ram,char_addr输入address,data输出data_in

lcd_rs<='1'whenstate=WRITERAMorstate=READRAMel--规定了

什么状态RS为'1'或'0',WRITERAM或READRAM,读写RAM,符合1602的指令

'0';

lcd_rw<='0'when(state=CLEARorstate=RETURNCURSORor

state=SETMODEorstate=SWITCHMODEorstate=SHIFTorstate=

SETFUNCTIONorstate=SETCGRAMorstate

=SETDDRAMorstate=WRITERAM)el

'1';--规定RW状态,按1602硬件指令设置

data<="00000001"when(state=CLEAR)el

"00000010"when(state=RETURNCURSOR)el

"000001"&cur_inc&cur_noshiftwhen(state=SETMODE)el

"00001"&open_display&open_cur&blank_curwhen(state

=SWITCHMODE)el

"0001"&shift_display&left_shift&"00"when(state=SHIFT)

el

FPGA培训模块资料应用物理系

20

"001"&datawidth8&twoline&font5x10&"00"when

(state=SETFUNCTION)el

"01000000"when(state=SETCGRAM)el

"10000000"when(state=SETDDRAMandcounter=0)el

"11000000"when(state=SETDDRAMandcounter/=0)el

data_inwhen(state=WRITERAM)el

"ZZZZZZZZ";

char_addr<=conv_std_logic_vector(counter,6)whenstate=WRITERAM

andcounter<40el

conv_std_logic_vector(counter-41+8,6)whenstate=WRITERAM

andcounter>40andcounter<81-8el

conv_std_logic_vector(counter-81+8,6)whenstate=WRITERAM

andcounter>81-8andcounter<81el

"000000";

process(clk_int,Ret)--用clk_int作为输入时钟,25Hz,0.04s

begin

if(Ret='0')thenstate<=IDLE;

counter<=0;

flag<='0';

div_counter<=0;

elsif(clk_int'eventandclk_int='1')then

castateis

whenIDLE=>if(flag='0')thenstate<=SETFUNCTION;

--flag='0',从IDLE进入SETFUNCTION

flag<='1';

counter<=0;

div_counter<=0;

elif(div_counter

div_counter<=div_counter+1;--flag='1',div_counter<15,则继续进入

IDLE

state<=IDLE;

eldiv_counter<=0;

state<=SHIFT;

endif;

endif;

whenCLEAR=>

state<=SETMODE;

whenSETMODE=>

FPGA培训模块资料应用物理系

21

state<=WRITERAM;

whenRETURNCURSOR=>

state<=WRITERAM;

whenSWITCHMODE=>

state<=CLEAR;

whenSHIFT=>

state<=IDLE;

whenSETFUNCTION=>

state<=SWITCHMODE;

whenSETCGRAM=>

state<=IDLE;

whenSETDDRAM=>

state<=WRITERAM;

whenREADFLAG=>

state<=IDLE;

whenWRITERAM=>

if(counter=40)then

state<=SETDDRAM;

counter<=counter+1;

elsif(counter/=40andcounter<81)then

state<=WRITERAM;

counter<=counter+1;

el

state<=SHIFT;

endif;

whenREADRAM=>

state<=IDLE;

whenothers=>

state<=IDLE;

endca;

endif;

endprocess;

endBehavioral;

本文发布于:2022-12-27 11:51:06,感谢您对本站的认可!

本文链接:http://www.wtabcd.cn/fanwen/fan/90/40199.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

上一篇:迎接新生
下一篇:个人礼仪培训
标签:fpga培训
相关文章
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图