1.原理
本次实验的目的是在LCD上显示五条不同颜色的彩带,本次我们采用的像素格式是RGB888,一个像素点为24Bit。
接下来是关于LCD如何显示一帧图像呢?我们是采取从左往右,从上往下的方式扫描每个像素点,并表明每个像素点对应的颜色。根据行显示的时序图,我们可以看到,整个构成并不只是由HSPW构成,它还由HBP+HOZVAL+HFP构成;场信号是一样的。
还有很多细节就不赘述了。
那么我们主要要实现一个什么样的东西呢?首先,我们接上LCD屏幕的时候,要能够自动判断出LCD的型号,也就是分辨率,从而可以给出适合的时钟频率(毕竟不同的型号时钟也不同),接下来再驱动LCD显示我们要求的数据。那我们大概可以分为这几个模块进行:(1)ID识别模块,(2)分频模块,(3)驱动模块,(4)显示模块。
接下来我们仔细介绍一下各个模块的思路。
2.设计思路
(1)ID模块
首先来说ID模块,端口方面我们需要的不多,时钟,复位,和lcd_rgb信号,这个信号需要重视一下,它其实是一个inout类型的信号,因为一方面,它要把信号给ID模块,让ID模块来识别,另一方面,它要负责把数据传给LCD以显示颜色,因此在这个模块里,它设为input类型就行了;然后最后,我们要输出一个lcd_id信号,把我们判断出来的ID传送给下一个模块。
代码:
module LCD_ID(
input clk,
input rst_n,
input [23:0] lcd_rgb,
output reg [15:0] lcd_id
);
reg lcd_flag;
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
lcd_flag<=1'b0;
lcd_id<=16'b0;
end
else begin
if(lcd_flag==1'b0)begin
lcd_flag<=1'b1;
case({
lcd_rgb[7],lcd_rgb[15],lcd_rgb[23]})
3'b000 : lcd_id <= 16'h4342;
3'b001 : lcd_id <= 16'h7084;
3'b010 : lcd_id <= 16'h7016;
3'b100 : lcd_id <= 16'h4384;
3'b101 : lcd_id <= 16'h1018;
default : lcd_id <= 16'd0;
endcase
end
end
end
endmodule
那么大家是否会对
if(lcd_flag==1'b0)begin
lcd_flag<=1'b1;
这一部分产生疑问呢?
其实这个设置还是比较巧妙,板子上电时,一般都有个复位操作,这个复位操作将lcd_flag拉到低电平,当低电平时触发条件,接下来将这一信号拉高,并进行接下来的操作;那么为什么我们要拉高呢?因为我们只需要进行一次ID的判断,如果反复进行其实是很浪费资源的一件事,因此我们拉高信号之后,就相当于只执行一次判断ID的操作,后面就不再执行了。
至于case语句里的条件,即lcd_rgb得位数,那是特定的,不必深究。
(2)分频模块
那么分频怎么做到的呢?我们举个例子,拿二分频为例:
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
clk_25m <= 1'b0;
else
clk_25m <= ~clk_25m;
end
在这个always块里,每当clk到来时,触发条件,让clk-25m反转,大家可以自己在图上画一下,就可以很明白的看出来这就是二分频:
四分频也是一样,接下来附上代码:
module LCD_DIV(
input clk,
input rst_n,
input [15:0] lcd_id,
output reg lcd_pclk
);
reg clk_25m;
reg clk_12_5m;
reg div_cnt;
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
clk_25m <= 1'b0;
else
clk_25m <= ~clk_25m;
end
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
clk_12_5m <= 1'b0;
div_cnt <= 1'b0;
end
else begin
div_cnt <= div_cnt + 1'b1;
if(div_cnt == 1)
clk_12_5m <= ~clk_12_5m;
end
end
always@(*)begin
if(!rst_n)
lcd_pclk <= 1'b0;
else begin
case(lcd_id)
16'h4342 : lcd_pclk = clk_12_5m;
16'h7084 : lcd_pclk = clk_25m;
16'h7016 : lcd_pclk = clk;
16'h4384 : lcd_pclk = clk_25m;
16'h1018 : lcd_pclk = clk;
default : lcd_pclk