当前位置: 首页 > news >正文

FPGA设计实践之电子秒表设计(VHDL版——ISE14.7)

前言

本设计使用VHDL语言在虚拟机(WIN7)上开发,环境为ISE14.7,开发板为Diligent NEXY3(板上时钟为100MHz),Spartan6内核,型号为XC6SLX16(-3),仅供参考学习使用。


一、设计实现功能

实现数字秒表设计并在开发板显示。

(1)采用层次化设计方式,将设计分为三个模块,分别是分频模块、计数模块、数码管显示模块,顶层模块例化这三个模块。

(2)秒表计数范围:00’到59’;

3带有复位、启动/停止功能。 

拓展功能:

  1. 不仅能正向计数,也能反向计数。增加置数功能,通过按键置数,能将计数值直接设置成指定的数字,采用6个拨码开关(置数范围从0-2^6)置数。
  2. LED控制模块,判断计数情况,当计数值处于不同的区间时,点亮相应数量的LED以提示计数进度。
  3. 串口输出功能,将计数状态数值即时传出串口TX,对LCD屏幕进行控制,实时显示计数状态。

二、代码编写及分析

综合设计采用的是模块化设计,顶层设计(TOP)将元件(Component)进行例化。整体模块分布关系如流程图所示:

总体结构如图所示

按照设计要求主要包含以上模块:

核心部分:

1、时钟分频模块:将100MHz的时钟通过计数器计数的方式,分频出对应频率的时钟:10ms、1s,10ms用于数码管刷新显示,1s用于时钟的标准计数。分频器将晶振产生的100MHz 的方波信号作为该模块的时钟信号,计算并设置对应的计数长度,设置对应的寄存器大小。当检测到一次上升沿计数变量cnt就自增1,当数值达到设定值的时候就将输出端的电平翻转,以此达到分频产生方波的效果。

2、数码管显示模块:对数码管的不同位进行刷新显示。共有两个进程:进程1根据翻转时钟进行数码管位选的切换,进程2根据进程1显示的数码管位选状态显示对应的数值(段选)。

3、计数模块:主要是if逻辑的嵌套,实现异步清零、启停,同步置数、同步加减控制(异步即为按键/开关即时控制,同步则需要在时钟上升沿之后才有效)。思路与之前构建十进制计数器是一样的,只不过现在是控制两位数显示。通过除法计算和取模计算的方式可以简单得到计数值的十位和个位。

4、串口输出模块:只需要使能一个TX口即可,绑定引脚也没有特殊的需求,任何一个普通引脚都可以用于串口时序的设计,体现了FPGA不同于单片机的特点。本部分的设计参考了网络的串口Usart例程进行设计,可以轻松修改串口的参数。外接LCD屏幕设计,LCD屏幕的设计此处略去,主要是通过串口输出对应格式的文本数据,以起到控制LCD的功能。

5、LED控制模块:这个模块更简单,只需要对计数数值进行简单的判断即可,起到一个丰富板上使用资源的效果。主要是通过一系列if逻辑,判断计数值的状态,亮起对应的LED。


ISE14.7中显示模块例化如上图所示

代码块:

