FPGA ——LCD12864 _verilog程序

1、

LCD12864 是一种单片机常用显示屏,按照其字库共可显示164个英文字母 或者 84个汉字,按数据传输方式具有很多分类。以下为较为常见的8数据线接口的显示教程。

2、

其工作原理是通过驱动RW,RS,E 、8位数据口 来写命令和写数据。在
RW表读“1”、写“0”操作。本次只进行读操作,故RW设为“0”。
E为使能端:高电平写入,故可与clock时钟相同。
RS在写入数据是为“1”。
PSB接高电平
BLK接GND
BLA与接电位器以控制lcd背光亮度
按照单片机使用它的一般工作顺序:指令初始化---->写数据。

3、

首先是指令初始化:下面是其指令表:
FPGA ——LCD12864 _verilog程序_第1张图片
首先通过状态机写指令(注意虽然12864指令具有默认值,但还是需要进行配置,否则非正常显示)。首先设置对其功能进行设定,这儿有个坑,刚开始看数据手册没有注意到这点,导致浪费很多时间,此坑如下:
FPGA ——LCD12864 _verilog程序_第2张图片
就是对此指令设置,必须要进行两次。一次设置选用的指令集,一次设置控制接口宽度。
随后就是按照指令表内容,设置光标、进入点等。很简单,详见代码

4、

