06 PWM呼吸灯实验
软件版本:VIVADO2021.1
操作系统:WIN10 64bit
硬件平台:适用XILINX A7/K7/Z7/ZU/KU系列FPGA
登录米联客(MILIANKE)FPGA社区-www.uisrc.com观看免费视频课程、在线答疑解惑!
1 概述
小小呼吸灯在很多设备上我们可以看到,我们可以在FPGA的控制主板上也可以加入呼吸灯,指示我们的FPGA主板正在运行。一般呼吸灯的亮灭周期是2S,呼吸灯的亮度可以通过PWM来调节。本文实现一个实用的小程序,读者完全可以自己编写代码,并且通过仿真测试代码的正确性,然后下载到开发板看实际运行效果。
2 硬件电路分析
硬件接口和子卡模块请阅读"附录 1"
配套工程的 FPGA PIN 脚定义路径为 fpga_prj/uisrc/04_pin/ fpga_pin.xdc。
3 PWM呼吸灯程序设计
3.1 系统框图
PWM呼吸灯程序设计中包含了3个定时计数器:
20us定时器,作为本系统的基本定时器,产生时间基准。
20ms定时器,通过20us定时器,计数100次完成20ms定时计数
2s定时器,通过20ms定时器,计数100次完成2S定时计数
PWM每间隔2ms更新一次,共计更新100次即2S后切换PWM的占空比调整方向。因此PWM占空比的调整是和2ms定时计数器和2S定时计数器相关。系统框图如下:
3.2 程序源码
`timescale 1ns / 1ns
module pwm_light# ( parameter REF_CLK = 64'd50_000_000 ) ( input I_sysclk_p, input I_rstn, output O_pwm );
localparam T20US_SET = REF_CLK/20000 - 1; //set 20us localparam T20MS_SET = 100 - 1; //set 20ms localparam PWM_SET = 100 - 1; //Set PWM duty cycle adjustment times
reg [23:0] t20us_cnt; reg [9 :0] t20ms_cnt; reg [9 :0] pwm_cnt; reg PWM_S;
wire t20us_done; wire t20ms_done; //设置20us计数,当计数条件达成时拉高 assign t20us_done = (t20us_cnt == T20US_SET); ///设置20ms计数,当计数条件达成时拉高 assign t20ms_done = t20us_done & (t20ms_cnt == T20MS_SET) ;
//1us base timer always @(posedge I_sysclk_p or negedge I_rstn)begin if(I_rstn == 1'b0) t20us_cnt <= 0; else if(t20us_cnt < T20US_SET) //t20us_cnt寄存器用来计数,目标值是T20US_SET t20us_cnt <= t20us_cnt + 1'b1; //未达到目标值+1 else t20us_cnt <= 24'd0; //达到目标值清零 end
//1ms pwm compare timer,based on 1us base timer always @(posedge I_sysclk_p or negedge I_rstn)begin //系统时钟的上升沿以及复位的下降沿触发 if(I_rstn == 1'b0) //复位清零 t20ms_cnt <= 0; else if(t20us_done) //t20us_done计数完成作为后续判断的大前提 t20ms_cnt <= (t20ms_cnt < T20MS_SET) ? (t20ms_cnt + 1'b1) : 10'd0; //判断语句,当t20ms_cnt < T20MS_SET满足时 else //t20ms_cnt计数器+1,否则就清零 t20ms_cnt <= t20ms_cnt; end
//PWM counter for generating duty cycle parameters as well as PWM adjustment count always @(posedge I_sysclk_p or negedge I_rstn)begin //系统时钟的上升沿以及复位的下降沿触发 if(I_rstn == 1'b0) //复位清零 pwm_cnt <= 0; else if(t20ms_done) //t20ms_done计数完成作为后续判断的大前提 pwm_cnt <= (pwm_cnt < PWM_SET) ? (pwm_cnt + 1'b1) : 10'd0; //判断语句,当pwm_cnt < PWM_SET满足时 else //pwm_cntt计数器+1,否则就清零 pwm_cnt <= pwm_cnt; end
//switch breathing state always @(posedge I_sysclk_p or negedge I_rstn)begin //系统时钟的上升沿以及复位的下降沿触发 if(I_rstn == 1'b0) PWM_S <= 0; //复位清零 else if(t20ms_done && (pwm_cnt == PWM_SET)) //pwm_cnt == PWM_SET达成时,对PWM_S的状态进行翻转 PWM_S <= ~PWM_S; //反应到LED灯上是LED灯的亮灭变换转换 else PWM_S <= PWM_S; end //添加ila IP ,Chipscope观察信号 ila_0 ila_debug ( .clk(I_sysclk_p), // input wire clk .probe0({t20us_done,O_pwm}) // input wire [1:0] probe0 ); //PWM wave generating assign O_pwm = PWM_S ? (pwm_cnt >= t20ms_cnt) : (pwm_cnt < t20ms_cnt); //判断语句,通过PWM_S的变换,使O_pwm输出的 endmodule
|
4 RTL仿真
4.1 添加仿真测试源码
仿真测试文件存放在工程目录uisrc\02_sim中,源码如下:
`timescale 1ns / 1ns
module tb_pwm_light();
reg I_sysclk_p,I_rstn; wire O_pwm; pwm_light# ( .REF_CLK(100_000) //调小时间参数,加快仿真速度 ) pwm_light_inst ( .I_sysclk_p(I_sysclk_p), //例化接口 .I_rstn(I_rstn), .O_pwm(O_pwm) );
initial begin I_sysclk_p <= 1'b0; //系统时钟设置初值 I_rstn <= 1'b0; //复位信号设置初值 #100; I_rstn <= 1'b1; //复位信号拉高,复位完成 end
always #10 I_sysclk_p=~I_sysclk_p;//时钟定时翻转
endmodule |
为了方便我们仿真观察现象,缩短我们的仿真时长,我们将时钟计数减小1000倍,所以仿真时长与实际时长相差了1000倍。
4.2 仿真结果
下图是刚开始的时候可以看到占空比是以减小的趋势调整
下图是2000us(实际为2s)处,占空比实现从大变小后又开始从小变大
下图是4000us(实际为4s)处,一个周期完成,占空比再次从最大开始往小调整。
5 在线仿真Captrue模式采样
添加ila在线逻辑分析仪的IP核
采用Capture Control功能,利用t20us_done作为Capture的采样触发信号,这是我们第一次实现Capture Control功能,对于Ila 低于20M的采样时钟会不能正常工作,但是可以用高采样时钟,配合Capture功能,实现低频的采样,合理利用采样深度。
设置位宽
下载程序后,设置Capture mode为BASIC
设置采样条件t20us_done为1的时候进行采样
根据设置条件开始采样
占空比变化明显
6 实验结果
(该教程为通用型教程,教程中仅展示一款示例开发板的连接方式,具体连接方式以所购买的开发板型号以及结合配套代码管脚约束为准。)
请确保下载器和开发板已经正确连接,并且开发板已经上电。(注意JTAG端子不支持热插拔,而USB接口支持,所以在不通电的情况下接通好JTAG后,再插入USB到电脑,之后再上电,以免造成JTAG IO损坏)
可以看到LED呼吸灯的亮灭变化
本文来米联客(milianke),作者:米联客(milianke),转载请注明原文链接:https://www.cnblogs.com/milianke/p/17934267.html