FPGA学习记录_ LCD字符图片显示_正点原子领航者开发板

前言

        今天学习正点原子领航者开发板LCD字符图片显示模块,以下是记录的笔记和重写的代码。


1:LCD字符图片显示

        char[y] [x] :代表第y行,第x列的像素点,可以通过工具来将图片和文字转化成矩阵数组。

        reg [15:0] char [15:0] :创建了一个16行x16列的数组。


2: 看波形——写代码

代码分析:

        1:像素点相对于字符区域起始点水平坐标:

        这里x_cnt和y_cnt的设置不是唯一的,是与字符的寄存器行列相关的,所以下面寄存器变了,他也会改变。

assign  x_cnt = pixel_xpos + 1'b1  - CHAR_X_START; //像素点相对于字符区域起始点水平坐标
assign  y_cnt = pixel_ypos - CHAR_Y_START; //像素点相对于字符区域起始点垂直坐标
assign  rom_rd_en = 1'b1;                  //读使能拉高,即一直读ROM数据

        2:为LCD不同显示区域绘制图片、字符和背景色:这段代码非常重要,既显示图片,又显示字符。

        图片:首先分析x轴的像素点pixel_xpos(行像素点)图片是在10~109的范围内,pixel_xpos对应110的位置不能赋值,根据时序图中的rom_data和pixel_data就可以看出来,要输出的pixel_data比rom_data要晚一个周期,所以pixel_data整体上对应行像素点pixel_xpos的位置晚一个周期(应该把D1的值赋给pixel_xpos的10),所以这里的x起始位必须减一,即早一个周期。其次是y的像素点pixel_xpos(场像素点)图片是在10~109的范围内,但是他的周期持续非常长时间,所以保持不变就可以了。

        字符:x起始位必须减一的原因同上,具体看时序图中的pixel_data和char两行。不一样的是这里使用的是寄存器,不是rom,所以逐个分析char[y_cnt][CHAR_WIDTH -1'b1 - x_cnt]里的内容。先看纵坐标y的范围是(0~31),而y_cnt = pixel_ypos - CHAR_Y_START中,字符里pixel_ypos的为(120~151),CHAR_Y_START为120,所以他符合行的范围。其次,看横坐标x的范围pixel_xpos是(10~137),[CHAR_WIDTH -1'b1 - x_cnt]中x_cnt = pixel_xpos + 1'b1  - CHAR_X_START,将x_cnt代入,即可得到CHAR_WIDTH-pixel_xpos+CHAR_X_START-2,CHAR_WIDTH为128,CHAR_X_START为10,所以这里得到[CHAR_WIDTH -1'b1 - x_cnt]的范围是(126~-1),符合时序图char信号的内容。因为char信号必须比pixel_xpos信号要早一个周期,因为这里用的是always时序赋值,会晚一个周期。而纵坐标y,行持续时间足够长不需要减一,具体时序图char信号的内容。

