当前位置: 首页 > news >正文

基于FPGA的LCD1602驱动(含代码)

目录

 LCD1602显示原理

LCD1602接口

LCD1602操作时序

(1)读操作时序

(2)写操作时序

 LCD1602初始化

LCD1602读写数据 


 LCD1602显示原理

将LCD显示屏与FPGA连接之后,需要做的第一件事就是进行LCD驱动(也就是LCD初始化),之后往LCD里写一些字符,调试LCD是否可以正常使用

这里用的是LCD1602如下图:一共2行,一行16个显示块,其地址和屏幕的对应关系如下:

 如果想在屏幕左上角显示字符‘A’,那么就把字符‘A’的字符代码41H写入DDRAM的00H地址处即可

但如果要显示CGROM中没有的字符,比如摄氏温标的符号,那么就只有先在CGRAM中定义,然后再在DDRAM中写入这个自定义字符的字符代码即可。具体参考这篇:基于FPGA的LCD1602显示屏驱动_panhongfeng111的博客-CSDN博客_基于fpga的lcd显示

LCD1602接口

 对这里面比较重要的几个接口进行说明:

(1)RS 命令/数据选择引脚当RS为低电平时,选择命令;当RS为高电平时,选择数据。

(2)RW 读/写选择引脚,当RW为低电平时,向LCD1602写入命令或数据;当RW为高电平时,从LCD1602读取状态或数据。如果不需要进行读取操作,可以直接将其接VSS。

(3) 执行命令的使能引脚。

(4)D0—D7 并行数据输入/输出引脚

LCD1602操作时序

(1)读操作时序

读状态:输入RS=0,RW=1,E=高脉冲。输出:D0—D7为状态字。

读数据:输入RS=1,RW=1,E=高脉冲。输出:D0—D7为数据。

(2)写操作时序

 写命令:输入RS=0,RW=0,E=高脉冲。输出:无。

 写数据:输入RS=1,RW=0,E=高脉冲。输出:无。
 

 LCD1602初始化

根据数据手册,LCD的初始化需要完成下面12步:

1   延时15ms
2   写指令38H(不检测忙信号)
3   延时5ms
4   写指令38H(不检测忙信号)
5   延时5ms
6   写指令38H(不检测忙信号)
7   以后每次写指令、读/写数据操作均需要检测忙信号
8   写指令38H:显示模式设置
9   写指令08H:显示关闭
10  写指令01H:显示清屏
11  写指令06H:显示光标移动设置
12  写指令0CH:显示开及光标设置

 这里面有1次15ms延时,和2次5ms延时,写指令是38H,我们可以把1~8步合在一起,延时25ms,写指令38H,那么初始化就可以简化为5步:

LCD1602读写数据 

初始化完成之后一般往LCD里写入一些字符串,验证一下是否可以正常显示

写的时候,要先指定地址,如果在第一行写入,首地址是00H,再加上DB7的1,即80H

如果在第二行写入,首地址是00H,再加上DB7的1,即C0H

因此在初始化完成之后,加入addr1 write1 addr2 write2 四个状态

把写数据和初始化放在一起,完整状态机如下:

