新闻  |   论坛  |   博客  |   在线研讨会
首次Verilog 操作液晶手记(1)
0750long | 2009-06-13 12:29:24    阅读:3205   发布文章

首次Verilog 操作液晶手记(1)

 

语言:Verilog

开发环境:Libero V8.5

FPGA型号:Actel公司 ProASIC3 系列 A3P030。

液晶型号:MS12232 带字库 串并并行模式可选,这里为并行模式。

 

关于A3P030 资源:

 点击看大图

 

下边是第一次独立用FPGA编程LCD MS12232的代码,预期完成的功能是在液晶的第一行的第一个字节位置显示一个数字“5”。

 

module lcd(clk, reset, e, rs, rw, db);

 

input clk, reset;

output e, rs, rw;

output [7:0] db;

 

wire clk, reset;

reg e, rs, rw;

reg [7:0] db;

 

reg [2:0] fenpin;

reg [9:0] state;

reg stop;

 

parameter Idle  = 10'b0000000001;

parameter S1    = 10'b0000000010;  // 发指令0x30

parameter S2    = 10'b0000000100;  // 发指令0x30

parameter S3    = 10'b0000001000;  // 发指令0x0e

parameter S4    = 10'b0000010000;  // 发指令0x01

parameter S5    = 10'b0000100000;  // 发指令0x02

parameter S6    = 10'b0001000000;  // 发指令0x04

parameter S7    = 10'b0010000000;  // 发指令0x80

parameter S8    = 10'b0100000000;  // 发数据0x35

parameter S9    = 10'b1000000000;

 

always @(posedge clk)

begin

    if(!reset)

    begin

        fenpin <= 3'd0;

        e <= 0;

        rs <= 0;

        rw <= 0;

        db <= 0;

        state <= Idle;

        stop <= 0;

    end

    else

    begin

         if(!stop) fenpin <= fenpin + 1;   

         else

         begin

            fenpin <= 3'd0;

            e <= 0;

            rs <= 0;

            rw <= 0;

            db <= 0;

            state <= Idle;

         end

    end

 

end

 

always @(fenpin)

begin

    if(fenpin==1) e <= 1;

    else if(fenpin == 5)   e <= 0;

end

 

always @(negedge e)

begin

    case(state)

    Idle:

    begin

        if(stop) state <= Idle;

        else     state <= S1;

    end

    S1:

    begin

        rs <= 0;

        rw <= 0;

        db <= 8'h30;

        state <= S2;

    end

    S2:

    begin

        rs <= 0;

        rw <= 0;

        db <= 8'h30;

        state <= S3;

    end

    S3:

    begin

        rs <= 0;

        rw <= 0;

        db <= 8'he;

        state <= S4;

    end

    S4:

    begin

        rs <= 0;

        rw <= 0;

        db <= 8'h1;

        state <= S5;

    end

    S5:

    begin

        rs <= 0;

        rw <= 0;

        db <= 8'h2;

        state <= S6;

    end

    S6:

    begin

        rs <= 0;

        rw <= 0;

        db <= 8'h4;

        state <= S7;

    end

    S7:

    begin

        rs <= 0;

        rw <= 0;

        db <= 8'h80;

        state <= S8;

    end

    S8:

    begin

        rs <= 1;

        rw <= 0;

        db <= 8'h35;

        state <= S9;

    end

    S9:

    begin

        state <= Idle;

        stop = 1;

    end

    endcase

end

 

endmodule

 

以上代码编译后0 ERROR, 0 WARNING。

然后综合出现一些错误了,如下:

1, Can't mix blocking and non-blocking assignments to a variable。

2, Only one always block may assign a given variable rs

 

关于第一个错误,错误的地方见代码的红色部分。

这里关系到阻塞式赋值(=)和非阻塞式赋值(<=)的使用方法。

A, 阻塞式赋值通常用在assign语句中,非阻塞式赋值通常用在always语句中。

B, 两者不能同时用assign或者always语句中。

C,              顺便提及,assign一般对wire型变量赋值,always一般对reg型变量赋值。

 

关于第二个错误:意思是变量rs在超过一个always语句块中被赋值,而这是不允许的。延伸:一个reg型变量的所有赋值操作只能在一个always块中进行。

 

将上述错误更正后,液晶有显示了,但显示的不是5,而是满屏幕的乱码,这又是什么原因呢?原因是:液晶执行指令的速度是很满的,通常一条指令的执行时间都在几百微妙,而这里只对系统时钟(48MHz)做8分频,对液晶的操作频率有6MHz(不到一微妙),显然液晶不能正确的执行指令了。

调试中发现,即使170us的周期,液晶仍不能稳定的工作。后更正分频系数,分频16*1024(指令周期341.333…us)后,液晶正常显示,完成了预期实现的功能。

 

(待续...)

*博客内容为网友个人发布,仅代表博主个人观点,如有侵权请联系工作人员删除。

参与讨论
登录后参与讨论
推荐文章
最近访客