FPGA:图形 LCD 面板- 文本

发布时间:2024-01-15  

图形 LCD 面板 4 - 文本

让我们尝试在面板上显示字符。 这样,面板就可以用作文本终端。
我们的 480x320 示例面板可用作 80 列 x 40 行控制台(使用 6x8 字符字体)或 60 列 x 40 行控制台(使用 8x8 字符字体)。 我们将使用“字符生成器”技术。

本文引用地址:

字符生成器

让我们假设“你好”这个词在屏幕上的某个地方。在 ASCII 中,它使用 5 个字节(0x48、0x65、0x6C、0x6C、0x6F)。 我们的简单字符生成器使用一个 RAM 来保存要显示的字符,并使用一个 ROM 来保存字体。

“Font ROM”包含每个可能字符的表示形式。 以下是示例集:

更改“Character RAM”的内容会使字符出现在面板上。

8x8 字体实现

在面板上,6x8 字体看起来比 8x8 字体好一些,但 8x8 更容易实现,所以我们首先尝试了。

通过使用 2KB RAM 作为“字符 RAM”,我们可以有 32 行 64 个字符......所以 5 位来计算行数,6 位来计算列数。
通过将所有数字保持为 <> 的幂,实现尽可能简单。

以下是我们得到的:

我们使用 CounterX 的 6 位和 CounterY 的 8 位(“字符 RAM”为 5 位,加上“字体 ROM”为 3 位)。 “字体ROM”总共使用11位。

设计如下:

wire [7:0] CharacterRAM_dout;
ram8x2048 CharacterRAM(
	.clk(clk),
	.rd_adr({CounterY[7:3],CounterX[6:1]}),
	.data_out(CharacterRAM_dout)
);
wire [7:0] raster8;
rom8x2048 FontROM(
	.clk(clk),
	.rd_adr({CharacterRAM_dout, CounterY[2:0]}),
	.data_out(raster8)
);
wire [3:0] LCDdata = CounterX[0] ? raster8[7:4] : raster8[3:0];

一些细节:

  • 因为我的 LCD 面板每个时钟需要 4 个像素,所以我们需要 2 个时钟来表示 1 个字符宽度(1 个字符宽度 = 8 像素)。这就是为什么“角色RAM”使用“CounterX[6:1]”而不是上面的“CounterX[5:0]”的原因。

  • 在中,“字体ROM”实际上是一个RAM是有道理的。这样,可以在运行时加载或更改字体。

  • 上面未显示写入 RAM 的机制。

这是带有 8x8 字体的 LCD 的照片:

6x8 字体实现

