首页 > 应用 > 物联网

编程将Mojo V3 FPGA板与16x2 LCD模块连接

Steve Arar 2019-07-18

在上一篇文章中,我们研究了将FPGA与通用16x2 LCD模块连接所需的构建模块。我们看到主要构建块是ROM、一些DFF和多路复用器。另外,我们需要一个FSM(有限状态机)来控制这些构建块。在本文中,我们将介绍设计FSM的细节。然后,我们将为不同的块编写Verilog代码并使用Mojo V3板来验证我们的设计。Ky1电子头条

 Ky1电子头条

系统框图Ky1电子头条

 Ky1电子头条

FPGA-LCD接口框图如下图1所示:Ky1电子头条

 Ky1电子头条

编程将Mojo V3 FPGA板与16x2 LCD模块连接Ky1电子头条

图1Ky1电子头条

 Ky1电子头条

如你所见,FSM有两个输入(addr_reg和cnt_reg)和五个输出(s1、s2、RS、RW和E)。FSM输入允许我们监视“路径1”和“路径2”块的状态。“s1”输出控制“路径1”,因此控制应用于DB7-DB0引脚的数据。“s2”输出控制“路径2”块,可用于生成所需的时间延迟。“RS”、“RW”和“E”输出为LCD控制引脚生成适当的波形。Ky1电子头条

 Ky1电子头条

设计FSMKy1电子头条

 Ky1电子头条

FSM的初始设计如图2所示。FSM有三种状态:“空闲”、“lcd_init”和“lcd_print”。Ky1电子头条

 Ky1电子头条

编程将Mojo V3 FPGA板与16x2 LCD模块连接Ky1电子头条

图2Ky1电子头条

 Ky1电子头条

“空闲”状态Ky1电子头条

 Ky1电子头条

在“空闲”状态期间,输出被初始化。该状态的ASM(算法状态机)块如图3所示。Ky1电子头条

 Ky1电子头条

编程将Mojo V3 FPGA板与16x2 LCD模块连接Ky1电子头条

图3Ky1电子头条

 Ky1电子头条

当处于“空闲”状态时,输出“RW”、“RS”和“E”被初始化为逻辑低。“s1”和“s2”输出等于2,因此“路径1”和“路径2”的DFF在下一个时钟沿复位(见图1)。请注意FSM的附加输入(“start”)。这将连接到面包板上的按钮。将“start”输入设置为逻辑高电平将启动LCD上的打印过程。Ky1电子头条

 Ky1电子头条

“lcd_init”状态Ky1电子头条

 Ky1电子头条

在这种状态下,LCD模块被初始化。为此,存储在ROM的地址0到3中的四个命令(0x38、0x06、0x0C和0x01)应该应用于LCD数据引脚。这就是图2的状态图将术语addr_reg = 3作为从“lcd_init”转换到下一个状态(“lcd_print”)条件的原因。Ky1电子头条

 Ky1电子头条

状态转换条件的另一个术语是cnt_reg = 3550000。ROM的每个字节应用于LCD数据引脚足够长的时间(在我们的设计中为71 ms)。条件cnt_reg = 3550000确保LCD有足够的时间(71 ms)来读取数据引脚。因此,条件addr_reg = 3 && cnt_reg = 3550000意味着存储在ROM中的第四个命令被施加到LCD的时间大约为71ms。满足此条件时,LCD成功初始化,我们可以将消息数据放在DB7—DB0上。“lcd_init”状态的ASM块如图4所示。Ky1电子头条

 Ky1电子头条

编程将Mojo V3 FPGA板与16x2 LCD模块连接Ky1电子头条

图4Ky1电子头条

 Ky1电子头条

在检查上面的ASM块之前,让我们看看如何确定cnt_reg的阈值数。LCD模块的写操作时序图如图5所示。Ky1电子头条

 Ky1电子头条

编程将Mojo V3 FPGA板与16x2 LCD模块连接Ky1电子头条

图5.使用HITACHI提供的图像。Ky1电子头条

 Ky1电子头条

注意,在t AS之后,“E”信号应该变为逻辑高。它在PW EH时保持逻辑高电平,然后在下一次写操作之前转换为逻辑低电平t H. 在本文中,t AS、PW EH和t H分别为10 ms、58 ms和3 ms。“E”信号的波形如图6所示。Ky1电子头条

 Ky1电子头条

编程将Mojo V3 FPGA板与16x2 LCD模块连接Ky1电子头条

