FPGA实现“打字机”

大熊FPGA 大熊FPGA 墨衍会员 · AI 创作全网分发 墨衍智能分发 通过墨衍一键同步至各平台 可同步平台 CSDN微信公众号微博知乎掘金百家号博客园抖音小红书 你的文章也可以这样分发 墨衍会员 ¥399起/年,写一次发全网 我也要 + 加入社区
看到标题中的“打字机”三个字,你是不是脑补了下面这幅图像。这是二战电影中常出现的道具,现在恐怕都见不到了。


我要实现的当然不是这个样子,只是功能上与之相似。先让你们看看实现的效果,直接上图。

这是串口发的字符串


显示屏显示的字符

之所以要写这个“打字机”工程,那是因为我在学习FPGA的道路上,它是我重要的一关。我一开始学FPGA,是从数字电路开始入门的,然后就是学习使用QuartusII,编写Verilog代码。我写的第一个工程是数字时钟(6个数码管两个一组实现时钟、分钟、秒钟的计时),通过它我学会了基本的逻辑(时序逻辑、组合逻辑,以及我们用的最频繁的译码器和选择器)。接下来就是这个“打字机”了,其实一开始这是学长给我布置的一个任务(现在想想学长也是用心良苦),通过它我基本上领会了如何驱动外设以及用各个外设组合成我们需要的工程(也就是模块化设计)。我相信,对于很多还在朝FPGA入门的同学来说,通过这个工程,你们的能力能获得显著提升。
好了,话就不多说了,接下来就来看看这个工程是怎么实现的。我们先来看看RTL视图:

从该图中可以看到,这里一共有5个模块:PLL模块、UARTRX接收模块、DISMEM显存模块、GETZIMO字模译码模块、VGA显示模块。PLL模块产生VGA(800*600@60Hz)所需的40M时钟,UARTRX模块接收上位机发来的数据,显存模块保存需要显示的字符,字模模块将显存的字符译码成VGA模块需要的数据。PLL、UARTRX、VGA这三个模块就不讲了,这是学习FPGA必然要遇到的模块(网上有很多代码),接下来就给大家重点分析一下显存模块和字模译码模块。
显存模块,顾名思义就是仿造显卡的显存,将显示的内容保存起来,当显示模块需要的时候再取出来。当我们按顺序将UART接收到的字符放入RAM中时,有一个问题,如果写满了RAM怎么办?当然,可以这么做,从头开始写,一直循环。那么读操作也按顺序读就会有问题了,这时如果写满了,之前显示的内容就突然没了。可是我们希望当写满时所有行都能往上卷一行,这样就和我们平时打字的效果一样了。解决这个问题的办法是改变读地址和写地址的映射关系。通常,读写地址是这么映射的:

为了解决该问题,映射关系改成这样:

每当写满一页,读地址就往上卷动一行(也就是减去一行)。具体的代码就是:
//从串口来一个数据就加1,直到计满清零
always @ (posedge CLK_50M or negedge RST_N)
begin
if(!RST_N)
RAM_WP <= 12'h0;
else
RAM_WP <= RAM_WP_N;
end

