VHDL双7段显示控制器:轻松集成Pmod SSD到FPGA
本文展示一个VHDL模块,可在Digilent的Pmod SSD:七段显示器上显示两位数字。双7段显示兼容Pmod接口,无需焊接即可使用。它适配标准于许多FPGA开发板的Pmod连接器。
测试VHDL实现用Lattice iCEstick,一款带Pmod连接器的低成本FPGA开发板。除iCEstick外,需2×6针转双6针Pmod分线缆,将iCEstick并行Pmod连接器转为7段显示器期望的串联版插头。另外建议买USB Type-A延长线,因直接插iCEstick到电脑USB口不便。
7段显示器工作原理
市面7段显示器种类繁多。位数、物理接口、引脚排布各异。覆盖所有可能遇到的7段显示器的通用解决方案可能不太用户友好。但可基于本文代码修改适配需求。
上图来自Digilent Pmod模块数据手册,展示7段显示器如何连接Pmod引脚。这些引脚在iCEstick上直接连FPGA可访问。七个引脚各控制显示器一个段。驱动此类引脚逻辑高电平,对应段点亮。但显示器有两位数字,一次只能控制一位。J2连接器P4/C引脚选左或右位。该引脚逻辑电压为'0'亮右位,为'1'激活左位。"DP"小数点未连、不可访问。
实体定义
下代码展示seg7 VHDL模块实体。实体有泛型端口含常量clk_cnt_bits。定义控制显示刷新率的内部计数器长度——左右位交替频率。精确频率非关键。选50至几百赫兹范围内的计数器长度。刷新率公式:refresh_hz = 2^clk_cnt_bits / clk_hz。
entity seg7 is generic ( -- refresh_hz = (2 ** clk_cnt_bits) / clk_hz clk_cnt_bits : integer ); port ( clk : in std_logic; rst : in std_logic; value : in integer range 0 to 99; segments : out std_logic_vector(6 downto 0); digit_sel : out std_logic ); end seg7;
除时钟复位,实体有一输入信号:要在7段显示器显示的值。value信号为integer类型限0至99范围,因仅两位只能显示这些数值。输出信号为七段向量与位选择信号,用于选亮左或右位。
二进制编码十进制(BCD)表示
为表示显示器上显示的数字,用二进制编码十进制(BCD)格式。二进制表示虽存十进制数最高效,但拆分左右位显示时遇麻烦。不能仅切片存数向量区分十进制数字。
subtype digit_type is integer range 0 to 9; type digits_type is array (1 downto 0) of digit_type; signal digit : digit_type; signal digits : digits_type;如上代码,声明0至9范围integer子类型描述单十进制位可表示值。再声明可容两个此类BCD值的新数组类型。
digit信号持有当前显示器左或右侧显示的数字。digits信号含将呈现给观看者的两位各自十进制字符。
十进制转BCD
模块输入value为0至99范围integer,数字的二进制表示。需转这单个integer为两个0至9范围integer即BCD。标准算法是Double Dabble即移位加3算法。虽可用,但我们仅两位需分离,选更短方案。
digits(1) <= value / 10; digits(0) <= value - ((value / 10) * 10);用整数除法如上代码,分离最高十进制位赋
digits(1)。取最低位,从value减最高位,剩下数赋digits(0)。
计数时钟周期
FPGA延时仅靠数时钟周期。时钟周期是VHDL代码唯一可靠的可预测时间间隔。下代码展示用于数时钟周期的clk_cnt信号。clk_cnt_bits泛型决定无符号信号保留位数。
signal clk_cnt : unsigned(clk_cnt_bits - 1 downto 0);显示器精确刷新率非关键,故用无符号类型。利用无符号信号自动回绕行为。只需每个时钟上升沿增计数器。下同步带复位进程处理此事。
COUNT_PROC : process(clk) begin if rising_edge(clk) then if rst = '1' then clk_cnt <= (others => '0'); else clk_cnt <= clk_cnt + 1; end if; end if; end process;
位间交替
现有自由运行计数器,可用无符号计数器信号最高有效位(MSB)在两位间切换。MSB以50%占空比在'0'与'1'间交替。下代码首行基于MSB值设digit_sel信号。第二行实现以MSB为选择器的多路复用器。将digits数组活动位值传给digit信号。
digit_sel <= clk_cnt(clk_cnt'high); digit <= digits(0) when clk_cnt(clk_cnt'high) = '0' else digits(1);
BCD转7段编码器
seg7模块最后步骤:将digit信号存储的BCD转为7段显示器视觉表示。下进程用case语句实现。
ENCODER_PROC : process(digit) begin case digit is when 0 => segments <= "0111111"; when 1 => segments <= "0000110"; when 2 => segments <= "1011011"; when 3 => segments <= "1001111"; when 4 => segments <= "1100110"; when 5 => segments <= "1101101"; when 6 => segments <= "1111101"; when 7 => segments <= "0000111"; when 8 => segments <= "1111111"; when 9 => segments <= "1101111"; end case; end process;向量各位位置对应显示器一段。索引0=段A,索引1=段B,依此到索引6控制段G。段到向量索引映射源自Digilent 7段显示器数据手册。
输出效果
seg7 VHDL模块将在显示器渲染您赋给value输入信号的任何值。测试台每秒递增value信号一次。仿真略超100秒观察value计数器回绕点。上波形图来自ModelSim,显示仿真前段,value从0数到15。可见digits数组也在计数。个位(0)每次value变化计数,十位(1)每十个数递增。可用下表单下载含测试台的ModelSim项目。若在FPGA上将seg7模块实现为顶层模块,显示器极大概率显稳定"00"。因'0'是FPGA中未初始化信号最常见默认值。value信号全零时显示器就显那样。为遍历所有可能输入数字,我创建包装VHDL模块每秒递增value十次。在包装中实例化seg7模块后在Lattice iCEstick实现设计。下循环Gif视频展示实现设计在7段显示器上的样子。
购买Pmod SSD:七段显示器
本文用的7段显示器来自Digilent。可从Digilent网店购买Pmod模块,或众多经销商处获取。下列表链接几家销售该商品的在线电子商店产品页。
- Digilent
- Digi-Key
- Mouser
- RS Electronics (UK)
(访问RS Electronics主页选您国家站点) - Farnell (UK)
(访问Farnell主页选您国家站点)
使用Digilent 7段显示器的VHDL课程
我推出面向绝对初学者的新VHDL与FPGA课程。课程用Digilent 7段显示器和Lattice iCEstick FPGA开发板教VHDL。点下链接了解课程详情!
FPGA和VHDL快速入门:面向绝对初学者的实战
您熟悉编程但VHDL新手?
需要简短入门这个陌生主题?
日程满无时间学习?
几个晚上掌握用VHDL做FPGA开发基础!本课程面向需快速上手的IT专业人士和学生。配合低成本Lattice iCEstick开发板,您将在数小时内开发真实硬件。
点击阅读更多并报名:
FPGA和VHDL快速入门:面向绝对初学者的实战
VHDL
- VHDL 生成随机数:从均匀分布到 OSVVM
- VHDL双7段显示控制器:轻松集成Pmod SSD到FPGA
- 将Quartus Prime IP库集成进VUnit:分步实战指南
- ModelSim 仿真入门:FPGA 与 ASIC 设计验证的实战指南
- 什么是 VHDL?硬件描述语言实用指南
- 测试你的 VHDL 基础知识 – 互动测验第 1 部分
- 用 VHDL TEXTIO 库从文本文件初始化 FPGA 块 RAM
- 掌握 Xilinx Vivado:集成逻辑分析器 (ILA) 与虚拟输入/输出 (VIO) 调试
- 利用进程内过程简化VHDL状态机设计
- 构建可靠VHDL计时器:从时钟周期计数到小时
- VHDL 实现 PWM 控制器:设计、仿真与 FPGA 演示
- 基于 Ready/Valid 握手在块 RAM 中实现 AXI FIFO