图6Ky1电子头条

 Ky1电子头条

该图还显示了每个时间延迟的等效计数。请注意,Mojo V3板的时钟频率为50 MHz(时钟周期= 20 ns)。如图4所示,我们检查“cnt_reg”的值以设置E的适当值。例如,当“cnt_reg”信号大于500000且小于3400000时,E信号应为逻辑高。同样,“s1”和“s2”输出是根据“cnt_reg”信号的值确定的。如果“cnt_reg”小于3550000(相当于71 ms),我们还没有达到当前写操作的结尾(参见图6)。因此,应用于LCD的数据不应改变(s1 = 0),计数器应计数(s2 = 1)。但是,当“cnt_reg”大于3550000(相当于71 ms)时,我们已达到当前写操作的结尾。在这种情况下,ROM的下一个地址中的数据应该应用于LCD(s1 = 1),计数器应该复位为0(s2 = 2)(见图1)。Ky1电子头条

 Ky1电子头条

如前所述,我们有四个LCD配置命令存储在ROM的地址0到3中。当第四个命令(addr_reg = 3)应用于LCD 71 ms(cnt_reg = 3,550,000)时,我们应该进入“lcd_print”状态,将消息数据发送到LCD。这是通过ASM块中的最后一个六边形实现的。请注意,LCD模块的“RS”输入指定DB7-DB0是应该被视为指令代码(RS = 0)还是数据(RS = 1)。因此,在“lcd_init”状态期间,RS引脚应处于逻辑低电平。RW引脚指定我们是写入模块(RW = 0)还是从模块读取(RW = 1)。在“lcd_init”和“lcd_print”状态下,我们执行写操作,RW应该是逻辑低。Ky1电子头条

 Ky1电子头条

“lcd_print”状态     Ky1电子头条

 Ky1电子头条

“lcd_print”状态与“lcd_init”状态非常相似,只是RS应该是逻辑高(因为现在DB7-DB0应该被视为数据而不是指令代码)。此外,为addr_reg信号检查的阈值应该改变,因为消息存储在ROM的地址4到19中。通过这些修改,我们得到了如图7所示的ASM块。Ky1电子头条

 Ky1电子头条

编程将Mojo V3 FPGA板与16x2 LCD模块连接Ky1电子头条

图7Ky1电子头条

 Ky1电子头条

最后,将所有这些ASM块连接在一起,我们获得了图8中所示的ASM图表。Ky1电子头条

 Ky1电子头条

编程将Mojo V3 FPGA板与16x2 LCD模块连接Ky1电子头条

图8Ky1电子头条

 Ky1电子头条

Verilog代码Ky1电子头条

 Ky1电子头条

如果我们有图1的框图和上面的ASM图表,那么创建系统的Verilog描述是一件容易的事。我们来看看不同构建块的代码:Ky1电子头条

 Ky1电子头条

路径1Ky1电子头条

 Ky1电子头条

对于“路径1”块,我们需要20✕8ROM:Ky1电子头条

 Ky1电子头条

                    //Path 1: ROMKy1电子头条

wire [7:0] rom_data [19:0];Ky1电子头条

 Ky1电子头条

assign rom_data[0] = 8'h38;Ky1电子头条

assign rom_data[1] = 8'h06;Ky1电子头条

assign rom_data[2] = 8'h0C;Ky1电子头条

assign rom_data[3] = 8'h01;Ky1电子头条

  Ky1电子头条

assign rom_data[4] = " ";Ky1电子头条

assign rom_data[5] = " ";Ky1电子头条

assign rom_data[6] = "H";Ky1电子头条

assign rom_data[7] = "E";Ky1电子头条

assign rom_data[8] = "L";Ky1电子头条

assign rom_data[9] = "L";Ky1电子头条

assign rom_data[10] = "O";Ky1电子头条

assign rom_data[11] = " ";Ky1电子头条

assign rom_data[12] = "W";Ky1电子头条

assign rom_data[13] = "O";Ky1电子头条

assign rom_data[14] = "R";Ky1电子头条

assign rom_data[15] = "L";Ky1电子头条

assign rom_data[16] = "D";Ky1电子头条

assign rom_data[17] = "!";Ky1电子头条

assign rom_data[18] = " ";Ky1电子头条

assign rom_data[19] = " ";Ky1电子头条

  Ky1电子头条

assign data = rom_data[addr_reg];Ky1电子头条

                  Ky1电子头条

