ZYNQ——脉宽调制之呼吸灯实现

news2024/11/14 18:18:50

文章目录

  • 原理简介
  • 实验代码
  • 软件仿真
  • 板上验证


原理简介

呼吸灯的实现过程就是把不同占空比的脉冲输出后加在LED上,LED灯就会显示不同的亮度,通过不断地调节方波的占空比,LED灯的亮度也会跟着变化,看起来就像是“呼吸”一样。
要得到不同占空比的脉冲,就要采用脉宽调制(Pulse Width Modulation, PWM)的方法,脉宽调制是比较常用的模块,实际应用中比如电机转速的控制,电灯亮暗的调节等,脉宽调制的示意图如下。
在这里插入图片描述
用一个N比特的计数器,其最大值可以表示为2的N次方,最小值0,计数器以一个给定的值为步进值进行累加,加到最大值后会溢出,然后进入下一个累加周期。当计数器的值大于某一门限时(注意,这里的门限值不是固定不变的,而是变化的),脉冲输出高,否则输出低,这样就可以完成上面图中红色线所示的脉冲占空比可调的脉冲输出。
计数器的步进值可以根据输出频率计算:step value = 输出频率 × 2 n 系统时钟频率 \frac{输出频率×2^n}{系统时钟频率} 系统时钟频率输出频率×2n


实验代码

本次实验中用到的代码有两个模块,首先第一个模块是脉宽调制模块,其代码如下。

`timescale 1ns / 1ps

module pwm 
# (parameter N = 16)   //端口使用的参数在这里定义
(
    input clk,
    input rst,
    input[N-1:0] period,  //步进值,根据想要的输出频率计算得到
    input[N-1:0] threshold,  //与count进行比较的门限值(可变的)
    output pwm_out
);

reg[N-1:0] period_reg;   //接收输入值对应的寄存器
reg[N-1:0] threshold_reg;
reg[N-1:0] count;  //以period为步进值的计数器
reg pwm_reg; 

assign pwm_out = pwm_reg;

always@(posedge clk or negedge rst)
begin
    if(rst == 0)
    begin
        period_reg <= {N{1'b0}};  //将N位二进制的0拼接
        threshold_reg <= {N{1'b0}};
    end
    else
    begin
        period_reg <= period;  //将输入值存放在各自的寄存器中
        threshold_reg <= threshold;
    end
end

always@(posedge clk or negedge rst)
begin
    if(rst == 0)
        count <= {N{1'b0}};
    else
        count <= count + period_reg;  //计数器累加
end

always@(posedge clk or negedge rst)
begin
    if(rst == 0)
        pwm_reg <= 1'b0;
    else
    begin
        if(count >= threshold_reg)  //将count值与输入的门限值比较,大于门限则将脉冲输出置为1,小于则置为0
            pwm_reg <= 1'b1;    
        else
            pwm_reg <= 1'b0;
    end
end

第二个模块是用来设置输入参数的,其代码如下。

`timescale 1ns / 1ps

module led_breathing(
    input clk,
    input rst,
    output led
);

localparam STEP = 32'd100000;   //threshold对应的步进值
localparam MIN_VALUE = 32'h6fffffff; //threshold最小值,减到比此值更小时就进行加操作 
localparam MAX_VALUE = 32'hffffffff; //threshold最大值,加到比此值更大时就进行减操作 

localparam IDLE = 0;      //空闲
localparam PWM_PLUS = 1;  //加操作
localparam PWM_MINUS = 2;  //减操作 
localparam PWM_GAP = 3;    //间隔,判断下次是加操作是减操作

wire pwm_out;  //脉冲输出
reg pwm_flag;  //加减操作的标志位,加操作设置为0,减操作设置为1
reg [1:0] state;  //四个状态
reg [31:0] period; //count的步进值
reg [31:0] threshold; 
reg [31:0] timer;    //PWM_GAP状态下使用

assign led = ~pwm_out;  //pwm_out输出高电平时,led亮,led是低电平有效的

