VHDL/CPLD硬件描述语言:2022年做的万年历实验

2024-06-01 23:20

本文主要是介绍VHDL/CPLD硬件描述语言:2022年做的万年历实验,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

之前接触过一些硬件描述语言以及VHDL/CPLD的单片机的设计实验,那时是2022年了

这里补写一篇笔记,以记录一下那十多个小时 万年历实验 研究中的心得体会:

说明解释都是个人理解,与标准描述有较大出入......

目录

输入输出器件的编写:

分频器点亮不同频率LED:

引用头文件:

实体(ENTITY)定义和架构(ARCHITECTURE)的开头部分:

主体:变量定义与时钟事件检查:

完整代码:

电路连接与效果描述:

级联分频/计时器实现时钟的效果:

四位计数器(10分频)的内部硬件描述代码:

接口与变量作用定义:

计数器过程:

数码管分频计数逻辑输出器:

​编辑

它的完整代码如下:

最后的输入输出总线连接:

编译下载效果如下:

回忆与感悟 :


 

输入输出器件的编写:

想必大家都听说过一些单片机外围电路上的芯片:

比如74HC138(三选八)芯片,74HC573扩展芯片等,这些芯片在硬件上定义一些输入与输出相联系的逻辑来实现他们的功能,

而这里的编程则是在软件上自己先使用硬件描述语言进行对输入输出逻辑的组合,自己编写出类似于分频器、片选芯片类似功能的器件模块,然后再将它们与具体的输入输出线引脚相组合,最后编译无报错下载进板子查看效果的过程。

分频器点亮不同频率LED:

这里展示了一个编写简单的分频器的硬件描述语言的逻辑代码,下面分布解释:

引用头文件:

LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;

实体(ENTITY)定义和架构(ARCHITECTURE)的开头部分:

PORT 描述了一个具有时钟分离功能的模块,

它接收一个输入时钟信号CLK,并产生两个输出时钟信号:

CLK_1HZ(1赫兹的时钟)和CLK_1KHZ(1千赫兹的时钟)

ENTITY CLK_SEP IS
PORT(CLK:IN STD_LOGIC;CLK_1HZ:OUT STD_LOGIC;CLK_1KHZ:OUT STD_LOGIC);
END CLK_SEP;
ARCHITECTURE BHV OF CLK_SEP IS

主体:变量定义与时钟事件检查:

COUNT1:一个24位的STD_LOGIC_VECTOR,用于产生1Hz的时钟信号。

COUNT2:一个14位的STD_LOGIC_VECTOR,用于产生1kHz的时钟信号。

IF CLK'EVENT AND CLK = '1' THEN:这一行检查CLK信号是否有一个事件(上升沿0变为1)

COUNT1COUNT2 在每个CLK上升沿递增。

COUNT1的值在"010110111000110110000000"(二进制表示,对应于某个十进制数)和"101101110001101100000000"之间时,CLK_1HZ被设置为'1'。这个范围代表了从某个特定开始点到结束点的时间段,用于产生1Hz的时钟周期。

COUNT1的值小于或等于结束点且大于或等于"000000000000000000000000"(即开始点)时,CLK_1HZ被设置为'0'

COUNT1达到结束点"101101110001101100000000"时,它被重置为"000000000000000000000000",以便开始下一个1Hz周期。

COUNT2的值在"01011101110000""10111011100000"之间时,CLK_1KHZ被设置为'1'。这个范围代表了从某个特定开始点到结束点的时间段,用于产生1kHz的时钟周期。

COUNT2的值小于或等于结束点且大于或等于"00000000000000"时,CLK_1KHZ被设置为'0'

COUNT2达到结束点"10111011100000"时,它被重置为"00000000000000",以便开始下一个1kHz周期。

