目录
一、3-8译码器
1.简介
3-8译码器,就是把3种输入状态翻译成8种输出状态,译码器是将输入的具有特定含义的二进制代码翻译成输出信号的不同组合,实现电路控制功能的逻辑电路。译码器在数字系统中应用广泛,可用于代码的转换、终端数字的显示、数据的分配等等。
2.实验目的
本次实验主要是为了理解verilog基础语法,掌握组合逻辑的设计方法。
3.设计原理
3-8 译码器有 3 个输入和 8 个输出,所以可以指定当输入为 111 时,译码后为指定的状态,即输出00000001,紧接着依次类推,当输入为 110 时,输出 01111111,当输入为 101 时,输出 11011111,当输入为 100 时,输出 11101111,输入 011 时,输出为 11110111,输入为 010 时,输出 11111011,输入为 001 时,输出 11111101,输入为 000 时,输出为 11111110。
如下图所示:
4.项目代码
module decoder(
input wire [2:0] a,//输入信号,3位
output reg [7:0] b//输出信号,8位
);
//译码器组合逻辑
always@(*)begin
case(a)
3'b000: b=8'b11111110;
3'b001: b=8'b11111101;
3'b010: b=8'b11111011;
3'b011: b=8'b11110111;
3'b100: b=8'b11101111;
3'b101: b=8'b11011111;
3'b110: b=8'b01111111;
3'b111: b=8'b10000000;
default: b=8'b00000000;
endcase
end
endmodule
5.项目仿真
仿真代码
`timescale 1ns/1ns //单位/精度
module decoder_tb();
reg [2:0] a;//输入信号
wire [7:0] b;//输出信号
initial begin
a = 3'b000;
#1 ;//延迟1ns
a = 3'b001;
#1 ;//延迟1ns
a = 3'b010;
#1 ;//延迟1ns
a = 3'b011;
#1 ;//延迟1ns
a = 3'b101;
#1 ;//延迟1ns
a = 3'b110;
#1 ;//延迟1ns
a = 3'b111;
#1 ;//延迟1ns
a = 3'bxxx;
#1 ;//延迟1ns
end
decoder u_decoder(
.a (a),//输入信号,3位
.b (b)//输出信号,8位
);
endmodule
仿真结果
二、点亮LED灯
1.实验任务
每间隔1S实现led灯的亮灭。
2.实验代码
//每间隔1S实现LED的亮灭
module led(
input clk ,
input rst_n ,
output reg [3:0] led
);
//计时1S
//parameter CNT0_2S = 24'd9;//如果要进行仿真的话就使用这个计数器
parameter CNT0_2S = 24'd9_999_999;
reg [23:0] cnt ;//保存时钟上升沿的个数
reg [1:0] state ;
always @(posedge clk or negedge rst_n) begin//对寄存器赋值要使用always
if(!rst_n)begin
cnt <= 24'd0;
end
else if(cnt == CNT0_2S)begin
cnt <= 24'd0;
end
else begin
cnt <= cnt + 1'd1;
end
end
always @(posedge clk or negedge rst_n) begin
if(!rst_n)begin
state <= 2'd0;
end
else if(state == 2'd3 && cnt == CNT0_2S)begin
state <= 2'd0;
end
else if(cnt == CNT0_2S)begin
state <= state + 1'd1;
end
end
always @(posedge clk or negedge rst_n) begin
if(!rst_n)begin
led <= 4'b0000;
end
else begin
case (state)
2'd0: led <= 4'b0001;
2'd1: led <= 4'b0010;
2'd2: led <= 4'b0100;
2'd3: led <= 4'b1000;
default:led <= 4'b0000;
endcase
end
end
//0001,0010,0100,1000,0001
// always @(posedge clk or negedge rst_n) begin
// if(!rst_n)begin
// led <= 4'b0001;
// end
// else if(cnt == CNT0_2S)begin
// led <= {led[2:0],led[3]};//使用位拼接可以更简单的实现流水灯
// end
// else begin
// led <= led;
// end
// end
endmodule
3.引脚配置
4.仿真测试
代码
`timescale 1ns/1ns
module led_tb();
reg clk;
reg rst_n;
wire [3:0] led;
always #10 clk = ~clk;
initial begin
clk = 1'b0;
rst_n = 1'b0;
#10 rst_n = 1'b1;
#1000 $stop ;
end
led u_led(
.clk (clk),
.rst_n (rst_n),
.led (led)
);
endmodule
结果
三、按键控制LED灯
1.实验任务
使用开发板上的四个按键控制四个LED灯。按下不同的按键时,四个LED灯显示不同效果。
2.系统设计
四个按键外加时钟和复位信号作为输入,两个计数器模块分别用于0.2s时间的计数和状态的计数。led模式选择模块根据状态计数器的改变,来改变四个led的状态,形成不同的样式。
3.实验代码
module key_led(
input clk ,//时钟50MHz
input rst_n,//复位信号,下降沿有效negtive
input [3:0] key ,//四个按键
output reg [3:0] led //四个led灯
);
parameter TIME = 24'd10_000_000;//0.2S
reg [23:0] cnt ;//计数器0.2S
reg [1:0] state;//记录四个led状态
//0.2s计数器模块
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin//复位
cnt <= 24'd0;//计数器清0
end
else if(cnt == TIME - 1)begin//记满10_000_000,0~9_999_999
cnt <= 24'd0;//计数器清0
end
else begin
cnt <= cnt + 1'd1;//其他情况下计数器加1
end
end
//状态计数模块
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin//复位信号
state <= 2'd0;//状态清0
end
else if(cnt == TIME - 1)begin//记满10_000_000,0~9_999_999 0.2s
state <= state + 2'd1;//状态加1
end
else begin
state <= state;//其他情况状态保持不变
end
end
//状态控制led模块
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin//复位信号
led <= 4'b0000;//led全灭
end
else if(key[0] == 0)begin//右边第1个按键按下,按键低电平0有效
case(state)//判断状态的值
2'd0: led <= 4'b0001;//右边第1个led灯亮
2'd1: led <= 4'b0010;//右边第2个led灯亮
2'd2: led <= 4'b0100;//右边第3个led灯亮
2'd3: led <= 4'b1000;//右边第4个led灯亮
default:;//默认情况不能忘,可以不写,但是要把stat情况考虑完
endcase
end
else if(key[1] == 0)begin//右边第2个按键按下,按键低电平0有效
case(state)//判断状态的值
2'd0: led <= 4'b1000;//左边第1个led灯亮
2'd1: led <= 4'b0100;//左边第2个led灯亮
2'd2: led <= 4'b0010;//左边第3个led灯亮
2'd3: led <= 4'b0001;//左边第4个led灯亮
default:;
endcase
end
else if(key[2] == 0)begin//右边第3个按键按下,按键低电平0有效
case(state)
2'd0: led <= 4'b1111;//全亮
2'd1: led <= 4'b0000;//全灭
2'd2: led <= 4'b1111;//全亮
2'd3: led <= 4'b0000;//全灭
default:;
endcase
end
else if(key[3] == 0)begin//右边第4个按键按下,按键低电平0有效
case(state)
2'd0: led <= 4'b1111;//全亮
2'd1: led <= 4'b1111;//全亮
2'd2: led <= 4'b1111;//全亮
2'd3: led <= 4'b1111;//全亮
default:;
endcase
end
else begin
led <= 4'b0000;//其他情况默认4个led灯全灭
end
end
endmodule
4.引脚配置
5.仿真测试
代码
`timescale 1ns/1ns//单位/精度
module key_led_tb();
reg clk ;//时钟信号
reg rst_n;//复位信号
reg [3:0] key ;//按键信号
wire [3:0] led ;//led灯信号
parameter TIME = 10;//间隔时间,由10_000_000变为10,便于仿真观察
parameter CYCLE = 20;//周期20ns
always #(CYCLE/2) clk = ~clk;//每10ns翻转一次,刚好模拟时钟周期50MHz
initial begin
clk = 1'b0;//初始时钟为低电平
rst_n = 1'b0;//复位信号置0,下降沿有效,初始化
#(CYCLE);//时钟20ns
rst_n = 1'b1;//复位信号置1
#(CYCLE * TIME * 4);//4个led灯,4个间隔,所以乘以4
key = 4'b1110;//按下右边第1个按键
#(CYCLE * TIME * 4);
key = 4'b1101;//按下右边第2个按键
#(CYCLE * TIME * 4);
key = 4'b1011;//按下右边第3个按键
#(CYCLE * TIME * 4);
key = 4'b0111;//按下右边第4个按键
#(CYCLE * TIME * 4);
$stop;//停止
end
//实例化模块
key_led #(.TIME (TIME)) u_key_led
(
.clk (clk) ,//时钟50MHz
.rst_n (rst_n),//复位信号,下降沿有效
.key (key) ,//按键信号
.led (led)//led灯
);
endmodule
结果
四、pwm呼吸灯
1.实验任务
呼吸灯是指灯光在微电脑的控制之下完成由亮到暗的逐渐变化,感觉好像是人在呼吸。本次实验是使用开发板上的四个led灯实现1s间隔的呼吸灯。使4个led灯由暗到亮,再由亮到暗的过程。
2.实验代码
module pwm_led (
input clk ,
input rst_n ,
output reg [3:0] led
);
parameter TIME_US = 6'd50;//50x20=1000ns=1us
parameter TIME_MS = 10'd999;//1usx1000=1ms
parameter TIME_S = 10'd999;//1msx1000=1s
reg [5:0] cnt_us;
reg [9:0] cnt_ms;
reg [9:0] cnt_s;
reg flag;
wire add_cnt_us;//开始计数的标志
wire end_cnt_us;//结束计数的标志
wire add_cnt_ms;
wire end_cnt_ms;
wire add_cnt_s;
wire end_cnt_s;
always @(posedge clk or negedge rst_n) begin
if(!rst_n)begin
cnt_us <= 6'd0;
end
else if(add_cnt_us)begin
if(end_cnt_us)begin
cnt_us <= 6'd0;
end
else begin
cnt_us <= cnt_us + 1'd1;
end
end
else begin
cnt_us <= cnt_us;
end
end
assign add_cnt_us = 1'b1;
assign end_cnt_us = add_cnt_us && cnt_us == TIME_US;
always @(posedge clk or negedge rst_n) begin
if(!rst_n)begin
cnt_ms <= 10'd0;
end
else if(add_cnt_ms)begin
if(end_cnt_ms)begin
cnt_ms <= 10'd0;
end
else begin
cnt_ms <= cnt_ms + 1'd1;
end
end
else begin
cnt_ms <= cnt_ms;
end
end
assign add_cnt_ms = end_cnt_us;
assign end_cnt_ms = add_cnt_ms && cnt_ms == TIME_MS;
always @(posedge clk or negedge rst_n) begin
if(!rst_n)begin
cnt_s <= 10'd0;
end
else if(add_cnt_s)begin
if(end_cnt_s)begin
cnt_s <= 10'd0;
end
else begin
cnt_s <= cnt_s + 1'd1;
end
end
else begin
cnt_s <= cnt_s;
end
end
assign add_cnt_s = end_cnt_ms;
assign end_cnt_s = add_cnt_s && cnt_s == TIME_S;
always @(posedge clk or negedge rst_n) begin
if(!rst_n)begin
flag <= 1'b0;
end
else if(end_cnt_s)begin
flag <= ~flag;
end
else begin
flag <= flag;
end
end
always @(posedge clk or negedge rst_n) begin
if(!rst_n)begin
led <= 4'b0000;
end
else if(!flag)begin//flag=0,led由灭到亮
led <= {cnt_s > cnt_ms,cnt_s > cnt_ms,cnt_s > cnt_ms,cnt_s > cnt_ms};
end
else if(flag)begin//flag=1,led由亮到灭
led <= {cnt_s < cnt_ms,cnt_s < cnt_ms,cnt_s < cnt_ms,cnt_s < cnt_ms};
end
else begin
led <= led;
end
end
endmodule
3.引脚配置
4.仿真测试
代码
`timescale 1ns/1ns
module pwm_led_tb();
reg clk;
reg rst_n;
wire [3:0] led;
parameter CYCLE = 20;
parameter TIME_US = 5;
parameter TIME_MS = 10;
parameter TIME_S = 10;
always #(CYCLE/2) clk = ~clk;
initial begin
clk = 1'b0;
rst_n = 1'b0;
#(CYCLE);
rst_n = 1'b1;
#(2*(TIME_US+1)*(TIME_MS+1)*(TIME_S+1)*CYCLE);
$stop;
end
pwm_led #(
.TIME_US (TIME_US),
.TIME_MS (TIME_MS),
.TIME_S (TIME_S)
) u_pwm_led(
.clk (clk),
.rst_n (rst_n),
.led (led)
);
endmodule
结果
五、静态数码管
1.实验原理
我们使用的数码管是8段数码管,每段是由led组成。通过控制每段led的亮灭,来控制数码管显示不同的数字和字母。
要显示不同的数字或者字母,就要选择点亮对应的led段。下图中、对应的是cyclone IV开发板上数码管的真值表,可以通过查找该表来显示我们想要的数字或者字母。
我们的开发板上的数码管分为了6位和8段,6位了控制6个数码管是否显示,8段来控制每个数码管显示的内容。本次实验是数码管的静态显示,因此只考虑段选信号。在不同的时刻,各个位选信号保持不变,并根据真值表,选择要显示的数字或者字母。并且Cyclone IV开发板中的数码管是共阳极,所以数码管中需要给低电平,对应的led段才会亮。
2.实验任务
六个数码管同时间隔0.5s显示0-f。要求:使用一个顶层模块,调用计时器模块和数码管静态显示模块。
3.实验代码
time_count模块
module time_count(
input clk ,//50MHz时钟信号
input rst_n,//复位信号
output reg flag//一个时钟周期的脉冲信号
);
parameter MAX_NUM = 25'd25_000_000;//计数器最大计数值
reg [24:0] cnt ; //时钟分频计数器
//计数器对时钟计数,每0.5s,输出一个时钟周期脉冲信号
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin//按复位时
flag <= 1'b0;//信号为0
cnt <= 25'd0;//计数器清零
end
else if(cnt < MAX_NUM - 1'b1)begin//如果没到时间
flag <= 1'b0;//信号为0
cnt <= cnt + 1'b1;//计数器正常累计+1
end
else begin //否则到时间
flag <= 1'b1;//信号变为1
cnt <= 25'd0;
end
end
endmodule
seg_led_static模块
module seg_led_static(
input clk ,
input rst_n ,
input flag ,
output reg [5:0] sel ,//数码管位选信号
output reg [7:0] seg //数码管段选信号
);
reg [3:0] num;//数码管显示十六进制数
//控制数码管位选信号(注:低电平有效),选中所有的数码管
always @(posedge clk or negedge rst_n)begin
if(!rst_n)//如果按复位键0
sel <= 6'b111111;//则默认为高电平
else
sel <= 6'b000000;//否则为低电平
end
//每次通知信号flag到达时,数码管计数加1
always @(posedge clk or negedge rst_n)begin
if(!rst_n)
num <= 4'h0;
else if(flag)begin
if(num < 4'hf)
num <= num + 1'h1;
else
num <= 4'h0;
end
else begin
num <= num;
end
end
//根据数码管显示的数值,控制段选信号
always @(posedge clk or negedge rst_n)begin
if(!rst_n)
seg <= 8'b0;
else begin
case(num)//匹配16进制数
4'h0: seg <= 8'b1100_0000;//匹配到后参考共阳极真值表
4'h1: seg <= 8'b1111_1001;
4'h2: seg <= 8'b1010_0100;
4'h3: seg <= 8'b1011_0000;
4'h4: seg <= 8'b1001_1001;
4'h5: seg <= 8'b1001_0010;
4'h6: seg <= 8'b1000_0010;
4'h7: seg <= 8'b1111_1000;
4'h8: seg <= 8'b1000_0000;
4'h9: seg <= 8'b1001_0000;
4'ha: seg <= 8'b1000_1000;
4'hb: seg <= 8'b1000_0011;
4'hc: seg <= 8'b1100_0110;
4'hd: seg <= 8'b1010_0001;
4'he: seg <= 8'b1000_0110;
4'hf: seg <= 8'b1000_1110;
default : seg <= 8'b1100_0000;
endcase
end
end
endmodule
top_seg_led_static模块
module top_seg_led_static(
input clk ,//50MHz系统时钟
input rst_n,//系统复位信号(低有效)
output [5:0] sel ,//数码管位选
output [7:0] seg//数码管段选
);
parameter MAX_NUM = 25'd25_000_000;// 数码管变化的时间间隔0.5s
wire add_flag ;// 数码管变化的通知信号
//每隔0.5s产生一个时钟周期的脉冲信号
time_count #(.MAX_NUM(MAX_NUM)) u_time_count(
.clk (clk) ,//50MHz时钟信号
.rst_n (rst_n),//复位信号
.flag (add_flag)//一个时钟周期的脉冲信号
);
//每当脉冲信号到达时,使数码管显示的数值加1
seg_led_static u_seg_led_static(
.clk (clk) ,
.rst_n (rst_n) ,
.flag (add_flag),
.sel (sel) ,
.seg (seg)
);
endmodule
4.引脚配置
5.仿真测试
代码
`timescale 1ns/1ns
module top_seg_led_static_tb();
reg clk ;
reg rst_n ;
wire [5:0] sel ;
wire [7:0] seg ;
parameter CYCLE = 5'd20;//周期20ns
parameter MAX_NUM = 8'd100;//调小间隔时间100*20ns
always #(CYCLE/2) clk = ~clk;//翻转时钟
initial begin
clk = 0 ;//时钟初始为0
rst_n = 0 ;//复位初始为0
#(CYCLE) ;//延迟20ns
rst_n = 1 ;//复位置1
#(16*MAX_NUM*CYCLE);//显示0-f时间
$stop ;//停止
end
top_seg_led_static#(.MAX_NUM (MAX_NUM)) u_top_seg_led_static(
.clk (clk) ,//50MHz系统时钟
.rst_n (rst_n),//系统复位信号(低有效)
.sel (sel) ,//数码管位选
.seg (seg) //数码管段选
);
endmodule
结果
六、实验成果
流水灯