一、顶层模块

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;  entity clock_60 is
Port(sys_clk : in STD_LOGIC;enable     : in STD_LOGIC;rst         : in STD_LOGIC;y         : out STD_LOGIC_VECTOR(6 downto 0);SEG_W     : out STD_LOGIC_VECTOR(3 downto 0);led         : out STD_LOGIC_VECTOR(5 downto 0);SEL     : in  STD_LOGIC;             LD      : in  STD_LOGIC;             Data    : in  STD_LOGIC_VECTOR(5 downto 0); tx      : out STD_LOGIC                 -- UART TX 输出
);
end clock_60;
architecture Behavioral of clock_60 is
Component count_number is
Port(clk_1s  : in  STD_LOGIC;              -- 输入时钟,1秒时钟rst     : in  STD_LOGIC;          enable  : in  STD_LOGIC;            SEL     : in  STD_LOGIC;            LD      : in  STD_LOGIC;              Data    : in  STD_LOGIC_VECTOR(5 downto 0); number  : out STD_LOGIC_VECTOR(5 downto 0)  
);
end Component;
Component SEG is
Port(clk_100ms : in STD_LOGIC;number : in STD_LOGIC_VECTOR(5 downto 0);y : out STD_LOGIC_VECTOR(6 downto 0);SEG_W : out STD_LOGIC_VECTOR(3 downto 0)
);
end Component;
Component clock is
Port(sys_clk: in STD_LOGIC;clk_1s: out STD_LOGIC;clk_100ms: out STD_LOGIC
);
end Component;
Component led_control is
Port(number : in STD_LOGIC_VECTOR(5 downto 0);led : out STD_LOGIC_VECTOR(5 downto 0)
);
end Component;
Component uart_auto_tx isPort (clk    : in  STD_LOGIC;                         tx     : out STD_LOGIC;                         number : in  STD_LOGIC_VECTOR(5 downto 0)       );
end Component;
signal clk_1s_sig    : STD_LOGIC;
signal clk_100ms_sig : STD_LOGIC;
signal number_sig    : STD_LOGIC_VECTOR(5 downto 0);
begin
U1_clock_div : clockport map(sys_clk   => sys_clk,clk_1s    => clk_1s_sig,clk_100ms => clk_100ms_sig);
U2_counter : count_numberport map(clk_1s => clk_1s_sig,rst    => rst,enable => enable,number => number_sig,LD         => LD,DATA   => DATA,SEL    => SEL);
U3_seg : SEGport map(clk_100ms => clk_100ms_sig,number    => number_sig,y         => y,SEG_W     => SEG_W);
U4_led : led_controlport map(number => number_sig,led    => led);
U5_uart : uart_auto_txport map(clk   => sys_clk,tx    => tx,number => number_sig);
end Behavioral;

二、时钟分频

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;  entity clock is
Port(sys_clk: in STD_LOGIC;clk_1s: out STD_LOGIC;clk_100ms: out STD_LOGIC
);
end clock;
architecture Behavioral of clock issignal count1: STD_LOGIC_VECTOR(24 downto 0) := (others => '0');signal count2: STD_LOGIC_VECTOR(25 downto 0) := (others => '0');signal sig_clk_100ms: STD_LOGIC := '0';signal sig_clk_1s: STD_LOGIC := '0';
beginprocess(sys_clk)beginif rising_edge(sys_clk) thenif count1 = 499_999 then   -- 5ms翻转周期count1   <= (others => '0');sig_clk_100ms <= not sig_clk_100ms;   -- 翻转输出,得到10Hz时钟clk_100ms <= sig_clk_100ms;elsecount1 <= count1 + 1;end if;end if;end process;process(sys_clk)beginif rising_edge(sys_clk) thenif count2 = 49_999_999 thencount2 <= (others => '0');sig_clk_1s <= not sig_clk_1s;clk_1s <= sig_clk_1s;elsecount2 <= count2 + 1;end if;end if;end process;
end Behavioral;

三、计数模块

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;  entity count_number is
Port(clk_1s : in STD_LOGIC;rst : in STD_LOGIC;enable : in STD_LOGIC;number : out STD_LOGIC_VECTOR(5 downto 0);SEL     : in  STD_LOGIC;              -- 控制加法或减法:'1' 加法,'0' 减法LD      : in  STD_LOGIC;              -- 置数Data    : in  STD_LOGIC_VECTOR(5 downto 0) -- 置数内容,用拨码开关表示
);
end count_number;
architecture Behavioral of count_number is
signal number1 : unsigned(5 downto 0) := (others => '0');
beginnumber <= std_logic_vector(number1);
process(clk_1s, rst)--进程1,执行复位和时钟加法
beginif rst = '1' thennumber1 <= (others => '0');elsif rising_edge(clk_1s) thenif enable = '1' thenif SEL = '1' thenif number1 < 59 thennumber1 <= number1 + 1;elsenumber1 <= (others => '0');end if;elseif number1 > 0 thennumber1 <= number1 - 1;elsenumber1 <= (others => '0');end if;end if; if LD = '1' then-- 置数,num 设置为输入值number1 <= unsigned(Data(5 downto 0));end if;end if;end if;
end process;
end Behavioral;

