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,操作系统,到现在学习树莓派、上位机

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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/20375.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Keil 5】Keil 5下载安装激活到2032年(含MDK、C51、STM32单片机)+附带百度网盘链接

这里写目录标题 安装包、激活文件下载1.双击mdk 514开始安装2.一路点next&#xff0c;信息随便写即可3.激活4.安装STM325.激活c51 安装包、激活文件下载 解压密码&#xff1a;lantongxue 链接&#xff1a;https://pan.baidu.com/s/15Aukt0j1HCFyHBE6whuDeg?pwdsjyh 提取码&…

Streamsets-JDBC模式使用更新时间字段数据同步

StreamSets的开源地址&#xff1a;https://github.com/streamsets/datacollector-oss Streamsets官网地址&#xff1a;https://streamsets.com/ Streamsets文档地址&#xff1a;https://docs.streamsets.com/portal/datacollector/3.16.x/help/index.html 我又来写Streamsets了…

LangChain实战技巧之四:当模型(Model)不支持Tool/Function的解决办法

文心大模型两大主力模型已全面免费&#xff0c;可参考我之前发的文章 AI菜鸟向前飞 — 今日三则AI相关新闻 但是&#xff0c;这些模型原生并不支持Tool/Function Call 如下所示&#xff1a; tool def greeting(name: str):向朋友致欢迎语return f"你好啊, {name}"…

基于LabVIEW虚拟示波器设计

随着计算机技术的发展&#xff0c;传统仪器开始向计算机化的方向发展。虚拟仪器是90年代提出的新概念。虚拟仪器技术的提出与发展&#xff0c;标志着二十一世纪自动测试与电子测量仪器领域技术发展的一个重要方向。所谓虚拟仪器&#xff0c;就是在通用的计算机平台上定义和设计…

TDR原理的介绍

目录 简介 简单定义 TDR测试原理 简介 时域和频域就像孪生兄弟一样&#xff0c;经常在测试测量领域同时出现&#xff0c;可谓是工程师们分析问题和解决问题的两大法宝。所以&#xff0c;在某些测试场景中&#xff0c;如果有时域信息的护法&#xff0c;咱们就能从时频域两个维…

【普通切换】【DC-based handover】【DAPS】协议栈分析

移动网络切换 移动通信中切换是保证终端业务的基本流程&#xff0c;而切换时延是终端(UE)不能与任何基站交互(传递)用户面数据包的最短时间。 在5G(NR)网络中当终端(UE)接收到切换命令时&#xff0c;将断开与源小区的连接向目标小区发起随机接入过程。在此期间终端(UE)的数据传…

牛客ONT45 距离是K的二叉树节点【中等 宽度优先遍历 Java/Go/PHP/C++】

题目 题目链接&#xff1a; https://www.nowcoder.com/practice/e280b9b5aabd42c9b36831e522485622 思路 图&#xff0c;队列 构件图&#xff0c;直接从target出发&#xff0c;扩展到第k层就是答案Java代码 import java.util.*;/** public class TreeNode {* int val 0;* …

架构设计之安全性属性深度剖析:从理论到实践的完美融合

文章目录 引言一、安全性属性的理论探讨1.1 定义说明1.2 安全原则1.3 安全模型1.4 安全机制 二、安全性属性的实践应用2.1 安全风险评估2.2 架构设计中的安全考虑2.3 技术手段和工具2.4 团队协作与沟通2.5 安全政策和流程2.6 合规性和标准2.7 持续监控和改进 三、理论与实践的融…

Python函数进阶

文章目录 1 函数多返回值2 函数多种传参方式2.1 位置参数2.2 关键字参数2.3 缺省参数2.4 不定长参数 3 匿名函数函数作为参数传递lambda匿名函数 1 函数多返回值 def test_return():return 1,2,3 x,y,z test_return() print(x) print(y) print(z)2 函数多种传参方式 2.1 位置参…

0基础认识C语言(理论+实操3)

所有籍籍无名的日子里 我从未看轻自己半分 小伙伴们&#xff0c;一起开始我们今天的话题吧 一、算法操作符 1.双目操作符 为何叫双目操作符呢&#xff1f;其实是因为我们进行加减乘除的时候&#xff0c;至少得需要两个数字进行这些运算&#xff0c;而这个数字就被称为操作数…