always @(posedge lcd_pclk or negedge rst_n) begin
    if (!rst_n)
        pixel_data <= BACK_COLOR;
    else if( (pixel_xpos >= PIC_X_START - 1'b1) && (pixel_xpos < PIC_X_START + PIC_WIDTH - 1'b1) 
          && (pixel_ypos >= PIC_Y_START) && (pixel_ypos < PIC_Y_START + PIC_HEIGHT) )
        pixel_data <= rom_rd_data ;  //显示图片
    else if((pixel_xpos >= CHAR_X_START - 1'b1) && (pixel_xpos < CHAR_X_START + CHAR_WIDTH - 1'b1)
         && (pixel_ypos >= CHAR_Y_START) && (pixel_ypos < CHAR_Y_START + CHAR_HEIGHT)) begin
        if(char[y_cnt][CHAR_WIDTH -1'b1 - x_cnt])
            pixel_data <= CHAR_COLOR;    //显示字符
        else
            pixel_data <= BACK_COLOR;    //显示字符区域的背景色
    end
    else
        pixel_data <= BACK_COLOR;        //屏幕背景色
end

        3:根据当前扫描点的横纵坐标为ROM地址赋值

        因为行持续时间很长,所以这里pixel_ypos不用进行减一的操作。而pixel_xpos的时间要减2则是因为always赋值语句会晚一个时钟周期为其赋值,所以得提前一个周期,所以减去1。其次是因为时序图中,rom——rom_data晚一个周期,所以也得提前一个周期,也就是rom为1在时序图中对应pixel_xpos的是9而非10,如果是对应pixel_xpos10就不用减这个1了。

always @(posedge lcd_pclk or negedge rst_n) begin
    if(!rst_n)
        rom_addr <= 14'd0;
    //当横纵坐标位于图片显示区域时,累加ROM地址    
    else if((pixel_ypos >= PIC_Y_START) && (pixel_ypos < PIC_Y_START + PIC_HEIGHT) 
        && (pixel_xpos >= PIC_X_START - 2'd2) && (pixel_xpos < PIC_X_START + PIC_WIDTH - 2'd2)) 
        rom_addr <= rom_addr + 1'b1;
    //当横纵坐标位于图片区域最后一个像素点时,ROM地址清零    
    else if((pixel_ypos >= PIC_Y_START + PIC_HEIGHT))
        rom_addr <= 14'd0;
end
module lcd_display(
    input             lcd_pclk,     //时钟
    input             sys_rst_n,        //复位,低电平有效
                                    
    input      [10:0] pixel_xpos,   //像素点横坐标
    input      [10:0] pixel_ypos,   //像素点纵坐标    
    output reg [23:0] pixel_data    //像素点数据,
);                                   
                                     
//parameter define                   
localparam PIC_X_START = 11'd10;     //图片起始点横坐标
localparam PIC_Y_START = 11'd10;     //图片起始点纵坐标
localparam PIC_WIDTH   = 11'd100;    //图片宽度
localparam PIC_HEIGHT  = 11'd100;    //图片高度
                       
localparam CHAR_X_START= 11'd10;     //字符起始点横坐标
localparam CHAR_Y_START= 11'd120;    //字符起始点纵坐标
localparam CHAR_WIDTH  = 11'd128;    //字符宽度,4个字符:32*4
localparam CHAR_HEIGHT = 11'd32;     //字符高度
                       
localparam BACK_COLOR  = 24'hE0FFFF; //背景色,浅蓝色
localparam CHAR_COLOR  = 24'hff0000; //字符颜色,红色

//reg define
reg   [127:0] char[31:0];  //字符数组
reg   [13:0]  rom_addr  ;  //ROM地址

//wire define   
wire  [10:0]  x_cnt;       //横坐标计数器
wire  [10:0]  y_cnt;       //纵坐标计数器
wire          rom_rd_en ;  //ROM读使能信号
wire  [23:0]  rom_rd_data ;//ROM数据

assign  x_cnt = pixel_xpos + 1'b1  - CHAR_X_START; //像素点相对于字符区域起始点水平坐标
assign  y_cnt = pixel_ypos - CHAR_Y_START; //像素点相对于字符区域起始点垂直坐标
assign  rom_rd_en = 1'b1;                  //读使能拉高,即一直读ROM数据

always @(posedge lcd_pclk) begin
    char[0 ]  <= 128'h00000000000000000000000000000000;
    char[1 ]  <= 128'h00000000000000000000000000000000;
    char[2 ]  <= 128'h00000000000100000000002000000000;
    char[3 ]  <= 128'h000000100001800002000070000000C0;
    char[4 ]  <= 128'h000000380001800003FFFFF803FFFFE0;
    char[5 ]  <= 128'h07FFFFFC0001800003006000000001E0;
    char[6 ]  <= 128'h0000C000000180600300600000000300;
    char[7 ]  <= 128'h0000C0000001FFF00300C00000000600;
    char[8 ]  <= 128'h0000C000000180000310804000001800;
    char[9 ]  <= 128'h0000C00000018000031FFFE000003000;
    char[10]  <= 128'h0000C00000018000031800400001C000;
    char[11]  <= 128'h0000C00000018000031800400001C000;
    char[12]  <= 128'h00C0C000018181800318004000018000;
    char[13]  <= 128'h00C0C00001FFFFC0031FFFC000018010;
    char[14]  <= 128'h00C0C060018001800318004000018038;
    char[15]  <= 128'h00C0FFF001800180031800403FFFFFFC;
    char[16]  <= 128'h00C0C000018001800318004000018000;
    char[17]  <= 128'h00C0C000018001800218004000018000;
    char[18]  <= 128'h00C0C00001800180021FFFC000018000;
    char[19]  <= 128'h00C0C000018001800210304000018000;
    char[20]  <= 128'h00C0C00001FFFF800200300000018000;
    char[21]  <= 128'h00C0C000018001800606300000018000;
    char[22]  <= 128'h00C0C000018001000607370000018000;
    char[23]  <= 128'h00C0C00000000000060E31C000018000;
    char[24]  <= 128'h00C0C000001000400418307000018000;
    char[25]  <= 128'h00C0C000020830600430303800018000;
    char[26]  <= 128'h00C0C010020C18300860301800018000;
    char[27]  <= 128'h00C0C038060E18180883700800018000;
    char[28]  <= 128'h3FFFFFFC0C0618181100F008003F8000;
    char[29]  <= 128'h000000001C0408182000600000070000;
    char[30]  <= 128'h00000000000000000000000000020000;
    char[31]  <= 128'h00000000000000000000000000000000;
end

//为LCD不同显示区域绘制图片、字符和背景色
always @(posedge lcd_pclk or negedge sys_rst_n) begin
    if(!sys_rst_n)
        pixel_data <= BACK_COLOR;
    else if((pixel_xpos >= PIC_X_START - 1'b1) && (pixel_xpos < PIC_X_START + PIC_WIDTH - 1'b1)
            && (pixel_ypos >= PIC_Y_START) && (pixel_ypos < PIC_Y_START + PIC_HEIGHT))
        pixel_data <= rom_rd_data;   //图片
    else if((pixel_xpos >= CHAR_X_START - 1'b1) && (pixel_xpos < CHAR_X_START + CHAR_WIDTH - 1'b1)
            && (pixel_ypos >= CHAR_Y_START) && (pixel_ypos < CHAR_Y_START + CHAR_HEIGHT))begin
            if(char[y_cnt][CHAR_WIDTH - 1'b1 - x_cnt])    //文字
                pixel_data <= CHAR_COLOR;   //字符颜色,红色
            else
                pixel_data <= BACK_COLOR;   //背景色,浅蓝色
    end
    else
        pixel_data <= BACK_COLOR;
end

//根据当前扫描点的横纵坐标为ROM地址赋值
always @(posedge lcd_pclk or negedge sys_rst_n) begin
    if(!sys_rst_n)
        rom_addr <= 14'd0;
    else if((pixel_ypos >= PIC_Y_START) && (pixel_ypos < PIC_Y_START + PIC_HEIGHT)
            && (pixel_xpos >= PIC_X_START - 2'd2) && (pixel_xpos < PIC_X_START + PIC_WIDTH - 2'd2))
        rom_addr <= rom_addr + 1'b1;
    else if(pixel_ypos >= PIC_Y_START + PIC_HEIGHT)
        rom_addr <= 14'd0;
    else
        rom_addr <= rom_addr;
end

blk_mem_gen_0  blk_mem_gen_0 (
  .clka  (lcd_pclk),    // input wire clkaendmodule
  .ena   (rom_rd_en),   // input wire ena
  .addra (rom_addr),    // input wire [13 : 0] addra
  .douta (rom_rd_data)  // output wire [23 : 0] douta
);
endmodule

参考内容

  • 12
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

学无止境_hjy

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值