四、数码管显示模块

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;  entity SEG is
Port(clk_100ms : in STD_LOGIC;number : in STD_LOGIC_VECTOR(5 downto 0);y : out STD_LOGIC_VECTOR(6 downto 0);SEG_W : out STD_LOGIC_VECTOR(3 downto 0)
);
end SEG;
architecture Behavioral of SEG is
signal number1 : unsigned(5 downto 0) := (others => '0');
signal seg_select : STD_LOGIC := '0';
signal ones_digit, tens_digit : unsigned(3 downto 0);
beginnumber1 <= resize(unsigned(number), 6);ones_digit <= resize(number1 mod 10, 4);tens_digit <= resize(number1 / 10, 4);
process(clk_100ms)
beginif rising_edge(clk_100ms) thenseg_select <= not seg_select;end if;
end process;
process(seg_select,ones_digit,tens_digit) --进程2,执行数码管显示
begin
case seg_select iswhen '0' =>SEG_W <= "1110";case ones_digit iswhen "0000" => y <= "1000000";  -- 显示 0when "0001" => y <= "1111001";  -- 显示 1when "0010" => y <= "0100100";  -- 显示 2when "0011" => y <= "0110000";  -- 显示 3when "0100" => y <= "0011001";  -- 显示 4when "0101" => y <= "0010010";  -- 显示 5when "0110" => y <= "0000010";  -- 显示 6when "0111" => y <= "1111000";  -- 显示 7when "1000" => y <= "0000000";  -- 显示 8when "1001" => y <= "0010000";  -- 显示 9when others => y <= "1111111";  -- 错误时显示全灭end case;when others =>SEG_W <= "1101";case tens_digit iswhen "0000" => y <= "1111111";  -- 不显示when "0001" => y <= "1111001";  -- 显示 1when "0010" => y <= "0100100";  -- 显示 2when "0011" => y <= "0110000";  -- 显示 3when "0100" => y <= "0011001";  -- 显示 4when "0101" => y <= "0010010";  -- 显示 5when "0110" => y <= "0000010";  -- 显示 6when "0111" => y <= "1111000";  -- 显示 7when "1000" => y <= "0000000";  -- 显示 8when "1001" => y <= "0010000";  -- 显示 9when others => y <= "1111111";  -- 错误时显示全灭end case;
end case;
end process;
end Behavioral;

五、LED控制模块

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;  entity led_control is
Port(number : in STD_LOGIC_VECTOR(5 downto 0);led : out STD_LOGIC_VECTOR(5 downto 0)
);
end led_control;
architecture Behavioral of led_control is
signal number1 : unsigned(5 downto 0) := (others => '0');
beginnumber1 <= resize(unsigned(number), 6);
process(number1)
beginif number1 > 0 and number1 < 10 thenled <= (others => '0');elsif number1 >= 10 and number1 < 20 thenled <= "000001";elsif number1 >= 20 and number1 < 30 thenled <= "000011";elsif number1 >= 30 and number1 < 40 thenled <= "000111";elsif number1 >= 40 and number1 < 50 thenled <= "001111";elsif number1 >= 50 and number1 < 60 thenled <= "011111";elseled <= "111111";end if;end process;
end Behavioral;

