在网上找了许久,发现FPGA用串口驱动LCD12864程序很少,基本上没有。刚开始窃喜,中间郁闷,最后还是高兴,为什么这样说呢!头一回在没有参考程序的情况下,完全是照时序图写(自信),中间调试过程遇到一点小插曲(郁闷),后来搞定(高兴),也算是对这段时间学习FPGA的一个能力检测吧。废话少说,赶紧步入正题。

首先来看一下串口模式的几个重要管脚:

1、lcd_cs(PIN4),使能信号,高有效(有的资料上写着低有效,高低我都试过,确认是低有效),定义output。

2、lcd_sid(PIN5),数据传输线,相当于I2C的SBDA数据传输线,可定义双向,这里仅只有写,所以定义output。

3、lcd_scl(PIN6),数据传输的时钟,相当于I2C的SBCL时钟线,定义output,这里注意,很多资料上没说这频率多少合适,而有的资料上写的是高脉冲和低脉冲不能小于800ns或其他数据,一开始本以为这个时钟会比并口时钟会快一些,参考“verilog hdl的那些事儿”中,频率设置100KHZ,他的是ST7566P,我的是ST7920,同一个系列,频率应该会差不多吧,以上条件完全让我把频率设置在100KHZ,那么这个实验注定要失败,我就是栽倒在这,中间调试时,把频率往小降,往大增(就是没想到要那么慢的时钟),结果就是不行,要么出现乱码,要么不显示,后来干脆就把这频率设置成与并口一样的时钟,周期6MS(当然这个频率不是最佳值,到底多少只有自己去试试了),喔、喔,终于正确的显示了,高兴阿。

4、PSB(PIN15),串口模式,可以直接接地,程序中是设置为低,定义output。

管脚都清楚了,那么接下来看时序图,是很重要的一步:在发送数据前,CS要为高,发送数据是先连续发送5个1,用来启动一个周期,此时传输计数被重置,并且串行传输被同步。紧接的两个位指定传输方向(RW,确定读还是写)和传输性质(RS,确定是命令寄存器还是数据寄存器),最后的第八位是一个“0”,一个启动字节发送完毕,那么紧接着发送数据或是指令。一个数据或指令要分为两个字节来处理,先发高4bit,紧接着连续发送4个0,在发送低4bit,又紧接着发送4个0,也就是说完整发送完一个数据或命令,lcd_scl得打24个节拍。由于本实验也是只写不读,所以得避开LCD的忙状态,所以每次发送完一个数据或是命令后,在打一个节拍(25个),本程序中一个节拍的时间(6MS)足够避开LCD的忙状态。这里也要注意,当把所有数据处理完之后,lcd_scl得关闭,也就是拉低,否则,屏会一直刷新,覆盖掉原有的内容,最终全屏成乱码。

OK,时序搞定,那么可以利用状态机完成,代码实现

