PWM 呼吸灯实验

news2024/9/20 6:10:24

PWM 呼吸灯实验

FPGA实现一个PWM模块(硬件)来控制灯的亮灭。

实验原理

PWM本质上就是一个输出脉冲的硬件,通过改变一个周期高电平(占空比)的时间来对其他的硬件进行控制,比如电机。
呼吸灯的实现利用了人眼的视觉特性,控制灯亮和暗的间隔时间就形成了对灯亮度的调节。
通过一个N比特的计数器(溢出相当于从0开始)和一个值就可以实现一个占空比可调的脉冲输出。

实验步骤

  1. 设计PWM模块
  2. 用硬件描述语言实现设计
  3. 查看硬件设计,添加管脚约束和时钟约束
  4. 本地仿真
  5. 上板验证

实验记录

  1. 设计PWM模块
信号名称方向说明
clkin时钟输入
rstin异步输入复位,高有效
periodinPWM 脉宽周期(频率)控制。实际是每次计数的步进值,根据系统输入时钟可以计算出pwm输出频率
dutyin占空比,小于该值时输出低电平,否则输出高电平
pwm_outoutpwm输出
  1. 用硬件描述语言实现设计
    ax_pwm.v
`timescale 1ns / 1ps
module ax_pwm
#(
    parameter N = 16
)
(
    input clk,
    input rst,
    input [N-1:0] period,
    input [N-1:0] duty,
    output pwm_out
);


reg[N-1:0] period_r;
reg[N-1:0] duty_r;
reg[N-1:0] period_cnt;
reg pwm_r;

assign pwm_out = pwm_r;

always @(posedge clk or posedge rst)
begin
    if(rst==1)
    begin
        period_r <= {N{1'b0}};
        duty_r <= {N{1'b0}};
    end
    else
    begin
        period_r <= period;
        duty_r <= duty;
    end
end
    
always @(posedge clk or posedge rst)
begin
    if(rst==1)
        period_cnt <= {N{1'b0}};
    else
        period_cnt <= period_cnt + period_r;
end

always @(posedge clk or posedge rst)
begin
    if(rst==1)
    begin
        pwm_r <= 1'b0;
    end
    else
    begin
        if(period_cnt >= duty_r)
            pwm_r <= 1'b1;
       else
            pwm_r <= 1'b0;
    end
end

endmodule

PWM测试模块

`timescale 1ns / 1ps

module pwm_test(
    input  sys_clk_p,    // 时钟是一个200MHz的差分时钟
    input  sys_clk_n,
    input  rst_n,        // 复位由一个按键来控制,按键默认状态为高,所以低复位
    output wire led          // 输出给led
);
localparam CLK_FREQ = 200 ; //200MHz,周期为 1s/200MHz = 1/200 us
localparam US_COUNT = CLK_FREQ ; //1 us counter,200个时钟周期是1us 
localparam MS_COUNT = CLK_FREQ*1000 ; //1 ms counter  1个ms的周期计数

localparam DUTY_STEP = 32'd100000 ; //duty step, 占空比调整大小,单次调整 100000/2^32 = 0.000000000232
localparam DUTY_MIN_VALUE = 32'h6fffffff ; //duty minimum value, 最小占空比 0.437
localparam DUTY_MAX_VALUE = 32'hffffffff ; //duty maximum value, 最大占空比 0.999

localparam IDLE = 0; //IDLE state 
localparam PWM_PLUS = 1; //PWM duty plus state 
localparam PWM_MINUS = 2; //PWM duty minus state 
localparam PWM_GAP = 3; //PWM duty adjustment gap

wire pwm_out; //pwm output 
reg[31:0] period; //pwm step value 
reg[31:0] duty; //duty value 
reg pwm_flag ; //duty value plus and minus flag, 0: plus; 1: minus

reg[3:0] state; 
reg[31:0] timer; //duty adjustment counter 该测试模块计数的

assign led = ~pwm_out ; //led low active

wire clk;
// 差分转单端
IBUFDS IBUFDS_inst(
    .O(clk),
    .I(sys_clk_p),
    .IB(sys_clk_n)
);