这指定“rom_data”是类型为wire的2D数组。请注意,在Verilog中,数组的第二个维度位于数组的名称之后。将期望的值分配给阵列,最后,将ROM的输出分配给“数据”;“data”是我们设计的输出,将连接到LCD模块的DB7-DB0。“路径1”的寄存器和多路复用器可以通过以下代码描述:Ky1电子头条

 Ky1电子头条

                    reg [4:0] addr_reg, addr_next;//Path 1: RegistersKy1电子头条

always@(posedge clk, posedge rst)Ky1电子头条

beginKy1电子头条

if(rst)Ky1电子头条

addr_reg <= 5'b0;Ky1电子头条

elseKy1电子头条

addr_reg <= addr_next;Ky1电子头条

endKy1电子头条

//Path 1: MuxKy1电子头条

always @* Ky1电子头条

case(s1)Ky1电子头条

2'b00:Ky1电子头条

addr_next = addr_reg;Ky1电子头条

Ky1电子头条

2'b01:Ky1电子头条

addr_next = addr_reg + 1'b1;Ky1电子头条

Ky1电子头条

2'b10:Ky1电子头条

addr_next = 5'b0;Ky1电子头条

Ky1电子头条

default:Ky1电子头条

addr_next = addr_reg;Ky1电子头条

endcaseKy1电子头条

                  Ky1电子头条

路径2Ky1电子头条

 Ky1电子头条

“Path 2”块描述如下:Ky1电子头条

 Ky1电子头条

 Ky1电子头条

                    reg [21:0] cnt_reg, cnt_next;//Path 2: RegistersKy1电子头条

always@(posedge clk, posedge rst)Ky1电子头条

beginKy1电子头条

if(rst)Ky1电子头条

cnt_reg <= 21'h0;Ky1电子头条

elseKy1电子头条

cnt_reg <= cnt_next;Ky1电子头条

endKy1电子头条

 Ky1电子头条

//Path 2: MuxKy1电子头条

always @* Ky1电子头条

case(s2)Ky1电子头条

2'b00:Ky1电子头条

cnt_next = cnt_reg;Ky1电子头条

Ky1电子头条

2'b01:Ky1电子头条

cnt_next = cnt_reg + 1'b1;Ky1电子头条

Ky1电子头条

2'b10:Ky1电子头条

cnt_next = 21'h0;Ky1电子头条

Ky1电子头条

default:Ky1电子头条

cnt_next = cnt_reg;Ky1电子头条

endcaseKy1电子头条

                  Ky1电子头条

FSMKy1电子头条

 Ky1电子头条

要在Verilog HDL中描述FSM,我们可以使用“localparam”语句来定义代表FSM状态的符号常量。我们的FSM有三个状态。这些状态可以通过“localparam”来描述:Ky1电子头条

 Ky1电子头条

                    localparam [1:0] idle      = 2'b00,Ky1电子头条

lcd_init  = 2'b01,Ky1电子头条

lcd_print = 2'b10;Ky1电子头条

                  Ky1电子头条

为了存储系统状态,我们定义了一个两位寄存器:Ky1电子头条

 Ky1电子头条

                    reg [1:0] state_reg, state_next;//State RegistersKy1电子头条

always@(posedge clk, posedge rst)beginKy1电子头条

if(rst)Ky1电子头条

state_reg <= idle;Ky1电子头条

elseKy1电子头条

state_reg <= state_next;endKy1电子头条

                  Ky1电子头条

然后,我们应该描述确定FSM下一个状态的组合电路。这部分代码可以基于图8中ASM图的六边形编写。但请注意,以下代码简化了我们之前派生的状态转换条件。Ky1电子头条

 Ky1电子头条

                    //Next State LogicKy1电子头条

always @*Ky1电子头条

beginKy1电子头条

case(state_reg)Ky1电子头条

idle:Ky1电子头条

if(start)Ky1电子头条

state_next = lcd_init;Ky1电子头条

elseKy1电子头条

state_next = idle;Ky1电子头条

Ky1电子头条

lcd_init:Ky1电子头条

