一、跟据参考的STM32代码了解初始化流程
LCD初始化函数
void LCD_Init(void);
首先是LCD的复位
void LCD_RESET(void)
{
LCD_RST_CLR; //拉低复位引脚
Delay_Ms(100); //延时100ms
LCD_RST_SET; //拉高复位引脚
Delay_Ms(50); //延时50ms
}
向LCD屏幕写入一个8位命令
void LCD_WR_REG(u8 data)
{
LCD_CS_CLR; //拉低片选引脚
LCD_RS_CLR; //拉低dc引脚
SPI_WriteByte(SPI1,data); //使用硬件SPI写入一个字节的数据
LCD_CS_SET; //拉高片选引脚
}
将8位数据写入LCD屏幕
void LCD_WR_DATA(u8 data)
{
LCD_CS_CLR; //拉低片选引脚
LCD_RS_SET; //拉高dc引脚
SPI_WriteByte(SPI1,data); //使用硬件SPI写入一个字节的数据
LCD_CS_SET; //拉高片选引脚
}
设置液晶显示屏的显示方向
void LCD_direction(u8 direction);
清屏,也就是整个屏幕的点都为白色
void LCD_Clear(u16 Color);
LCD显示窗口设置
void LCD_SetWindows(u16 xStar, u16 yStar,u16 xEnd,u16 yEnd);
二、模块框图
文章来源地址https://www.toymoban.com/news/detail-427685.html
三、设计状态机
1、初始化命令
初始化命令是厂家已经配置好的,直接调用这部分就行了。
LCD_WR_REG(0xCF);
LCD_WR_DATA(0x00);
(省略~)
LCD_WR_DATA(0xef);
LCD_WR_REG(0x11); //Exit Sleep
Delay_Ms(120);
LCD_WR_REG(0x29); //display on
2、设置LCD显示方向
为了方便省事,只考虑参考代码中液晶屏顺时针旋转方向为0的情况。
#define USE_HORIZONTAL 0//定义液晶屏顺时针旋转方向 0-0度旋转,1-90度旋转,2-180度旋转,3-270度旋转
void LCD_direction(u8 direction)函数只需要知道LCD_WriteReg(0x36,(1<<3)|(0<<6)|(0<<7));
传输到lcd_write模块的数据(最高位决定命令/数据,0为命令,1为数据)为9'h036和9'h108。
3、清屏
lcd的清屏步骤是先设置LCD的填充窗口大小(320x240)
9'h02A; //列地址设置
{1'b1,7'b0000_000,start_x[8]}; //x的开始坐标高8位
{1'b1,start_x[7:0]}; //x的开始坐标低8位
{1'b1,7'b0000_000,end_x[8]}; //x的结束坐标高8位
{1'b1,end_x[7:0]}; //x的结束坐标低8位
9'h02B; //页面地址设置
{1'b1,7'b0000_000,start_y[8]}; //y的开始坐标高8位
{1'b1,start_y[7:0]}; //y的开始坐标低8位
{1'b1,7'b0000_000,end_y[8]}; //y的结束坐标高8位
{1'b1,end_y[7:0]}; //y的结束坐标低8位
9'h02C; //存储器写入
清屏的时候设置的窗口大小(320x240)和start_x、start_y、end_x、end_y已经确定,可以直接用以下部分。
9'h02A
9'h100
9'h100
9'h100
9'h1ef
9'h02B
9'h100
9'h100
9'h101
9'h13f
9'h02C
然后在需要填充的点进行对应颜色(白色)的填充。颜色填充为16位,先传高8位,再传低8位。
一共传输320*240*2-1=153,599次。
四、波形图绘制
五、代码编写
module lcd_init
// #(//仿真时调用
// parameter TIME100MS = 23'd100, //23'd5000_000
// TIME150MS = 23'd150, //23'd7500_000
// TIME120MS = 23'd120, //23'd6000_000
// TIMES4MAX = 18'd51 , //320*240*2+13(设置窗口大小)=153_613
// DATA_IDLE = 9'b0_0000_0000
// )
#(//驱动lcd时调用
parameter TIME100MS = 23'd5000_000, //23'd5000_000
TIME150MS = 23'd7500_000, //23'd7500_000
TIME120MS = 23'd6000_000, //23'd6000_000
TIMES4MAX = 18'd153_613 , //320*240*2+13(设置窗口大小)=153_613
DATA_IDLE = 9'b0_0000_0000
)
(
input wire sys_clk_50MHz ,
input wire sys_rst_n ,
input wire wr_done ,
output reg lcd_rst ,
output reg [8:0] init_data ,
output wire en_write ,
output wire init_done
);
//****************** Parameter and Internal Signal *******************//
//画笔颜色
parameter WHITE = 16'hFFFF,
BLACK = 16'h0000,
BLUE = 16'h001F,
BRED = 16'hF81F,
GRED = 16'hFFE0,
GBLUE = 16'h07FF,
RED = 16'hF800,
MAGENTA = 16'hF81F,
GREEN = 16'h07E0,
CYAN = 16'h7FFF,
YELLOW = 16'hFFE0,
BROWN = 16'hBC40, //棕色
BRRED = 16'hFC07, //棕红色
GRAY = 16'h8430; //灰色
//-----------------------------------------------------------------
reg [5:0] state;
parameter S0_DELAY100MS = 6'b000_001,
S1_DELAY50MS = 6'b000_010,
S2_WR_90 = 6'b000_100,
S3_DELAY120MS = 6'b001_000,
S4_WR_DIRECTION_CLEAR = 6'b010_000,
DONE = 6'b100_000;
reg [22:0] cnt_150ms;
reg lcd_rst_high_flag;
reg [6:0] cnt_s2_num;
reg cnt_s2_num_done;
reg [17:0] cnt_s4_num;
reg cnt_s4_num_done;
//-----------------------------------------------------------------
//状态跳转
always@(posedge sys_clk_50MHz or negedge sys_rst_n)
if(!sys_rst_n)
state <= S0_DELAY100MS;
else
case(state)
S0_DELAY100MS:
state <= (cnt_150ms == TIME100MS) ? S1_DELAY50MS : S0_DELAY100MS;
S1_DELAY50MS:
state <= (cnt_150ms == TIME150MS) ? S2_WR_90 : S1_DELAY50MS;
S2_WR_90:
state <= (cnt_s2_num_done) ? S3_DELAY120MS : S2_WR_90;
S3_DELAY120MS:
state <= (cnt_150ms == TIME120MS) ? S4_WR_DIRECTION_CLEAR : S3_DELAY120MS;
S4_WR_DIRECTION_CLEAR:
state <= (cnt_s4_num_done) ? DONE : S4_WR_DIRECTION_CLEAR;
DONE:
state <= DONE;
default:
state <= S0_DELAY100MS;
endcase
//cnt_150ms
always@(posedge sys_clk_50MHz or negedge sys_rst_n)
if(!sys_rst_n)
cnt_150ms <= 23'd0;
else if(state == S0_DELAY100MS || state == S1_DELAY50MS || state == S3_DELAY120MS )
cnt_150ms <= cnt_150ms + 1'b1;
else
cnt_150ms <= 23'd0;
//lcd_rst_high_flag
always@(posedge sys_clk_50MHz or negedge sys_rst_n)
if(!sys_rst_n)
lcd_rst_high_flag <= 1'b0;
else if(state == S0_DELAY100MS && (cnt_150ms == TIME100MS - 1'b1))
lcd_rst_high_flag <= 1'b1;
else
lcd_rst_high_flag <= 1'b0;
//lcd_rst
always@(posedge sys_clk_50MHz or negedge sys_rst_n)
if(!sys_rst_n)
lcd_rst <= 1'b0;
else if(lcd_rst_high_flag)
lcd_rst <= 1'b1;
else
lcd_rst <= lcd_rst;
//-----------------------------------------------------------------
//cnt_s2_num决定要传的命令/数据
always@(posedge sys_clk_50MHz or negedge sys_rst_n)
if(!sys_rst_n)
cnt_s2_num <= 7'd0;
else if(state != S2_WR_90)
cnt_s2_num <= 7'd0;
else if(wr_done && state == S2_WR_90)
cnt_s2_num <= cnt_s2_num + 1'b1;
else
cnt_s2_num <= cnt_s2_num;
//cnt_s2_num_done == 1'b1则S2_WR_90完成
always@(posedge sys_clk_50MHz or negedge sys_rst_n)
if(!sys_rst_n)
cnt_s2_num_done <= 1'b0;
else if(cnt_s2_num == 7'd89 && wr_done == 1'b1)
cnt_s2_num_done <= 1'b1;
else
cnt_s2_num_done <= 1'b0;
//init_data[8:0]
always@(posedge sys_clk_50MHz or negedge sys_rst_n)
if(!sys_rst_n)
init_data <= DATA_IDLE;
else if(state == S2_WR_90)
//初始化命令/数据,直接借用厂家的
case(cnt_s2_num) //init_data[8] == 1'b1写数据; == 1'b0写命令
7'd0 : init_data <= 9'h0CF ;
7'd1 : init_data <= 9'h100 ;
7'd2 : init_data <= 9'h1C9 ;
7'd3 : init_data <= 9'h130 ;
7'd4 : init_data <= 9'h0ED ;
7'd5 : init_data <= 9'h164 ;
7'd6 : init_data <= 9'h103 ;
7'd7 : init_data <= 9'h112 ;
7'd8 : init_data <= 9'h181 ;
7'd9 : init_data <= 9'h0E8 ;
7'd10: init_data <= 9'h185 ;
7'd11: init_data <= 9'h110 ;
7'd12: init_data <= 9'h17A ;
7'd13: init_data <= 9'h0CB ;
7'd14: init_data <= 9'h139 ;
7'd15: init_data <= 9'h12C ;
7'd16: init_data <= 9'h100 ;
7'd17: init_data <= 9'h134 ;
7'd18: init_data <= 9'h102 ;
7'd19: init_data <= 9'h0F7 ;
7'd20: init_data <= 9'h120 ;
7'd21: init_data <= 9'h0EA ;
7'd22: init_data <= 9'h100 ;
7'd23: init_data <= 9'h100 ;
7'd24: init_data <= 9'h0C0 ;
7'd25: init_data <= 9'h11B ;
7'd26: init_data <= 9'h0C1 ;
7'd27: init_data <= 9'h100 ;
7'd28: init_data <= 9'h0C5 ;
7'd29: init_data <= 9'h130 ;
7'd30: init_data <= 9'h130 ;
7'd31: init_data <= 9'h0C7 ;
7'd32: init_data <= 9'h1B7 ;
7'd33: init_data <= 9'h036 ;
7'd34: init_data <= 9'h108 ;
7'd35: init_data <= 9'h03A ;
7'd36: init_data <= 9'h155 ;
7'd37: init_data <= 9'h0B1 ;
7'd38: init_data <= 9'h100 ;
7'd39: init_data <= 9'h11A ;
7'd40: init_data <= 9'h0B6 ;
7'd41: init_data <= 9'h10A ;
7'd42: init_data <= 9'h1A2 ;
7'd43: init_data <= 9'h0F2 ;
7'd44: init_data <= 9'h100 ;
7'd45: init_data <= 9'h026 ;
7'd46: init_data <= 9'h101 ;
7'd47: init_data <= 9'h0E0 ;
7'd48: init_data <= 9'h10F ;
7'd49: init_data <= 9'h12A ;
7'd50: init_data <= 9'h128 ;
7'd51: init_data <= 9'h108 ;
7'd52: init_data <= 9'h10E ;
7'd53: init_data <= 9'h108 ;
7'd54: init_data <= 9'h154 ;
7'd55: init_data <= 9'h1A9 ;
7'd56: init_data <= 9'h143 ;
7'd57: init_data <= 9'h10A ;
7'd58: init_data <= 9'h10F ;
7'd59: init_data <= 9'h100 ;
7'd60: init_data <= 9'h100 ;
7'd61: init_data <= 9'h100 ;
7'd62: init_data <= 9'h100 ;
7'd63: init_data <= 9'h0E1 ;
7'd64: init_data <= 9'h100 ;
7'd65: init_data <= 9'h115 ;
7'd66: init_data <= 9'h117 ;
7'd67: init_data <= 9'h107 ;
7'd68: init_data <= 9'h111 ;
7'd69: init_data <= 9'h106 ;
7'd70: init_data <= 9'h12B ;
7'd71: init_data <= 9'h156 ;
7'd72: init_data <= 9'h13C ;
7'd73: init_data <= 9'h105 ;
7'd74: init_data <= 9'h110 ;
7'd75: init_data <= 9'h10F ;
7'd76: init_data <= 9'h13F ;
7'd77: init_data <= 9'h13F ;
7'd78: init_data <= 9'h10F ;
7'd79: init_data <= 9'h02B ;
7'd80: init_data <= 9'h100 ;
7'd81: init_data <= 9'h100 ;
7'd82: init_data <= 9'h101 ;
7'd83: init_data <= 9'h13f ;
7'd84: init_data <= 9'h02A ;
7'd85: init_data <= 9'h100 ;
7'd86: init_data <= 9'h100 ;
7'd87: init_data <= 9'h100 ;
7'd88: init_data <= 9'h1ef ;
7'd89: init_data <= 9'h011 ;
default: init_data <= DATA_IDLE;
endcase
else if(state == S4_WR_DIRECTION_CLEAR)
case(cnt_s4_num)
'd0 : init_data <= 9'h029;
//设置LCD显示方向
'd1 : init_data <= 9'h036;
'd2 : init_data <= 9'h108;
//LCD显示窗口设置
'd3 : init_data <= 9'h02a;
'd4 : init_data <= 9'h100;
'd5 : init_data <= 9'h100;
'd6 : init_data <= 9'h100;
'd7 : init_data <= 9'h1ef;
'd8 : init_data <= 9'h02b;
'd9 : init_data <= 9'h100;
'd10: init_data <= 9'h100;
'd11: init_data <= 9'h101;
'd12: init_data <= 9'h13f;
'd13: init_data <= 9'h02c;
//填充对应点的颜色,可以换用比较明显的红色,便于观察现象
default :
//当cnt_s4_num大于14且为偶数时,传输颜色数据的高8位
if(cnt_s4_num >= 'd14 && cnt_s4_num[0] == 0)
init_data <= {1'b1,WHITE[15:8]};
//当cnt_s4_num大于14且为奇数时,传输颜色数据的低8位
else if(cnt_s4_num >= 'd14 && cnt_s4_num[0] == 1)
init_data <= {1'b1,WHITE[7:0]};
else
init_data <= DATA_IDLE;
endcase
else
init_data <= DATA_IDLE;
//cnt_s4_num决定要传的命令/数据
always@(posedge sys_clk_50MHz or negedge sys_rst_n)
if(!sys_rst_n)
cnt_s4_num <= 18'd0;
else if(state != S4_WR_DIRECTION_CLEAR)
cnt_s4_num <= 18'd0;
else if(wr_done && state == S4_WR_DIRECTION_CLEAR)
cnt_s4_num <= cnt_s4_num + 1'b1;
else
cnt_s4_num <= cnt_s4_num;
//cnt_s4_num_done
always@(posedge sys_clk_50MHz or negedge sys_rst_n)
if(!sys_rst_n)
cnt_s4_num_done <= 1'b0;
else if(cnt_s4_num == TIMES4MAX && wr_done == 1'b1)
cnt_s4_num_done <= 1'b1;
else
cnt_s4_num_done <= 1'b0;
assign en_write = (state == S2_WR_90 || state == S4_WR_DIRECTION_CLEAR) ? 1'b1 : 1'b0;
assign init_done = (state == DONE) ? 1'b1 : 1'b0;
endmodule
六、仿真代码
`timescale 1ns/1ns
module tb_lcd_init();
reg sys_clk_50MHz;
reg sys_rst_n ;
reg wr_done ;
wire lcd_rst ;
wire [8:0] init_data ;
wire en_write ;
wire init_done ;
reg [1:0] cnt1;
initial
begin
sys_clk_50MHz <= 1'b1;
sys_rst_n <= 1'b0;
wr_done <= 1'b0;
#100
sys_rst_n <= 1'b1;
end
always #10 sys_clk_50MHz <= ~sys_clk_50MHz;
always@(posedge sys_clk_50MHz or negedge sys_rst_n)
if(!sys_rst_n)
cnt1 <= 'd0;
else if(en_write)
cnt1 <= cnt1 + 1'b1;
always@(posedge sys_clk_50MHz or negedge sys_rst_n)
if(!sys_rst_n)
wr_done <= 1'b0;
else if(cnt1 == 'd3)
wr_done <= 1'b1;
else
wr_done <= 1'b0;
lcd_init lcd_init_inst
(
.sys_clk_50MHz (sys_clk_50MHz),
.sys_rst_n (sys_rst_n ),
.wr_done (wr_done ),
.lcd_rst (lcd_rst ),
.init_data (init_data ),
.en_write (en_write ),
.init_done (init_done )
);
endmodule
七、仿真波形图
文章来源:https://www.toymoban.com/news/detail-427685.html
到了这里,关于FPGA驱动SPI接口的LCD(三)——LCD的初始化的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!