差别

这里会显示出您选择的修订版和当前版本之间的差别。

到此差别页面的链接

后一修订版
前一修订版
文本lcd模块的控制 [2020/07/09 10:38]
zili 创建
文本lcd模块的控制 [2020/07/09 13:13] (当前版本)
zili
行 3: 行 3:
 \\ \\
  
-文本LCD模块便宜且易于使用微控制器或FPGA进行接口。+文本LCD模块便宜且易于使用微控制器或FPGA进行接口。\\
  
 这是一个1行x 16个字符的模块: 这是一个1行x 16个字符的模块:
- +{{ ::​lcd_fpgas_are_fun.jpg |}}
  
 要控制LCD模块,您需要11个IO引脚来驱动8位数据总线和3个控制信号。3个控制信号是: 要控制LCD模块,您需要11个IO引脚来驱动8位数据总线和3个控制信号。3个控制信号是:
 +  * E:启用或“ LCD选择”。高活跃。
 +  * 读/​写:读/​写。0写入,1读取。
 +  * RS:寄存器选择,0表示命令字节,1表示数据字节。
 +\\
 +大多数LCD模块都基于HD44780芯片或是兼容的。查阅[[https://​en.wikipedia.org/​wiki/​Hitachi_HD44780_LCD_controller|Wikipedia]]以获取更多信息。
 +\\
  
-E:启用或“ LCD选择”。高活跃。 +\\ 
-读/​写:读/​写。0写入,1读取。 +####7位设计 
-RS:寄存器选择,0表示命令字节,1表示数据字节。 +让我们FPGA板驱动LCD模块。\\
-大多数LCD模块都基于HD44780芯片或兼容的。查看Wikipedia以获取更多信息。 +
- +
-7位设计 +
-让我们FPGA板驱动LCD模块。+
 这是我们设计的框图: 这是我们设计的框图:
 +{{ ::​lcdmodule.gif |}}
  
 +[[http://​www.knjn.com/​FPGA-RS232.html|Pluto]]从PC串行端口接收数据,对其进行反序列化,然后将其发送到LCD模块。解串器与串行接口项目中的模块相同,因此此处仅对其进行实例化。\\
  
-Pluto从PC串行端口接收数据,对其进行反序列化,然后将其发送到LCD模块。解串器与串行接口项目中的模块相同,因此此处仅对其进行实例化。+<code verilog>​ 
 +module LCDmodule(clk,​ RxD, LCD_RS, LCD_RW, LCD_E, LCD_DataBus);​ 
 +input clk, RxD; 
 +output LCD_RS, LCD_RW, LCD_E; 
 +output [7:0] LCD_DataBus;​
  
-LCD 模块模块(clk,RxD,LCD_RS,LCD_RW,LCD_E,LCD_DataBus)+wire RxD_data_ready
-输入 clk,RxD;​ +wire [7:0] RxD_data; 
-输出 LCD_RS,LCD_RW,LCD_E;​ +async_receiver deserializer(.clk(clk),​ .RxD(RxD), .RxD_data_ready(RxD_data_ready),​ .RxD_data(RxD_data));​ 
-输出 ​[70] LCD_DataBus;+</​code>​
  
-连线 RxD_data_ready;​ +每当串行端口提供一个字节时,“ RxD_data_ready”将在一个时钟周期内处于活动状态。\\ 
-线 [7:0] RxD_data; +\\ 
-async_receiver解串器(.clk(clk)、. RxD(RxD)、. RxD_data_ready(RxD_data_ready)、. RxD_data(RxD_data));​ +PC通过串口以8位模式向我们发送数据。理想情况下,我们需要从PC接收9位,以便我们可以驱动8位数据总线和LCD模块的“ RS”线。现在,让我们使用接收到的数据的MSB(第7位)来驱动“ RS”,并将仅7位发送到数据总线。\\
-每当串行端口提供一个字节时,“ RxD_data_ready”将在一个时钟周期内处于活动状态。+
  
-PC通过串口以8位模式向我们发送数据。理想情况下,我们需要从PC接收9位,以便我们可以驱动8位数据总线和LCD模块的“ RS”线。现在,让我们使用接收到的数据的MSB(第7位)来驱动“ RS”,并将仅7位发送到数据总线。+<code verilog>​ 
 +assign LCD_RS = RxD_data[7]; 
 +assign LCD_DataBus = {1'b0, RxD_data[6:​0]}; ​  // sends only bits to the module, padded with a '​0'​ in front to make 8 bits
  
-分配 LCD_RS ​RxD_data [7]+assign LCD_RW ​0
-分配 LCD_DataBus = {1'​b0,RxD_data [6:0]}; ​//​仅发送7位到模块,在前面加一个'​0'​使8位+</code>
  
-分配 LCD_RW = 0; +我们从不读取LCD模块,所以R / W线接地的。\\ 
-我们从不读取LCD模块,因此R / W线接地。+\\ 
 +最后一个麻烦是“ E”信号需要长时间激活,即220ns。从FPGA的角度来看,这很长,因为我使用的是25MHz时钟(周期为40ns)。因此,“ E”至少需要驱动5.5个时钟。在这里,我们使用一个计数器对时钟进行计数,将其驱动7个时钟\\
  
-最后一个麻烦是“ E”信号需要长时间激活,即220ns。从FPGA的角度来看,这很长,因为我使用的是25MHz时钟(周期为40ns)。因此,“ E”至少需要驱动5.5个时钟。在这里,我们使用一个计数器对时钟进行计数,将其驱动7个时钟。+<code verilog>​ 
 +reg [2:0] count; 
 +always @(posedge clk) if(RxD_data_ready | (count!=0)) count <= count + 1; 
 +</​code>​
  
-reg [2:0]计数;如果(RxD_data_ready |(count!= 0))count <= count + 1; +“ E”信号是通过寄存器创建的,因此可以保证无干扰。\\
-总是 @(posege clk) +
-“ E”信号是通过寄存器创建的,因此可以保证无干扰。+
  
 +<code verilog>
 reg LCD_E; reg LCD_E;
-总是 ​@posedge ​CLK)LCD_E <=(计数!= 0;+always ​@(posedge ​clk) LCD_E <= (count!=0); 
 +</​code>​ 
 波形如下所示: 波形如下所示:
 +{{ ::​lcdmodule_waveform.gif |}}
  
 +HDL设计在[[https://​www.fpga4fun.com/​files/​LCDmodule.zip|这里]]。\\
  
 +\\
 +####​软件方面
 +我们对LCD进行初始化并发送一些要显示的数据。
 +{{ ::​lcd_hello.jpg |}}
 +\\
 +以下是初始化LCD模块并显示“ hello”的C代码。
  
-HDL设计在这里。 +<code verilog> 
- +void main()
-该软件 +
-我们初始化LCD并发送一些要显示的数据。 +
- +
- +
- +
-这是初始化LCD模块并显示“ hello”的C代码。 +
- +
-void main()+
 { {
-  OpenComm();+  OpenComm();
  
-  //初始化LCD模块 +  // initialize the LCD module 
-  WriteCommByte0x38; // 8位模式下的“功能集” +  WriteCommByte(0x38)  ​// "​Function Set" in bits mode 
-  WriteCommByte0x0F; //光标打开时“ ​Display ON +  WriteCommByte(0x0F)  ​// "Display ON" with cursors ON 
-  WriteCommByte0x01; //“ Clear Display”,最多可能需要1.64ms,因此延迟 +  WriteCommByte(0x01)  ​// "Clear Display", can take up to 1.64ms, so the delay 
-  Sleep2;+  Sleep(2);
  
-  //显示“你好” +  // display "​hello"​ 
-  WriteCommByte'​h'​+ 0x80+  WriteCommByte('​h'​ + 0x80)
-  WriteCommByte'​e'​+ 0x80+  WriteCommByte('​e'​ + 0x80)
-  WriteCommByte'​l'​+ 0x80+  WriteCommByte('​l'​ + 0x80)
-  WriteCommByte'​l'​+ 0x80+  WriteCommByte('​l'​ + 0x80)
-  WriteCommByte'​o'​+ 0x80;+  WriteCommByte('​o'​ + 0x80);
  
-  CloseComm();+  CloseComm();
 } }
-完整的代码在这里。+</​code>​ 
 +\\ 
 +完整的代码在[[https://​www.fpga4fun.com/​files/​LCDmodule_com.zip|这里]]\\
  
-要获取有关HD44780指令集的更多信息,请在此处检查。+要获取有关HD44780指令集的更多信息,[[http://​www.doc.ic.ac.uk/​~ih/​doc/​lcd/​instruct.html|请在此处检查]]\\ 
 +\\
  
-8位设计 +####8位设计 
-主要缺点是较早的设计是我们仅向LCD数据总线发送7位。这是一个问题,因为无法再使用LCD模块的设置DD RAM地址命令。+主要缺点是较早的设计是我们仅向LCD数据总线发送7位。这是一个问题,因为无法再使用LCD模块的设置DD RAM地址命令。\\
  
-一种简单的解决方法是使用转义符。我们选择了字符0x00。+一种简单的解决方法是使用转义符。我们选择了字符0x00。\\
  
 新协议如下: 新协议如下:
- +  * 要发送命令字节,请在其前面加上0x00。 
-要发送命令字节,请在其前面加上0x00。 +  ​* ​要发送数据字节,只需发送它,不需要前缀。 
-要发送数据字节,只需发送它,不需要前缀。+\\
 新的C代码是: 新的C代码是:
  
-void main()+<code verilog>​ 
 +void main()
 { {
-  OpenComm();+  OpenComm();
  
-  //初始化LCD模块 +  // initialize the LCD module 
-  WriteCommByte0x00; WriteCommByte0x38; // 8位模式下的“功能集” +  WriteCommByte(0x00) WriteCommByte(0x38)  ​// "​Function Set" in bits mode 
-  WriteCommByte0x00; WriteCommByte0x0F; //光标打开时“显示打开” +  WriteCommByte(0x00) WriteCommByte(0x0F)  ​// "​Display ON" with cursors ON 
-  WriteCommByte0x00; WriteCommByte0x01; //“ Clear Display”,最多可能需要1.64ms,因此延迟 +  WriteCommByte(0x00) WriteCommByte(0x01)  ​// "Clear Display", can take up to 1.64ms, so the delay 
-  Sleep2;+  Sleep(2);
  
-  WriteCommByte'​h'​+  WriteCommByte('​h'​)
-  WriteCommByte'​e'​+  WriteCommByte('​e'​)
-  WriteCommByte'​l'​+  WriteCommByte('​l'​)
-  WriteCommByte'​l'​+  WriteCommByte('​l'​)
-  WriteCommByte'​o'​;+  WriteCommByte('​o'​);
  
-  WriteCommByte0x00; WriteCommByte0xC0; //进入LCD +  WriteCommByte(0x00) WriteCommByte(0xC0)  ​// go on second half of LCD 
-  WriteCommByte'​e'​)的后半部分; +  WriteCommByte('​e'​); 
-  WriteCommByte'​v'​+  WriteCommByte('​v'​)
-  WriteCommByte'​e'​+  WriteCommByte('​e'​)
-  WriteCommByte'​r'​+  WriteCommByte('​r'​)
-  WriteCommByte'​y'​+  WriteCommByte('​y'​)
-  WriteCommByte'​o'​+  WriteCommByte('​o'​)
-  WriteCommByte'​n'​+  WriteCommByte('​n'​)
-  WriteCommByte'​e'​;+  WriteCommByte('​e'​);
  
-  CloseComm();+  CloseComm();
 } }
 +</​code>​
 +\\
 新的HDL代码如下所示: 新的HDL代码如下所示:
  
-LCD 模块模块(clkRxDLCD_RSLCD_RWLCD_ELCD_DataBus+<code verilog>​ 
-输入 ​clkRxD; +module LCDmodule(clkRxDLCD_RSLCD_RWLCD_ELCD_DataBus)
-输出 ​LCD_RSLCD_RWLCD_E; +input clkRxD; 
-输出 ​[70] LCD_DataBus;​+output ​LCD_RSLCD_RWLCD_E; 
 +output ​[7:0] LCD_DataBus;​
  
-连线 ​RxD_data_ready;​ +wire RxD_data_ready;​ 
-线 [70] RxD_data; +wire [7:0] RxD_data; 
-async_receiver deserialer.clkclk)、. RxDRxD)、. RxD_data_readyRxD_data_ready)、. RxD_dataRxD_data));+async_receiver deserialer(.clk(clk), .RxD(RxD), .RxD_data_ready(RxD_data_ready), .RxD_data(RxD_data));
  
-分配 ​LCD_RW = 0; +assign ​LCD_RW = 0; 
-分配 ​LCD_DataBus = RxD_data;+assign ​LCD_DataBus = RxD_data;
  
-电线 ​Received_Escape = RxD_data_ready&(RxD_data == 0+wire Received_Escape = RxD_data_ready ​& (RxD_data==0)
-电线 ​Received_Data = RxD_data_ready&(RxD_data= 0;+wire Received_Data = RxD_data_ready ​& (RxD_data!=0);
  
-reg [20]计数; +reg [2:0] count; 
-总是 ​@(posege ​clk)如果(Received_Data |count= 0))count <= count + 1;+always ​@(posedge ​clk) if(Received_Data | (count!=0)) count <= count + 1;
  
-//激活LCD_E6个时钟,所以在25MHz的,这是6x40ns = 240ns +// activate ​LCD_E for clocks, so at 25MHz, that'​s ​6x40ns=240ns 
-REG LCD_E; +reg LCD_E; 
-总是 ​@posedge ​CLK) +always ​@(posedge ​clk) 
-如果(LCD_E == 0+if(LCD_E==0)
   LCD_E <= Received_Data;​   LCD_E <= Received_Data;​
-否则 +else 
-  LCD_E <=count= 6;+  LCD_E <= (count!=6);
  
 reg LCD_instruction;​ reg LCD_instruction;​
-总是 ​@posedge ​CLK) +always ​@(posedge ​clk) 
-如果(LCD_instruction == 0+if(LCD_instruction==0)
   LCD_instruction <= Received_Escape;​   LCD_instruction <= Received_Escape;​
-否则 +else 
-  LCD_instruction <=count= 7;+  LCD_instruction <= (count!=7);
  
-分配 ​LCD_RS =LCD_instruction;​+assign ​LCD_RS = ~LCD_instruction;​
  
-终端模块 +endmodule 
-HD44780规范显示,“ E”变低后,“ RS”必须在10ns内有效。因此,您会注意到这里“ E”仅被驱动6个时钟,并且“ LCD_instruction”标志仅在时钟7之后被复位,以提供25ns的空间。+</​code>​ 
 +\\ 
 +HD44780规范显示,“ E”变低后,“ RS”必须在10ns内有效。因此,您会注意到这里“ E”仅被驱动6个时钟,并且“ LCD_instruction”标志仅在时钟7之后被复位,以提供25ns的空间。\\ 
 +{{ ::​lcdmodule_waveform2.gif |}} 
 +\\
  
 +\\
  
 +**That'​s all folks!轮到您尝试了。**
  
  
-那就是所有人!轮到您尝试了。