always@(posedge clk or negedge rst)
begin
    if(rst == 1'b0)
    begin
        pwm_flag <= 1'b0;
        period <= 32'd0;
        threshold <= 32'd0;
        timer <= 32'd0;
        state <= IDLE;
    end
    else
        case(state)
            IDLE:
            begin
                period <= 32'd17179;  //period = 200*2^32/50000000,pwm=200Hz
                state <= PWM_PLUS;    //状态设置为加
                threshold <= MIN_VALUE;  //threshold的初始值设置为最小值
            end
            PWM_PLUS:
            begin
                if(threshold > MAX_VALUE - STEP)  //判断threshold的值是否超过了最大值,超过了就将加减操作状态标志设为减操作状态
                begin
                   pwm_flag <= 1'b1; 
                   threshold <= threshold - STEP; 
                end
                else
                begin
                    pwm_flag <= 1'b0; 
                    threshold <= threshold + STEP;
                end
                state <= PWM_GAP;  //完成一次加操作后进入PWM_GAP状态
            end
            PWM_MINUS:
            begin
                if(threshold < MAX_VALUE + STEP) //判断threshold的值是否低于了最小值,小于了就将加减操作状态标志设为加操作状态
                begin
                   pwm_flag <= 1'b0; 
                   threshold <= threshold + STEP; 
                end
                else
                begin
                    pwm_flag <= 1'b1; 
                    threshold <= threshold - STEP;
                end
                state <= PWM_GAP;  //完成一次减操作后进入PWM_GAP状态
            end
            PWM_GAP:
            begin
                if(timer >= 5000)  //100us的计数次数,做仿真时,这里设置的小一点
                begin
                    if(pwm_flag)  //根据加减操作标志决定下一次执行的操作
                        state <= PWM_MINUS;
                    else
                        state <= PWM_PLUS;
                    timer <= 32'd0;
                end
                else
                    timer <= timer + 32'd1;  //计数到达规定的时长后再执行下次加或减操作
            end
            default: state <= IDLE;
        endcase
end

pwm      //将第一个模块在这里进行例化
# (.N(32))
pwm_inst(
    .clk(clk),
    .rst(rst),
    .period(period),
    .threshold(threshold),
    .pwm_out(pwm_out)
);
endmodule

软件仿真

本实验用到的仿真测试代码如下。

`timescale 1ns / 1ps

module led_breathing_sim();
reg clk;
reg rst;
wire led;

initial
begin 
    clk = 0;
    rst = 0;
    #100
    rst = 1;
end

always #10 clk = ~clk;

led_breathing uut_led_breathing(
    .clk(clk),
    .rst(rst),
    .led(led)
);
endmodule

仿真的结果如下图所示。
在这里插入图片描述
上图中,pwm_out就是脉宽调制之后的输出波形,而led就是pwm_out信号的翻转,可以看到,波形的占空比各不相同。
代码中设置的计数器的步进值period是200Hz对应的值,200Hz对应的周期就是5ms,将上面的仿真图放大可以看到,尽管每个方波的占空比不同,但是其周期都是5ms。
在这里插入图片描述
当时看代码的时候挺头晕的,搞不太懂为啥输出的方波波形的占空比各不相同。我将代码中的几个十六进制数转化为十进制数看,首先,threshold对应的最小值是1879048191(十六进制的6fffffff),最大值是4294967295(十六进制的ffffffff),而其步进值是100000,也就是说,从1879048191到4294967295,每次加100000,需要24159次;count对应的最小值是0,最大值就是自动溢出后,也就是4294967295,count的步进值是period=17179,从0到溢出需要250013次。两者差不多是十倍的关系,而且有一点不太一样的是threshold加到最大值后不是直接掉到最小值,而是一步步减下来,而count则是加满溢出,相当于从0开始新一轮的计数。
根据上面的分析,我简单的画了一个示意图,如下图所示。
在这里插入图片描述
按理说,count从0到溢出应该对应大概10个这样的波形,但是为了绘图清楚,这里绘制了简单的示意图,阐明其中的原理即可。而且这里我用直线替代了阶梯上升和阶梯下降,因为这些小的阶梯在宏观上来看可以抽象成一个点。上图中,蓝色线(count)高于黑色线(threshold)的部分,输出的脉冲为高;蓝色线低于黑色线的部分,输出脉冲为低。通过画一幅这样的示意图就能清楚地反映代码中是怎么生成占空比不同的波形了。


板上验证

本实验中的引脚分配如下图所示。
在这里插入图片描述
通过上面的仿真,只看输出信号led的波形,其波形的占空比在不断地变化,表现在开发板的LED亮灭特性上就像“呼吸”一般,呼吸灯实现的动图如下图所示。
请添加图片描述


以上就是ZYNQ——脉宽调制之呼吸灯实现的全部内容了!
参考资料:
ZYNQ 开发平台 FPGA 教程 AX7020

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

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

相关文章

陪诊小程序系统|陪诊软件开发|陪诊系统功能和特点

随着医疗服务的逐步改善和完善&#xff0c;越来越多的人群开始走向医院就诊&#xff0c;而其中不少人往往需要有人陪同前往&#xff0c;这就导致了许多矛盾与问题的发生&#xff0c;比如长时间等待、找不到合适的陪诊人员等。因此为人们提供一种方便快捷的陪诊服务成为了一种新…

如何挽救误剪切的TF卡数据 ?三招救援

在日常使用TF卡过程中&#xff0c;我们可能会遇到误操作导致数据被剪切并丢失的情况。这无疑给我们带来了困扰&#xff0c;因为我们可能丢失了重要的照片、视频、文档等文件。然而&#xff0c;不必过于担心&#xff0c;因为TF卡数据剪切后的恢复仍然有希望。本文将向您介绍几种…

基于DeepLabv3Plus开发构建人脸人像分割系统

在图像分割领域中有不少优秀出色的网络&#xff0c;DeepLab系列就是其中非常经典的分支之一&#xff0c;在之前的很多项目中陆续都已经有接触到了&#xff0c;在处理图像分割中表现出色。 DeepLabV3Plus是一种用于语义分割任务的深度学习模型&#xff0c;它是DeepLab系列模型的…

市场营销书籍推荐,这些书帮你学好营销

市场营销一直是商业运作中的重要环节&#xff0c;因此市场营销的知识一直备受关注。在这篇文章中&#xff0c;小编将向你推荐三本经典市场营销书籍&#xff0c;通过阅读这些书籍能让你更深入了解市场营销的基本概念和策略。 1、《经理人参阅&#xff1a;市场营销》 《经理人参…

高效游戏项目进度管理指南:打造顺畅开发之路!

完成一个游戏项目可能是一项具有挑战性的任务&#xff0c;特别是当你刚刚开始时。为了确保你的项目在预算内按时运行&#xff0c;制定计划并管理你的进度是很重要的。以下是一些帮助你管理游戏项目进度的技巧。 1、明确游戏目标: 在开始之前&#xff0c;你必须明确项目的范围以…

附件类文件存储在环信和不存储在环信时的两种实现方式

场景一: 附件类文件存储在环信服务器 使用环信EMChatManager#downloadAttachment下载附件方案 &#xff08;本篇文章以图片消息为例&#xff0c;其他附件类消息类似&#xff09;&#xff1a; 一、 通过EMFileMessageBody#getLocalUrl判断有没有本地文件&#xff1b; EMImageM…

ROS学习篇之硬件准备(零)-thinkbook16+锐龙版 安装ubuntu20.04遇到的各种坑

文章目录 一.计算机配置二.遇到的问题及解决办法1.键盘失灵2.无法联wifi3.蓝牙搜索不到设备4.无法开热点 三.最后的感想 一.计算机配置 CPU: AMD R7 6800H &#xff08;网卡&#xff0c;娱乐大师读出来的不对&#xff0c;在windos系统下&#xff0c;联想管家读出来网卡的型号是…

C++数据结构笔记(5)栈的顺序存储结构实现

1.对于栈和队列&#xff0c;相比于数组和线性表&#xff0c;使用规则受到了限制&#xff0c;因此也被称为“受限线性表”。 2.对于栈类型来说&#xff0c;元素符合先进后出的规律&#xff0c;且栈中的元素不能自由遍历。 3.栈的顺序存储结构简称为顺序栈&#xff0c;其思想是…

神经网络之VGG

目录 1.VGG的简单介绍 1.2结构图 3.参考代码 VGGNet-16 架构&#xff1a;完整指南 |卡格尔 (kaggle.com) 1.VGG的简单介绍 经典卷积神经网络的基本组成部分是下面的这个序列&#xff1a; 带填充以保持分辨率的卷积层&#xff1b; 非线性激活函数&#xff0c;如ReLU&a…

制作投票链接小程序教程,让你的活动更具吸引力与效果

相信投票链接是一种方便快捷的投票方式&#xff0c;不仅可以用于活动中的投票&#xff0c;还可以用于品牌营销和市场调研。投票链接是一种非常方便的方式来进行在线投票。这里就推荐一个免费制作投票活动的网站&#xff1a;乔拓云&#xff0c;创建简单、免费使用、操作灵活。支…

Linux环境搭建(三)— 搭建数据库服务器

linux &#xff08;ubuntu&#xff09;安装mysql 和环境配置 一、安装MySql二、配置环境三、外网访问四、重置密码五、卸载 写在前面&#xff1a; 本文默认你的Linux系统已经安装vim&#xff0c;yum等&#xff0c;如你使用的是一个全新的操作系统&#xff0c;移步上一篇开始配置…

回波数据adc_data.bin解析(附MATLAB程序)

毫米波雷达系统性能参数分析 1、xWR1642—DCA1000 TI目前有两款采集卡TSW1400和DCA1000&#xff0c;可以为xWR1243/1443和1642毫米波雷达进行回波数据采集。本文将主要介绍几款雷达分别用2款采集卡数据采集的回波数据格式以及MATLAB数据解析程序。 1、xWR1642—DCA1000 &…

【Servlet学习二】Servlet原理(Tomcat) ServletAPI

目录 &#x1f31f;一、Servlet运行原理 &#x1f308;1、Servlet的执行原理&#xff08;重点&#xff09; &#x1f308;2、Tomcat伪代码的简单理解 2.1 Tomcat初始化流程 2.2 Tomcat处理请求流程 2.3 Servlet 的 service 方法的实现 &#x1f31f;二、Servlet API 详…

SFP3012-ASEMI代理MHCHXM(海矽美)快恢复二极管SFP3012

编辑&#xff1a;ll SFP3012-ASEMI代理MHCHXM&#xff08;海矽美&#xff09;二极管SFP3012 型号&#xff1a;SFP3012 品牌&#xff1a;MHCHXM&#xff08;海矽美&#xff09; 封装&#xff1a;TO-247AB 恢复时间&#xff1a;≤65ns 正向电流&#xff1a;30A 反向耐压&a…

初学spring5(三)依赖注入(DI)

学习回顾&#xff1a;初学spring (五) 快速上手spring Dependency Injection 一、概念 依赖注入&#xff08;Dependency Injection,DI&#xff09;。依赖 : 指Bean对象的创建依赖于容器 . Bean对象的依赖资源 .注入 : 指Bean对象所依赖的资源 , 由容器来设置和装配 . 二、构造器…

SQL-每日一题【180.连续出现的数字】

题目 表&#xff1a;Logs 编写一个 SQL 查询&#xff0c;查找所有至少连续出现三次的数字。 返回的结果表中的数据可以按 任意顺序 排列。 查询结果格式如下面的例子所示&#xff1a; 示例 1: 解题思路 1.要查询至少连续出现三次的数字&#xff0c;则可以转化为&#xff08;…

软考A计划-系统集成项目管理工程师-项目整体管理-下

点击跳转专栏>Unity3D特效百例点击跳转专栏>案例项目实战源码点击跳转专栏>游戏脚本-辅助自动化点击跳转专栏>Android控件全解手册点击跳转专栏>Scratch编程案例点击跳转>软考全系列 &#x1f449;关于作者 专注于Android/Unity和各种游戏开发技巧&#xff…

【C#】文件拖拽,获取文件路径

系列文章 【C#】编号生成器&#xff08;定义单号规则、固定字符、流水号、业务单号&#xff09; 本文链接&#xff1a;https://blog.csdn.net/youcheng_ge/article/details/129129787 【C#】日期范围生成器&#xff08;开始日期、结束日期&#xff09; 本文链接&#xff1a;h…

vue2实现一个上边为搜索,下面为复选框选中后,右侧显示已选中组件

目录 vue2实现一个上边为搜索&#xff0c;下面为复选框选中后&#xff0c;右侧显示已选中组件component / ProjectSelectItem.vue使用组件效果 vue2实现一个上边为搜索&#xff0c;下面为复选框选中后&#xff0c;右侧显示已选中组件 component / ProjectSelectItem.vue <…

对于小米随手吸尘器各种问题的初始办法

本人在什么值得买发过&#xff0c;现在只不过是为了让账号看起来更丰盈一点&#xff0c;现在再发一次。 充不进去电/使用的时候短暂吸气&#xff0c;这两个问题&#xff0c;在上个月的时候我就已经发现了这个问题。 然后我就拆开了那个主机&#xff0c;就是那个保温杯一样的东…