六、串口输出模块

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;entity uart_auto_tx isPort (clk    : in  STD_LOGIC;          tx     : out STD_LOGIC;                      number : in  STD_LOGIC_VECTOR(5 downto 0)      );
end uart_auto_tx;
architecture Behavioral of uart_auto_tx isconstant BAUD_RATE  : integer := 115200;                -- 波特率 115200constant CLOCK_FREQ : integer := 100_000_000;constant BAUD_DIV   : integer := CLOCK_FREQ / BAUD_RATE; -- 每 1 秒发送一次constant SEND_INTERVAL : integer := CLOCK_FREQ;signal baud_cnt   : integer range 0 to BAUD_DIV := 0;signal baud_tick  : std_logic := '0';signal send_timer : integer range 0 to SEND_INTERVAL := 0;signal send_req   : std_logic := '0';-- 串口逐位发送signal tx_shift   : std_logic_vector(9 downto 0) := (others => '1');signal bit_index  : integer range 0 to 9 := 0;signal sending    : std_logic := '0';signal tx_reg     : std_logic := '1';-- 待发字节缓冲(固定 12 字节:n0.val= + 数据值 + 3 个 0xFF)type byte_array_t is array (0 to 11) of std_logic_vector(7 downto 0);signal tx_buf     : byte_array_t := (others => (others => '0'));signal buf_idx    : integer range 0 to 11 := 0;-- 把数字转换为 ASCII '0'..'9'function to_ascii_digit(d : integer) return std_logic_vector isvariable r : std_logic_vector(7 downto 0);beginr := std_logic_vector(to_unsigned(48 + d, 8)); -- 48 = '0'return r;end function;
begintx <= tx_reg;-- 波特率115200process(clk)beginif rising_edge(clk) thenif baud_cnt = BAUD_DIV - 1 thenbaud_cnt  <= 0;baud_tick <= '1';elsebaud_cnt  <= baud_cnt + 1;baud_tick <= '0';end if;end if;end process;process(clk)beginif rising_edge(clk) thenif send_timer = SEND_INTERVAL - 1 thensend_timer <= 0;send_req   <= '1';elsesend_timer <= send_timer + 1;send_req   <= '0';end if;end if;end process;-- UART 发送状态机(一次请求发送 12 个字节:n0.val= + 数据值 + 3 个 0xFF)process(clk)variable n     : integer;variable ones  : integer;variable tens  : integer;variable buf_local : byte_array_t;beginif rising_edge(clk) thenif sending = '0' thenif send_req = '1' thenn    := to_integer(unsigned(number));          tens := n / 10;                                ones := n mod 10;          -- 输出格式:n0.val=XX后跟三个 0xFFbuf_local(0)  := std_logic_vector(to_unsigned(110, 8)); -- 'n'buf_local(1)  := std_logic_vector(to_unsigned(48, 8));  -- '0'buf_local(2)  := std_logic_vector(to_unsigned(46, 8));  -- '.'buf_local(3)  := std_logic_vector(to_unsigned(118, 8)); -- 'v'buf_local(4)  := std_logic_vector(to_unsigned(97, 8));  -- 'a'buf_local(5)  := std_logic_vector(to_unsigned(108, 8)); -- 'l'buf_local(6)  := std_logic_vector(to_unsigned(61, 8));  -- '='buf_local(7)  := to_ascii_digit(tens);                  -- 十位buf_local(8)  := to_ascii_digit(ones);                  -- 个位buf_local(9)  := x"FF";                                 -- 0xFFbuf_local(10) := x"FF";                                 -- 0xFFbuf_local(11) := x"FF";                                 -- 0xFFtx_buf <= buf_local;buf_idx <= 0;tx_shift  <= '1' & buf_local(0) & '0';bit_index <= 0;sending   <= '1';end if;elsif baud_tick = '1' thentx_reg   <= tx_shift(0);tx_shift <= '1' & tx_shift(9 downto 1);if bit_index = 9 thenif buf_idx = 11 thensending <= '0';elsebuf_idx  <= buf_idx + 1;tx_shift <= '1' & tx_buf(buf_idx + 1) & '0';bit_index <= 0;end if;elsebit_index <= bit_index + 1;end if;end if;end if;end process;
end Behavioral;

