ytphrx 发表于 2013-11-2 20:28:46

请大神帮忙看看LCD1602的问题?

感谢先。上程序请大神观赏,本程序是要在LCD1602上显示字符,至于什么字符不重要,本来是想做一个LCD1602的驱动,结果卡壳了:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.All;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITY driver_hd44780_lcd1602 IS
PORT(Clk:IN STD_LOGIC;   --50兆输入时钟
   Reset:IN STD_LOGIC;    --复位信号
   LCD_RS:OUT STD_LOGIC;--数据和指令模式的选择信号
   LCD_RW:OUT STD_LOGIC; --读写使能信号
   LCD_EN:OUT STD_LOGIC;--指令执行时序信号
   LCD_Data:OUT STD_LOGIC_VECTOR(7 DOWNTO 0) --LCD1602的8条数据线
   );
END ENTITY driver_hd44780_lcd1602;
ARCHITECTURE Behavioral OF driver_hd44780_lcd1602 IS
TYPE State IS(clear_screen,setup_function,setup_input,setup_screen,setup_ddram,write_ddram); --状态机
SIGNAL Current_State:State;
TYPE Ram2 IS ARRAY(0 to 7) OF STD_LOGIC_VECTOR(7 DOWNTO 0);
SIGNAL ddram_line:Ram2:=(("01000000"),("01000001"),("01000010"),("01000011"),("01000100"),("01000101"),("01000110"),("01000111"));                      --2维数组存储要在LCD上显示的字符代码@ABCDEFG
SIGNAL Count:INTEGER RANGE 0 TO 25000 :=0;       --时钟分频计数器,目的是分频50兆输入时钟成1KHZ时钟。
SIGNAL Clk_Out:STD_LOGIC;            --1khz的clk输出
BEGIN
LCD_EN<=Clk_Out;          --置LCD_EN信号为1kHZ的信号
LCD_RW<='0';               --置写LCD DDRAM模式
PROCESS(Clk,Reset)         --分频器,用于产生1KHZ的信号
BEGIN
    IF(Reset='0') THEN
       Count<=0;
    ELSIF(RISING_EDGE(Clk)) THEN
       IF(Count=25000) THEN
       Count<=0;
       Clk_out<=not Clk_out;
       ELSE
       Count<=Count+1;
       END IF;
    END IF;
END PROCESS;
PROCESS(Clk_Out,Reset,Current_State)
VARIABLE cnt1:STD_LOGIC_VECTOR(2 DOWNTO 0);
BEGIN
   IF(Reset='0')THEN      --复位
      LCD_RS<='0';
      Current_State<=clear_screen;--置状态机初始状态
      cnt1:="000";   --要显示的字符计数器赋0
   ELSIF(RISING_EDGE(Clk_Out))THEN    --每个1khz clk的上升边沿执行如下操作:
      LCD_RS<='0';                                 --置LCD1602写指令状态
      CASE Current_State IS
      WHEN clear_screen => LCD_Data <= "00000001";Current_State<=setup_function; --向LCD发出清屏命令
      WHEN setup_function=>LCD_Data <= "00111100";Current_State<=setup_input;--向LCD发出显示布局设置命令
      WHEN setup_input => LCD_Data <= "00000110";Current_State<=setup_screen;--向LCD发出每次写入数据后的光标自动移动方向
      WHEN setup_screen => LCD_Data<="00001111";Current_State<=setup_ddram;--设置屏幕光标闪烁否
      WHEN setup_ddram => LCD_Data<="10000000";Current_State<=write_ddram; --设置初始写ddram的地址
      WHEN write_ddram => LCD_RS<='1';LCD_Data<=ddram_line(CONV_INTEGER(cnt1));cnt1:=cnt1+1;开始顺序写入ddram预先设置好的数组中的字符,直到数组结束。
      WHEN OTHERS => NULL;
      END CASE;
   END IF;
END PROCESS;
END ARCHITECTURE Behavioral;

问题描述:
Q1:预置数组是8个数据,当cnt1加到数据8以上时再输出就是第9个数据,数组没有第9个数据,所以应该是空的才对,为什么我的LCD上居然循环重复二维数组输出16个字符:@ABCDEFG@ABCDEFG。
请大神告知怎么回事,并给一个处理办法?
Q2:这个程序需要按reset键才能开始显示,枚举状态机不是会自动取值第一个状态clear_screen,然后根据时钟继续其他输出在开机的时候?奇怪的是开机不能显示,必须按reset键之后才会显示?
Q3:第一次按reset键会开始显示东西,虽然内容多输出了一遍。但是再次按reset之后居然没有复位,而是没有内容显示了。这个是为什么?只有第一次复位成功。
感谢大神指点。

ytphrx 发表于 2013-11-2 22:17:28

Q1:已经解决:
方法:在其中一行增加一个控制语句,使输出超过8个字符时程序运行进入空状态,如下:
      WHEN write_ddram => LCD_RS<='1';LCD_Data<=ddram_line(CONV_INTEGER(cnt1));cnt1:=cnt1+1;IF cnt1="000" THEN Current_State <= null_state; END IF;
Q2:Q3,已经解决,按reset的时间间隔太短导致系统出错。慢慢按就可以了。
把输入数据更改成端口,然后映射到数组就应该可以按照元件的格式调用,输出任意英文数字了。
页: [1]
查看完整版本: 请大神帮忙看看LCD1602的问题?