题解 | #信号发生器#
题目说明
1.方波的周期是20,至于为什么是20,原因如下:按理来说wave是5位的,方波应该在0~15是低电平(即0),在16~31是高电平(即1),但是这里是按0~9是低电平(即0),在10~19是高电平(即1),这是提交结果后发现wave的最大值为20,所以就变为了紫色字体所表示的范围;
always@(posedge clk or negedge rst_n) begin
if(!rst_n)
cnt <= 0;
else
cnt <= wave_choise != 0 ? 0 : (cnt == 5'd19) ? 5'b0 : cnt + 1'b1;
// 当wave_choise变为除0以外的数值时,要让计数器cnt的值恢复为0,
// 方便下次wave_choise变为0后,计数器可以从0开始进行计数;
end
2.锯齿波的实现原理很简单,就是让一个计数器从0累加到20,计数器等于20的下个上升沿变为0,之后继续累加到20,周而复始罢了;
wave <= wave == 5'd20 ? 0 : wave + 1'b1; // 当wave_choise从0变为1时,此时wave的值从20经一个时钟沿后变为0,这时可以让wave充当这个计数器的任务, // 即为 --> 从0累加到20,wave等于20的下个上升沿变为0,之后继续累加到20,周而复始;
3.三角波的实现原理也很简单,就是当wave从0累加到20后就开始递减,当wave递减到0后,在下一个时钟上升沿到来后开始累加,周而复始,在C语言中,也就是设置一个标志位flag(初始化设置为0),当wave递减到0后,标志位flag置为1,wave开始累加,当wave累加到20后,标志位flag置为0,进行减法,直到wave递减为0后,标志位flag置为1,即标志位flag=1表示进行累加,标志位flag=0表示进行递减;
always@(posedge clk or negedge rst_n)begin if(!rst_n) flag <= 1'b0; else if(wave_choise == 2'b10)begin if(wave == 5'd1)// 这里不是wave == 5'd0;是因为非阻塞赋值会延后一个周期才能收到更新后的值 flag <= 1'b1; else if(wave == 5'd19)// 这里不是wave == 5'd20;是因为非阻塞赋值会延后一个周期才能收到更新后的值 flag <= 1'b0; else flag <= flag; end else flag <= flag; end wave <= flag == 1'b0 ? wave - 1'b1 : wave + 1'b1;
最终verilog程序如下:
`timescale 1ns/1ns
module signal_generator(
input clk,
input rst_n,
input [1:0] wave_choise,
output reg [4:0]wave
);
reg [4:0] cnt;
reg flag;
always@(posedge clk or negedge rst_n) begin
if(!rst_n)
cnt <= 0;
else
cnt <= wave_choise != 0 ? 0 : (cnt == 5'd19) ? 5'b0 : cnt + 1'b1;
end
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
flag <= 1'b0;
else if(wave_choise == 2'b10)begin
if(wave == 5'd1)
flag <= 1'b1;
else if(wave == 5'd19)
flag <= 1'b0;
else
flag <= flag;
end
else
flag <= flag;
end
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
wave <= 5'b0;
else
case(wave_choise)
2'b00 : wave <= cnt == 5'd9 ? 5'd20 : cnt == 5'd19 ? 5'd0 : wave;
2'b01 : wave <= wave == 5'd20 ? 0 : wave + 1'b1;
2'b10 : wave <= flag == 1'b0 ? wave - 1'b1 : wave + 1'b1;
default : wave <= 5'bx;
endcase
end
endmodule