module LCD(clk,rst,LCD_E,LCD_RW,LCD_RS,LCD_DATA); input clk; //时钟信号,50Mhz input rst; //复位信号,低电平进行复位 output LCD_E; //1602使能引脚,1时读取信息,1->0(下降沿)执行命令 output LCD_RS; //1602数据——H/命令——L 选择端 output LCD_RW; //1602写——L/读——H 选择端 output [7:0] LCD_DATA; //1602数据传输端口 wire LCD_E; reg [8:0] count; reg clk_div1; //500个clk的周期,20ns*500=10us reg clk_div2; //1000个,20us reg [7:0] count1; //250个clk_div2的周期,20us*250=5000u=5ms reg clk_buf; //****************** //-----分频模块----- //******************
always @(posedge clk or negedge rst) begin if(!rst) //rst=0 count<=0; else begin if(count<250) //2500 begin clk_div1<=0; count<=count+1'b1; end else if(count>=500-1) //5000 count<=0; else begin clk_div1<=1; count<=count+1'b1; end end end
always @(posedge clk_div1 or negedge rst) begin if(!rst) clk_div2<=0; else clk_div2<=~clk_div2; end always @(posedge clk_div2 or negedge rst) begin if(!rst) //rst=0 begin count1<=0; clk_buf<=0; // end else begin if(count1<125) //2500 begin clk_buf<=0; count1<=count1+1'b1; end else if(count1>=250-1) //5000 count1<=0; else begin clk_buf<=1; count1<=count1+1'b1; end end end assign LCD_E=clk_buf; //********************** //-----显示控制模块----- //********************** reg [4:0] state; //当前状态寄存器 ,10个状态 reg [5:0] address; //地址的位置,0~31, reg [7:0] LCD_DATA; reg LCD_RW,LCD_RS; parameter IDLE = 4'd0, //空闲 CLEAR = 4'd1, SET_FUNCTION = 4'd2, //工作方式设置指令 SWITCH_MODE = 4'd3, //开关控制指令 SET_MODE = 4'd4, //输入方式设置 SET_DDRAM1 = 4'd5, //设定第一行DDRAM地址指令 WRITE_RAM1 = 4'd6, //向第一行写入的数码 SET_DDRAM2 = 4'd7, //设定第2行DDRAM地址指令 WRITE_RAM2 = 4'd8, //向第2行写入的数码 SHIFT = 4'd9, //设定显示屏或光标移动方向指令 STOP = 4'd10; reg [7:0] Data_First [15:0]; reg [7:0] Data_Second [15:0]; initial begin Data_First[0] = " "; Data_First[1] = "W"; Data_First[2] = "W"; Data_First[3] = "W"; Data_First[4] = "."; Data_First[5] = "N"; Data_First[6] = "B"; Data_First[7] = "U"; Data_First[8] = "."; Data_First[9] = "E"; Data_First[10]= "D"; Data_First[11]= "U"; Data_First[12]= "."; Data_First[13]= "C"; Data_First[14]= "N"; Data_First[15]= " "; Data_Second[0] = " "; Data_Second[1] = " "; Data_Second[2] = " "; Data_Second[3] = "X"; Data_Second[4] = "I"; Data_Second[5] = "N"; Data_Second[6] = "-"; Data_Second[7] = "X"; Data_Second[8] = "I"; Data_Second[9] = "-"; Data_Second[10]= "4"; Data_Second[11]= "1"; Data_Second[12]= "1"; Data_Second[13]= " "; Data_Second[14]= " "; Data_Second[15]= " ";
end //-----状态控制----- always @(posedge clk_buf or negedge rst) // clk_div1 clk_buf begin if(!rst) begin state<=IDLE; address<=6'd0; LCD_DATA<=8'b0000_0000; LCD_RS<=0; LCD_RW<=0; end else begin case(state) IDLE: //空闲状态 begin LCD_DATA<=8'bzzzz_zzzz; //8'bzzzz_zzzz state<=CLEAR; end CLEAR: //清屏指令 begin LCD_RS<=0; LCD_RW<=0; LCD_DATA<=8'b0000_0001; //指令 state<=SET_FUNCTION; end SET_FUNCTION: //工作方式设置 begin LCD_RS<=0; LCD_RW<=0; LCD_DATA<=8'b0011_1100; //38h //第4位DL:0=数据总线为4位;1=数据总线为8位★★★ //第3位N:0=显示1行;1=显示2行★★★ //第2位F:0=5×7点阵/每字符;1=5×10点阵/每字符★★★ state<=SWITCH_MODE; end SWITCH_MODE: //显示开关控制指令 begin LCD_RS<=0; LCD_RW<=0; LCD_DATA<=8'b0000_1111; //0Fh //第2位D:0=显示功能关;1=显示功能开★★★ //第1位C:0=无光标;1=有光标★★★ //第0位B:1=光标闪烁; 0=光标不闪烁★★★ state<=SET_MODE; end SET_MODE: //设定显示屏或光标移动方向指令 begin LCD_RS<=0; LCD_RW<=0; LCD_DATA<=8'b0000_0110; //06h //第1位N:0=读或者写一个字符后,地址指针-1,光标-1 // 1=读或者写一个字符后,地址指针+1,光标+1★★★ //第0位S:0=当写一个字符,整屏显示不移动★★★ // 1=当写一个字符,整屏显示左移(N=1)或者右移(N=0),以得到光标不移动而屏幕移动的效果 state<=SHIFT; end SHIFT: //设定显示屏或光标移动方向指令 begin LCD_RS<=0; LCD_RW<=0; LCD_DATA<=8'b0001_0100; //第3位S/C;第2位R/L // S/C R/L 设定情况 // 0 0 光标左移1格,且地址指针值减1 // 0 1 光标右移1格,且地址指针值加1 ★★★ // 1 0 显示器上字符全部左移一格,但光标不动 // 1 1 显示器上字符全部右移一格,但光标不动 state<=SET_DDRAM1; end SET_DDRAM1: //设定第一行DDRAM地址指令 begin LCD_RS<=0; LCD_RW<=0; //-----写入第一行显示起始地址:----- // 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 // 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 第一行 LCD_DATA<=8'h80+8'd0; //第一行第1个位置 address<=2'd0; state<=WRITE_RAM1; // Data_First_Buf<=Data_First; end WRITE_RAM1: //向第一行写入的数码 begin if(address<=15) //表示写第一行 begin LCD_RS<=1; LCD_RW<=0; LCD_DATA<=Data_First[address]; // Data_First_Buf<=(Data_First_Buf<<8); //左移 address<=address+1'b1; state<=WRITE_RAM1; end else begin LCD_RS<=0; LCD_RW<=0; LCD_DATA<=8'h80+address; state<=SET_DDRAM2; end end SET_DDRAM2: //设定第2行DDRAM地址指令 begin LCD_RS<=0; LCD_RW<=0; //-----写入第2行显示起始地址:----- // 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 // 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 第二行 LCD_DATA<=8'hC0+8'd0; //第2行第1个位置 state<=WRITE_RAM2; // Data_Second_Buf<=Data_Second; address<=6'd0; end WRITE_RAM2: //向第2行写入的数码 begin if(address<=15) //表示写第一行 begin LCD_RS<=1; LCD_RW<=0; LCD_DATA<=Data_Second[address]; // Data_Second_Buf<=(Data_Second_Buf<<8); address<=address+1'b1; state<=WRITE_RAM2; end else begin LCD_RS<=0; LCD_RW<=0; LCD_DATA<=8'hC0+address; state<=STOP; end end STOP: begin state<=STOP; address<=6'd0; LCD_RW<=1; end default: state<=CLEAR; endcase end end endmodule
基于DE2-115的LCD1602应用
最新推荐文章于 2023-11-19 12:06:31 发布