BEGINPROCESS(CLK)VARIABLE COUNT1:STD_LOGIC_VECTOR(23 DOWNTO 0);VARIABLE COUNT2:STD_LOGIC_VECTOR(13 DOWNTO 0);BEGINIF CLK'EVENT AND CLK = '1' THENCOUNT1:=COUNT1+1;COUNT2:=COUNT2+1;IF ((COUNT1>="010110111000110110000000") AND	(COUNT1<="101101110001101100000000") ) THENCLK_1HZ<='1'; ELSIF ((COUNT1<="010110111000110110000000") AND(COUNT1>="000000000000000000000000")) THENCLK_1HZ<='0';IF COUNT1="101101110001101100000000" THENCOUNT1:="000000000000000000000000";END IF;END IF;IF ((COUNT2>="01011101110000") AND (COUNT2<="10111011100000")) THENCLK_1KHZ<='1';ELSIF ((COUNT2<="01011101110000")AND(COUNT2>="00000000000000")) THENCLK_1KHZ<='0';IF(COUNT2="10111011100000") THENCOUNT2:="00000000000000";END IF;END IF;END IF;END PROCESS;
END BHV;

完整代码:

LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITY CLK_SEP IS
PORT(CLK:IN STD_LOGIC;CLK_1HZ:OUT STD_LOGIC;CLK_1KHZ:OUT STD_LOGIC);
END CLK_SEP;
ARCHITECTURE BHV OF CLK_SEP IS
BEGINPROCESS(CLK)VARIABLE COUNT1:STD_LOGIC_VECTOR(23 DOWNTO 0);VARIABLE COUNT2:STD_LOGIC_VECTOR(13 DOWNTO 0);BEGINIF CLK'EVENT AND CLK = '1' THENCOUNT1:=COUNT1+1;COUNT2:=COUNT2+1;IF ((COUNT1>="010110111000110110000000") AND	(COUNT1<="101101110001101100000000") ) THENCLK_1HZ<='1'; ELSIF ((COUNT1<="010110111000110110000000") AND(COUNT1>="000000000000000000000000")) THENCLK_1HZ<='0';IF COUNT1="101101110001101100000000" THENCOUNT1:="000000000000000000000000";END IF;END IF;IF ((COUNT2>="01011101110000") AND (COUNT2<="10111011100000")) THENCLK_1KHZ<='1';ELSIF ((COUNT2<="01011101110000")AND(COUNT2>="00000000000000")) THENCLK_1KHZ<='0';IF(COUNT2="10111011100000") THENCOUNT2:="00000000000000";END IF;END IF;END IF;END PROCESS;
END BHV;

电路连接与效果描述:

最终是实现了俩个LED不同频率的亮灭:

 

级联分频/计时器实现时钟的效果:

有人在设计时钟时想得十分麻烦,又是10分频器,又是6分频器,又是12分频,又是60分...

其实时间的进位关系是一目了然的,

我们只需要给每个分频器写一个到达某个特定时分进位的逻辑,然后将这个逻辑进行级联,即可只靠俩种分频器即可做到时钟的效果:

这里我明显当年没考虑到一天是有24小时的,毕竟是个大学的课设,并未想得做得完善

但其中器件的逻辑还是设计得清晰的:

Q_OUT                 用于分频器后的进位级联,计数到分频计数器逻辑定义的极限

                           (10或者6 )时就会在这个输出口产生一个进位信号,然后分频计数器

                             就会 重新开始计数

CNT[0]~CNT[3]    是一个提供当前分频/计数器 计数值的总线,(二进制表示0~9)

en                         是一个使能,直接连接了VCC,(其实可以不定义这个输入)

                             但定义了以后可以实现其他复杂的片选功能,实现想开就开,想关就关

                             的灵活分频计时功能把

    

四位计数器(10分频)的内部硬件描述代码:

LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;ENTITY COUNT_10 ISPORT(clk,clr,en:IN STD_LOGIC;qa1,qb1,qc1,qd1,Q_OUT:OUT STD_LOGIC);
END COUNT_10;ARCHITECTURE rtl OF COUNT_10 IS
SIGNAL count_4:STD_LOGIC_VECTOR(3 DOWNTO 0);
BEGINqa1<=count_4(0);qb1<=count_4(1);qc1<=count_4(2);  qd1<=count_4(3);
PROCESS(clk,clr)BEGINIF(clr='1')THENcount_4<="0000";ELSIF(clk'EVENT AND clk='1')THENIF(en='1')THENIF(count_4="1001")THENcount_4<="0000";Q_OUT<='1';ELSEcount_4<=count_4+'1';Q_OUT<='0';END IF;END IF;END IF;
END PROCESS;
END rtl;

接口与变量作用定义:

PORT(clk,clr,en:IN STD_LOGIC;qa1,qb1,qc1,qd1,Q_OUT:OUT STD_LOGIC);

定义器件包含的输入输出接口

SIGNAL count_4:STD_LOGIC_VECTOR(3 DOWNTO 0);

定义了一个四位的STD_LOGIC_VECTOR信号count_4,用于存储计数器的值。

qa1, qb1, qc1, qd1分别被赋值为count_4的四位

计数器过程:

clr为高电平时,计数器count_4被清零。

clk的上升沿到来(clk'EVENT AND clk='1')且en为高电平时,计数器进行更新:

如果count_4的值为1001(即十进制的10),则计数器被清零,并且Q_OUT输出高电平。否则,计数器加1,并且Q_OUT输出低电平。

数码管分频计数逻辑输出器:

最后还有个原始接收1khz信号,以及各级分频计时器的 CNT[0]~CNT[3]  计时输出来对数码管进行段选和位选的逻辑器件,它也是需要接收一个clk时钟信号进行段选位选的

它的完整代码如下:

LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;ENTITY SMG_WXQ ISPORT(CLK:IN STD_LOGIC;C_IN1:IN STD_LOGIC_VECTOR(3 DOWNTO 0);C_IN2:IN STD_LOGIC_VECTOR(3 DOWNTO 0);C_IN3:IN STD_LOGIC_VECTOR(3 DOWNTO 0);C_IN4:IN STD_LOGIC_VECTOR(3 DOWNTO 0);C_OUNT:BUFFER STD_LOGIC_VECTOR(6 DOWNTO 0);SMG_WX:out std_logic_vector(7 downto 0)	);
END SMG_WXQ;ARCHITECTURE rtl OF SMG_WXQ IS
BEGIN
process(clk)
variable cnt : integer range 0 to 3 := 0;BEGINIF CLK'EVENT AND CLK = '1' THENIF cnt=0 THEN SMG_WX<="00000001";case C_IN1 iswhen "0000"=>C_OUNT<="1111110";when "0001"=>C_OUNT<="0000110";when "0010"=>C_OUNT<="1101101";when "0011"=>C_OUNT<="1111001";when "0100"=>C_OUNT<="0110011";when "0101"=>C_OUNT<="1011011";when "0110"=>C_OUNT<="1011111";when "0111"=>C_OUNT<="1110000";when "1000"=>C_OUNT<="1111111";when "1001"=>C_OUNT<="1111011";when others=>C_OUNT<="0000000";end case;cnt:=cnt+1;ELSIF cnt=1 THEN SMG_WX<="00000010";case C_IN2 iswhen "0000"=>C_OUNT<="1111110";when "0001"=>C_OUNT<="0110000";when "0010"=>C_OUNT<="1101101";when "0011"=>C_OUNT<="1111001";when "0100"=>C_OUNT<="0110011";when "0101"=>C_OUNT<="1011011";when "0110"=>C_OUNT<="1011111";when others=>C_OUNT<="0000000";end case;cnt:=cnt+1;ELSIF cnt=2 THEN SMG_WX<="00000100";case C_IN3 iswhen "0000"=>C_OUNT<="1111110";when "0001"=>C_OUNT<="0000110";when "0010"=>C_OUNT<="1101101";when "0011"=>C_OUNT<="1111001";when "0100"=>C_OUNT<="0110011";when "0101"=>C_OUNT<="1011011";when "0110"=>C_OUNT<="1011111";when "0111"=>C_OUNT<="1110000";when "1000"=>C_OUNT<="1111111";when "1001"=>C_OUNT<="1111011";when others=>C_OUNT<="0000000";end case;cnt:=cnt+1;	 ELSIF cnt=3 THEN SMG_WX<="00001000";case C_IN4 iswhen "0000"=>C_OUNT<="1111110";when "0001"=>C_OUNT<="0110000";when "0010"=>C_OUNT<="1101101";when "0011"=>C_OUNT<="1111001";when "0100"=>C_OUNT<="0110011";when "0101"=>C_OUNT<="1011011";when "0110"=>C_OUNT<="1011111";when others=>C_OUNT<="0000000";END CASE;cnt:=0;END IF;END IF;END PROCESS;
END rtl;

 

最后的输入输出总线连接:

最后将讲到的四个主要器件、VCC、GND、数码管对应的引脚(并成总线形式),正确完整连接就组成了万年历:

但从这个设计我们发现,这个万年历并不完整!

从左往右看:只存在秒的个位、秒的十位、分的个位、分的十位,不存在小时!

 

编译下载效果如下:

这里的位选有些问题,而且我还没进编写空开 分与秒 位置的冒号显示:

 

 

回忆与感悟 :

这样接近底层对CLK时钟信号进行自由编程的感受释放奇妙,让我感觉任何信号的运转并不是凭空而来的,而是我自己靠着抽丝引线一点一点连接起来的!

现在许多STM32的编程都是调用库函数,导致很多人连寄存器都摸不到

而我从51、CPLD、汇编、硬件描述语言开始缓慢往上爬,到后来学习MSP432库函数残缺不完整,自己用库函数+寄存器混编,到STM32,操作系统,到现在学习树莓派、上位机

深刻感受到,编程的上限永远在底层,就像皇帝智力国家一样,只接触到大臣(调用库),只会在后面被底层人架空,然后终有一天被底层错误搅合得摸不着头脑。

如果底层都是直接可以被我摸清调遣的,那整个系统的逻辑就基本没有不明朗的地方了,出错也能比其余人更快找到病灶!

这篇关于VHDL/CPLD硬件描述语言:2022年做的万年历实验的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1022385

相关文章

【STM32】SPI通信-软件与硬件读写SPI

SPI通信-软件与硬件读写SPI 软件SPI一、SPI通信协议1、SPI通信2、硬件电路3、移位示意图4、SPI时序基本单元(1)开始通信和结束通信(2)模式0---用的最多(3)模式1(4)模式2(5)模式3 5、SPI时序(1)写使能(2)指定地址写(3)指定地址读 二、W25Q64模块介绍1、W25Q64简介2、硬件电路3、W25Q64框图4、Flash操作注意事项软件SPI读写W2

STM32(十一):ADC数模转换器实验

AD单通道: 1.RCC开启GPIO和ADC时钟。配置ADCCLK分频器。 2.配置GPIO,把GPIO配置成模拟输入的模式。 3.配置多路开关,把左面通道接入到右面规则组列表里。 4.配置ADC转换器, 包括AD转换器和AD数据寄存器。单次转换,连续转换;扫描、非扫描;有几个通道,触发源是什么,数据对齐是左对齐还是右对齐。 5.ADC_CMD 开启ADC。 void RCC_AD

HNU-2023电路与电子学-实验3

写在前面: 一、实验目的 1.了解简易模型机的内部结构和工作原理。 2.分析模型机的功能,设计 8 重 3-1 多路复用器。 3.分析模型机的功能,设计 8 重 2-1 多路复用器。 4.分析模型机的工作原理,设计模型机控制信号产生逻辑。 二、实验内容 1.用 VERILOG 语言设计模型机的 8 重 3-1 多路复用器; 2.用 VERILOG 语言设计模型机的 8 重 2-1 多

61.以太网数据回环实验(4)以太网数据收发器发送模块

(1)状态转移图: (2)IP数据包格式: (3)UDP数据包格式: (4)以太网发送模块代码: module udp_tx(input wire gmii_txc ,input wire reset_n ,input wire tx_start_en , //以太网开始发送信

机器视觉硬件选型根据某项目相机镜头

一 项目总需求 1、大视野检测需求: (1)大视野: ①产品尺寸15.6寸屏幕,产品大小:350mm x 225mm; ②产品料盘尺寸大小:565mm x 425mm; ③工作距离:880mm;检测精度:500μm; 1、大视野检测需求: (1)大视野: ①产品尺寸15.6寸屏幕,产品大小:350mm x 225mm; ②产品料盘尺寸大小:565mm x 425mm; 工作距离:

LTspice模拟CCM和DCM模式的BUCK电路实验及参数计算

关于BUCK电路的原理可以参考硬件工程师炼成之路写的《 手撕Buck!Buck公式推导过程》.实验内容是将12V~5V的Buck电路仿真,要求纹波电压小于15mv. CCM和DCM的区别: CCM:在一个开关周期内,电感电流从不会到0. DCM:在开关周期内,电感电流总会到0. CCM模式Buck电路仿真: 在用LTspice模拟CCM电路时,MOS管驱动信号频率为100Khz,负载为10R(可自

HCIA--实验十:路由的递归特性

递归路由的理解 一、实验内容 1.需求/要求: 使用4台路由器,在AR1和AR4上分别配置一个LOOPBACK接口,根据路由的递归特性,写一系列的静态路由实现让1.1.1.1和4.4.4.4的双向通信。 二、实验过程 1.拓扑图: 2.步骤: (下列命令行可以直接复制在ensp) 1.如拓扑图所示,配置各路由器的基本信息: 各接口的ip地址及子网掩码,给AR1和AR4分别配置

学习硬件测试05:NTC(ADC)+正弦波(DAC)+DMA(ADC+DAC)(P73、P76、P78)

文章以下内容全部为硬件相关知识,鲜有软件知识,并且记的是自己需要的部分,大家可能看不明白。 一、NTC(ADC) 1.1实验现象 本实验用 NTC 采集温度,数码管实时显示温度数据(整数),左下角 USB 小串口每隔 1S 打印温度信息。 1.2硬件电路 NTC 电阻是一个模拟温度传感器,随着温度的升高,电阻值逐渐减小。电路简单介绍如下: 电源滤波电容在 25℃ 室温下 NTC 电

集运系统需要与哪些硬件设备集成?

随着电商和跨境贸易的不断发展,集运服务越来越受到海外用户的青睐。集运系统作为一种高效的跨境物流管理工具,可以协调各个环节之间的物流流程,提高物流效率和管理水平,被越来越多的集运企业采用。而集运系统作为集运服务的重要组成部分,也需要配套相应的硬件设备才能更好地支持跨境集运业务。下面就来介绍一下集运系统需要哪些硬件设备支持呢? 1.PDA:是一种便携式电子设备,可以轻松地进行数据采集和处理,具有移

OpenGL/GLUT实践:流体模拟——数值解法求解Navier-Stokes方程模拟二维流体(电子科技大学信软图形与动画Ⅱ实验)

源码见GitHub:A-UESTCer-s-Code 文章目录 1 实现效果2 实现过程2.1 流体模拟实现2.1.1 网格结构2.1.2 数据结构2.1.3 程序结构1) 更新速度场2) 更新密度值 2.1.4 实现效果 2.2 颜色设置2.2.1 颜色绘制2.2.2 颜色交互2.2.3 实现效果 2.3 障碍设置2.3.1 障碍定义2.3.2 障碍边界条件判定2.3.3 障碍实现2.3.