always@(posedge clk or negedge rst_n) 
begin 
    if(rst_n == 1'b0) 
    begin  // 复位,设置初始值
        period <= 32'd0; 
        timer <= 32'd0; 
        duty <= 32'd0; 
        pwm_flag <= 1'b0 ; 
        state <= IDLE; 
    end
    else 
    case(state) 
        IDLE: 
        begin 
            // N位计数器,CLK Hz的时钟(周期1/CLK s),要输出n Hz的PWM波,PWM周期为1/n s,要在一个PWM周期计数完一轮,而一个周期会计数((1/n)/(1/CLK))次
            //  2^N/((1/n)/(1/CLK)) = 2^32*n/CLK  
            //  这个地方的时钟写的50M,PWM是800Hz的,周期0.00125s。
            period <= 32'd17179; //The pwm step value, pwm 200Hz(period = 200*2^32/50000000) 
            state <= PWM_PLUS; 
            duty <= DUTY_MIN_VALUE; 
        end 
        PWM_PLUS : 
        begin 
            if (duty > DUTY_MAX_VALUE - DUTY_STEP) //if duty is bigger than DUTY MAX VALUE minus DUTY_STEP , begin to minus duty value 
            begin 
                pwm_flag <= 1'b1 ; 
                duty <= duty - DUTY_STEP ; 
            end 
            else 
            begin 
                pwm_flag <= 1'b0 ; 
                duty <= duty + DUTY_STEP ; 
            end 
            state <= PWM_GAP ; 
        end
        PWM_MINUS : 
        begin 
            if (duty < DUTY_MIN_VALUE + DUTY_STEP) //if duty is little than DUTY MIN VALUE plus duty step, begin to add duty value 
            begin 
                pwm_flag <= 1'b0 ; 
                duty <= duty + DUTY_STEP ; 
            end 
            else 
            begin 
                pwm_flag <= 1'b1 ;
                duty <= duty - DUTY_STEP ; 
            end 
            state <= PWM_GAP ; 
        end 
        PWM_GAP: 
        begin 
            if(timer >= US_COUNT*100) //adjustment gap is 100us 
            begin 
                if (pwm_flag) 
                    state <= PWM_MINUS ; 
                else 
                    state <= PWM_PLUS ; 
                timer <= 32'd0; 
            end 
            else 
                begin 
                    timer <= timer + 32'd1; 
                end 
        end
        default: 
        begin 
            state <= IDLE; 
        end 
    endcase
end

ax_pwm
#(
.N(32)
)
ax_pwm_m0(
    .clk(clk),
    .rst(~rst_n),
    .period(period),
    .duty(duty),
    .pwm_out(pwm_out)
);

endmodule

  1. 查看硬件设计,添加管脚约束和时钟约束
    约束文件
set_property PACKAGE_PIN AE15 [get_ports led]
set_property PACKAGE_PIN AE14 [get_ports rst_n]
set_property PACKAGE_PIN AE5 [get_ports sys_clk_p]
set_property IOSTANDARD LVCMOS33 [get_ports led]
set_property IOSTANDARD LVCMOS33 [get_ports rst_n]
set_property IOSTANDARD DIFF_SSTL12 [get_ports sys_clk_p]
create_clock -period 5.000 -name sys_clk_p -waveform {0.000 2.500} [get_ports sys_clk_p]
  1. 本地仿真
    激励文件