if(addr_reg == 5'h03 && cnt_reg == 3550000)Ky1电子头条

state_next = lcd_print;Ky1电子头条

else Ky1电子头条

state_next = lcd_init;Ky1电子头条

Ky1电子头条

lcd_print:Ky1电子头条

if(addr_reg == 5'h19 && cnt_reg == 3550000)Ky1电子头条

state_next = idle;Ky1电子头条

else Ky1电子头条

state_next = lcd_print;Ky1电子头条

Ky1电子头条

default:Ky1电子头条

state_next = idle;Ky1电子头条

endcaseKy1电子头条

endKy1电子头条

                  Ky1电子头条

最后,我们应该为FSM输出编写Verilog代码。可以基于图8的省略号来编写这部分代码,其代表FSM的条件分配。Ky1电子头条

 Ky1电子头条

                    //Output Logic Ky1电子头条

always @*Ky1电子头条

beginKy1电子头条

case(state_reg)Ky1电子头条

idle:Ky1电子头条

beginKy1电子头条

s1 = 2'b10;Ky1电子头条

s2 = 2'b10;Ky1电子头条

RW = 0;Ky1电子头条

RS = 0;Ky1电子头条

E = 0;Ky1电子头条

endKy1电子头条

Ky1电子头条

lcd_init:Ky1电子头条

beginKy1电子头条

s1 = 2'b00;Ky1电子头条

s2 = 2'b01;Ky1电子头条

RS = 0;Ky1电子头条

RW = 0;Ky1电子头条

E = 0;Ky1电子头条

if (cnt_reg >= 500000)Ky1电子头条

E = 1;Ky1电子头条

if (cnt_reg >= 3400000)Ky1电子头条

E = 0;Ky1电子头条

if (cnt_reg == 3550000)Ky1电子头条

beginKy1电子头条

s1 = 2'b01;Ky1电子头条

s2 = 2'b10;Ky1电子头条

endKy1电子头条

end Ky1电子头条

lcd_print:Ky1电子头条

beginKy1电子头条

s1 = 2'b00;Ky1电子头条

s2 = 2'b01;Ky1电子头条

RS = 1;Ky1电子头条

RW = 0;Ky1电子头条

E = 0;Ky1电子头条

if (cnt_reg >= 500000)Ky1电子头条

E = 1;Ky1电子头条

if (cnt_reg >= 3400000)Ky1电子头条

E = 0;Ky1电子头条

if (cnt_reg == 3550000)Ky1电子头条

beginKy1电子头条

s1 = 2'b01;Ky1电子头条

s2 = 2'b10;Ky1电子头条

endKy1电子头条

endKy1电子头条

default:Ky1电子头条

beginKy1电子头条

s1 = 2'b10;Ky1电子头条

s2 = 2'b10;Ky1电子头条

RW = 0;Ky1电子头条

RS = 0;Ky1电子头条

E = 0;Ky1电子头条

endKy1电子头条

endcaseKy1电子头条

endKy1电子头条

                  Ky1电子头条

Mojo项目Ky1电子头条

 Ky1电子头条

现在,你可以获取Mojo基础项目的副本 并将上述代码段添加到其中。请记住,你必须修改顶级Verilog模块的输入和输出。最终的代码是:Ky1电子头条

 Ky1电子头条

                    module mojo_top(Ky1电子头条

    // 50MHz clock inputKy1电子头条

    input clk,Ky1电子头条

    // Input from reset button (active low)Ky1电子头条

    input rst_n,Ky1电子头条

    // cclk input from AVR, high when AVR is readyKy1电子头条

    input cclk,Ky1电子头条

    // Outputs to the 8 onboard LEDsKy1电子头条

    output[7:0]led,Ky1电子头条

    // AVR SPI connectionsKy1电子头条

    output spi_miso,Ky1电子头条

    input spi_ss,Ky1电子头条

    input spi_mosi,Ky1电子头条

    input spi_sck,Ky1电子头条

    // AVR ADC channel selectKy1电子头条

    output [3:0] spi_channel,Ky1电子头条

    // Serial connectionsKy1电子头条

    input aVR_tx, // AVR Tx => FPGA RxKy1电子头条

    output avr_rx, // AVR Rx => FPGA TxKy1电子头条

    input avr_rx_busy, // AVR Rx buffer fullKy1电子头条

 Ky1电子头条

//My Inputs and OutputsKy1电子头条

input start,Ky1电子头条

output [7:0] data, Ky1电子头条

output reg RS, RW, EKy1电子头条

);Ky1电子头条

wire rst = ~rst_n; // make reset active high// these signals should be high-z when not usedKy1电子头条

assign spi_miso = 1'bz;Ky1电子头条

assign avr_rx = 1'bz;Ky1电子头条

assign spi_channel = 4'bzzzz;Ky1电子头条

 Ky1电子头条

assign led[7:0] = 5'h00;Ky1电子头条

localparam [1:0] idle      = 2'b00,Ky1电子头条

  lcd_init  = 2'b01,Ky1电子头条

  lcd_print = 2'b10;Ky1电子头条

  Ky1电子头条

reg [1:0] state_reg, state_next;Ky1电子头条

reg [4:0] addr_reg, addr_next;Ky1电子头条

reg [21:0] cnt_reg, cnt_next;Ky1电子头条

reg [1:0] s1, s2;Ky1电子头条

 Ky1电子头条

//State RegistersKy1电子头条

always@(posedge clk, posedge rst)Ky1电子头条

beginKy1电子头条

if(rst)Ky1电子头条

state_reg <= idle;Ky1电子头条

elseKy1电子头条

state_reg <= state_next;Ky1电子头条

endKy1电子头条

 Ky1电子头条

//Next State LogicKy1电子头条

always @*Ky1电子头条

beginKy1电子头条

case(state_reg)Ky1电子头条

idle:Ky1电子头条

if(start)Ky1电子头条

state_next = lcd_init;Ky1电子头条

elseKy1电子头条

state_next = idle;Ky1电子头条

Ky1电子头条

lcd_init:Ky1电子头条

if(addr_reg == 5'h03 && cnt_reg == 3550000)Ky1电子头条

state_next = lcd_print;Ky1电子头条

else Ky1电子头条

state_next = lcd_init;Ky1电子头条

Ky1电子头条

lcd_print:Ky1电子头条

if(addr_reg == 5'h19 && cnt_reg == 3550000)Ky1电子头条

state_next = idle;Ky1电子头条

else Ky1电子头条

state_next = lcd_print;Ky1电子头条

Ky1电子头条

default:Ky1电子头条

state_next = idle;Ky1电子头条

endcaseKy1电子头条

endKy1电子头条

 Ky1电子头条

//Output Logic Ky1电子头条

always @*Ky1电子头条

beginKy1电子头条

case(state_reg)Ky1电子头条

idle:Ky1电子头条

beginKy1电子头条

s1 = 2'b10;Ky1电子头条

s2 = 2'b10;Ky1电子头条

RW = 0;Ky1电子头条

RS = 0;Ky1电子头条

E = 0;Ky1电子头条

endKy1电子头条

Ky1电子头条

lcd_init:Ky1电子头条

beginKy1电子头条

s1 = 2'b00;Ky1电子头条

s2 = 2'b01;Ky1电子头条

RS = 0;Ky1电子头条

RW = 0;Ky1电子头条

E = 0;Ky1电子头条

if (cnt_reg >= 500000)Ky1电子头条

E = 1;Ky1电子头条

if (cnt_reg >= 3400000)Ky1电子头条

E = 0;Ky1电子头条

if (cnt_reg == 3550000)Ky1电子头条

beginKy1电子头条

s1 = 2'b01;Ky1电子头条

s2 = 2'b10;Ky1电子头条

endKy1电子头条

endKy1电子头条

Ky1电子头条

lcd_print:Ky1电子头条

beginKy1电子头条

s1 = 2'b00;Ky1电子头条

s2 = 2'b01;Ky1电子头条

RS = 1;Ky1电子头条

RW = 0;Ky1电子头条

E = 0;Ky1电子头条

if (cnt_reg >= 500000)Ky1电子头条

E = 1;Ky1电子头条

if (cnt_reg >= 3400000)Ky1电子头条

E = 0;Ky1电子头条

if (cnt_reg == 3550000)Ky1电子头条

beginKy1电子头条

s1 = 2'b01;Ky1电子头条

s2 = 2'b10;Ky1电子头条

endKy1电子头条

endKy1电子头条

default:Ky1电子头条

beginKy1电子头条

s1 = 2'b10;Ky1电子头条

s2 = 2'b10;Ky1电子头条

RW = 0;Ky1电子头条

RS = 0;Ky1电子头条

E = 0;Ky1电子头条

endKy1电子头条

Ky1电子头条

endcaseKy1电子头条

endKy1电子头条

 Ky1电子头条

//Path 1: ROMKy1电子头条

wire [7:0] rom_data [19:0];Ky1电子头条

 Ky1电子头条

  assign rom_data[0] = 8'h38;Ky1电子头条

  assign rom_data[1] = 8'h06;Ky1电子头条

  assign rom_data[2] = 8'h0C;Ky1电子头条

  assign rom_data[3] = 8'h01;Ky1电子头条

  Ky1电子头条

  assign rom_data[4] = " ";Ky1电子头条

  assign rom_data[5] = " ";Ky1电子头条

  assign rom_data[6] = "H";Ky1电子头条

  assign rom_data[7] = "E";Ky1电子头条

  assign rom_data[8] = "L";Ky1电子头条

  assign rom_data[9] = "L";Ky1电子头条

  assign rom_data[10] = "O";Ky1电子头条

  assign rom_data[11] = " ";Ky1电子头条

  assign rom_data[12] = "W";Ky1电子头条

  assign rom_data[13] = "O";Ky1电子头条

  assign rom_data[14] = "R";Ky1电子头条

  assign rom_data[15] = "L";Ky1电子头条

  assign rom_data[16] = "D";Ky1电子头条

  assign rom_data[17] = "!";Ky1电子头条

  assign rom_data[18] = " ";Ky1电子头条

  assign rom_data[19] = " ";Ky1电子头条

 Ky1电子头条

  assign data = rom_data[addr_reg];Ky1电子头条

 Ky1电子头条

//Path 1: RegistersKy1电子头条

always@(posedge clk, posedge rst)Ky1电子头条

beginKy1电子头条

if(rst)Ky1电子头条

addr_reg <= 5'b0;Ky1电子头条

elseKy1电子头条

addr_reg <= addr_next;Ky1电子头条

end//Path 1: MuxKy1电子头条

always @* Ky1电子头条

case(s1)Ky1电子头条

2'b00:Ky1电子头条

addr_next = addr_reg;Ky1电子头条

Ky1电子头条

2'b01:Ky1电子头条

addr_next = addr_reg + 1'b1;Ky1电子头条

Ky1电子头条

2'b10:Ky1电子头条

addr_next = 5'b0;Ky1电子头条

Ky1电子头条

default:Ky1电子头条

addr_next = addr_reg;Ky1电子头条

endcaseKy1电子头条

Ky1电子头条

 Ky1电子头条

//Path 2: RegistersKy1电子头条

always@(posedge clk, posedge rst)Ky1电子头条

beginKy1电子头条

if(rst)Ky1电子头条

cnt_reg <= 21'h0;Ky1电子头条

elseKy1电子头条

cnt_reg <= cnt_next;Ky1电子头条

end//Path 2: MuxKy1电子头条

always @* Ky1电子头条

case(s2)Ky1电子头条

2'b00:Ky1电子头条

cnt_next = cnt_reg;Ky1电子头条

Ky1电子头条

2'b01:Ky1电子头条

cnt_next = cnt_reg + 1'b1;Ky1电子头条

Ky1电子头条

2'b10:Ky1电子头条

cnt_next = 21'h0;Ky1电子头条

Ky1电子头条

default:Ky1电子头条

cnt_next = cnt_reg;Ky1电子头条

endcaseKy1电子头条

 Ky1电子头条

endmoduleKy1电子头条

                  Ky1电子头条

原理图和UCF文件Ky1电子头条

 Ky1电子头条

下面的图9显示了Mojo和LCD模块之间的连接。Ky1电子头条

 Ky1电子头条

编程将Mojo V3 FPGA板与16x2 LCD模块连接Ky1电子头条

图9Ky1电子头条

 Ky1电子头条

现在,我们可以向Mojo基础项目的用户定义约束文件(UCF)添加一些新约束,以指定连接到顶层模块输入/输出的FPGA引脚。以下UCF文件中的前几行已包含在Mojo基础项目中;但是,最后12行指定了与DB7-DB0、Start、RS、RW和E信号连接的FPGA管脚。Ky1电子头条

 Ky1电子头条

编程将Mojo V3 FPGA板与16x2 LCD模块连接Ky1电子头条

 Ky1电子头条

总结Ky1电子头条

 Ky1电子头条

对于FPGA,我们通常必须在设计的最低层次上查看问题。我们所拥有的是逻辑门和一些基本构建模块,如加法器和比较器。虽然这可能使FPGA设计有些困难,但FPGA确实提供了一些优势。在这个项目中,我们研究了用于将FPGA与通用16x2 LCD模块连接的构建模块。需要ROM、一些DFF和多路复用器来实现FPGA到LCD连接。此外,我们需要一个FSM来控制这些构建块。我们查看了设计FSM的详细信息,并找到了设计的不同构建块的Verilog描述。最后,我们将代码下载到Mojo V3板上,并在LCD上显示“HELLO WORLD!”消息。Ky1电子头条