语言:Verilog<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />
开发环境:Libero V8.5
FPGA型号:Actel公司 ProASIC3 系列 A3P030。
液晶型号:MS12232 带字库 串并并行模式可选,这里为并行模式。
关于A3P030 资源:
<?xml:namespace prefix = v ns = "urn:schemas-microsoft-com:vml" />
下边是第一次独立用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)后,液晶正常显示,完成了预期实现的功能。
(待续...)
tengjingshu_112148725 2009-6-8 15:55