基于单片机的微型嵌入式温度测量仪的设计与实现分析

摘要 &#xff1a; 作为信息技术中重要的技术手段之一嵌入式单片机系统已经被应用到越来越多不同的行业领域中。如&#xff0c;各种手持监测设备、智能家电设备等。当前展开对单片机的微型嵌入式温度测量仪的设计和实现研究&#xff0c;从微型嵌入式单片机相关理论入手&#xf…

【实战教程】构建可复用的 Spring Boot starter 微服务组件

案例 Demo&#xff1a;https://gitee.com/regexpei/coding-trainee/tree/demo/20240526_starter 介绍 在 Spring Boot 中&#xff0c;starter 启动依赖就像一个“开箱即用”的工具箱&#xff0c;它包含了第三方组件的配置和依赖&#xff0c;让我们无需手动配置和添加这些组件。…

【多目标跟踪】《FlowMOT: 3D Multi-Object Tracking by Scene Flow Association》论文阅读笔记

0.论文 论文地址链接:https://arxiv.org/pdf/2012.07541v1 通过流的方式跟踪是一个比较新颖的点,所以这里比较关注运动跟踪,是如果做到流的跟踪来预测目标的位置以及ID绑定的。 FlowMOT的框架结构如下所示,本中会主要关注下运动跟踪、数据关联、ID分配、新生/消亡…

python替换占位符为变量,实现读取配置文件

文章目录 背景1、定义正则表达式2、替换变量占位符3、实现功能 背景 使用python编写小工具&#xff0c;有一个配置文件&#xff0c;希望实现类似shell命令的&#xff0c;定义变量并且使用${}或者$来引用。如果有好的建议欢迎讨论。 配置文件示例内容如下: D:\project\test\pr…

Arrays(操作数组工具类)、Lambda表达式

package exercise;import java.util.Arrays;public class ArraysDemo {public static void main(String[] args) {int[] arr {1, 2, 3, 4, 5};//将数组变成字符串System.out.println(Arrays.toString(arr));//二分查找法查找元素//细节1&#xff1a;1.数组必须是有序的 2.元素…

OpenCASCADE入门(2)——openCasCade7.6.0版本的exe方式安装,vs2017环境配置,编译和使用draw

3rd party Components | Open CASCADE Technology 目录 引出安装好vs2017和occt7.6设置环境变量 启动occt和编译关于custom.bat批处理文件双击运行 打开draw使用方式一&#xff1a;双击draw.bat批处理vs设置启动项 总结其他自定义信号和槽1.自定义信号2.自定义槽3.建立连接4.进…

路由器设置——隐藏SSID(隐藏WiFi名称)

参考来源&#xff1a; https://www.192ly.com/qiu-zhu/33315.htmlhttps://www.yunqishi.net/video/109743.html 一、什么是SSID? SSID是Service Set ldentifier的缩写&#xff0c;意思是服务集标识&#xff0c;简单来说SSID就是wifi的名字。 二、怎么隐藏SSID 将 开启SSI…

为什么要学习数据结构和算法

前言 控制专业转码学习记录&#xff0c;本科没学过这门课&#xff0c;但是要从事软件行业通过相关面试笔试基础还是要打牢固的&#xff0c;所以通过写博客记录一下。 必要性 1.越是厉害的公司&#xff0c;越是注重考察数据结构与算法这类基础知识 2.作为业务开发&#xff0c…

MMPose-RTMO推理详解及部署实现(上)

目录 前言1. 概述1.1 MMPopse1.2 MMDeploy1.3 RTMO 2. 环境配置3. Demo测试4. ONNX导出初探5. ONNX导出代码浅析6. 剔除NMS7. 输出合并8. LayerNormalization算子导出9. 动态batch的实现10. 导出修改总结11. 拓展-MMPose中导出ONNX结语下载链接参考 前言 最近在 MMPose 上看到了…

【NOIP2018普及组复赛】题2:龙虎斗

题2&#xff1a;龙虎斗 【题目描述】 轩轩和凯凯正在玩一款叫《龙虎斗》的游戏&#xff0c;游戏的棋盘是一条线段&#xff0c;线段上有 n n n 个兵营&#xff08;自左至右编号 1 ∼ n 1∼n 1∼n&#xff09;&#xff0c;相邻编号的兵营之间相隔 1 1 1 厘米&#xff0c;即棋…