三、设计原理图及分析

 

上图为整体顶层视图

这里仅放下数码管显示、计数、时钟分频模块,其他电路过于复杂不宜放入


分析:

时钟方向:

系统基础时钟经过分频器(clock_div)分为两个频率,clk_1s输出1HZ分频给予计数器。Clk_10ms输出100hz频率给与数码管显示切换刷新。

数码管显示方向:

数码管轮询显示模块共有2个4位的输入端,每次clk_10ms时钟信号到来后,该模块都会切换状态,改变数码管的位选,并根据当前数码管的位选选通输入端的信号,并将选通的输入端信号输入7段译码器进行译码,再将译码信号输入数码管,使其显示出对应的数字。

计数器方向:

计数器接入EN,SEL,CLR,LD。首先两者都是接入分频产生的1HZ时钟,EN是总使能开关,控制启停,SEL是选择加法或者减法开关,CLR是异步清零开关。当SEL=1时候,选择加法器计数模式,SEL=0则为减法器。本设计没有采用十进制+六进制的计数器设计方法,而是直接使用6位寄存器进行加减计算。在数码管显示时计算出个位和十位进行显示。计数器的时钟源是开发板时钟源经过分频引出的1Hz时钟信号。

拨码开关方向

该FPGA开发板上一共有8位的拨码开关,每个拨码开关都有‘1’和‘0’两种状态,因此可以用6位拨码开关以二进制的形式表示0—2^6-1范围内数字,即0-63,满足60进制内任意置数。拨码开关与计数器的置数输入端相连。当按下按键置数按键触发LD=1后,还需要等待一个时钟上升沿的到来(同步置数),数码管上显示的时间会变成用6位拨码开关表示的两位数字。


四、仿真波形图及分析

1Hz分频时钟仿真验证

数码管七段译码器仿真

计数器仿真


五、开发板验证分析

如图,LCD与数码管显示同步,并且每计数10s会自左向右亮起LED灯示意。


http://www.dtcms.com/a/542029.html

相关文章:

  • 江苏高校品牌专业建设工程网站wordpress 开发 表单
  • 郑州网站建设公司 排行关键词排名 收录 查询
  • 用服务器ip做网站域名青岛关键词优化排名
  • 网站搭建怎么收费163邮箱官方注册入口
  • 101-Spring AI Alibaba RAG 示例
  • 免费大空间网站漯河网站建设 千弘网络
  • 一个逆向工具 Ghidra 在 Linux 上的安装和基本使用
  • linux21 线程同步--互斥锁
  • 建设网站的申请信用卡分期付款jsp做的网站代码
  • 致同研究:可变对价的披露示例
  • 做会员卡的网站在线制作海宁市建设局官方网站6
  • 图神经网络入门:用 MLP 作为 Cora 数据集的基线模型
  • 邢台建设银行网站网站挂载
  • 主要的网站开发技术路线网站投放
  • 金昌做网站秦皇岛优化seo
  • 短剧小程序开发的技术新蓝海:交互、社交与AIGC的落地实践
  • 鹤岗做网站怎么把文件发送到网站
  • 2025年--Lc220--589. N 叉树的前序遍历(递归版)-Java版
  • 网站制作好吗上海影视公司
  • 网站公司怎么做的好兴隆大院网站哪个公司做的
  • JS睡眠函数(JS sleep()函数、JS单线程、Event Loop事件循环)假睡眠
  • Windows配置解压版MySQL5(免安装)
  • 营销网站建设阿凡达平面设计主要做什么
  • 有什么好的网站设计思想的博客张掖高端网站建设公司
  • 公司网上注册在哪个网站做产品网站营销推广
  • 网站在线留言的用途建设专业网站哪家技术好
  • 做阀门网站效果怎么样网站建设-部署与发布
  • 达梦数据库笔记--分权
  • 网站建设php书籍免费制作微信小程序的网站
  • 潍城区住房和城乡建设局网站frontpage新建网站