`timescale 1ns / 1ps

module pwm_test_tb;
// Inputs
reg sys_clk_p;
wire sys_clk_n;
reg rst_n;
wire led ;

// Instantiate the Unit Under Test (UUT)
pwm_test uut (
	.sys_clk_p(sys_clk_p), 		
	.sys_clk_n(sys_clk_n), 	
	.rst_n		(rst_n),
	.led       (led)
);

initial begin
	// Initialize Inputs
	sys_clk_p = 0;
	rst_n = 0;

	// Wait 100 ns for global reset to finish
	#100;
      rst_n = 1;      

 end

always #2.5 sys_clk_p = ~ sys_clk_p;   //5ns一个周期,产生200MHz时钟源

assign sys_clk_n = ~ sys_clk_p;
   
endmodule

这里的PWM周期为1.25ms,和前面的分析相符。
在这里插入图片描述

  1. 上板验证
    加载后会产生类似流水灯的效果。

实验总结

  1. 时钟很重要,是硬件系统的心跳,有了时钟硬件才可以动起来。如果PWM模块没有时钟输入的话,就无法被驱动,无法正常工作。另外设计的时候不考虑时钟,将会无从下手。
  2. 逻辑调试和软件调试虽然形式有所不一样,但本质都是相同的,需要一级一级的分析问题出在哪里,不能慌张。
  3. 本地调试很有必要,可以看到更详细的信号,有利于找出问题。

问题记录

  1. 时序约束没让添加时钟的约束,不知道什么原因,手动添加。
  2. 上板的时候流水灯没亮,本地仿真发现led是一个蓝色的线,发现原因是少了一行assign语句,没把pwm的输出接出去。

参考资料

  1. PWM原理 PWM频率与占空比详解
  2. Xilinx 7系列SelectIO结构之IO标准和端接匹配(三)
  3. XILINX 原语的使用之 IBUFDS 差分转单端、OBUFDS 单端转差分

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

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

相关文章

谈谈如何用开源网关进行 API 管理

需求痛点 1.企业不清楚到底有多少个API&#xff0c;无法形成API资产管理等问题。 2.API在不同集群的生命周期问题。 3.API运行状态监控和告警问题。 4.API请求限流、流量控制以及安全等问题。 功能介绍 Apinto的API管理提供API生命周期控制&#xff1a;可管理所有API&…

Cortex-R52 GIC:Generic Interrupt Controller(一)

ARM Cortex-R52 GIC:Generic Interrupt Controller 1.关于GIC 1.1 GIC Overview ARM的中断控制器被称为GIC(Generic Interrupt Controller)&#xff0c;GIC是支持和管理系统中断的资源的模块。它支持中断优先级、中断路由到CPU或输出端口、中断抢占和中断虚拟化等功能。 中断…

深入浅出Rust核心概念:生命周期

简介 Rust是一种快速、安全、并发的系统级编程语言&#xff0c;它的设计目标是提供一种高效、内存安全的编程方式。而生命周期&#xff08;Lifetime&#xff09;是Rust语言中的一个核心概念&#xff0c;它与内存管理、函数传参和引用操作等方面密切相关。LZ将详细介绍Rust中生…

GitHub 开启 2FA 双重身份验证的方法

为什么要开启 2FA 自2023年3月13日起&#xff0c;我们登录 GitHub 都会看到一个要求 Enable 2FA 的重要提示&#xff0c;具体如下&#xff1a; GitHub users are now required to enable two-factor authentication as an additional security measure. Your activity on Git…

Matplotlib 轴标签和标题

我们可以使用 xlabel() 和 ylabel() 方法来设置 x 轴和 y 轴的标签。 实例 import numpy as np import matplotlib.pyplot as pltx np.array([1, 2, 3, 4]) y np.array([1, 4, 9, 16]) plt.plot(x, y)plt.xlabel("x - label") plt.ylabel("y - label")…

Java BIO

1.Java BIO(Blocking IO:同步并阻塞式IO)编程 1.1.基本介绍 1>.Java BIO就是传统的java io编程,其相关的类和接口在"java.io"包下; 2>.BIO(Blocking I/O): 同步阻塞,服务器实现模式为一个连接一个线程,即客户端有连接请求时服务器端就需要启动一个线程进行处…

深入分析,Redis为什么这么快?

我们都知道Redis很快&#xff0c;它QPS可达10万&#xff08;每秒请求数&#xff09; Redis为什么这么快&#xff1f; 基于内存实现高效的数据结构合理的数据编码合理的线程模型虚拟内存机制 基于内存实现 我们都知道内存读写是比磁盘读写快很多的。Redis是基于内存存储实现的…

电磁兼容原理、方法及设计的科普好文

什么是电磁兼容 电磁兼容性&#xff08;EMC&#xff09;是指设备或系统在其电磁环境中符合要求运行并不对其环境中的任何设备产生无法忍受的电磁干扰的能力。因此&#xff0c;EMC包括两个方面的要求&#xff1a;一方面是指设备在正常运行过程中对所在环境产生的电磁干扰不能超…

操作系统之调度

目录 什么是调度 进程调度的时机、切换、过程与方式 调度器/调度程序 调度算法 先来先服务算法 短作业优先算法 高响应比优先算法 时间片轮转算法 优先级调度算法 多级反馈队列调度算法 什么是调度 调度的三个层次 高级调度 中级调度 低级调度 总结如下&#xff1a; …

利用docker部署深度学习环境摆脱操作系统版本限制与cuda版本限制

利用docker部署深度学习环境摆脱操作系统版本限制与cuda版本限制 文章背景描述&#xff1a; 近期公司想给客户部署OCR文本识别项目&#xff0c;项目用到了tensorflow1.13&#xff0c;可支持该框架版本的cuda得低于10.2&#xff0c;但是客户要求的操作系统版本是Ubuntu22.04&…

学成在线笔记+踩坑(9)——课程发布,xxl-job+消息SDK实现分布式事务、页面静态化、Hystrix熔断降级

导航&#xff1a; 【黑马Java笔记踩坑汇总】JavaSEJavaWebSSMSpringBoot瑞吉外卖SpringCloud黑马旅游谷粒商城学成在线牛客面试题_java黑马笔记 目录 1 业务流程&#xff0c;入库缓存ESMinIO存静态化页面 2 分布式事务技术方案 2.1 回顾本地事务和分布式事务 2.2 什么是CA…

Nginx下载和使用

nginx: downloadhttp://nginx.org/en/download.html下载成功后打开 \nginx-x.xx.x\conf\nginx.conf 文件 #user nobody; worker_processes 1;#error_log logs/error.log; #error_log logs/error.log notice; #error_log logs/error.log info;#pid logs/nginx.pid…

国内top5正规好用纸黄金交易软件最新排名(2023评测版)

随着互联网技术的不断发展&#xff0c;网上投资理财变得越来越流行。而随着互联网理财产品的日益增多&#xff0c;越来越多的投资者开始选择纸黄金交易软件进行交易。然而&#xff0c;对于初入此行的投资者而言&#xff0c;如何选择合适的纸黄金交易软件显得尤为重要。 首先&…

PostgreSQL的数据类型有哪些?

数据类型分类 分类名称 说明 与其他数据库的对比 布尔类型PG支持SQL标准的boolean数据类型与MySQL中的bool、boolean类型相同&#xff0c;占用1字节存储空间数值类型整数类型有2字节的smallint、4字节的int、8字节的bigint&#xff1b;精确类型的小数有numeric&#xff1b;非精…

C语言CRC-8 ITU格式校验函数

C语言CRC-8 ITU格式校验函数 CRC校验基于前处理和后处理的不同&#xff0c;由不同的协会标准推出了一些不同格式的版本。这里介绍CRC-8 ITU格式的校验函数。 CRC-8 ITU格式特征 标准CRC-8的校验函数参考&#xff1a; C语言标准CRC-8校验函数 CRC-8 ITU格式和标准CRC-8校验算…

Mybatis是什么?Mybatis入门程序

一、框架是什么&#xff1f; 1.java常见框架&#xff1a; SSM三大框架&#xff1a;SpringMybatisSpringMvc 2.什么是框架&#xff1f; 框架本身就是对于通用代码的封装,提前写好的类和方法&#xff0c;我们在做项目的时候直接引入这些框架(本质就是引入类…

Matlab 最远点采样(FPS,二维版本)

文章目录 一、简介二、实现代码三、实现效果参考资料一、简介 简而言之,该方法是通过迭代、增量的方式来选择距离前一个点集最远的点从而实现数据的采样过程。其算法步骤如下所述: (1)从点集 S S S中随机选择一个点

【Linux基本指令和权限(1)】

本文思维导图&#xff1a; 文章目录 一、Linux操作的特点二、使用指令从Xhell登录云服务器三、基本指令1.ls指令2. pwd指令&#xff1a;3.cd指令4. touch指令5. rm指令 写在最后 Linux是一个操作系统&#xff0c;操作系统是一款做软硬件管理的软件。 一、Linux操作的特点 Li…

报错解决:关于swagger的Caused by: java.lang.NullPointerException: null

目录 一、遇到问题 二、解决办法 方法一 方法二 方法二中导入依赖报错的解决方案 一、遇到问题 在往springboot项目里面添加swagger时候&#xff0c;启动的时候就报了如下null了的错误 遇到问题的报错提示&#xff1a; Error starting ApplicationContext. To display the…

200人 500人 园区网设计

实验要求&#xff1a; ① 设置合理的STP优先级、边缘端口、Eth-trunk ② 企业内网划分多个vlan &#xff0c;减少广播域大小&#xff0c;提高网络稳定性 ③ 所有设备&#xff0c;在任何位置都可以telnet远程管理 ④ 出口配置NAT ⑤ 所有用户均为自动获取ip地址 ⑥ 在企业…