always @ (*)
begin
if(RAM_WP == 12'd3699 && DATAFLAG)
RAM_WP_N = 12'h0;
else if(DATAFLAG)
RAM_WP_N = RAM_WP + 12'h1;
else
RAM_WP_N = RAM_WP;
end

//RAM_WP对100取模得RAM_WP100,可以作为写指针的列
always @ (posedge CLK_50M or negedge RST_N)
begin
if(!RST_N)
RAM_WP100 <= 12'h0;
else
RAM_WP100 <= RAM_WP100_N;
end
always @ (*)
begin
if(RAM_WP100 == 12'd99 && DATAFLAG)
RAM_WP100_N = 12'h0;
else if(DATAFLAG)
RAM_WP100_N = RAM_WP100 + 12'h1;
else
RAM_WP100_N = RAM_WP100;
end

//以下实现卷行

//判断页尾,判断成功则一直保持
always @ (posedge CLK_50M or negedge RST_N)
begin
if(!RST_N)
sroll_flag <= 1'b0;
else
sroll_flag <= sroll_flag_n;
end
always @ (*)
begin
if(RAM_WP == 12'd3699 && DATAFLAG)
sroll_flag_n = 1'b1;
else
sroll_flag_n = sroll_flag;
end
字模译码模块就是将从显存RAM中的字符译码得到VGA需要显示的数据,这是因为字符是不能直接给VGA显示的,所以有这个译码的过程。译码过程需要根据显示的位置得到VGA显示的像素,也就是根据字符从ROM中(里面存有字模信息)取得字符的字模,其过程见代码:
//得到需要输出的字模数据的哪行,打一拍
always @ (posedge CLK_50M or negedge RST_N)
begin
if(!RST_N)
linechar <= 4'h0;
else
linechar <= position_VS[3:0];
end
//得到该行数据
GETLINE getlineA
(
.CLK_50M (CLK_50M ),
.CHAR (CHAR ),
.linechar (linechar ),
.dataline (dataline )
);

//得到需要输出字模数据的某列
always @ (posedge CLK_50M or negedge RST_N)
begin
if(!RST_N)
bitcnt <= 3'h0;
else
bitcnt <= bitcnt_n;
end

always @ (posedge CLK_50M or negedge RST_N)
begin
if(!RST_N)
bitcnt_n <= 3'h0;
else
bitcnt_n <= position_HS[2:0];
end

//得到字模数据某行某列上的值,并将这一位值译成8位数据(8'hff或8'h0)
DECODEPIXEL decodeA
(
.datain (dataline ),
.bitcnt (bitcnt ),
.dataout (databit )
);

assign DATAOUT = databit;
这个“打字机”的工作流程可以通过下图来理解,数据由上位机发过来,UART模块接收,当接收到一个完整字符时,将这个字符写入到RAM。RAM中的数据读出后经过ROM译码,最后通过VGA送给显示器显示。

“打字机”的具体实现就是上面将的这些,有兴趣的朋友可以在此基础上改进,改进的内容可以是增加控制字符的操作,也可以是将显示的字符保存到SDRAM中这样就可以容纳更多的字符了。另外,需要源码的朋友可以到此处下载:http://download.csdn.net/detail/qq_39210525/9873359。


...全文

相关推荐

FPGA"打字机" (VGA & UART)

用VGA和UART在FPGA上实现了一个打字机,挺有意思的

大熊FPGA

基于FPGA的串口通信程序设计与实现

在嵌入式系统设计中,串口通信(UART)因其协议简单、资源占用少、兼容性强,成为设备间通信的基石。FPGA通过硬件逻辑实现UART协议栈,相较传统MCU软件模拟具备显著优势:低延迟响应、高时序精度、强并行处理能力。典型应用包括工业PLC调试接口、传感器数据汇聚、FPGA与PC之间的命令交互等。-- 示例:基础UART发送模块使能控制该特性使得FPGA在实时性要求严苛的场景中表现卓越。此外,FPGA允许深度定制帧格式、波特率及流控逻辑,支持多通道UART并行运行,极大提升了系统集成度与灵活性。

张哲华

FPGA入门:0和1——精彩世界由此开始

现实世界中本不存在所谓的数字,数字从某种意义上看也是模拟的一种特殊表现形式。但也正是数字的出现,让模拟得到更好的存储、传输和处理。

weixin_38735182

FPGA新手必看:Verilog实现VGA显示从原理到代码全解析(附时序图)

本文详细解析了如何使用Verilog实现VGA显示控制器,从基本原理到代码实现,包括时序参数配置、状态机设计、同步信号生成及调试技巧。适合FPGA新手快速掌握VGA显示技术,附带实用代码示例和时序图,帮助避开常见开发陷阱。

江平舟

FPGA实战:手把手教你驱动1080p VGA显示器

本文详细介绍了如何使用FPGA驱动1080p VGA显示器的实战教程,从VGA显示原理、1080p时序参数解析到Verilog驱动逻辑实现,逐步指导开发者掌握核心技术和常见问题排查方法。重点讲解了精确时钟控制和彩条测试图案生成,帮助读者快速实现稳定的VGA显示输出。

碗丸
评论 1
收藏 已收藏
分享
返回顶部
大熊FPGA
其他硬件开发 2,432 成员 4,281 内容