【AG32VH407开发板】完善官方CPLD案例(锁相环、PWM发波、按键)
[复制链接]
本帖最后由 edwinfir 于 2025-3-29 09:03 编辑
之前的测评文章已经体验了CPLD初级的功能,加上姚总给的LED例程比较简单,这次自己改善了一下,基本上把开发板的资源用了起来。
功能:利用内部的锁相环,将输入(PIN_2)的50Mhz时钟信号倍频到100Mhz, U2按键(PIN_35)按下后,在输出管脚(PIN_62)产生3KHZ,占空比为50%的PWM波形。
管脚设置文件编辑如下:
- I_CPLD_CLK_50M PIN_2 时钟输入50M
- SCR_OUT PIN_62 PWM波形输出
- rst PIN_53 随意设置的,不能是7脚,否则波形出错。
- button_in PIN_35 按键输入
- ledout[0] PIN_39 LED输出
- ledout[1] PIN_38 LED输出
- ledout[2] PIN_37 LED输出
- ledout[3] PIN_36 LED输出
- test1[0] PIN_9 测试引脚,反应按键变化,同35脚
- test1[1] PIN_10 测试引脚,输出高电平
- test1[2] PIN_11 测试引脚,输出PWM信号
- test1[3] PIN_14 测试引脚,未使用
U7的3和39上都可以量到输出信号。
下面大致讲解程序:
在Quartus II 13.0sp1 (64-bit)建立工程,本文是利用Quartus II 13.0sp1 (64-bit)生成文件,再给Supra.exe 编译使用。
- module SCR_DRIVER(I_CPLD_CLK_50M,rst,SCR_OUT,button_in,ledout,test1);
-
- input I_CPLD_CLK_50M;
- input rst;
- input button_in;
- output SCR_OUT;
- output [3:0] ledout;
- output [3:0] test1;
- reg [3:0] ledout;
- reg [31:0] counter;
- // 内部信号
- wire button_in,button_debounced,clk,I_CPLD_CLK_50M,rst,SCR_OUT,PWMX,pwm_en1,enable;
- wire [3:0] test1;
-
- assign test1[0]=button_in;
- assign test1[1]=enable;
- assign test1[2]=PWMX;
- assign SCR_OUT=PWMX;
- assign enable=1'b1;
- // assign button_debounced=1'b1;
- // 实例化按键消抖模块
- debounce debounce_inst (
- .clk(clk),
- .rst_n(1'b1),
- .button_in(button_in),
- .button_out(button_debounced)
- );
-
-
- PLL_CLK pll1_inst (
- .areset ( 1'b0 ),
- .inclk0 (I_CPLD_CLK_50M),
- .c0 (clk)
- );
-
- pwm_gen PWMA( .nreset(1'b1),.clk(clk),.en(button_debounced), .pwm(PWMX));
-
-
-
-
-
- always@(posedge clk )
-
- begin
- counter <= counter+1;
- case(counter[28:25])
- 0: ledout <= 4'b1110;
- 1: ledout <= 4'b1101;
- 2: ledout <= 4'b1011;
- 3: ledout <= 4'b0111;
- 4: ledout <= 4'b1100;
- 5: ledout <= 4'b0011;
- 6: ledout <= 4'b0000;
- 7: ledout <= 4'b1111;
- endcase
-
- end
-
- endmodule
-
程序架构如上图,SCR_DRIVER 部分是顶层文件,定义了输入输出,变量声明,LED部分的控制逻辑。
pwm_gen PWM波形发生模块,产生PWM波形输出。
- module pwm_gen(
-
- input nreset,
- input clk,
- input en,
- output reg pwm
-
- );
-
- parameter CLK_FREQ = 100_000_000;
- parameter PWM_FREQ = 3_000;
- parameter period = CLK_FREQ / PWM_FREQ;
- parameter h_time = period / 2;
-
-
-
- reg [31:0] CNT;
-
- always @ (posedge clk or negedge nreset)
- begin
- if(!nreset)
- CNT <= 0;
- else if(CNT >= period - 1 )
- CNT <= 0;
- else
- CNT <= CNT + 1;
- end
-
- always @ (posedge clk or negedge nreset)
- begin
- if(!nreset)
- pwm <= 0;
- else
- begin
- if(en == 0)
- pwm <= 0;
- else
- begin
- if(CNT <= h_time - 1)
- pwm <= 1;
- else
- pwm <= 0;
- end
- end
- end
-
- endmodule
debounce 按键消抖动模块,按下按钮,输出信号给PWM模块。
- module debounce (
- input wire clk,
- input wire rst_n,
- input wire button_in,
- output reg button_out
- );
-
-
- parameter CLK_FREQ = 100_000_000;
- parameter DEBOUNCE_TIME = 20;
- parameter COUNTER_MAX = CLK_FREQ / 1000 * DEBOUNCE_TIME;
-
-
- reg [31:0] counter;
- reg button_sync;
- reg button_prev;
-
-
- always @(posedge clk or negedge rst_n) begin
- if (!rst_n) begin
- button_sync <= 1'b0; // 默认按键未按下
- button_prev <= 1'b0;
- end else begin
- button_sync <= button_in;
- button_prev <= button_sync;
- end
- end
-
-
- always @(posedge clk or negedge rst_n) begin
- if (!rst_n) begin
- counter <= 0;
- button_out <= 1'b0;
- end else begin
- if (button_sync != button_prev) begin
- // 按键状态发生变化,重置计数器
- counter <= 0;
- end else if (counter < COUNTER_MAX) begin
- // 计数器未达到最大值,继续计数
- counter <= counter + 1;
- end else begin
- // 计数器达到最大值,按键状态稳定
- button_out <= ~button_sync; // 按键按下为低电平,输出高电平
- end
- end
- end
-
- endmodule
PLL_CLK 锁相环模块,倍频输入时钟,得到稳定的时钟信号。
输入50MHZ
输出100MHZ,注意,这部分锁相环是利用Quartus II软件生成的,详细步骤可以查阅相关资料。
需要注意的是,有部分代码老是调试有问题,有个调试问题困扰了两个星期调试不出来,幸亏原厂工程师给出了相关建议解决了,感谢他们的付出!问题是:原理图里面的7脚,NRST,这个是芯片复位,按下后cpLd程序会重新加载, CPLD程序不能拿这个当做逻辑复位脚,这里我设置了任意不用的53脚。
CPLD逻辑复位,不能使用这个NRST重新加载程序,要不波形持续一段时间就没有了,切记,切记。
最终演示视频:
|