6x8 字体允许显示更多字符(并且在面板上看起来也更好! 我的特定面板宽度为 480 像素,可以方便地转换为 80 列。

6x8 字体比 8x8 字体处理起来更复杂,因为字体宽度 (6) 不是 2 的幂。
这意味着我们不再在每个时钟周期中显示字符的相同部分。

  • 当 CounterX=0 时,我们显示 CHAR[4] 的前 0 个像素

  • 当 CounterX=1 时,我们显示 CHAR[2] 的最后 0 个像素和 CHAR[2] 的前 1 个像素

  • 当 CounterX=2 时,我们显示 CHAR[4] 的最后 1 个像素

  • 当 CounterX=3 时,我们显示 CHAR[4] 的前 2 个像素

  • 当 CounterX=4 时,我们显示 CHAR[2] 的最后 2 个像素和 CHAR[2] 的前 3 个像素

  • ...

这是使用简单的 case 语句完成的

wire [3:0] charfont0, charfont1;
always @(posedge clk)begin
  case(cnt_mod3)
    2'b00: LCDdata <=  charfont0;
    2'b01: LCDdata <= {charfont0[3:2], charfont1[3:2]};
    2'b10: LCDdata <= {charfont1[3:2], charfont0[1:0]};  
    endcase
    end

带有模数 3 计数器(计数 0、1、2、0、1、2、0、1 等)

reg [1:0] cnt_mod3;
always @(posedge clk) if(cnt_mod3==2) cnt_mod3 <= 0; 
else cnt_mod3 <= cnt_mod3 + 1;

但我们还需要一个用于“字符RAM”的字符计数器

// character-counter (increments only twice every 3 clocks)
reg [6:0] cnt_charbuf;
always @(posedge clk) if(cnt_mod3!=1) cnt_charbuf <= cnt_charbuf + 1;
wire [11:0] CharacterRAM_rdaddr = CounterY[8:3]*80 + cnt_charbuf;
wire [7:0] CharacterRAM_dout;ram8x2048 CharacterRAM(
	.clk(clk),
	.rd_adr(CharacterRAM_rdaddr),
	.data_out(CharacterRAM_dout)
);

和两个“字体ROM”。

// remember the previous character displayed
reg [7:0] RAM_charbuf_dout_last;
always @(posedge clk) CharacterRAM_dout_last <= CharacterRAM_dout;

// because we need it when we display 2 half characters at once
wire [10:0] readaddr0 = {CharacterRAM_dout, CounterY[2:0]};
wire [10:0] readaddr1 = {CharacterRAM_dout_last, CounterY[2:0]};

// The font ROMs are split in two blockrams, holding 4 pixels each
// (half of the second ROM is not used, since we need only 6 pixels)
rom4x2048 FontROM0(.clk(clk), .rd_adr(readaddr0), .data_out(charfont0));
rom4x2048 FontROM1(.clk(clk), .rd_adr(readaddr1), .data_out(charfont1));

这是带有 6x8 字体的 LCD 的照片:

硬件光标

让我们实现一个闪烁的光标,它可以放置在面板上的任何字符上。

首先,我们使用视频帧计数器来“计时”闪烁。 使用 6 位,光标每 64 帧闪烁一次。

reg [5:0] cnt_cursorblink;
always @(posedge clk) if(vsync & hsync) cnt_cursorblink <= cnt_cursorblink + 1;
wire cursorblinkstate = cnt_cursorblink[5];  // cursor on for 32 frames, off for 32 frames

现在,我们假设游标地址位置在“CursorAddress”寄存器中可用。

// Do we have a cursor-character match?
wire cursorblink_adrmatch = cursorblinkstate & (CharacterRAM_rdaddr==CursorAddress);

// When we have a match, "invert" the character
// First for charfont0
wire [3:0] charfont0_cursor = charfont0 ^ {4{cursorblink_adrmatch}};

// Next for charfont1
reg cursorblink_adrmatch_last;
always @(posedge clk) cursorblink_adrmatch_last <= cursorblink_adrmatch;
wire [3:0] charfont1_cursor = charfont1 ^ {4{cursorblink_adrmatch_last}};

哇,我们可以显示图形和文本!

所有这些都适用于单色和彩色 LCD。
当我们在彩色 LCD 上得意忘形时会发生什么......

轮到你来实验了!

文章来源于:电子产品世界    原文链接
本站所有转载文章系出于传递更多信息之目的,且明确注明来源,不希望被转载的媒体或个人可与我们联系,我们将立即进行删除处理。

我们与500+贴片厂合作,完美满足客户的定制需求。为品牌提供定制化的推广方案、专属产品特色页,多渠道推广,SEM/SEO精准营销以及与公众号的联合推广...详细>>

利用葫芦芯平台的卓越技术服务和新产品推广能力,原厂代理能轻松打入消费物联网(IOT)、信息与通信(ICT)、汽车及新能源汽车、工业自动化及工业物联网、装备及功率电子...详细>>

充分利用其强大的电子元器件采购流量,创新性地为这些物料提供了一个全新的窗口。我们的高效数字营销技术,不仅可以助你轻松识别与连接到需求方,更能够极大地提高“闲置物料”的处理能力,通过葫芦芯平台...详细>>

我们的目标很明确:构建一个全方位的半导体产业生态系统。成为一家全球领先的半导体互联网生态公司。目前,我们已成功打造了智能汽车、智能家居、大健康医疗、机器人和材料等五大生态领域。更为重要的是...详细>>

我们深知加工与定制类服务商的价值和重要性,因此,我们倾力为您提供最顶尖的营销资源。在我们的平台上,您可以直接接触到100万的研发工程师和采购工程师,以及10万的活跃客户群体...详细>>

凭借我们强大的专业流量和尖端的互联网数字营销技术,我们承诺为原厂提供免费的产品资料推广服务。无论是最新的资讯、技术动态还是创新产品,都可以通过我们的平台迅速传达给目标客户...详细>>

我们不止于将线索转化为潜在客户。葫芦芯平台致力于形成业务闭环,从引流、宣传到最终销售,全程跟进,确保每一个potential lead都得到妥善处理,从而大幅提高转化率。不仅如此...详细>>