(总结)(原创)LCD屏的学习总结
(总结)(原创)LCD屏的学习总结(针对ST7920)
前言:这么长时间一直没有写博客,是因为总结的东西不能随便的发出来,因为不够完善,尤其对于我这种初学者,但经过一段时间的经历,必须要有深思熟虑,有自己的亲身经历在里面。在这两个星期的时间里,在一个简单的LCD屏的驱动上汲取了许多 营养。该有个学习总结了。
1、学习态度和做事的方式。
认真、全面、仔细、耐心。这是最重要的几点,我一共写了多达3个完全不同的版本去驱动LCD,却一直没有我想要的结果,一直在怀疑我的软件问题,可到最后在发现是我没有仔细阅读通信协议,在初始化的过程中 少了一个指令。另外在仿真的时候也没有对所有的情况做一个完整的检查。
2、将组合电路和时序电路的分离。
一个好用的设计应该是在设计的初期就应该预想到寄存器的个数和它的功能,我认为在电路设计中有很大的部分是在于决定我的寄存器的安放。 在我最后的设计中,我使用了一个移位寄存器,一个发送数据缓冲器,对于每行的数据存储区的输出也有一个数据缓冲,以应对于作出显示内容的选择。我在初学设计的时候使用的都是时序和组合混合的方式,但在这次的设计中我使用的是分开描述的方式,这样书写的方式有利于对于整个系统的理解和实现,对于电路综合后有一个预测和把握。刚开始的时候应用的不是很熟练,渐渐的发现自己对于Verilog的语句和实现方式都没有很好的理解,比如阻塞赋值和非阻塞赋值没有很好的理解,对于begin和end块语句的顺序执行方式也没有体会到。
3、软件代码和说明
(1)我没有使用专门的ROM是直接自己书写的ROM。
(2)我对于发送数据的方式有点问题,应该是先发高位再发低位,我做成了先发低位再发高位,只需要将右移改为左移,将高8位输出。
(3)控制方式,我将每行要发送的汉字存储到ROM里,然后根据输入的显示编码,就达到文字的改变(这是因为我是为任意波形发生器写的专门的调节显示模块的,经过改进可以应用于其他方式),然后向LCD发送数据是从第一行向最后一行不断地重复扫描。
(4)希望大家提出建议,诚恳的需要大家的批评。
(5) 本文是针对st7920写的驱动。
4、源代码如下:
//-----------------------------------------------------
// File Name : gz_lcd_v3.v
// Function : lcd
// Aurthor : guanzhou
//Vertion : v 3.0
//Date : 2009.10.22
//-----------------------------------------------------
`timescale 1ns/100ps
module lcd
(
//input
rclk,rst,
addr_f,addr_p,addr_m,
control,
//ouput
e,rs,rw,
data
);
parameter max_count_f = 4_749_999;
//parameter max_count_f = 2;
parameter wide_count_f = 23;
parameter wide_f = 3,
wide_p = 3,
wide_m = 3;
parameter word_size = 11;
parameter max_b = 63;
parameter order_set = 8'b0011_0000,
cursor_set = 8'b0000_1110,
addr_set = 8'b0000_0001,
display_set = 8'b0000_0100;
parameter idle = 4'b0001,
mode = 4'b0010,
freq = 4'b0100,
phase = 4'b1000;
input rclk,rst;
input [wide_f-1:0] addr_f;
input [wide_p-1:0] addr_p;
input [wide_m-1:0] addr_m;
input [2:0] control;
output e,rs,rw;
output [7:0] data;
reg shift;
//========================================================
//分频
//========================================================
reg [wide_count_f-1:0] count_f;
reg clk;
always @(posedge rclk or negedge rst)
begin
if(!rst)
begin
count_f <= 0;
clk <= 0;
end
else if(count_f==max_count_f)
begin
count_f <= 0;
clk <= ~clk;
end
else
count_f <= count_f + 1'b1;
end
wire e;
assign e = clk; //读写信号为4Hz的时钟信号
reg [max_b+15:0] data_f,
data_p,
data_m;
always @(addr_m or addr_f or addr_p) //定义ROM
begin
case(addr_m)
3'd0: data_m[max_b-1:0] = 64'hCEF7_D3CA_CEA2_B5E7;
3'd1: data_m[max_b-1:0] = 64'hCFE0_CEBB_CFE0_CEBB;
3'd2: data_m[max_b-1:0] = 64'hC6B5_C2CA_C6B5_C2CA;
3'd3: data_m[max_b-1:0] = 64'hCEF7_D3CA_CEA2_B5E7;
3'd4: data_m[max_b-1:0] = 64'hCEF7_D3CA_CEA2_B5E7;
3'd5: data_m[max_b-1:0] = 64'hCFE0_CEBB_CFE0_CEBB;
3'd6: data_m[max_b-1:0] = 64'hC6B5_C2CA_C6B5_C2CA;
3'd7: data_m[max_b-1:0] = 64'hCEF7_D3CA_CEA2_B5E7;
endcase
case(addr_f)
3'd0: data_f[max_b-1:0] = 64'hC6B5_C2CA_C6B5_C2CA;
3'd1: data_f[max_b-1:0] = 64'hCFE0_CEBB_CFE0_CEBB;
3'd2: data_f[max_b-1:0] = 64'hCEF7_D3CA_CEA2_B5E7;
3'd3: data_f[max_b-1:0] = 64'hCFE0_CEBB_CFE0_CEBB;
3'd4: data_f[max_b-1:0] = 64'hC6B5_C2CA_C6B5_C2CA;
3'd5: data_f[max_b-1:0] = 64'hCEF7_D3CA_CEA2_B5E7;
3'd6: data_f[max_b-1:0] = 64'hCFE0_CEBB_CFE0_CEBB;
3'd7: data_f[max_b-1:0] = 64'hCEF7_D3CA_CEA2_B5E7;
endcase
case(addr_p)
3'd0: data_p[max_b-1:0] = 64'hCFE0_CEBB_CFE0_CEBB;
3'd1: data_p[max_b-1:0] = 64'hC6B5_C2CA_C6B5_C2CA;
3'd2: data_p[max_b-1:0] = 64'hCFE0_CEBB_CFE0_CEBB;
3'd3: data_p[max_b-1:0] = 64'hCEF7_D3CA_CEA2_B5E7;
3'd4: data_p[max_b-1:0] = 64'hC6B5_C2CA_C6B5_C2CA;
3'd5: data_p[max_b-1:0] = 64'hCFE0_CEBB_CFE0_CEBB;
3'd6: data_p[max_b-1:0] = 64'hCEF7_D3CA_CEA2_B5E7;
3'd7: data_p[max_b-1:0] = 64'hC6B5_C2CA_C6B5_C2CA;
endcase
end
always @(control) //要求在每一行前面加上指示星号,表明当前的波形设置
begin
case(control)
3'b001:
begin
data_m[max_b+15:max_b] <= 16'hA1F2;
data_f[max_b+15:max_b] <= 16'hA2A0;
data_p[max_b+15:max_b] <= 16'hA2A0;
end
3'b010:
begin
data_m[max_b+15:max_b] <= 16'hA2A0;
data_f[max_b+15:max_b] <= 16'hA1F2;
data_p[max_b+15:max_b] <= 16'hA2A0;
end
3'b100:
begin
data_m[max_b+15:max_b] <= 16'hA2A0;
data_f[max_b+15:max_b] <= 16'hA2A0;
data_p[max_b+15:max_b] <= 16'hA1F2;
end
default:
begin
data_m[max_b+15:max_b] <= 16'hA2A0;
data_f[max_b+15:max_b] <= 16'hA2A0;
data_p[max_b+15:max_b] <= 16'hA2A0;
end
endcase
end
//========================================================
//行扫描循环控制状态机
//========================================================
reg [7:0] data;
reg rs,rw;
reg [4:0] bit_count;
reg [4:0] state,next_state;
reg [max_b+15:0] data_shift;
always @(state or bit_count)
begin
shift = 0;
next_state = state;
case(state)
idle:
begin
if(bit_count==word_size-2)
shift = 1;
if(bit_count==word_size-3)
next_state = mode;
end
mode:
begin
if(bit_count==word_size-2)
shift = 1;
if(bit_count==word_size-3)
next_state = freq;
end
freq:
begin
if(bit_count==word_size-2)
shift = 1;
if(bit_count==word_size-3)
next_state = phase;
end
phase:
begin
if(bit_count==word_size-2)
shift = 1;
if(bit_count==word_size-3)
next_state = mode;
end
default:
begin
shift = 0;
next_state = state;
end
endcase
end
always @(posedge clk or negedge rst)
begin
if(!rst)
state <= idle;
else
state <= next_state;
end
//==========================================================
//发送文字信息数据
//==========================================================
always @(posedge clk or negedge rst)
begin
if(!rst)
begin
data <= order_set;
bit_count <= 0;
data_shift <= {39'd0,display_set,addr_set,cursor_set,order_set,order_set};
end
else
begin
if(shift) // ?????
case(state)
idle:
begin
data_shift <= {39'd0,display_set,addr_set,cursor_set,order_set,order_set};
data <= order_set;
end
mode:
begin
data_shift <= data_m;
data <= 8'h90;
end
freq:
begin
data_shift <= data_f;
data <= 8'h80;
end
phase:
begin
data_shift <= data_p;
data <= 8'h98;
end
default:
begin
data_shift <= data_shift;
data <= 8'h00;
end
endcase
else
begin
data <= data_shift[7:0];
data_shift <= {8'b1111_1111,data_shift[max_b+15:8]};
end
if(shift)
bit_count <= 0;
else
bit_count <= bit_count + 1'b1;
end
end
//================================================================
//发送数据格式指令
//================================================================
always @(posedge clk or negedge rst)
begin
if(!rst)
begin
rw <= 1;
rs <= 1;
end
else
if(state==idle)
begin
rs <= 0;
rw <= 0;
end
else if(shift)
begin
rs <= 0;
rw <= 0;
end
else
begin
rs <= 1;
rw <= 0;
end
end
endmodule