module lcd(
  input				clk			,
	input				rst	,
	input      delay_en ,    //延时完成
	output	reg			lcd_rs		,//状态or数据选择
	output	reg		lcd_rw		,//读or写选择
	output	reg			lcd_en		,//使能信号
	output	reg	[7:0]	lcd_data //输出LCD指令
    );
    
    
    reg	[7:0]	data_display	;//显示数据
    
    reg [5:0] data_cnt; //数据计数器
    
    reg [3:0] state; //状态
    
    parameter IDLE =4'd0;
    parameter S0   =4'd1;
    parameter S1   =4'd2;
    parameter S2   =4'd3;
    parameter S3   =4'd4;
    parameter S4   =4'd5;
    parameter Addr1=4'd6;
    parameter WR1  =4'd7;
    parameter Addr2=4'd8;
    parameter WR2  =4'd9;
    parameter stop =4'd10;
    
  always @(*) begin//根据数据计数器输出显示数据
		case(data_cnt)
			5'd0: data_display   = "H";
			5'd1: data_display   = "E";
			5'd2: data_display   = "L";
			5'd3: data_display   = "L";
			5'd4: data_display   = "O";
			5'd5: data_display   = "W";
			5'd6: data_display   = "-";
			5'd7: data_display   = "W";
			5'd8: data_display   = "O";
			5'd9: data_display   = "R";
			5'd10: data_display  = "L";
			5'd11: data_display  = "D";
			5'd12: data_display  = "1";
			5'd13: data_display  = "6";
			5'd14: data_display  = "0";
			5'd15: data_display  = "2";
			5'd16: data_display  = "h";
			5'd17: data_display  = "e";
			5'd18: data_display  = "l";
			5'd19: data_display  = "l";
			5'd20: data_display  = "o";
			5'd21: data_display  = "w";
			5'd22: data_display  = "h";
			5'd23: data_display  = "e";
			5'd24: data_display  = "l";
			5'd26: data_display  = "l";
			5'd27: data_display  = "o";
			5'd28: data_display  = "w";
			5'd29: data_display  = "-";
			5'd30: data_display  = "-";
			5'd31: data_display  = "-";

			default:data_display = "-";
		endcase
	end
  
  always@(posedge clk)begin
  	if(rst)begin
  		lcd_rs  <=1'd0;
      lcd_rw  <=1'd0;
      lcd_en  <=1'd0;
      lcd_data<=8'd0;
      data_cnt<=6'd0;
      state   <=IDLE;
  	end
  	else begin
  		case(state)
  			IDLE :begin
  				if(delay_en)begin
  					state   <=S0;
  				end
  				else begin
  					state   <=IDLE;
  				end
  			end
        S0 :begin
  				lcd_rs  <=1'd0;
          lcd_rw  <=1'd0;
          lcd_en  <=1'd1;
          lcd_data<=8'h38;
          state   <=S1;
  			end  
        S1  :begin
  				lcd_rs  <=1'd0;
          lcd_rw  <=1'd0;
          lcd_en  <=1'd1;
          lcd_data<=8'h08;
          state   <=S2;
  			end 
        S2  :begin
  				lcd_rs  <=1'd0;
          lcd_rw  <=1'd0;
          lcd_en  <=1'd1;
          lcd_data<=8'h01;
          state   <=S3;
  			end 
        S3  :begin
  				lcd_rs  <=1'd0;
          lcd_rw  <=1'd0;
          lcd_en  <=1'd1;
          lcd_data<=8'h06;
          state   <=S4;
  			end 
        S4 :begin
  				lcd_rs  <=1'd0;
          lcd_rw  <=1'd0;
          lcd_en  <=1'd1;
          lcd_data<=8'h0C;
          state   <=Addr1;
  			end
        Addr1:begin
  				lcd_rs  <=1'd0;
          lcd_rw  <=1'd0;
          lcd_en  <=1'd1;
          lcd_data<=8'h80;//第一行地址
          state   <=WR1;
  			end
        WR1 :begin
  				lcd_rs  <=1'd1;
          lcd_rw  <=1'd0;
          lcd_en  <=1'd1;
          
          if(data_cnt==6'd15)begin//第一行写完
          	state   <=Addr2;
          	data_cnt<=6'd0;
          end
          else begin
          	data_cnt<=data_cnt+6'd1;
          	state   <=WR1;
          	lcd_data<=data_display;//显示第一行数据
          end
  			end 
        Addr2:begin
  				lcd_rs  <=1'd0;
          lcd_rw  <=1'd0;
          lcd_en  <=1'd1;
          lcd_data<=8'hC0;//第二行地址
          state   <=WR2;
  			end
        WR2 :begin
  				lcd_rs  <=1'd1;
          lcd_rw  <=1'd0;
          lcd_en  <=1'd1;
         
          if(data_cnt==6'd15)begin//第二行写完
          	state   <=stop;
          	data_cnt<=6'd0;
          end
          else begin
          	data_cnt<=data_cnt+6'd1;
          	lcd_data<=data_display;//显示第二行数据
          	state   <=WR2;
          end
  			end 
        stop :begin
  				lcd_rs  <=1'd0;
          lcd_rw  <=1'd0;
          lcd_en  <=1'd0;
          lcd_data<=8'h38;
          state   <=IDLE;
  			end

  		endcase
  	end
  end
    
endmodule

仿真结果如下:

 

相关文章:

  • 高并发场景下,6种方案,保证缓存和数据库的最终一致性!
  • Elasticsearch HTTP查询
  • ArkID开源IDaaS系统插件OAuth2轻松实现单点登录安心做应用服务集成
  • 判断一个数是否是质数
  • 诊断Android系统原生代码Native崩溃问题
  • React中实现一键复制——五种办法
  • byName自动装配和byType自动装配
  • 【黑马Java笔记汇总】JavaSE+JavaWeb+SSM+Springboot笔记汇总
  • DRF 用户认证
  • 系统架构演变历史及集群、分布式、微服务、SOA的概念区别
  • 四、RocketMq本地集群搭建
  • 金仓数据库 KingbaseES 插件参考手册 xml2
  • FITC-PEG-SH/Fluorescent-PEG-SH 多种分子量可选/荧光素聚乙二醇巯基 FITC-PEG-SH
  • 常用hooks用法总结
  • 赛默飞世尔Thermo Fisher仪器电路板维修故障概述
  • [PHP内核探索]PHP中的哈希表
  • 【399天】跃迁之路——程序员高效学习方法论探索系列(实验阶段156-2018.03.11)...
  • 4. 路由到控制器 - Laravel从零开始教程
  • C++类中的特殊成员函数
  • CEF与代理
  • Iterator 和 for...of 循环
  • javascript 哈希表
  • MySQL主从复制读写分离及奇怪的问题
  • Spring Cloud Alibaba迁移指南(一):一行代码从 Hystrix 迁移到 Sentinel
  • springMvc学习笔记(2)
  • ubuntu 下nginx安装 并支持https协议
  • UEditor初始化失败(实例已存在,但视图未渲染出来,单页化)
  • 程序员该如何有效的找工作?
  • 从零开始的无人驾驶 1
  • 大型网站性能监测、分析与优化常见问题QA
  • 大整数乘法-表格法
  • 构建二叉树进行数值数组的去重及优化
  • 基于Javascript, Springboot的管理系统报表查询页面代码设计
  • 新书推荐|Windows黑客编程技术详解
  • 在Docker Swarm上部署Apache Storm:第1部分
  • 正则表达式-基础知识Review
  • ​configparser --- 配置文件解析器​
  • ​Java并发新构件之Exchanger
  • !!Dom4j 学习笔记
  • # MySQL server 层和存储引擎层是怎么交互数据的?
  • #宝哥教你#查看jquery绑定的事件函数
  • #周末课堂# 【Linux + JVM + Mysql高级性能优化班】(火热报名中~~~)
  • $.extend({},旧的,新的);合并对象,后面的覆盖前面的
  • (9)STL算法之逆转旋转
  • (C语言版)链表(三)——实现双向链表创建、删除、插入、释放内存等简单操作...
  • (html转换)StringEscapeUtils类的转义与反转义方法
  • (java版)排序算法----【冒泡,选择,插入,希尔,快速排序,归并排序,基数排序】超详细~~
  • (Redis使用系列) Springboot 实现Redis消息的订阅与分布 四
  • (二)丶RabbitMQ的六大核心
  • (附源码)ssm基于微信小程序的疫苗管理系统 毕业设计 092354
  • (每日持续更新)jdk api之FileFilter基础、应用、实战
  • (学习日记)2024.04.10:UCOSIII第三十八节:事件实验
  • (转)用.Net的File控件上传文件的解决方案
  • ***详解账号泄露:全球约1亿用户已泄露
  • .locked1、locked勒索病毒解密方法|勒索病毒解决|勒索病毒恢复|数据库修复