写入数据。
写数据是应将RS设“1”。在写入数据时应注意其行数的选择,其不能自动换行,应进行指令操控换行。本里程使用ST7920字库。其英文字库可以直接使用英文字母如“A”。注意如果现实数值需要加0'd48.
(没有数据手册可以点击后面链接下载,PDF支持Ctr+F查找汉字很是方便:
下载链接:https://download.csdn.net/download/szsfate/10526436)。
使用汉字可以在数据手册自行查找如下:
FPGA ——LCD12864 _verilog程序_第3张图片

5、

注意其时钟频率的设定,经实测3KHz左右基本为其最大时钟频率,5k会在指令和数据转换之间出现错误。

6、

以下为其代码:具有详细备注说明。为演示,程序中将data_buf接口注释掉。

/*
* Title:    <话机屏幕显示>
* description:
* @author:  fateszs
* @data:    2018.7.06
*
*/
module lcd_12864(
	input	clk_50M, 
	input	rst,
//	input [511:0]data_buf,							//使用时去掉注释。
	output lcd_rs, 									//寄存器选择输出信号
	output lcd_rw, 										//读、写操作选择输出信号
	output lcd_e, 											
	output [7:0]lcd_data); 							//本实验只做读信号使用		
	/*其余管脚:
					PSB接高电平		
					BLK接GND		
					BLA与接电位器以控制lcd背光亮度			
	*/
//*****************以下为其测试所用数据,使用时删除*****************/
	wire 	 [511:0]data_buf;
	assign data_buf[511:504] = 8'hBF;
	assign data_buf[503:496] = 8'hAA;		//开
	assign data_buf[495:488] = 8'hCA;
	assign data_buf[487:480] = 8'hBC;		//始
	assign data_buf[31:24]	 = 8'hBD;
	assign data_buf[23:16]   = 8'hE1;		//结
	assign data_buf[15:8]	 = 8'hCA;
	assign data_buf[7:0]	 	 = 8'hF8;		//束
//***************************************************************//
	 
/**************************产生lcd时钟信号*************************/

	reg clk_lcd; 										
	reg [16:0]cnt;    									              
	always @(posedge clk_50M or negedge rst)
	begin
		if (!rst)
		begin 
			cnt <= 17'b0;
			clk_lcd <= 0;
		end   
		else if(cnt == 17'd7999)				//时钟频率非常重要!!将近3k,经实测5k会在第0位出错。
		begin 
			cnt <= 17'd0;
			clk_lcd <= ~clk_lcd;
		end   
		else 
			cnt <= cnt +1'b1;
	end

	

//****************************lcd12806控制信号*****************************************/                           
	reg [8:0] state; //State Machine code
	parameter IDLE  			= 4'd0;             
	parameter CMD_WIDTH 		= 4'd1;             //设置数据接口数量
	parameter CMD_SET 		= 4'd2;					//选择指令集
	parameter CMD_CURSOR 	= 4'd3;             //设置光标
	parameter CMD_CLEAR 		= 4'd4;          	//清屏
	parameter CMD_ACCESS    = 4'd5;          	//输入方式设置:数据读写操作后,地址自动加一/画面不动
	parameter CMD_DDRAM     = 4'd6;          	//DDRAM行地址
	parameter DATA_WRITE		= 4'd7;             //数据写入
	parameter STOP 			= 4'd8;             //

	reg lcd_rs_r;
   //输出管教配置
	assign lcd_rs = lcd_rs_r;
	assign lcd_rw = 1'b0; 
	assign lcd_e  = clk_lcd; 									//与lcd时钟相同
	assign lcd_data = lcd_data_r;
	
	reg [5:0] cnt_time;
	reg [7:0] lcd_data_r;
	reg [7:0] data_buff;
	always @(posedge clk_lcd , negedge rst)
	begin
		if(!rst)
		begin
			lcd_rs_r <= 1'b0;
			state <= IDLE;
			lcd_data_r <= 8'bzzzzzzzz;							//高阻态
			cnt_time <= 6'd0;
		end
		else 
		begin
			case(state)
				IDLE:  
				begin  
					lcd_rs_r <= 1'b0;
					cnt_time <= 6'd0;
					state <= CMD_WIDTH;
					lcd_data_r <= 8'bzzzzzzzz;  
				end
				CMD_WIDTH:					
				begin
					lcd_rs_r <= 1'b0;
					state <= CMD_SET;	
					lcd_data_r <= 8'h30; 							//8位数据口
				end
				CMD_SET:
				begin
					lcd_rs_r <= 1'b0;
					state <= CMD_CURSOR;
					lcd_data_r <= 8'h30; 							//基本指令集
					//同一指令之动作不可同时改变 RE 及 DL ,需先改变 DL 后在改变 RE 才可确保 FLAG 正确设定
				end
				CMD_CURSOR:
				begin
					lcd_rs_r <= 1'b0;
					state <= CMD_CLEAR;
					lcd_data_r <= 8'h0c; 							// 关光标
				end
				CMD_CLEAR:
				begin
					lcd_rs_r <= 1'b0;
					state <= CMD_ACCESS;
					lcd_data_r <= 8'h01;							//清屏
				end
				CMD_ACCESS:
				begin
					lcd_rs_r <= 1'b0;
					state <= CMD_DDRAM;
					lcd_data_r <= 8'h06; 							//进入点设定
				end
				CMD_DDRAM:											//行数命令
				begin
					lcd_rs_r <= 1'b0;
					state <= DATA_WRITE;
					case (cnt_time)
						6'd0:		lcd_data_r <= 8'h80;
						6'd16:	lcd_data_r <= 8'h90;
						6'd32:	lcd_data_r <= 8'h88;
						6'd48:	lcd_data_r <= 8'h98;
					endcase
				end
				DATA_WRITE:												//写数据
				begin
					lcd_rs_r <= 1'b1;
					cnt_time <= cnt_time + 1'b1;
					lcd_data_r <= data_buff;
					case (cnt_time)
						6'd15:	state <= CMD_DDRAM;
						6'd31:	state <= CMD_DDRAM;
						6'd47:	state <= CMD_DDRAM;
						6'd63:	state <= STOP;
						default:	state <= DATA_WRITE;
					endcase
				end
				STOP:
				begin
					lcd_rs_r <= 1'b0;
					state <= CMD_DDRAM;
					lcd_data_r <= 8'h80;								//从第几行循环
					cnt_time <= 6'd0;
				end
				default: 
					state <= IDLE;
			endcase
		end
	end
	
	
	always @(cnt_time) 
	begin
		case (cnt_time)
			6'd0:  data_buff <= data_buf[511:504];
			6'd1:  data_buff <= data_buf[503:496]; 	//开
			6'd2:  data_buff <= data_buf[495:488];
			6'd3:  data_buff <= data_buf[487:480];  	//始
			6'd4:  data_buff <= 8'h20;  	
			6'd5:  data_buff <= 8'h20;  	
			6'd6:  data_buff <= 8'h20;
			6'd7:  data_buff <= 8'h20;  	
			6'd8:  data_buff <= 8'h20;
			6'd9:  data_buff <= 8'h20;		
			6'd10:  data_buff <= 8'h20;
			6'd11:  data_buff <= 8'h20;	
			6'd12:  data_buff <= 8'h20;
			6'd13:  data_buff <= 8'h20;	
			6'd14:  data_buff <= 8'h20;
			6'd15:  data_buff <= 8'h20;
			
			6'd16:  data_buff <= 8'h20;
			6'd17:  data_buff <= 8'h20;
			6'd18:  data_buff <= 8'h20;//如果显示数字,需要加0'd48,例如data_buff <= num+8'd48
			6'd19:  data_buff <= 8'h20;
			6'd20:  data_buff <= "F";
			6'd21:  data_buff <= "A";
			6'd22:  data_buff <= "T";
			6'd23:  data_buff <= "E";
			6'd24:  data_buff <= "S";
			6'd25:  data_buff <= "Z";
			6'd26:  data_buff <= "S";
			6'd27:  data_buff <= 8'h20;
			6'd28:  data_buff <= 8'h20;
			6'd29:  data_buff <= 8'h20;
			6'd30:  data_buff <= 8'h20;
			6'd31:  data_buff <= 8'h20;
			
			6'd32:  data_buff <= 8'h20;
			6'd33:  data_buff <= 8'h20;
			6'd34:  data_buff <= 8'h20;
			6'd35:  data_buff <= 8'h20;
			6'd36:  data_buff <= 8'h20;
			6'd37:  data_buff <= 8'h20;
			6'd38:  data_buff <= 8'h20;
			6'd39:  data_buff <= 8'h20;
			6'd40:  data_buff <= 8'h20;
			6'd41:  data_buff <= 8'h20;
			6'd42:  data_buff <= 8'h20;
			6'd43:  data_buff <= 8'h20;
			6'd44:  data_buff <= 8'h20;
			6'd45:  data_buff <= 8'h20;
			6'd46:  data_buff <= 8'h20;
			6'd47:  data_buff <= 8'h20;
			
			6'd48:  data_buff <= 8'h20;
			6'd49:  data_buff <= 8'h20;
			6'd50:  data_buff <= 8'h20;
			6'd51:  data_buff <= 8'h20;                                       
			6'd52:  data_buff <= 8'h20;
			6'd53:  data_buff <= 8'h20;
			6'd54:  data_buff <= 8'h20;
			6'd55:  data_buff <= 8'h20; 
			6'd56:  data_buff <= 8'h20;
			6'd57:  data_buff <= 8'h20;
			6'd58:  data_buff <= 8'h20;
			6'd59:  data_buff <= 8'h20;
			6'd60:  data_buff <= data_buf[31:24];
			6'd61:  data_buff <= data_buf[23:16];		//结
			6'd62:  data_buff <= data_buf[15:8];	
			6'd63:  data_buff <= data_buf[7:0];			//束
 
			default :  data_buff <= 8'h02;
		endcase
	end
endmodule 


7/

在DE2FPGA开发板测试如下:
FPGA ——LCD12864 _verilog程序_第4张图片

你可能感兴趣的:(FPGA)