zoukankan      html  css  js  c++  java
  • 简单三段式状态机实验2-LCD12864

      此实验是在“基于I2C EPPRPM(AT24C02B) + LCD12864实验”基础上,把LCD模块里的一段式状态机改成三段式,I2C EPPROM模块暂时未改出来,一步一步来吧,改完后代码下载到板子上验证是OK的。

        三段式状态机里面要注意的是,抽出来reg 如计数器num、lcd_rs,在利用状态作为判断条件时,得注意是用n_state呢还是用c_state,对于我这样的初学者,一时半会弄不清是用哪个作为判断条件好,怎么办,每种情况都试一次吧。结果用n_state能正常显示,用c_state显示乱码。

    用c_state作为判断条件的仿真波形如下:

    好奇怪哦,左边框中num为什么没有清零呢?这是因为if else产生的优先权导致,一不小心就范这样的错误。

     1 /***************************************************/
     2 reg [4:0] c_state,n_state;
     3 reg [6:0] num;
     4 reg lcd_rs;
     5 always @(posedge lcd_clk or negedge rst_n)
     6 if(!rst_n)
     7     lcd_rs <= 1'b0;
     8 else if((c_state == WRITE_DATA0)||(c_state == WRITE_DATA1)||(c_state == WRITE_DATA2)||(c_state == WRITE_DATA3))
     9     lcd_rs <= 1'b1;        //data mode
    10 else
    11     lcd_rs <= 1'b0;        //cmd mode
    12 /***************************************************/
    13 
    14 
    15 /***********************************************************/
    16 always @(posedge lcd_clk or negedge rst_n)
    17 if(!rst_n)
    18     num <= 7'd0;
    19 else if((c_state == WRITE_DATA0) || (c_state == WRITE_DATA1))
    20     num <= num + 1'b1;
    21 else if(num == 7'd20) //不能放在状态判断后面,否则num不会归零
    22     num <= 7'd0;
    23 /***********************************************************/

    用n_state作为判断条件的仿真波形如下:

    虽然把c_state改成n_state ,但是这个num能清零,好奇怪哦,有时间在好好研究吧,为了保险起见还是改成如下形式:

     1 /***************************************************/
     2 reg [4:0] c_state,n_state;
     3 reg [6:0] num;
     4 reg lcd_rs;
     5 always @(posedge lcd_clk or negedge rst_n)
     6 if(!rst_n)
     7     lcd_rs <= 1'b0;
     8 else if((n_state == WRITE_DATA0)||(n_state == WRITE_DATA1)||(n_state == WRITE_DATA2)||(n_state == WRITE_DATA3))
     9     lcd_rs <= 1'b1;        //data mode
    10 else
    11     lcd_rs <= 1'b0;        //cmd mode
    12 /***************************************************/
    13 
    14 
    15 /***********************************************************/
    16 always @(posedge lcd_clk or negedge rst_n)
    17 if(!rst_n)
    18     num <= 7'd0;
    19 else if(num == 7'd20)
    20     num <= 7'd0;
    21 else if((c_state == WRITE_DATA0) || (c_state == WRITE_DATA1))
    22     num <= num + 1'b1;
    23 /***********************************************************/

    注意看上面两种仿真波形,右边框的位置上是有区别的,c_state要比n_state慢一节拍,但对应输出数据值是c_state,比如当c_state=7时,是对LCD写数据,故lcd_rs=1,输出lcd_data="I",很明显,用c_state作为判断条件的是不对的,输出已经延长一拍。

    三段式状态机里还要注意一个地方,在状态机里面既要作为输出,又要作为其他输出信号的判断条件,如下面的en,会产生警告,报出间接指出latch。

    /***********************************************************/
    reg en;
    always @(posedge sys_clk or negedge rst_n)
    if(!rst_n) begin
        en <= 1'b1;
        dis_data <= 8'h00;
    end
    else case(num)
            //I2C閫氫俊瀹為獙
            7'd0:    dis_data <= "I";
            7'd1:    dis_data <= "2"; 
            .
            .
            .
    /***********************************************************/
    
    assign    lcd_en = en ?  lcd_clk : 1'b0;
    /***********************************************************/

    “Warning (10240): Verilog HDL Always Construct warning at LCD12864.v(121): inferring latch(es) for variable "en", which holds its previous value in one or more paths through the always construct”

    虽然有些警告无关紧要的,但还是应尽量避免这样写,办法也是要把en抽出来,我这里是简单的处理下。

    1 /***************************************************/
    2 wire    en;
    3 assign    en = 1'b1;//(n_state == STOP) ? 1'b0 : 1'b1;
    4 assign    lcd_en = en ?  lcd_clk : 1'b0;
    5 /***************************************************/

    其实这里还有个问题,程序中在IDLE时,lcd_data <= 8'hzz;但仿真波形中没有看到,跟踪调试时,发现这语句永远不执行,自己屡了屡,确实执行不到,一时半会我也想不明白。比较简单的状态机,差不多先这样吧。

    代码实现:

    LCD12864.v

      1 module LCD12864(
      2                     //input 
      3                     sys_clk,
      4                     rst_n,
      5                     dis_data_low,
      6                     dis_data_hig,
      7                     
      8                     //output 
      9                     lcd_rs,
     10                     lcd_rw,
     11                     lcd_en,
     12                     lcd_data,
     13                     lcd_psb
     14                 );
     15 input         sys_clk;// 50MHZ
     16 input         rst_n;
     17 input [7:0] dis_data_low;
     18 input [7:0] dis_data_hig;
     19 
     20 output         lcd_rs;//H:data    L:command
     21 output         lcd_rw;//H:read module    L:write module
     22 output         lcd_en;//H active
     23 output [7:0]lcd_data;
     24 output        lcd_psb;//H:parallel    module    L:SPI module
     25 
     26 /***************************************************/
     27 parameter     T3MS            = 18'd149_999;
     28 parameter    IDLE            = 5'd0,
     29             INIT_FUN_SET1    = 5'd1,
     30             INIT_FUN_SET2    = 5'd2,
     31             INIT_DISPLAY    = 5'd3,
     32             INIT_CLEAR        = 5'd4,
     33             INIT_DOT_SET    = 5'd5,
     34             SET_DDRAM        = 5'd6,
     35             WRITE_DATA0        = 5'd7,
     36             SET_DDRAM2        = 5'd8,
     37             WRITE_DATA1        = 5'd9,
     38             WRITE_DATA2        = 5'd10,
     39             WRITE_DATA3        = 5'd11;
     40 /***************************************************/
     41 //产生周期为6MS的lcd_clk给LCD
     42 reg [17:0] cnt;
     43 reg lcd_clk;
     44 always @(posedge sys_clk or negedge rst_n)
     45 if(!rst_n) begin
     46     cnt <= 18'd0;
     47     lcd_clk <= 1'b0;
     48 end
     49 else if(cnt == T3MS)begin
     50     cnt <= 18'd0;
     51     lcd_clk <= ~lcd_clk;
     52 end
     53 else
     54     cnt <= cnt + 1'b1;
     55 /***************************************************/
     56 reg lcd_rs;
     57 always @(posedge lcd_clk or negedge rst_n)
     58 if(!rst_n)
     59     lcd_rs <= 1'b0;
     60 else if((n_state == WRITE_DATA0)||(n_state == WRITE_DATA1)||(n_state == WRITE_DATA2)||(n_state == WRITE_DATA3))
     61     lcd_rs <= 1'b1;        //data mode
     62 else
     63     lcd_rs <= 1'b0;        //cmd mode
     64 /***************************************************/
     65 reg [4:0] c_state,n_state;
     66 always @(posedge lcd_clk or negedge rst_n)
     67 if(!rst_n)
     68     c_state <= IDLE;
     69 else
     70     c_state <= n_state;
     71 /***************************************************/
     72 always @(*)
     73 case(c_state)
     74     IDLE:             n_state = INIT_FUN_SET1;
     75     INIT_FUN_SET1:    n_state = INIT_FUN_SET2;
     76     INIT_FUN_SET2:    n_state = INIT_DISPLAY;
     77     INIT_DISPLAY:    n_state = INIT_CLEAR; 
     78     INIT_CLEAR:     n_state = INIT_DOT_SET;
     79     INIT_DOT_SET:   n_state = SET_DDRAM;    
     80     SET_DDRAM:        n_state = WRITE_DATA0;
     81     WRITE_DATA0:    if(num == 7'd11) n_state = SET_DDRAM2;
     82                     else n_state = WRITE_DATA0;
     83     SET_DDRAM2:     n_state = WRITE_DATA1;
     84     WRITE_DATA1:     if(num == 7'd20) n_state = WRITE_DATA2;
     85                     else n_state = WRITE_DATA1;
     86     WRITE_DATA2:    n_state = WRITE_DATA3;
     87     WRITE_DATA3:    n_state = SET_DDRAM;
     88     default:         n_state = IDLE;
     89 endcase    
     90 /***************************************************/
     91 reg [7:0] lcd_data;
     92 reg [7:0] dis_data;
     93 always @(posedge lcd_clk or negedge rst_n)
     94 if(!rst_n)    lcd_data <= 8'h00;
     95 else case(n_state)
     96         IDLE:            lcd_data <= 8'hzz;
     97         INIT_FUN_SET1:    lcd_data <= 8'h30;    //function setting    
     98         INIT_FUN_SET2:    lcd_data <= 8'h30;    //function setting        
     99         INIT_DISPLAY:    lcd_data <= 8'h0c;    //display setting    
    100         INIT_CLEAR:        lcd_data <= 8'h01;    //clear setting
    101         INIT_DOT_SET:    lcd_data <= 8'h06;    //dot setting    
    102         SET_DDRAM:        lcd_data <= 8'h91; //2 line
    103         WRITE_DATA0:    lcd_data <= dis_data;
    104         SET_DDRAM2:        lcd_data <= 8'h89; //3 line
    105         WRITE_DATA1:    lcd_data <= dis_data;
    106         WRITE_DATA2:    lcd_data <= dis_data_hig;    //high byte
    107         WRITE_DATA3:    lcd_data <= dis_data_low; //low byte
    108         default: ;
    109     endcase
    110 /***********************************************************/
    111 reg [6:0] num;
    112 always @(posedge lcd_clk or negedge rst_n)
    113 if(!rst_n)
    114     num <= 7'd0;
    115 else if(num == 7'd20)
    116     num <= 7'd0;
    117 else if((n_state == WRITE_DATA0) || (n_state == WRITE_DATA1))
    118     num <= num + 1'b1;
    119 /***********************************************************/
    120 always @(posedge sys_clk or negedge rst_n)
    121 if(!rst_n)
    122     dis_data <= 8'h00;
    123 else case(num)
    124         7'd0:    dis_data <= "I";
    125         7'd1:    dis_data <= "2"; 
    126         7'd2:    dis_data <= "C";
    127         7'd3:    dis_data <= " ";//8'hcd;
    128         7'd4:    dis_data <= "E";//8'ha8;
    129         7'd5:    dis_data <= "P";//8'hd0;
    130         7'd6:    dis_data <= "P";//8'hc5;
    131         7'd7:    dis_data <= "R";//8'hca;
    132         7'd8:    dis_data <= "O";//8'hb5;
    133         7'd9:    dis_data <= "M";//8'hd1;
    134         7'd10:    dis_data <= " ";//8'he9;
    135         7'd11:    dis_data <= "0";
    136         7'd12:    dis_data <= "3";
    137         7'd13:    dis_data <= 8'hb5;
    138         7'd14:    dis_data <= 8'hd8; 
    139         7'd15:    dis_data <= 8'hd6; 
    140         7'd16:    dis_data <= 8'hb7; 
    141         7'd17:    dis_data <= 8'hd6;
    142         7'd18:    dis_data <= 8'hb5;
    143         7'd19:    dis_data <= " ";
    144         default:dis_data <= 8'h00;
    145     endcase
    146 /***************************************************/
    147 assign    lcd_rw = 1'b0;//只有写模式
    148 assign    lcd_psb = 1'b1;//并口模式
    149 wire    en;
    150 assign    en = 1'b1;//(n_state == STOP) ? 1'b0 : 1'b1;
    151 assign    lcd_en = en ?  lcd_clk : 1'b0;
    152 /***************************************************/
    153 endmodule
    View Code

    激励文件(只对LCD模块进行仿真):

    lcd_top.v

     1 `timescale 1ns/10ps
     2 module lcd_top;
     3 /*************************************************************/
     4 reg          sys_clk;
     5 reg          rst_n;
     6 wire         start_cnt;
     7 /*************************************************************/
     8 initial begin
     9     sys_clk = 1'b0;
    10     rst_n = 1'b0;
    11     #100;
    12     rst_n = 1'b1;
    13 end
    14 /*************************************************************/
    15 always #10 sys_clk = ~sys_clk;
    16 /*************************************************************/
    17 wire         lcd_rs;//H:data    L:command
    18 wire         lcd_rw;//H:read module    L:write module
    19 wire         lcd_en;//H active
    20 wire [7:0]    lcd_data;
    21 wire        lcd_psb;//H:parallel    module    L:SPI module 
    22 LCD12864    LCD12864_u1(
    23                     //input 
    24                     .sys_clk(sys_clk),
    25                     .rst_n(rst_n),
    26                     .dis_data_low("8"),
    27                     .dis_data_hig("c"),
    28                     
    29                     //output 
    30                     .lcd_rs(lcd_rs),
    31                     .lcd_rw(lcd_rw),
    32                     .lcd_en(lcd_en),
    33                     .lcd_data(lcd_data),
    34                     .lcd_psb(lcd_psb)
    35                 );
    36 endmodule
    View Code

    这里在把一段式状态机的仿真波形贴出来,可以好好的比较比较,这样做有什么不同,但要知道,三段式从输入到输出要比一段式要延时一个节拍。

  • 相关阅读:
    刚刚开通
    腾讯面试经历2015
    排序之归并排序
    AC自动机
    后缀数组初步
    概率dp初探
    【NOIP2015】反思+题解
    Built-in functions
    poj2528 Mayor's posters(线段树区间覆盖)
    Codeforces #317 C.Lengthening Sticks(数学)
  • 原文地址:https://www.cnblogs.com/wen2376/p/3448116.html
Copyright © 2011-2022 走看看