• LCD12864 液晶显示-汉字及自定义显示(串口)


    在网上找了许久,发现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

      1 module LCD12864_SPI(
      2                         //input
      3                         sys_clk,
      4                         rst_n,
      5                         
      6                         //output
      7                         lcd_cs,
      8                         lcd_sid,
      9                         lcd_scl,
     10                         lcd_psb
     11                     );
     12 input sys_clk;//50MHZ
     13 input rst_n;
     14 
     15 output lcd_cs;  //enable,H active
     16 output lcd_sid; //SPI data
     17 output lcd_scl; //SPI clk
     18 output lcd_psb;    ////H:parallel module   L:SPI module
     19 /***************************************************/
     20 assign lcd_psb = 1'b0;//串口模式
     21 /***************************************************/
     22 parameter   T3MS         = 18'd149_999;
     23 parameter   IDLE        = 4'd0,  //准备状态
     24             SEND_1      = 4'd1,     //连续发送5个1
     25             SNED_RW     = 4'd2,  //是写还是读
     26             SEND_RS     = 4'd3,  //是指令还是数据
     27             SEND_0      = 4'd4,  //发送一个0,代表启动字节结束
     28             SEND_DATA_H = 4'd5,  //发送数据的高4bit
     29             SEND_FOUR_0 = 4'd6,     //连续发送四个0
     30             SEND_DATA_L = 4'd7,     //发送数据的低4bit
     31             DELAY       = 4'd8,  //延时一个lcd_clk周期,避开LCD的忙状态
     32             STOP        = 4'd9;  //结束
     33 /***************************************************/
     34 ////产生周期为6MS的lcd_clk给LCD
     35 reg [17:0] cnt;
     36 reg lcd_clk;
     37 always @(posedge sys_clk or negedge rst_n)
     38 if(!rst_n) begin
     39     cnt <= 18'd0;
     40     lcd_clk <= 1'b0;
     41 end
     42 else if(cnt == T3MS)begin
     43     cnt <= 18'd0;
     44     lcd_clk <= ~lcd_clk;
     45 end
     46 else
     47     cnt <= cnt + 1'b1;
     48 /***************************************************/
     49 assign lcd_scl = en ? lcd_clk : 1'b0; //发送完之后,必须得停止,否则屏一直刷新,最后成全屏乱码
     50 /***************************************************/
     51 //在下降沿设置数据或命令
     52 reg lcd_sid;
     53 reg lcd_cs;
     54 reg [2:0] i;
     55 reg [2:0] j;
     56 reg [6:0] num;
     57 reg [3:0] state; 
     58 reg [7:0] dis_data;
     59 reg flag;  //用来标志一个dis_data数据发送完
     60 reg en;  //lcd_scl的使能信号
     61 always @(posedge lcd_clk or negedge rst_n)
     62 if(!rst_n) begin
     63     lcd_sid <= 1'bz;
     64     lcd_cs <= 1'b0;
     65     i <= 3'd0;
     66     j <= 3'd0;
     67     num <= 7'd0;
     68     state <= IDLE;
     69     flag <= 1'b0;
     70     en <= 1'b1;
     71 end
     72 else
     73     case(state)
     74     
     75     IDLE:
     76     begin
     77         lcd_cs <= 1'b1;
     78         state <= SEND_1;
     79     end
     80     
     81     SEND_1://发送5个1
     82     begin
     83         i <= i + 1'b1;
     84         lcd_sid <= 1'b1;
     85         if(i == 3'd4) begin
     86             i <= 3'd0;
     87             state <= SNED_RW;
     88         end
     89         else
     90             state <= SEND_1;
     91     end
     92         
     93     SNED_RW:
     94     begin 
     95         lcd_sid <= 1'b0;//写
     96         state <= SEND_RS;
     97     end
     98     
     99     SEND_RS:
    100     begin
    101         state <= SEND_0;
    102         if((num <= 7'd5)  || (num == 7'd18)
    103         || (num == 7'd25) || (num == 7'd34)
    104         || (num == 7'd41) || (num == 7'd42)
    105         || (num == 7'd75))
    106             lcd_sid <= 1'b0;//命令
    107         else
    108             lcd_sid <= 1'b1;//数据
    109     end
    110     
    111     SEND_0:
    112     begin
    113         lcd_sid <= 1'b0;//一个启动字节结束
    114         state <= SEND_DATA_H;
    115     end
    116     
    117     SEND_DATA_H: //进入发送高4bit
    118     begin
    119         j <= j + 1'b1;
    120         lcd_sid <= dis_data[7-j];
    121         if(j == 3'd3)
    122             state <= SEND_FOUR_0;
    123         else
    124             state <= SEND_DATA_H;
    125     end
    126     
    127     SEND_FOUR_0: //进入连续发送四个0
    128     begin
    129         i <= i + 1'b1;
    130         lcd_sid <= 1'b0;
    131         if(i == 3'd3) begin
    132             i <= 3'd0;
    133             if(flag) begin
    134                 num <= num + 1'b1;
    135                 flag <= 1'b0;
    136                 state <= DELAY;
    137             end
    138             else
    139                 state <= SEND_DATA_L;
    140         end
    141         else
    142             state <= SEND_FOUR_0;
    143     end
    144     
    145     SEND_DATA_L: //进入连续发送低4bit
    146     begin
    147         j <= j + 1'b1;
    148         lcd_sid <= dis_data[7-j];
    149         if(j == 3'd7) begin
    150             j <= 3'd0;
    151             flag <= 1'b1;  //标志一个字节发送完
    152             state <= SEND_FOUR_0;
    153         end
    154         else
    155             state <= SEND_DATA_L;
    156     end
    157 
    158     DELAY:   //延时,避开LCD的忙状态
    159     if(num <= 7'd77) 
    160         state <= SEND_1;
    161     else 
    162         state <= STOP;
    163         
    164     STOP: 
    165     begin
    166         lcd_cs <= 1'b0;
    167         en <= 1'b0;
    168         state <= STOP;
    169     end 
    170 
    171     endcase
    172 /***************************************************/
    173 always @(num)
    174     case(num)
    175         7'd0   :    dis_data = 8'h30;//功能设定
    176         7'd1   :    dis_data = 8'h30;//功能设定
    177         7'd2   :    dis_data = 8'h0c;//显示设定
    178         7'd3   :    dis_data = 8'h01;//清屏
    179         7'd4   :    dis_data = 8'h06;//进入设定点
    180         7'd5   :    dis_data = 8'h81;//设置DDRAM地址
    181         //欢迎访问博客
    182         7'd6   :    dis_data = 8'hbb; 
    183         7'd7   :    dis_data = 8'hb6; 
    184         7'd8   :    dis_data = 8'hd3; 
    185         7'd9   :    dis_data = 8'had; 
    186         7'd10  :    dis_data = 8'hb7; 
    187         7'd11  :    dis_data = 8'hc3; 
    188         7'd12  :    dis_data = 8'hce; 
    189         7'd13  :    dis_data = 8'hca; 
    190         7'd14  :    dis_data = 8'hb2; 
    191         7'd15  :    dis_data = 8'ha9; 
    192         7'd16  :    dis_data = 8'hbf; 
    193         7'd17  :    dis_data = 8'hcd; 
    194         //2line 显示 文少清
    195         7'd18  :    dis_data = 8'h92;//设置DDRAM地址
    196         7'd19  :    dis_data = 8'hce; 
    197         7'd20  :    dis_data = 8'hc4; 
    198         7'd21  :    dis_data = 8'hc9; 
    199         7'd22  :    dis_data = 8'hd9; 
    200         7'd23  :    dis_data = 8'hC7; 
    201         7'd24  :    dis_data = 8'he5; 
    202         //3line 显示 LCD12864   
    203         7'd25  :    dis_data = 8'h8a;//设置DDRAM命令
    204         7'd26  :    dis_data =  "L";  
    205         7'd27  :    dis_data =  "C";  
    206         7'd28  :    dis_data =  "D";  
    207         7'd29  :    dis_data =  "1";  
    208         7'd30  :    dis_data =  "2";  
    209         7'd31  :    dis_data =  "8";  
    210         7'd32  :    dis_data =  "6";  
    211         7'd33  :    dis_data =  "4";  
    212         //4Line显示 谢谢! 
    213         7'd34  :    dis_data = 8'h9d;//设置DDRAM地址
    214         7'd35  :    dis_data = 8'hd0; 
    215         7'd36  :    dis_data = 8'hbb; 
    216         7'd37  :    dis_data = 8'hd0; 
    217         7'd38  :    dis_data = 8'hbb; 
    218         7'd39  :    dis_data = 8'ha3; 
    219         7'd40  :    dis_data = 8'ha1; 
    220         //4Line显示喇叭
    221         7'd41  :    dis_data = 8'h30;//功能设定
    222         7'd42  :    dis_data = 8'h40;//设定CGRAM字符的位置
    223         7'd43  :    dis_data = 8'h00; 
    224         7'd44  :    dis_data = 8'h39; 
    225         7'd45  :    dis_data = 8'h00; 
    226         7'd46  :    dis_data = 8'h6a; 
    227         7'd47  :    dis_data = 8'h00; 
    228         7'd48  :    dis_data = 8'ha8; 
    229         7'd49  :    dis_data = 8'h01; 
    230         7'd50  :    dis_data = 8'h29; 
    231         7'd51  :    dis_data = 8'h7e; 
    232         7'd52  :    dis_data = 8'h2a; 
    233         7'd53  :    dis_data = 8'hfc; 
    234         7'd54  :    dis_data = 8'h28; 
    235         7'd55  :    dis_data = 8'hfc; 
    236         7'd56  :    dis_data = 8'h29;     
    237         7'd57  :    dis_data = 8'hcc; 
    238         7'd58  :    dis_data = 8'h2a; 
    239         7'd59  :    dis_data = 8'hcc; 
    240         7'd60  :    dis_data = 8'h28; 
    241         7'd61  :    dis_data = 8'hfc; 
    242         7'd62  :    dis_data = 8'h29; 
    243         7'd63  :    dis_data = 8'hfc; 
    244         7'd64  :    dis_data = 8'h2a; 
    245         7'd65  :    dis_data = 8'h7e; 
    246         7'd66  :    dis_data = 8'h28; 
    247         7'd67  :    dis_data = 8'h01; 
    248         7'd68  :    dis_data = 8'h29;         
    249         7'd69  :    dis_data = 8'h00; 
    250         7'd70  :    dis_data = 8'haa; 
    251         7'd71  :    dis_data = 8'h00; 
    252         7'd72  :    dis_data = 8'h68; 
    253         7'd73  :    dis_data = 8'h00; 
    254         7'd74  :    dis_data = 8'h38;         
    255         7'd75  :    dis_data = 8'h99;//设置DDRAM地址
    256         7'd76  :    dis_data = 8'h00;//设置自定义显示字符编码 高8bit 是数据不是命令
    257         7'd77  :    dis_data = 8'h00;//设置自定义显示字符编码 低8bit 
    258         default:    dis_data = 8'h00;
    259     endcase 
    260 
    261 endmodule
    View Code

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

  • 相关阅读:
    Tiny_4412的NFS挂载
    tiny4412学习一:编译uboot,体验裸机
    开通博客,记录历程,开启新的征程
    mysql 多表联合做运算(求俩点的距离)
    golang gin框架使用图形验证码
    js rgb和16进制相互转换
    [转载] Centos7的安装、Docker1.12.3的安装,以及Docker Swarm集群的简单实例
    openstack golang sdk使用
    sendcloud golang 发送短信 示例代码
    Harbor配置https,并安装内容信任插件(notary)
  • 原文地址:https://www.cnblogs.com/wen2376/p/3318071.html
Copyright © 2020-2023  润新知