LCD12864_SPI.v

 module LCD12864_SPI(
//input
sys_clk,
rst_n, //output
lcd_cs,
lcd_sid,
lcd_scl,
lcd_psb
);
input sys_clk;//50MHZ
input rst_n; output lcd_cs; //enable,H active
output lcd_sid; //SPI data
output lcd_scl; //SPI clk
output lcd_psb; ////H:parallel module L:SPI module
/***************************************************/
assign lcd_psb = 'b0;//串口模式
/***************************************************/
parameter T3MS = 'd149_999;
parameter IDLE = 'd0, //准备状态
SEND_1 = 'd1, //连续发送5个1
SNED_RW = 'd2, //是写还是读
SEND_RS = 'd3, //是指令还是数据
SEND_0 = 'd4, //发送一个0,代表启动字节结束
SEND_DATA_H = 'd5, //发送数据的高4bit
SEND_FOUR_0 = 'd6, //连续发送四个0
SEND_DATA_L = 'd7, //发送数据的低4bit
DELAY = 'd8, //延时一个lcd_clk周期,避开LCD的忙状态
STOP = 'd9; //结束
/***************************************************/
////产生周期为6MS的lcd_clk给LCD
reg [:] cnt;
reg lcd_clk;
always @(posedge sys_clk or negedge rst_n)
if(!rst_n) begin
cnt <= 'd0;
lcd_clk <= 'b0;
end
else if(cnt == T3MS)begin
cnt <= 'd0;
lcd_clk <= ~lcd_clk;
end
else
cnt <= cnt + 'b1;
/***************************************************/
assign lcd_scl = en ? lcd_clk : 'b0; //发送完之后,必须得停止,否则屏一直刷新,最后成全屏乱码
/***************************************************/
//在下降沿设置数据或命令
reg lcd_sid;
reg lcd_cs;
reg [:] i;
reg [:] j;
reg [:] num;
reg [:] state;
reg [:] dis_data;
reg flag; //用来标志一个dis_data数据发送完
reg en; //lcd_scl的使能信号
always @(posedge lcd_clk or negedge rst_n)
if(!rst_n) begin
lcd_sid <= 'bz;
lcd_cs <= 'b0;
i <= 'd0;
j <= 'd0;
num <= 'd0;
state <= IDLE;
flag <= 'b0;
en <= 'b1;
end
else
case(state) IDLE:
begin
lcd_cs <= 'b1;
state <= SEND_1;
end SEND_1://发送5个1
begin
i <= i + 'b1;
lcd_sid <= 'b1;
if(i == 'd4) begin
i <= 'd0;
state <= SNED_RW;
end
else
state <= SEND_1;
end SNED_RW:
begin
lcd_sid <= 'b0;//写
state <= SEND_RS;
end SEND_RS:
begin
state <= SEND_0;
if((num <= 'd5) || (num == 7'd18)
|| (num == 'd25) || (num == 7'd34)
|| (num == 'd41) || (num == 7'd42)
|| (num == 'd75))
lcd_sid <= 'b0;//命令
else
lcd_sid <= 'b1;//数据
end SEND_0:
begin
lcd_sid <= 'b0;//一个启动字节结束
state <= SEND_DATA_H;
end SEND_DATA_H: //进入发送高4bit
begin
j <= j + 'b1;
lcd_sid <= dis_data[-j];
if(j == 'd3)
state <= SEND_FOUR_0;
else
state <= SEND_DATA_H;
end SEND_FOUR_0: //进入连续发送四个0
begin
i <= i + 'b1;
lcd_sid <= 'b0;
if(i == 'd3) begin
i <= 'd0;
if(flag) begin
num <= num + 'b1;
flag <= 'b0;
state <= DELAY;
end
else
state <= SEND_DATA_L;
end
else
state <= SEND_FOUR_0;
end SEND_DATA_L: //进入连续发送低4bit
begin
j <= j + 'b1;
lcd_sid <= dis_data[-j];
if(j == 'd7) begin
j <= 'd0;
flag <= 'b1; //标志一个字节发送完
state <= SEND_FOUR_0;
end
else
state <= SEND_DATA_L;
end DELAY: //延时,避开LCD的忙状态
if(num <= 'd77)
state <= SEND_1;
else
state <= STOP; STOP:
begin
lcd_cs <= 'b0;
en <= 'b0;
state <= STOP;
end endcase
/***************************************************/
always @(num)
case(num)
'd0 : dis_data = 8'h30;//功能设定
'd1 : dis_data = 8'h30;//功能设定
'd2 : dis_data = 8'h0c;//显示设定
'd3 : dis_data = 8'h01;//清屏
'd4 : dis_data = 8'h06;//进入设定点
'd5 : dis_data = 8'h81;//设置DDRAM地址
//欢迎访问博客
'd6 : dis_data = 8'hbb;
'd7 : dis_data = 8'hb6;
'd8 : dis_data = 8'hd3;
'd9 : dis_data = 8'had;
'd10 : dis_data = 8'hb7;
'd11 : dis_data = 8'hc3;
'd12 : dis_data = 8'hce;
'd13 : dis_data = 8'hca;
'd14 : dis_data = 8'hb2;
'd15 : dis_data = 8'ha9;
'd16 : dis_data = 8'hbf;
'd17 : dis_data = 8'hcd;
//2line 显示 文少清
'd18 : dis_data = 8'h92;//设置DDRAM地址
'd19 : dis_data = 8'hce;
'd20 : dis_data = 8'hc4;
'd21 : dis_data = 8'hc9;
'd22 : dis_data = 8'hd9;
'd23 : dis_data = 8'hC7;
'd24 : dis_data = 8'he5;
//3line 显示 LCD12864
'd25 : dis_data = 8'h8a;//设置DDRAM命令
'd26 : dis_data = "L";
'd27 : dis_data = "C";
'd28 : dis_data = "D";
'd29 : dis_data = "1";
'd30 : dis_data = "2";
'd31 : dis_data = "8";
'd32 : dis_data = "6";
'd33 : dis_data = "4";
//4Line显示 谢谢!
'd34 : dis_data = 8'h9d;//设置DDRAM地址
'd35 : dis_data = 8'hd0;
'd36 : dis_data = 8'hbb;
'd37 : dis_data = 8'hd0;
'd38 : dis_data = 8'hbb;
'd39 : dis_data = 8'ha3;
'd40 : dis_data = 8'ha1;
//4Line显示喇叭
'd41 : dis_data = 8'h30;//功能设定
'd42 : dis_data = 8'h40;//设定CGRAM字符的位置
'd43 : dis_data = 8'h00;
'd44 : dis_data = 8'h39;
'd45 : dis_data = 8'h00;
'd46 : dis_data = 8'h6a;
'd47 : dis_data = 8'h00;
'd48 : dis_data = 8'ha8;
'd49 : dis_data = 8'h01;
'd50 : dis_data = 8'h29;
'd51 : dis_data = 8'h7e;
'd52 : dis_data = 8'h2a;
'd53 : dis_data = 8'hfc;
'd54 : dis_data = 8'h28;
'd55 : dis_data = 8'hfc;
'd56 : dis_data = 8'h29;
'd57 : dis_data = 8'hcc;
'd58 : dis_data = 8'h2a;
'd59 : dis_data = 8'hcc;
'd60 : dis_data = 8'h28;
'd61 : dis_data = 8'hfc;
'd62 : dis_data = 8'h29;
'd63 : dis_data = 8'hfc;
'd64 : dis_data = 8'h2a;
'd65 : dis_data = 8'h7e;
'd66 : dis_data = 8'h28;
'd67 : dis_data = 8'h01;
'd68 : dis_data = 8'h29;
'd69 : dis_data = 8'h00;
'd70 : dis_data = 8'haa;
'd71 : dis_data = 8'h00;
'd72 : dis_data = 8'h68;
'd73 : dis_data = 8'h00;
'd74 : dis_data = 8'h38;
'd75 : dis_data = 8'h99;//设置DDRAM地址
'd76 : dis_data = 8'h00;//设置自定义显示字符编码 高8bit 是数据不是命令
'd77 : dis_data = 8'h00;//设置自定义显示字符编码 低8bit
default: dis_data = 'h00;
endcase endmodule

显示效果:这次把星星月亮换成一个小喇叭

LCD12864 液晶显示-汉字及自定义显示(串口)的更多相关文章

  1. LCD12864 液晶显示-汉字及自定义显示(并口)

    LCD12864带字库,型号:CM12864-12.其相关数据手册可以在百度中搜索“ST7920 系列中文图形液晶模块使用说明书”,里面有详细的介绍.这里就不在多描述. 其原理简图:(我们只需关心接口 ...

  2. Siteserver-stl:searchOutput(搜索结果)自定义显示样式

    stl:searchOutput 自定义显示样式 自定义搜索提交表单需要在<stl:searchOutput>中嵌入显示搜索结果的标签,必须包含的标签 有<stl:pageConte ...

  3. TreeView 自定义显示checkbox

    本项目需要对TreeView进行定制,要求比较简单,主要要求如下: Winform中TreeView控件默认只支持所有级别的CheckBox显示或者不显示,不能控制制定Level的树节点显示 效果如下 ...

  4. SharePoint 2013 关于自定义显示列表表单的bug

    1.在SharePoint 2013中,我们隐藏列表Dispform页面的ListFormWebPart部件,转而使用自定义显示列表表单进行展示,因为这样更容易定制我们需要的显示: 2.之后发现文件夹 ...

  5. Protege汉字不能正常显示问题

    在Protege5.0中有下面的问题: 点击uses,汉字不能正常显示. 在qq群里面问到,可以通过设置label的方式,在对类,子类命名成英语的,点击annotations,在label中设置汉字名 ...

  6. LR脚本自定义显示Controller虚拟用户状态

    在场景监控的过程中,想知道场景运行时Vusers的运行状态以及每一个Vuser虚拟用户在本次场景运行的过程共迭代了多少次,那么就需要在VuGen脚本中自定义显示虚拟用户状态信息. 代码如下: stat ...

  7. ToastCustom【自定义显示风格的Toast】

    版权声明:本文为HaiyuKing原创文章,转载请注明出处! 前言 基于系统Toast的自定义显示风格的Toast. 效果图 代码分析 ToastCustom类基于系统Toast,不是继承Toast, ...

  8. Myeclipse和 eclipse中的控制台汉字横着显示修改

    Myeclipse和 eclipse中的控制台汉字横着显示问题的修改 如图: 同一种字体有两种显示方式,比如微软雅黑和@微软雅黑,前一种汉字是竖着显示,后一种汉字是横着显示. 修改方法: prefer ...

  9. piwik获取访客头像,自定义显示访问者头像(URL)和描述(标题和替代)

    访客头像 自定义显示访问者头像(URL)和描述(标题和替代) 链接地址:https://plugins.matomo.org/VisitorAvatar#description

随机推荐

  1. Storm官方文档翻译之在生产环境集群中运行Topology

    在进群生产环境下运行Topology和在本地模式下运行非常相似.下面是步骤: 1.定义Topology(如果使用Java开发语言,则使用TopologyBuilder来创建) 2.使用StormSub ...

  2. Java 中的四种引用及垃圾回收策略

    Java 中有四种引用:强引用.软引用.弱引用.虚引用: 其主要区别在于垃圾回收时是否进行回收: 1.强引用 使用最普遍的引用.如果一个对象具有强引用,那就 类似于必不可少的生活用品,垃圾回收器绝不会 ...

  3. MySql 加锁问题

    1.设置非自动提交 set autocommit=0;  这时候 for update才会起作用 2.一般用法 set autocommit=0;  for update(加锁)  ;  commit ...

  4. Asp:Cookies应用指南

    实际上,在web开发中,cookie仅仅是一个文本文件,当用户访问站点时,它就被存储在用户使用的计算机上,其中,保存了 一些信息,当用户日后再次访问这个站点时,web可以将这些信息提取出来.    尽 ...

  5. JavaScript 常用功能实现一览(一)

    摘自于网络:http://www.cnblogs.com/joinger/articles/1506482.html 适合阅读范围:对JavaScript一无所知-离精通只差一步之遥的人基础知识:HT ...

  6. WPF子窗体:ChildWindow

    wpf的子窗体选择有很多种,如最常见的是项目新建窗体(Window)作为子窗体 ,或者新建wpf用户控件(UserControl).而其实利用Xceed.Wpf.Toolkit.dll 可以轻松布局如 ...

  7. 【0-1 背包模板】 poj 3624

    先看个未经优化的二维空间dp: #include <iostream> #include <cstdio> #include <cmath> #include &l ...

  8. linux的学习系列 4---文件权限和访问模式

    为了更加安全的存储文件,Linux为不同的文件赋予了不同的权限,每个文件都拥有下面三种权限: 所有者权限:文件所有者能够进行的操作 组权限:文件所属用户组能够进行的操作 外部权限(其他权限):其他用户 ...

  9. 常用的JS页面跳转代码调用大全

    一.常规的JS页面跳转代码 1.在原来的窗体中直接跳转用 <script type="text/javascript"> window.location.href=&q ...

  10. jz2440 环境搭建遇到的问题

    已解决: