1. PWM波原理非常简单, 核心是精度控制, 原定占空比输入为百分比, 导致精度只能到1%, 现在直接引入pid输入, 在module计算占空比, 精度可以到0.01%
2. 四舍五入的两种技巧
`timescale 1ns / 1ps
//****************************************VSCODE PLUG-IN**********************************//
//----------------------------------------------------------------------------------------
// IDE : VSCODE
// VSCODE plug-in version: Verilog-Hdl-Format-3.7.20250728
// VSCODE plug-in author : Jiang Percy
//----------------------------------------------------------------------------------------
//****************************************Copyright (c)***********************************//
// Copyright(C) Please Write Company name
// All rights reserved
// File name:
// Last modified Date: 2025/08/07 11:50:51
// Last Version: V1.0
// Descriptions:
//----------------------------------------------------------------------------------------
// Created by: Please Write You Name
// Created date: 2025/08/07 11:50:51
// mail : Please Write mail
// Version: V1.0
// TEXT NAME: pwm.v
// PATH: C:\Users\Administrator\Desktop\工作记录\vivado\PWM\PWM.srcs\sources_1\new\pwm.v
// Descriptions:
// 频率生成、占空比精度均为万一
//----------------------------------------------------------------------------------------
//****************************************************************************************//
module pwm(
input clk ,
input rst_n ,
input enable ,//enable 为0输出默认值
input [ 17: 0] Freq_wave ,
input [ 15: 0] Duty_cycle ,//由pid产生 max 为65535--》100%
output pwm_out_p ,
output pwm_out_n
);
//---------------------------------------------------------------------------------------
// PWM Parameters
//我们使用锯齿波和直流比较生成pwm
// 1. sys_clk_freq_hz 生成PWM的系统时钟频率
// 2. Freq_wave 决定锯齿波的频率,同时也是pwm的频率
// 3. duty_cycle 定义pwm波的占空比 单位为百分比
// 4 thres为锯齿波的比较值,大于时pwm为0;小于时pwm为1
//---------------------------------------------------------------------------------------
parameter sys_clk_freq_hz = 400_000_000 ;
//parameter Freq_wave = 100_000 ;
//parameter Duty_cycle = 50 ;
//parameter max_cnt_wave = sys_clk_freq_hz/Freq_wave;
//parameter thres = Duty_cycle * max_cnt_wave /100;
//---------------------------------------------------------------------------------------
// 内部变量定义
//---------------------------------------------------------------------------------------
reg [ 17: 0] r_Freq_wave ;
reg [ 6: 0] r_Duty_cycle ;
reg [ 11: 0] cnt_wave ;
reg out_pwm ;
wire [ 11: 0] max_cnt_wave ;
wire [ 10: 0] thres ;
wire [ 27: 0] duty_temp ;
//---------------------------------------------------------------------------------------
// 时序与组合逻辑定义
//---------------------------------------------------------------------------------------
// 1. 频率计算(带四舍五入,降低频率误差)
assign max_cnt_wave = (sys_clk_freq_hz+ r_Freq_wave/2) / r_Freq_wave;
// 2. 占空比计算(基于PID输出,无比例误差)
// 公式:duty_threshold = (pid_output * max_cnt_wave) / MAX_DUTY
//assign thres = r_Duty_cycle * max_cnt_wave/100;
assign duty_temp = r_Duty_cycle * max_cnt_wave;
assign thres = duty_temp[27:16] + (duty_temp[15] ? 1'b1 : 1'b0);// 四舍五入
// 输入数据打拍
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
r_Freq_wave <= 100_000;
r_Duty_cycle <= 37268;
end
else if(enable)
begin
r_Freq_wave <= Freq_wave;
r_Duty_cycle <= Duty_cycle;
end
end
//
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
cnt_wave <= 0;
else if(cnt_wave == max_cnt_wave-1)
cnt_wave <= 0;
else cnt_wave <= cnt_wave + 1;
end
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
out_pwm <= 0;
else if(cnt_wave <= thres-1)
out_pwm <= 1;
else
out_pwm <= 0;
end
assign pwm_out_p = out_pwm ;
assign pwm_out_n = ~out_pwm ;
endmodule