题解 | #信号发生器#
题目说明
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