版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
Verilog学习笔记1.我的第一个 verilog程序:三态门modulethree_status_device(in,out,oe);inputin,oe;outputout;assignout=(oe)?in:1'bz;endmodule其中oe为输出有效端,当 oe置高则输入能顺利通过,否则输出高阻态。查看TechnologySchematic后可知three_status_device模块使用的 FPGA内部资源:分别是输入缓冲器 IBUF,非门INV和三态缓冲器 OBUFT。我们还可以通过 ViewSynthesisReport 来观察到底使用了多少资源:我们可以看出所选的芯片类型为 V5系列的fx100,SPEED等级为-2,使用了 1个查找表,1个FlipFlop触发器和3个IO口。由于模块比较简单,我们直接进入后仿真阶段;最后,我们可以通过 中的ViewHDLInstantiationTemplate看到生成的 HDL模板供我们调用实例:three_status_deviceinstance_name(.in(in),.out(out),.oe(oe));小结:通过设计三态门,熟悉了 verilog开发的主要流程和 ise中的常用工具。反思:对于高阻态,一般FPGA内部是不支持判断的。现在有些比较新的FPGA内部已经带有BUFT三态门让用户直接调用(在IOB中),而对于市面上常用的FPGA则无法做到,因为内部并没有BUFT三态门,所以就需要用到slice资源中的MUX复用器,用MUX除了多占用LC/LE的资源以外,受控信号(如数据总线等)会随着驱动源的增加而使延时加大。也有说法是使用RAM或ROM的总线结构提供高阻态的输出。在FPGA开发时,一般将不用的IO口设置为三态状态,如果IO口较多的时候既占用连线资源也占用slice资源,对系统产生延迟。2.组合逻辑:有毛刺怎么办?引用《数字电路基础》的描述,当一个逻辑门的两个输入端的信号同时向相反方向变化,而变化的时间有差异的现象,称为竞争。由竞争而可能产生的输出干扰脉冲的现象就叫做冒险,也就是通俗上说的毛刺。书上还给出了常用的消除竞争冒险的方法:○1消除互补相乘项:通过人为优化逻辑表达式,消去同一信号的同反相同时存在项,降低竞争的发生几率。○2增加乘积项避免互补项相加:若组合逻辑表达式中,在某些信号取一定值的情况下,表达式可化为一个信号的同反相同时相乘或相加时,则需要人为加入相乘项以确保此时输出状态的稳定。那么在verilog如何实现消除毛刺呢?信号在 fpga器件中通过逻辑单元连线时,一定存在延时。延时的大小不仅和连线的长短和逻辑单元的数目有关,而且也和器件的制造工艺、工作环境等有关。因此,信号在器件中传输的时候,所需要的时间是不能精确估计的,当多路信号同时发生跳变的瞬间,就产生了“竞争冒险”。这时,往往会出现一些不正确的尖峰信号,这些尖峰信号就是“毛刺”。另外,由于fpga以及其它的cpld器件内部的分布电容和电感对电路中的毛刺基本没有什么过滤作用,因此这些毛刺信号就会被“保留”并传递到后一级,从而使得毛刺问题更加突出。尽管毛刺持续时间很短,但在高速电路中,这样的毛刺足以使后一级电路产生“误动作”。要消除毛刺,我们先要了解FPGA内部毛刺的具体特点:由于布线延迟,和器件延迟,取决于FPGA内部结构,这个涉及到约束问题,/shineboy19850420/blog/ 09-10/178252_efbd3.html,由于接触不多,不在此进行讨论。通过阅读资料,可以知道大多数毛刺都比较短(大概几个纳秒)刺不出现在时钟跳变沿,毛刺信号就不会对系统造成危害。
,只要毛FPGA中消除毛刺的常用方法是:1.触发器输出通过添加触发器,使输出信号在 clk跳变沿进行读取,并输出,能有效地降低毛刺的发生几率。但这样的话,延时也就增大。但是,毛刺的产生是不定时的,如果毛刺在时钟跳变时期产生,则使用触发器的方法无法解决问题。2.信号延时法信号延时法,顾名思义,延时信号处理时期,等待信号稳定时再对数据进行处理。它的具体做法有很多:○1信号延时检测信号延时方法很多,如使用门级电路延时, fpga的专用延时单元 lcell,毛刺的产生随机性,单凭延时是无法解决问题的。○2时钟延时像使用触发器的原理类似,通过增加时钟计数器, 对时钟进行分频,加大时钟间隔,来保证对信号进行处理的时候信号已经稳定; 或者为防止在信号检测时钟跳变时, 信号发生变化,延时对信号检测时间, 比如加入标志位寄存器, 信号跳变后的下一个检测时钟对其检测。这针对检测时期瞬变信号导致检测错误的方法。○3状态机检测使用状态机对信号进行多次检测, 首先第一次检测信号, 进入下一状态,再次检测信号并与前面进行比较, 如果不同则重新开始检测知道检测一定次数后确定信号不变动后, 进行数据处理。这种方法结合了上述方法,极好地消除了竞争冒险。信号延时法缺点是用速度换取电路的稳定性,我们只能择优而取。下面我们来看一些例子:按照设想 out=abc+bde;其时序图要求如下:(用TimingDesigner画图)下面我们一一验证一下不同方法所实现的逻辑组合的效果。方法一,直接使用assign语句(数据流)assignout=a&b&c|d&e&b;类似的描述组合逻辑方法还有:always@(aorborcordore) wiretemp1,temp2;begin andmyand1(temp1,a,b,c);temp1=a&c|d&e; out=temp1&b; andmyand2(temp2,d,e,b);end ormyor(out,temp1,temp2);由于表达式 out=abc+bde可转换成 out=b(ac+de),因此b的取值至关重要,当输入信号 b变为0时,输出即变为 0,所以上述语句一般写成:wiretemp;assign temp=a&c|d&e;assign out=temp&b;这样一来,当 b变为0,输出立即变化,这就是关键路径的选取。关键路径所生成的 RTL结构如下:与没有选取关键路径相比:由行为仿真波形可以看出,这样的逻辑设计与设想相同:我们通过修改仿真文件.twf对某些输入信号进行人为的延时,观察加入延时后出来的效果:输入信号波形代码段均写在Initial段中:(我们就在这里修改),为了保持毛刺持续时间尽量满足实际情况(一般为十几ns)所以这里设置延时均为10ns,即在`timescale1ns/1ps情况下,使用#10;语句进行延时动作。initialbegin//-------------CurrentTime:490ns#490;a=1'b1;b=1'b1;c=1'b1;d=1'b1;//-------------------------------------//-------------CurrentTime:1090ns#600;a=1'b0;c=1'b0;#10;e=1'b1;#10;b=1'b0;//-------------------------------------//-------------CurrentTime:1690ns#600;b=1'b1;#10;e=1'b0;//-------------------------------------//-------------CurrentTime:2290ns#600;e=1'b1;//-------------------------------------//-------------CurrentTime:2690ns#400;e=1'b0;//-------------------------------------//-------------CurrentTime:3090ns#400;e=1'b1;#10;b=1'b0;c=1'b1;//-------------------------------------//-------------CurrentTime:3690ns#600;b=1'b1;#10;d=1'b0;#10;a=1'b1;//-------------------------------------end仿真出来的效果(毛刺出现了)可见,尽管做出了关键路径的选取,
组合逻辑电路还是非常容易产生毛刺。
下面我们使用上面的说法,加入寄存器后观察结果。regout; wiretemp;assigntemp=a&b&c|d&e&b;always@(posedgeclk)out=temp;从RTL结构图中可以直观看到加入
D触发器(即寄存器)输出:依旧采用改动后的仿真文件,所得出的仿真波形如下:可见,上面的毛刺完全被消除了,而且不留一点痕迹。由于使用触发器免不了使用时钟,详细的使用放到后面的时序电路学习一节中。小结:从本节中,实现了简单的逻辑组合,并透过阅读修改仿真文件,了解毛刺的产生;通过观察 RTL结构图,了解到代码风格与生成的模型之间的联系,并通过使用 D触发器消除毛刺。反思:如果外部情况比较恶劣,延时级别大于 ns级,或者输入信号的跳变在时钟跳变时期发生,会产生什么效果,这需要在后面的学习中逐步体会。3.使用组合逻辑:加法器的设计一个设计,其实现方案多样,而且不同的实现方案,电路结构是不一样的, 这将导致速度或使用资源的差异。所以,在学习过程中, 需要对不同的方法进行比较, 了解各种编码风格实现的差别,对将来的系统设计有极大的帮助。 下面我们以加法器的设计为引导, 延伸本节的讨论。首先,我们要知道一个加法器模型应该有的端口,他们分别为:加数,被加数,上级进位,和,进位这几个端口。注意verilog的编码规范,模块端口有高位至低位,从输出到输入进行描述:moduleadder(cout,sum,clk,rst,a,b,cin);(1)实现方法一assign{cout,sum}=a+b+cin;这样看来,加法器的实现非常简单,从结构上看,它直接调用了一个加法器(如图) :但是对于“+”号的综合,FPGA内部是采用查找表所实现的,下面是由上述语句生成的查找表结构:(查找表的级数是延时的主要因素,降低查找表级数是代码优化的首要任务
二级)其中LUT3_E8表示3输入查找表, E8指查找表内部真值表的结果值。由于使用查找表实现,容易出现毛刺,我们回顾下上一节所用到的方法,我们再使用一次:再次出现了 D触发器。(仿真波形就不看了,大家可以自己试试)(2)串行加法器wire[1:0]temp;assign{temp[0],sum[0]}=a[0]+b[0];assign{temp[1],sum[1]}=a[1]+b[1]+temp[0];assigncout=temp[1];虽然咋一看,与第一种方法相当类似,你确定是一样吗?我们看看生成的,如下图:我们可以看出,这样的代码,只使用了一级的LUT,这样设计有助于降低延时,而且并没有增多LUT的使用量,反而少用一个LUT。可见资源利用率是第二种略为节省些。(3)查找法reg[1:0]sum;regcout;always@(posedgeclkornegedgerst)beginif(!rst){cout,sum}=3'bzzz;elsecase({a,b})4'b00_00:{cout,sum}=3'b000; 4'b00_01:{cout,sum}=3'b001;4'b00_10:{cout,sum}=3'b010; 4'b00_11:{cout,sum}=3'b011;4'b01_00:{cout,sum}=3'b001; 4'b01_01:{cout,sum}=3'b010;4'b01_10:{cout,sum}=3'b011; 4'b01_11:{cout,sum}=3'b100;4'b10_00:{cout,sum}=3'b010; 4'b10_01:{cout,sum}=3'b011;4'b10_10:{cout,sum}=3'b100; 4'b10_11:{cout,sum}=3'b101;4'b11_00:{cout,sum}=3'b011; 4'b11_01:{cout,sum}=3'b100;4'b11_10:{cout,sum}=3'b101; 4'b11_11:{cout,sum}=3'b110;default:{cout,sum}=3'bzzz;endcaseend我们看生成的 RTL图如下:可见编译器知道我们的用意,使用了 ROM作为查找的存储,加数为取址信号。通过观察.ngc文件可知,这样的描述仍然使用了一级的 3个LUT,输出使用寄存器同步输出。4)卡诺图法我们写出他的真值表,通过卡诺图进行简化,得出各输出的逻辑表达式:assignsum[0]=(~a[0]&b[0])|(a[0]&~b[0]);assignsum[1]=(~a[1]&~a[0]&b[1])|(~a[1]&a[0]&~b[1]&b[0])|(a[1]&a[0]&b[1]&b[0])|(~a[1]&b[1]&~b[0])|(a[1]&~b[1]&~b[0])|(a[1]&~a[0]&~b[1]);assigncout=(a[0]&b[1]&b[0])|(a[1]&a[0]&b[0])|(a[1]&b[1]);这种方法是用门电路数目较多,延时参次不齐,而且使用不方便,但速度相对会快些。要注意,有时候适当的加上括号,除了有助于阅读,还可以减少逻辑门的级数,下面再举个例子:assignout=(da+db)+(dc+dd);和assignout=da+db+dc+dd;da+db+dc+dd生成的模块内部图(da+db)+(dc+dd)所生成的模块内部图尽管使用的加法器个数一样,但级数变少了, 这样的编码风格,提高了模块运行的速度,但由于FPGA内部使用LUT实现,所以最终对提高速度影响不大,但对于ASIC(专用集成芯片)的模块设计,这样的考虑是很有必要的。(5)超前加法器assignsum[0]=a[0]^b[0]^cin;assignsum[1]=a[1]^b[1]^((a[0]&b[0])|(a[0]^b[0])&cin);assigncout=(a[1]&b[1])|((a[1]^b[1])&(a[0]&b[0]))|((a[0]^b[0])&(a[1]^b[1])&cin);根据数电书上的解释,人为地观察进位与输入的关系,由输入直接导出进位是这种方法的核心思想。但我们仍然可以看出,当位数增加的时候,电路的设计变得非常复杂,下面我们通过调用模块来简化多位加法器的设计。(6)调用模块moduleone_bit_adder(cout,sum,cin,ina,inb);inputina,inb,cin;outputcout,sum;assign{cout,sum}=ina+inb+cin;endmodule//twobitadder(byusingonebitadder)//Thisisatopmodulemoduleuse_adder(cout,sum,c,x,y);input[1:0]x,y;inputc;output[1:0]sum;outputcout;wirec_temp;one_bit_adderu1(.cout(c_temp),.sum(sum[0]),.cin(c),.ina(x[0]),.inb(y[0]));one_bit_adderu2(.cout(cout),.sum(sum[1]),.cin(c_temp),.ina(x[1]),.inb(y[1]));endmodule这里先设计一位计数器(当然,计数器的设计可以使用上面的任何一个例子) ,然后通过对模块端口的连线,而模块的调用有以下两种方法:○1模块端口的对齐:即按照模块原型声明的端口顺序○2模块端口对应连接:使用 .端口名(线名),.端口名(线名)这样的方式进行模块调用,当某一端口需要悬空,必须加上“, ”但可以不填写任何东西。(7)流水线input[3:0]a,b;output[3:0]sum;
inputclk,cin;outputcout;reg[3:0]tempa,tempb;reg[1:0]firstsum;
regtempci;reg[2:0]firsta,firstb;
regcout;
regfirstco;reg[3:0]sum;always@(posedgeclk)begintempa=a;
tempb=b;
tempci=cin;endalways@(posedgeclk)begin{firstco,firstsum}=tempa[1:0]+tempb[1:0]+tempci;firsta=tempa[3:2]; firstb=tempb[3:2];endalways@(posedgeclk)begin{cout,sum}={firsta[2:0]+firstb[2:0]+firstco,firstsum};endendmodule使用流水线的方法,最重要的是将未用到的数据进行存储,这样做使得流水线不同级之间相互独立,这样做大大提高了速度(除了第一次运算需要额外的两个时钟周期),但是这样的设计使用大量资源,这需要在性能和资源中进行折衷。使用的资源:我们从图中可以看出,流水线极大提高了触发器的使用量, 是典型的以面积换取速度的例子。小结:通过对加法器的各种设计以及编码风格, 我们可以看出 VerilogHDL——硬件描述语言的优势,不同的编码风格所产生的电路在速度与面积上都将产生不同的变化,要学好 HDL,则需要经验的积累和对电路结构的了解, 必须明白语言与电路之间的对应关系, 这样,Verilog语言才能用得得心应手。反思:Verilog的编码与 FPGA内部结构、内部器件特性有着很大关系, 要编写一个好的代码,学习FPGA内部结构成为必不可少的一个阶段。4.有限状态机时序电路由组合电路和存储电路组成,时序电路是状态依赖的,所以称为状态机。其中Melay状态机,其状态与当前状态,输入,输出均有关系,而 Moore状态机则只跟当前状态有关,一下用两个实例对其进行探讨。1)Melay状态机moduleserial_checkout(same,din,clk,rst);inputdin; inputclk,rst; outputsame;reg[2:0]status;
regsame_temp;//Writedownyourserialwhichyouwanttocheckoutparameterserial_number=8'h11010011;//checkthelowestbitfirstparameterbit1=1'b1;parameterbit2=1'b1;parameterbit3=1'b0;parameterbit4=1'b0;parameterbit5=1'b1;parameterbit6=1'b0;parameterbit7=1'b1;parameterbit8=1'b1;assignsame=same_temp;always@(posedgeclkornegedgerst)if(rst==0)beginstatus<=3'b000; same_temp<=1'b0;endelsecase(status)3'b000:beginif(din==bit1)status<=3'b001;elsestatus<=3'b000;end3'b001:beginif(din==bit2)status<=3'b010;elsestatus<=3'b000;end3'b010:beginif(din==bit3)status<=3'b011;elsestatus<=3'b000;end3'b011:beginif(din==bit4)status<=3'b100;elsestatus<=3'b000;end3'b100:beginif(din==bit5)status<=3'b101;elsestatus<=3'b000;end3'b101:beginif(din==bit6)status<=3'b110;elsestatus<=3'b000;end3'b110:beginif(din==bit7)status<=3'b111;elsestatus<=3'b000;end3'b111:beginif(din==bit8)same_temp<=1;elsestatus<=3'b000;endendcaseendmodule上述是使用Melay有状态均通过时,
状态机实现的序列检测模块的完整代码, 每一个状态都与输入有关,same_temp输出1以表示检测到特定序列。
当所(2)Moore状态机:实现 LCD1602的初始化,显示和移位输出moduleLCD1602_ctrl_8data(clk,rst,lcd_data,lcd_rs,lcd_rw,lcd_en);inputclk,rst; //系统时钟与系统复位信号outputlcd_rs,lcd_rw,lcd_en; //rs命令/数据选择信号, rw
读/写数据选择信号,
en操作使能output[7:0]lcd_data;
//8
位数据总线
//如果要求
lcd_data
为
inout
型引脚,这时候只能为
wire
型,需要使用
reg变量驱动他暂时没有输入,只作演示说明reglcd_rs,lcd_rw,lcd_en;reg[7:0]lcd_data;reg[3:0]stage;reg[7:0]ddram_address;reg[4:0]shift_count;reg[7:0]shift_freq;regflag,shift_flag;//命令参数parameterSTART=4'b0000;//RSRWD7D6D5D4D3D2D1D0//指令1:清?0000000001parameterCLEAR_SCREEN=4'b0001;//指令2:光标复位0000000010//光标回到00h地址parameterCURSOR_BACK=4'b0010;//指令3:置输入模式00000001I/DS光标和显示模式设置->I/D:光标移动方向,I/D=1时右移(当读写一个字符后,地址指针加1),I/D=0时左移(当读写一个字符后,地址指针减1)S:当写一个字符屏幕上所有文字是否左移(I/D=1)或者右移(I/D=0)。S=1时表示有效,S=0时则无效parameterSETMODE=4'b0011;parameterCURSOR_MOVE_RIGHT=1;parameterCURSOR_MOVE_LEFT=0;parameterWORD_SHIFT=1;parameterWORD_NOSHIFT=0;//RSRWD7D6D5D4D3D2D1D0//指令4:显示开关控制0000001DCB//D:控制整体显示的开与关,D=1表示开显示,D=0表示关显示//C:控制光标的开与关,C=1表示有光标,C=0表示无光标//B:控制光标是否闪烁,B=1闪烁,B=0不闪烁;闪烁只对于当前地址指针指向的字符位有效。parameterDISPLAY_CTRL_OFF=4'b0100;parameterDISPLAY_ON=1;parameterDISPLAY_OFF=0;parameterCURSOR_ON=1;parameterCURSOR_OFF=0;parameterCURSOR_FLASH_ON=1;parameterCURSOR_FLASH_OFF=0;//RSRWD7D6D5D4D3D2D1D0//指令5:光标或字符移动000001S/CR/L00//S/C:滚动对象选择:S/C=1时移动显示的文字,S/C=0时移动光标//R/L:滚动方向选择:R/L=1时向右滚动,R/L=0向左滚动parameterSHIFT=4'b0101;parameterSEL_WORD=1;parameterSEL_CURSOR=0;parameterRIGHT_SHIFT=1;parameterLEFT_SHIFT=0;//RSRWD7D6D5D4D3D2D1D0//指令6:功能设置命令00001D/LNF00//D/L:DL=1时为8位总线(DB7-DB0有效),D/L=0?位(DB7-DB4行В?//N:N=0时为单行显示,N=1时双行显示//F:F=0时?x7的阏字符,F=1时显示5x10的阏笾?parameterSETFUNCTION=4'b0110;parameterDATAWIDTH8=1;parameterDATAWIDTH4=0;parameterTWOLINE_DISPLAY=1;parameterONELINE_DISPLAY=0;parameterFONT5x10=1;parameterFONT5x7=0;//RSRWD7D6D5D4D3D2D1D0//指令7:置字符发生器贮存地址0001(AGG)//AGG:设置CGRAM地址,AGG高三位为自定义字符代码,低三位为字模数据地址(5X8),可最多定义8个字符调用自定义字符时,调?~7这8?parameterSETCGRAM=4'b0111;//RSRWD7D6D5D4D3D2D1D0//指令8:置数据存贮器地址001(ADD)//ADD:DDRAM地址parameterSETDDRAM=4'b1000;//指令9:读忙信号(不用)parameterRESERVE=4'b1001;//RSRWD7D6D5D4D3D2D1D0//指令10:写RAM数据10(data)parameterWRITE_RAM=4'b1010;//RSRWD7D6D5D4D3D2D1D0//指令11:读RAM数据11(data)parameterREAD_RAM=4'b1011;parameterSTOP=4'b1100;//parameterDELAY=4'b1101;parameterDISPLAY_CTRL_ON=4'b1110;parameterSETFUNCTION2=4'b1111;//时钟信号reg[15:0]clkcnt;//分频函数always@(posedgeclk)beginif(!rst)clkcnt<=16'b0000_0000_0000_0000;elsebeginif(clkcnt==16'b1111_1111_0101_0000)//if(clkcnt==16'b1001_1100_0100_0000)//if(clkcnt==16'b1001_1000_0100_0000)clkcnt<=16'b0000_0000_0000_0000;elseclkcnt<=clkcnt+1;endendwiretc_clkcnt;assigntc_clkcnt=(clkcnt==16'b1111_1111_0101_0000)?1:0; //100000? //assigntc_clkcnt=(clkcnt==16'b1001_1100_0100_0000)?1:0; //80000分频//assigntc_clkcnt=(clkcnt==16'b1001_1000_0100_0000)?1:0;//对tc_clkcnt二分频regclkdiv;always@(posedgetc_clkcnt)if(!rst)clkdiv<=0;elseclkdiv<=~clkdiv;//对clkdiv二分频regclk_int;always@(posedgeclkdiv)if(rst==0)clk_int<=0;elseclk_int<=~clk_int;always@(negedgeclkdiv)if(rst==0)lcd_en<=0;elselcd_en<=~lcd_en;//为满足总线时序而进行的两次二分频,在 rs,rw,io n,所以这里孟跳沿触?有限状态机//reg[15:0]myclkcnt;//regmyclk;always@(posedgeclk_intornegedgerst)if(!rst)beginstage<=START;ddram_address<=8'h80;shift_flag<=1;shift_freq<=8'h00;//ddram_address<=8'b1001_0000; //写DDRAM缓冲区shift_count<=5'b0_0000;//myclkcnt<=16'h0000;flag<=0;//flag1<=1;endelsebegincase(stage)START
:beginlcd_data<=8'bzzzz_zzzz;stage<=SETFUNCTION;endSTOP
:beginstage<=STOP;endCLEAR_SCREEN :begin //0000_0001 01Hlcd_rs<=0;lcd_rw<=0;lcd_data<=8'b0000_0001;stage<=SETMODE;endSETMODE :begin //0000_0110 06Hlcd_rs<=0;lcd_rw<=0;lcd_data[7:2]<=6'b000001;lcd_data[1]<=CURSOR_MOVE_RIGHT;lcd_data[0]<=WORD_NOSHIFT;stage<=DISPLAY_CTRL_ON;endCURSOR_BACK :begin //0000_0010 02Hlcd_rs<=0;lcd_rw<=0;lcd_data<=8'b00000010;stage<=SETDDRAM;endDISPLAY_CTRL_OFF:begin//0000_1010 08Hlcd_rs<=0;lcd_rw<=0;lcd_data[7:3]<=5'b00001;lcd_data[2]<=DISPLAY_OFF;lcd_data[1]<=CURSOR_OFF;lcd_data[0]<=CURSOR_FLASH_OFF;stage<=CLEAR_SCREEN;endDISPLAY_CTRL_ON:begin//0000_1100 0CHlcd_rs<=0;lcd_rw<=0;lcd_data[7:3]<=5'b00001;lcd_data[2]<=DISPLAY_ON;lcd_data[1]<=CURSOR_ON;lcd_data[0]<=CURSOR_FLASH_ON;stage<=SETDDRAM;endSETFUNCTION :begin //0011_1000 38Hlcd_rs<=0;lcd_rw<=0;lcd_data[7:5]<=3'b001;lcd_data[4]<=DATAWIDTH8;lcd_data[3]<=TWOLINE_DISPLAY;lcd_data[2]<=FONT5x7;lcd_data[1:0]<=2'b00;stage<=SETFUNCTION2;endSETFUNCTION2 :begin //0011_1000 38Hlcd_rs<=0;lcd_rw<=0;lcd_data[7:5]<=3'b001;lcd_data[4]<=DATAWIDTH8;lcd_data[3]<=TWOLINE_DISPLAY;lcd_data[2]<=FONT5x7;lcd_data[1:0]<=2'b00;stage<=DISPLAY_CTRL_OFF;end// SETCGRAM :beginlcd_rs<=0;lcd_rw<=0;data<=8'b01000000;state<=START;endSETDDRAM :begin //1XXX_XXXXlcd_rs<=0;lcd_rw<=0;lcd_data[7:0]<=ddram_address;stage<=WRITE_RAM;end// SETDDRAM1 :beginlcd_rs<=0;lcd_rw<=0;data<=8'b11000000;state<=WRITERAM;end//设置第二行首地址WRITE_RAM
:begin
//XXXX_XXXXif(ddram_address<=8'h8F)//if(ddram_address<=8'h9F)beginlcd_rs<=1; //写数据lcd_rw<=0;//data<=ddram(address);case(ddram_address)8'h80:lcd_data<=8'h43;8'h81:lcd_data<=8'h68;
//C//h8'h82:lcd_data<=8'h61;8'h83:lcd_data<=8'h6e;8'h84:lcd_data<=8'h67;8'h85:lcd_data<=8'h73;8'h86:lcd_data<=8'h68;8'h87:lcd_data<=8'h61;8'h88:lcd_data<=8'h4d;
//a//n//g//s//h//a//M8'h89:lcd_data<=8'h69;8'h8A:lcd_data<=8'h6e;8'h8B:lcd_data<=8'h67;8'h8C:lcd_data<=8'h77;8'h8D:lcd_data<=8'h65;8'h8E:lcd_data<=8'h69;8'h8F:lcd_data<=8'h21;default:lcd_data<=8'h20;endcaseddram_address<=ddram_address+1;//stage<=WRITE_RAM;
//i//n//g//w//e//i//!endelsebeginif(flag==0)beginddram_address<=8'hC0;flag<=1; //flga 指明当前操作的行号,0为第一行,1为第二行//lcd_data<=8'h20;lcd_rs<=1;lcd_rw<=1; //屏蔽下次输入stage<=SETDDRAM;endelsebeginif(ddram_address<=8'hCF)//if(ddram_address<=8'hDF)beginlcd_rs<=1;lcd_rw<=0;case(ddram_address)8'hC0:lcd_data<=8'h44;8'hC1:lcd_data<=8'h65;8'hC2:lcd_data<=8'h73;8'hC3:lcd_data<=8'h69;8'hC4:lcd_data<=8'h67;8'hC5:lcd_data<=8'h6e;8'hC6:lcd_data<=8'h62;8'hC7:lcd_data<=8'h79;8'hC8:lcd_data<=8'h3a;
//D//e//s//i//g//n//b//y//:8'hC9:lcd_data<=8'h53;8'hCA:lcd_data<=8'h68;8'hCB:lcd_data<=8'h75;8'hCC:lcd_data<=8'h77;8'hCD:lcd_data<=8'h61;8'hCE:lcd_data<=8'h6e;8'hCF:lcd_data<=8'h67;default:lcd_data<=8'h20;
//S//h//u//w//a//n//gendcaseddram_address<=ddram_address+1;//stage<=WRITE_RAM;endelsebeginstage<=SHIFT;//stage<=STOP;lcd_rs<=1;lcd_rw<=1;//shift_flag<=0;//lcd_data<=8'h00;endendendendSHIFT :beginif(shift_count<=5'b10000)beginif(shift_freq==8'h50)beginshift_freq<=8'h00;lcd_rs<=0;lcd_rw<=0;lcd_data[7:4]<=4'b0001;lcd_data[3]<=SEL_WORD;lcd_data[2]<=LEFT_SHIFT;lcd_data[1:0]<=2'b00;shift_count<=shift_count+1;注释掉后一直移位endelsebeginshift_freq<=shift_freq+1;lcd_rs<=1;lcd_rw<=1;lcd_data<=8'h00;endendelsebeginstage<=START;ddram_address<=8'h80;shift_flag<=1;shift_freq<=8'h00;shift_count<=5'b0_0000;flag<=0;lcd_rs<=1;lcd_rw<=1;endenddefault :beginstage<=STOP;endendcaseendendmodule由于我们需要直接下到开发板上所以,需要对芯片进行管脚约束:(注意管脚约束文件中使用#做注释符)打开,编写代码:NET"clk"LOC="p18";NET"lcd_data[0]"LOC="p140";NET"lcd_data[1]"LOC="p139";NET"lcd_data[2]"LOC="p141";NET"lcd_data[3]"LOC="p4";NET"lcd_data[4]"LOC="p5";NET"lcd_data[5]"LOC="p6";NET"lcd_data[6]"LOC="p7";NET"lcd_data[7]"LOC="p10";NET"lcd_en" LOC="p19" ;NET"lcd_rs" LOC="p21" ;NET"lcd_rw" LOC="p20" ;NET"rst" LOC="p102" ;然后Enjoyyourself!(注意:上面的管脚约束是根据我自己的板子所写的,我们必须根据实际情况写,不然最终是出不了结果的— —|||)等等,讲到生成bit流文件(配置文件),也就是最终需要下载到FPGA里面的,我们可以选择下到FPGA中(直接配置FPGA),但这个在重新上电后,程序就没了,我们还可以下到专用的PROM中,这样可以永久保存起来。下面我们一起看如何使用 IMPACT直接生成.xcs文件。首先我们打开 IMPACT后会自动弹出窗口,我们新建
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025年AI赋能餐具设计卫生性研究
- 2026年广西安全工程职业技术学院单招职业技能测试题库带答案详解(新)
- 2026年山西警官职业学院单招职业适应性测试题库含答案详解(精练)
- 2026年广州城市职业学院单招职业倾向性测试题库附参考答案详解(a卷)
- 2026年山西省大同市单招职业适应性考试题库附参考答案详解(满分必刷)
- 2026年山西警官职业学院单招职业适应性测试题库带答案详解(培优b卷)
- 2026年广东水利电力职业技术学院单招职业倾向性测试题库附答案详解(完整版)
- 2026年山西艺术职业学院单招职业技能考试题库含答案详解(黄金题型)
- 2026年山西省阳泉市单招职业适应性测试题库附答案详解(综合题)
- 2026年广东岭南职业技术学院单招职业适应性考试题库带答案详解ab卷
- 2026春统编版三年级下册道德与法治每课知识点清单
- 2025中国国新控股有限责任公司招聘7人笔试历年常考点试题专练附带答案详解
- 2026秋招:平安银行笔试题及答案
- 2026贵州毕节织金县部分县直单位公开考调工作人员47人实施笔试参考题库及答案解析
- 2026年六安职业技术学院单招职业适应性考试题库附参考答案详解ab卷
- 2026陕煤集团榆林化学有限责任公司招聘(162人)考试备考题库及答案解析
- GB/T 27664.3-2026无损检测仪器超声检测设备的性能与检验第3部分:组合设备
- 2026广东江门职业技术学院管理教辅人员招聘4人备考题库带答案详解(基础题)
- GB/T 46977-2026铸造用再生砂氮、硫、磷含量测定方法
- 突发事件创伤伤员医疗救治规范2025年版
- 2026年跨境电商平台合同
评论
0/150
提交评论