1.3_8译码器编写
module decoder_3_8(
input a,
input b,
input c,
output reg [7:0] out
);
always @(*) begin
case({a,b,c})//注意如何对多个输入进行要求
3'd0: out = 8'b0000_0001;//这里输入采用十进制,输出采用2进制,方便观察
3'd1: out = 8'b0000_0010;
3'd2: out = 8'b0000_0100;
3'd3: out = 8'b0000_1000;
3'd4: out = 8'b0001_0000;
3'd5: out = 8'b0010_0000;
3'd6: out = 8'b0100_0000;
3'd7: out = 8'b1000_0000;
endcase
end
endmodule
//测试文件编写
`timescale 1ns/1ns //这个是必须加的,第一个1ns是步进,第二个1ns是精度
module decoder_3_8_tb();
reg t_a;
reg t_b;
reg t_c;
wire [7:0]t_out;
decoder_3_8 tb(
.a(t_a),
.b(t_b),
.c(t_c),
.out(t_out)
);//这里是调用之前写的模块
initial begin//这里是形成一个从“000”到“111”以“10ns”为间隔的连续输入
t_a=0;t_b=0;t_c=0;
#10;
t_a=0;t_b=0;t_c=1;
#10;
t_a=0;t_b=1;t_c=0;
#10;
t_a=0;t_b=1;t_c=1;
#10;
t_a=1;t_b=0;t_c=0;
#10;
t_a=1;t_b=0;t_c=1;
#10;
t_a=1;t_b=1;t_c=0;
#10;
t_a=1;t_b=1;t_c=1;
#10;
$stop;
end
endmodule
2.计数器+D触发器(10KHz的闪烁灯,50M的板子频率)
一、模型部分:
-
10KHz的闪烁灯,也就是每50us电平翻转一次,因为板子频率为50MHz,则周期为20ns,因此需要计数50us/20ns=2500次以后进行一次电平翻转
-
注意“2500-1”的原因,是最后从(2499-0)也需要计数一次,因此需要-1;
-
同时counter的位宽需要根据2^n>2500,即n=12可以实现,所以定义[11:0]的counter;
-
注意每个always块中尽量只对一个变量操作,方便后续修改和综合;
-
注意always块中的赋值对象必须为reg类型,同时赋值必须为“<=”,不可以为“=”
module counter_50M_10K(
input clk,
input Reset_n,
output reg led
);
reg [11:0] counter;
always@(posedge clk or negedge Reset_n)
if(!Reset_n)
counter <= 0;
else if(counter == 2500-1)
counter <=0;
else
counter <= counter+1'd1;
always@(posedge clk or negedge Reset_n)
if(!Reset_n)
led <= 0;
else if(counter==2500-1)
led <= ~led;
else
led <= led;
endmodule
二、测试部分:
- 需要写两个信号的测试激励:时钟信号;复位信号
- 时钟信号:10ns翻转一次
- 复位信号:短暂复位(但是需要包括至少一次翻转,同时要多一点,防止跟clk的上升沿重合),长时间无效(需要包含两个周期差不多)
`timescale 1ns/1ns
module counter_10M_10K_tb;
//需要对两个信号进行测试输入:时钟信号;复位信号
reg clk_t;
reg Reset_n_t;
wire led_t;
counter_50M_10K tb(
.clk(clk_t),
.Reset_n(Reset_n_t),
.led(led_t)
);
//时钟信号:t=20ns,也就是每10ns翻转一次
initial clk_t=0;
always#10 clk_t=~clk_t;
//复位信号:初始电位为0,经过短暂复位后,保持长时间的1
initial begin
Reset_n_t=0;
#21;
Reset_n_t=1;
//因为我们得到的信号是每50us翻转一次,那么我们需要看到两个周期也就是0.2ms=200000ns
#200000;
$stop;
end
endmodule
3. 8个LED灯50us速率循环跑马灯
通过计数器+LED控制实现;
其中LED控制部分可以有三种方式,分别为:1.移位 2.拼接 3.调用3_8译码器
tb部分与之前同,这里不重复
1.移位
module led_run(
input clk,
input rst_n,
output reg[7:0] led
);
parameter MCN=2500-1;
reg [24:0] counter;
//计数器部分
always@(posedge clk or negedge rst_n)
if(!rst_n)
counter<=0;
else if(counter==MCN)
counter<=0;
else
counter<=counter+1'b1;
//led部分
always@(posedge clk or negedge rst_n)
if(!rst_n)
led<=8'b0000_0001;
else if(counter==MCN)begin
if(led==8'b1000_0000)
led<=8'b0000_0001;
else
led<=led<<1;
end
else
led <= led;
endmodule
2.拼接
module led_run2(
input clk,
input rst_n,
output reg[7:0] led
);
parameter MCN=2500-1;
reg [24:0] counter;
//计数器部分
always@(posedge clk or negedge rst_n)
if(!rst_n)
counter<=0;
else if(counter==MCN)
counter<=0;
else
counter<=counter+1'b1;
//led部分
always@(posedge clk or negedge rst_n)
if(!rst_n)
led<=8'b0000_0001;
else if(counter==MCN)
led<={led[6:0],led[7]};//这个地方需要理解~
else
led <= led;
endmodule
3.调用3_8译码器
module led_run3(
input clk,
input rst_n,
output [7:0] led
//首先注意led此时不能再为reg类型,因为定义的底层模块decoder中已经声明,因此这里只能是默认wire
);
parameter MCN=2500-1;
reg [24:0] counter;
//计数器部分
always@(posedge clk or negedge rst_n)
if(!rst_n)
counter<=0;
else if(counter==MCN)
counter<=0;
else
counter<=counter+1'b1;
//led部分
reg [2:0] counter_led;
always@(posedge clk or negedge rst_n)
if(!rst_n)
counter_led<=0;
else if(counter==MCN)
counter_led<=counter_led+1'b1;
//这里的调用不包含在always块中,而是在每次always块之后调用一次,注意always块中是不能调用模块的!!!
decoder_3_8 led_run(
.a(counter_led[2]),
.b(counter_led[1]),
.c(counter_led[0]),
.out(led)//注意位次的排布a-2,b-1,c-0
);
endmodule
4.线性序列状态机
1.一个LED灯,先亮0.25s,再灭0.75s
//基本逻辑在于控制计数时间,从而控制状态变化,将一个长的时间段划分成两个状态
module LED_counter_1(
input clk,
input rst_n,
output reg led
);
reg [25:0] counter;
parameter CNM=12500;
//计数器部分
always@(posedge clk or negedge rst_n )
if(!rst_n)
counter<=0;
else if (counter==(4*CNM)-1)
counter<=0;
else
counter<=counter+1'b1;
//led部分
always@(posedge clk or negedge rst_n )
if(!rst_n)
led<=1'b1;
else if(counter==CNM-1)
led<=1'b0;
else if(counter==(CNM*4)-1)
led<=1'b1;
endmodule
2.一个LED灯,亮0.25s,灭0.75s,亮1.5s,灭2s
//此时加入了多个状态,但是方法与之前相同,这里只是将一个周期变成(0.25+0.75+1.5+2),并划分为四个状态
module LED_counter_2(
input clk,
input rst_n,
output reg led
);
reg [26:0] counter;
parameter MCN=12500000;
//计数器
always@(posedge clk or negedge rst_n)
if(!rst_n)
counter<=0;
else if (counter==MCN*10-1)
counter<=0;
else
counter<=counter+1'b1;
//led
always@(posedge clk or negedge rst_n)
if(!rst_n)
led<=1;
else case(counter)
MCN-1:led<=~led;
MCN*3-1:led<=~led;
MCN*6-1:led<=~led;
MCN*10-1:led<=~led;
default: led<=led;
endcase
endmodule
3.一个LED灯,一个周期内有8个状态,这8个状态的亮灭未知(外部输入),每个状态的持续时间为0.25s
//关键在于引入了外部输入来控制灯的亮灭情况,而周期划分还是没变
module LED_counter_3(
input clk,
input rst_n,
input [7:0] ctrl,
output reg led
);
reg [26:0] counter;
parameter MCN=12500000;
//计数器
always@(posedge clk or negedge rst_n)
if(!rst_n)
counter<=0;
else if (counter==MCN*8-1)
counter<=0;
else
counter<=counter+1;
//led
always@(posedge clk or negedge rst_n)
if(!rst_n)
led<=1;
else case(counter)
MCN-1:led<=ctrl[7];
MCN*2-1:led<=ctrl[6];
MCN*3-1:led<=ctrl[5];
MCN*4-1:led<=ctrl[4];
MCN*5-1:led<=ctrl[3];
MCN*6-1:led<=ctrl[2];
MCN*7-1:led<=ctrl[1];
MCN*8-1:led<=ctrl[0];
default:led<=led;
endcase
endmodule
4.一个LED灯,一个周期内有8个状态,这8个状态的亮灭未知(外部输入),每个状态的持续时间为未知(外部输入)
//关键在于“状态持续时间未知”,此时不方便再进行周期的状态划分,而且需要两个计数器,一个用于每个状态的持续时间计数(counter),一个用于状态次数的计数(8次:counter_time),这里通过counter来控制counter_time的计数即可
module LED_counter_4(
input clk,
input rst_n,
input [7:0] ctrl,
input [31:0]Time,//已经÷了20
output reg led
);
reg [31:0] counter;
//计数器
always@(posedge clk or negedge rst_n)
if(!rst_n)
counter<=0;
else if (counter==Time-1)
counter<=0;
else
counter<=counter+1;
reg [2:0] counter_time;//用于状态变化
//counter_time:本质在于两段计数器的控制,一段用于控制时间,一段用于控制状态,最后把控制状态的counter给到led来控制即可
always@(posedge clk or negedge rst_n)
if(!rst_n)
counter_time<=0;
else if(counter==Time-1)
counter_time<=counter_time+1;
else
counter_time<=counter_time;
//led
always@(posedge clk or negedge rst_n)
if(!rst_n)
led<=1;
else case(counter_time)
3'd0: led<=ctrl[7];
3'd1: led<=ctrl[6];
3'd2: led<=ctrl[5];
3'd3: led<=ctrl[4];
3'd4: led<=ctrl[3];
3'd5: led<=ctrl[2];
3'd6: led<=ctrl[1];
3'd7: led<=ctrl[0];
default:led<=led;
endcase
endmodule
5.一个LED灯,一个周期内有8个状态,这8个状态的亮灭未知(外部输入),每个状态的持续时间为未知(外部输入),且每次经历完一个周期之后进行延缓,延缓的时间与状态时间之和为10ms。
//这里的关键在与延缓的与状态的控制,其实可以将8个状态看作一个整体,再将延缓看作一个整体,通过一个标志位来控制10ms这个大周期内控制状态的计数器的计数情况;
//但是我这里是直接看作9个状态
module LED_counter_5(
input clk,
input rst_n,
input [7:0] ctrl,
input [31:0]Time,//已经÷了20
output reg led
);
parameter MCN=500000;//10ms
reg [18:0] counter_Per;
reg [31:0] counter_Time;
reg [3:0] counter_Num;
//周期计数器10ms
always@(posedge clk or negedge rst_n)
if(!rst_n)
counter_Per<=0;
else if (counter_Per==MCN-1)
counter_Per<=0;
else
counter_Per<=counter_Per+1;
//状态时间计数器Time
always@(posedge clk or negedge rst_n)
if(!rst_n)
counter_Time<=0;
else if (counter_Time==Time-1)
counter_Time<=0;
else
counter_Time<=counter_Time+1;
//状态次数计数器Num
always@(posedge clk or negedge rst_n)
if(!rst_n)
counter_Num<=0;
else if (counter_Num==4'b1000)//这里变成到9置零
counter_Num<=0;
else if (counter_Num==4'b0111) begin
if(counter_Per==MCN-1)
counter_Num<=counter_Num+1;
else
counter_Num<=counter_Num;
end
else if (counter_Time==Time-1)
counter_Num<=counter_Num+1;
else
counter_Num<=counter_Num;
//led
always@(posedge clk or negedge rst_n)
if(!rst_n)
led<=0;
else case(counter_Num)
4'd0: led<=ctrl[7];
4'd1: led<=ctrl[6];
4'd2: led<=ctrl[5];
4'd3: led<=ctrl[4];
4'd4: led<=ctrl[3];
4'd5: led<=ctrl[2];
4'd6: led<=ctrl[1];
4'd7: led<=ctrl[0];
4'd8: led<=0;
default:led<=led;
endcase
endmodule