LCD1602

  • 功能描述:

  通过写入指令或数据,控制内部的驱动芯片,从而实现在LCD显示屏上显示字符串:

\[{I\_❤LOVE❤\_BUAA!} \]

\[{1952--2022} \]

  • 设计方案:

  设计将以有限状态机的形式完成功能设计,其中涉及的状态及相关功能如下图1所示,


图1 状态表

  CGRAM_ADDR前面均为LCD初始化状态,不多赘述。CGRAM_ADDR状态下,传送指令:要写入CGRAM,地址为00H;下面CGRAM_WRITE状态下,传送数据:其中字模数据为8行八列数据,不能一次传入,故设计一计数器,若计数到7,则跳转下一状态ADDR1,否则继续CGRAM_WRITE状态直到完成一个字符的写入;ADDR1和ADDR2状态下均传送指令:要写入DDRAM,地址分别为00H和40H,完成后均跳转到WRITE_DDRAM状态;WRITE_DDRAM也需要一计数器来监控传到了第几行 以及是否传送完毕,结束后跳转至STOP状态,维持当下显示

  下面将说明具体实现。

  ①使能信号的生成: 当LCD的时钟频率设置错误时,LCD的显示就会闪,或者没有显示,故选择控制使能信号的周期生成,来达到设计要求的500Hz,这里选择的是计数方法,已知我们的初始时钟是CLOCK_50,若每逢上升沿计数,为生成500Hz的工作时钟,需每逢计数99999,进行一次归零进入下一计数周期,并设置使能信号LCD_EN,每逢49999进行一次翻转,即可对应得到使能信号;

  ②延时15ms的实现: 在空闲IDLE状态下,需延时15ms进入下一状态,综合考虑电路性能,选择以计数的形式来实现,同上①;

  ③LCD的显示: 在LCD上显示字符的过程就是向DDRAM的相应地址写入数据的过程,其中DDRAM地址与显示位置的对应关系如下图2所示。若想要在LCD的第一行最左显示字母A,则过程为:传指令DDRAM地址00H\({→}\)传数据字母A(41H)


图2 DDRAM地址与显示对照表

  ④自定义字符的实现: 在芯片中内置了192个常用字符的字模,存于CGROM中,可以实现基本数字和字母的直接调用显示(如上文中字母A),此外还有8个允许用户自定义字符的CGRAM,即为下图3中绿框中所示,我们可以通过先将自定义字符写入CGRAM,再调入写入DDRAM的方法实现自定义字符的显示,下面以字符\({❤}\)为例加以说明:


图3 CGRAM
  • 取字模: 将图形转换为二进制数,显示出来的部分置1,未显示的部分置0,如下图4所示,可以得到8列八位数据

图4 字模结果
  • 写入CGRAM: 写入CGRAM的指令如下图5所示,其中CGRAM的地址为00H-0FH,这里我们选择写入地址为00H,将上面得到的8列八位数据依次写入CGRAM,则CGROM中00H就代表了字符\({♥}\)

图5 写入CGRAN指令
  • 显示: 即将地址指针指向DDRAM即可,写入数据为00H。

  • 关键代码:

	/***main_FSM***/
	//Section1
	always@(posedge clk, negedge rstn)	begin
		if(!rstn)	cur_state <= IDLE;
		else if(cnt_500hz == 17'b01100001101001111)
			cur_state <= next_state;
	end

    //Section2
	always @(cur_state)	begin
		case(cur_state)
			IDLE:				begin
									if(flag)	next_state = CLEAR_LCD;
									else		next_state = IDLE;
								end
			CLEAR_LCD:		next_state = SET_DISP_MODE;
			SET_DISP_MODE:	next_state = DISP_ON;
			DISP_ON: 		next_state = SHIFT_DOWN;
			SHIFT_DOWN: 	next_state = CGRAM_ADDR;
			CGRAM_ADDR:		next_state = WRITE_CGRAM;
			WRITE_CGRAM:	begin
									if(cnt_cgram == 4'd7)		next_state = ADDR1;
									else								next_state = WRITE_CGRAM;
								end
			ADDR1:			next_state <= WRITE_DDRAM;
			WRITE_DDRAM:	begin
									if(cnt_char == 6'd15)		next_state = ADDR2;
									else if(cnt_char == 6'd31)	next_state = STOP;
									else								next_state = WRITE_DDRAM;
								end
			ADDR2:			next_state = WRITE_DDRAM;
			STOP:				next_state = STOP;
			default:			next_state = IDLE;
		endcase
	end

	//Section3
	always @(posedge clk, negedge rstn)	begin
		if(!rstn)	begin
			lcd_rs <= 1'b0;
			lcd_data <= 8'b00000000;
		end
		else	begin
			case(cur_state)	
				IDLE:				begin	lcd_rs<=1'b0; lcd_data<=8'b00000000;	end
				CLEAR_LCD:		begin lcd_rs<=1'b0; lcd_data<=8'b00000001;	end
				SET_DISP_MODE:	begin lcd_rs<=1'b0; lcd_data<=8'b00111000;	end
				DISP_ON: 		begin lcd_rs<=1'b0; lcd_data<=8'b00001100;	end
				SHIFT_DOWN: 	begin	lcd_rs<=1'b0; lcd_data<=8'b00000110;	end
				CGRAM_ADDR: 	begin lcd_rs<=1'b0; lcd_data<=8'b01000000;	end
				WRITE_CGRAM:	begin lcd_rs<=1'b1; lcd_data<=char_heart[cnt_cgram];		end
				ADDR1:			begin lcd_rs<=1'b0; lcd_data<=8'b10000000;	end
				WRITE_DDRAM:	begin lcd_rs<=1'b1; lcd_data<=char;				end
				ADDR2:			begin lcd_rs<=1'b0; lcd_data<=8'b11000000;	end
				STOP:				begin lcd_rs<=1'b0; lcd_data<=8'b00111000;	end
				default:			begin	lcd_rs<=1'b0; lcd_data<=8'b00111000;	end
			endcase
		end
	end
  • 综合结果:

  顶层模块的综合结果如下图6所示,仅有一lcd1602模块;


图6 顶层模块综合结果

  lcd1602模块的综合结果如下图7所示,无LATCH;


图7 lcd1602综合结果

  得到的状态转移图如下图8所示,与设计思路相符合;


图8 状态转移图

  SUMMARY的结果如下图9所示。


图9 SUMMARY结果
  • 显示结果:
posted @ 2022-11-30 23:21  Mundane-_-  阅读(219)  评论(0编辑  收藏  举报