目录
前言
FPGA小白,第一次写文章,记录自己写的关于数码管循环播放滚动数字实验的一点想法和成品,分享出来,一起开发新方法。
一,设计思想
本次实验我使用的是Cyclone IV 的板子,这种板子的数码管特点是共阳极(给其低电平就亮),也就是当位选信号为0(低电平)时,数码管亮起,位选信号为1(高电平),且这六个数码管是公用相同位置的段选信号,即相同位置那一段的二极管由一个信号控制,这就意味着我们不能同时对六个数码管进行复制,要想其显示不同内容,只能一个一个的亮,然后将转换状态时间设置得特别短,光还来不及消失下一个就亮起,看起来就是不同数码管显示不同内容。
通过状态机的思想,相同时间间隔,对不同数码管赋予不同的值,这样状态转化时间一短,就会有所有数字一起亮起的错觉,而在这基础上,再设置几个大状态,每个大状态里面就是这样的小状态,就能得到数字循环流动的错觉。
二,模块代码
1.编写time_count模块,其中输出得两个参数分别是小状态和大状态切换的信号。
module time_count(
input clk,
input rst_n,
output reg flag,
output reg [2:0]flag_value
);
parameter MAX_NUM = 26'd60_0000 ; //大状态时间
parameter more_num = MAX_NUM / 600; // 小状态时间,可自己酌情变化
reg [25:0] cnt;
reg [25:0] cnt_t;
always @(posedge clk or negedge rst_n) begin
if(!rst_n)begin
cnt <= 26'd0;
end
else if(cnt == MAX_NUM - 1'd1)begin
cnt <= 26'd0;
end
else begin
cnt <= cnt + 1'd1;
end
end
always @(posedge clk or negedge rst_n) begin
if(!rst_n)begin
cnt_t <= 26'd0;
end
else if(cnt_t == more_num - 1'd1)begin
cnt_t <= 26'd0;
end
else begin
cnt_t <= cnt_t + 1'd1;
end
end
always @(posedge clk or negedge rst_n) begin//对大状态变化的信号,这里设置六重变化,可酌情增添。
if(!rst_n)begin这里变化一次,数码管显示由-----1变成----12 ---123 --1234 -12343 123456
flag_value <= 3'd1;
end
else if(cnt == MAX_NUM - 1'd1)begin
if(flag_value < 6)begin
flag_value <= flag_value + 1'd1;
end
else begin
flag_value <= 3'd1;
end
end
else begin
flag_value <= flag_value;
end
end
always @(posedge clk or negedge rst_n) begin//数码管位选信号变化信号
if(!rst_n)begin
flag <= 1'b0;
end
else if(cnt_t == more_num - 1'd1)begin
flag <= 1'b1;
end
else begin
flag <= 1'b0;
end
end
endmodule
2.编写sel_control 模块,该模块通过传过来的信号对数码管显示进行状态切换。
module sel_control(
input clk,
input rst_n,
input flag,
input [2:0] flag_value,
output reg [5:0] sel,//位选信号
output reg [7:0] seg//段选信号-----该板子六个位公用八个位选信号
);
reg [2:0] cstate; //当前状态
reg [2:0] nstate; // 下一时刻状态
always @(posedge clk or negedge rst_n) begin
if(!rst_n)begin
cstate <= 3'd0;
end
else begin
cstate <= nstate; // 状态跳转
end
end
//下一个状态判断
always @(*) begin
case (cstate)
3'd0: if(flag)begin
nstate = 3'd1;
end
else begin
nstate = 3'd0;
end
3'd1: if(flag)begin
nstate = 3'd2;
end
else begin
nstate = 3'd1;
end
3'd2: if(flag)begin
nstate = 3'd3;
end
else begin
nstate = 3'd2;
end
3'd3: if(flag)begin
nstate = 3'd4;
end
else begin
nstate = 3'd3;
end
3'd4: if(flag)begin
nstate = 3'd5;
end
else begin
nstate = 3'd4;
end
3'd5: if(flag)begin
nstate = 3'd6;
end
else begin
nstate = 3'd5;
end
3'd6 : if(flag)begin
nstate = 3'd0;
end
else begin
nstate = 3'd6;
end
default: ;
endcase
end
reg [2:0] value;
always @(*) begin //对数码管位选信号进行判断
if(!rst_n)begin
sel = 6'b111_110;
end
else begin
case (cstate)
3'd0:begin
sel = 6'b111_110;
end
3'd1:begin
sel = 6'b111_101;
end
3'd2:begin
sel = 6'b111_011;
end
3'd3:begin
sel = 6'b110_111;
end
3'd4:begin
sel = 6'b101_111;
end
3'd5:begin
sel = 6'b011_111;
end
3'd6:begin
sel = 6'b111_111;
end
default: begin
sel = 6'b111_110;
end
endcase
end
end
always @(posedge clk or negedge rst_n) begin
if(!rst_n)begin
value <= 3'd1;
end
else if(flag_value == 3'd1)begin//当第一次时间计满 , 显示-----1 -表示不亮
if(cstate == 3'd0) begin //状态位第一个二极管亮
value <= 3'd0; //赋值为1
end
else if(cstate == 3'd1)begin//状态为第二个二极管亮
value <= 3'd0;//赋值为2
end
else if(cstate == 3'd2)begin//三
value <= 3'd0;//赋值为3
end
else if(cstate == 3'd3)begin//四
value <= 3'd0;//赋值为4
end
else if(cstate == 3'd4)begin//五
value <= 3'd0;//赋值为5
end
else if(cstate == 3'd5)begin//六
value <= 3'd1;//赋值为6
end
else begin
value <= 3'd3;
end
end
else if(flag_value == 3'd2)begin//当第二次时间计满, 显示----12
if(cstate == 3'd0) begin //状态位第一个二极管亮
value <= 3'd0; 赋值为2
end
else if(cstate == 3'd1)begin//状态为第二个二极管亮
value <= 3'd0;//赋值为3
end
else if(cstate == 3'd2)begin//三
value <= 3'd0;//赋值为4
end
else if(cstate == 3'd3)begin//四
value <= 3'd0;//赋值为5
end
else if(cstate == 3'd4)begin//五
value <= 3'd1;//赋值为6
end
else if(cstate == 3'd5)begin//六
value <= 3'd2;//赋值为1
end
else begin
value <= 3'd3;
end
end
else if(flag_value == 3'd3)begin//当第三次时间计满,显示---123
if(cstate == 3'd0) begin //状态位第一个二极管亮
value <= 3'd0; 赋值为3
end
else if(cstate == 3'd1)begin//状态为第二个二极管亮
value <= 3'd0;//赋值为4
end
else if(cstate == 3'd2)begin//三
value <= 3'd0;//赋值为5
end
else if(cstate == 3'd3)begin//四
value <= 3'd1;//赋值为6
end
else if(cstate == 3'd4)begin//五
value <= 3'd2;//赋值为1
end
else if(cstate == 3'd5)begin//六
value <= 3'd3;//赋值为2
end
else begin
value <= 3'd3;
end
end
else if(flag_value == 3'd4)begin//当第四次时间计满 ,显示--1234
if(cstate == 3'd0) begin //状态位第一个二极管亮
value <= 3'd0; 赋值为4
end
else if(cstate == 3'd1)begin//状态为第二个二极管亮
value <= 3'd0;//赋值为5
end
else if(cstate == 3'd2)begin//三
value <= 3'd1;//赋值为6
end
else if(cstate == 3'd3)begin//四
value <= 3'd2;//赋值为1
end
else if(cstate == 3'd4)begin//五
value <= 3'd3;//赋值为2
end
else if(cstate == 3'd5)begin//六
value <= 3'd4;//赋值为3
end
else begin
value <= 3'd3;
end
end
else if(flag_value == 3'd5)begin//当第五次时间计满,显示-12345
if(cstate == 3'd0) begin //状态位第一个二极管亮
value <= 3'd0; 赋值为5
end
else if(cstate == 3'd1)begin//状态为第二个二极管亮
value <= 3'd1;//赋值为6
end
else if(cstate == 3'd2)begin//三
value <= 3'd2;//赋值为1
end
else if(cstate == 3'd3)begin//四
value <= 3'd3;//赋值为2
end
else if(cstate == 3'd4)begin//五
value <= 3'd4;//赋值为3
end
else if(cstate == 3'd5)begin//六
value <= 3'd5;//赋值为4
end
else begin
value <= 3'd3;
end
end
else if(flag_value ==3'd6)begin//当第六次时间计满,显示123456
if(cstate == 3'd0) begin //状态位第一个二极管亮
value <= 3'd1; 赋值为6
end
else if(cstate == 3'd1)begin//状态为第二个二极管亮
value <= 3'd2;//赋值为1
end
else if(cstate == 3'd2)begin//三
value <= 3'd3;//赋值为2
end
else if(cstate == 3'd3)begin//四
value <= 3'd4;//赋值为3
end
else if(cstate == 3'd4)begin//五
value <= 3'd5;//赋值为4
end
else if(cstate == 3'd5)begin//六
value <= 3'd6;//赋值为5
end
else begin
value <= 3'd3;
end
end
else begin
value <= 3'd2;
end
end
always @(*) begin
if(!rst_n)begin
seg <= 8'b1111_1111;
end
else begin
case (value)
3'd0 : seg = 8'b1111_1111;//全部不量,留白以达到流动效果。
3'd1: seg = 8'b11111001;//根据数码管真值表查找
3'd2: seg = 8'b10100100;
3'd3: seg = 8'b10110000;
3'd4: seg = 8'b10011001;
3'd5: seg = 8'b10010010;
3'd6: seg = 8'b10000010;
default: seg = 8'b0000_0000;
endcase
end
end
endmodule
3.编写top文件
module sel_control_top(
input clk,
input rst_n,
output [5:0] sel,//位选信号
output [7:0] seg//段选信号-----该板子六个位公用八个位选信号
);
wire add_flag;
wire [2:0]add_flag_value;
parameter TIME = 26'd3000_0000;
time_count #(.MAX_NUM(TIME)) u_time_count(
.clk(clk),
.rst_n(rst_n),
.flag(add_flag),
.flag_value(add_flag_value)
);
sel_control u_sel_control(
.clk(clk),
.rst_n(rst_n),
.flag(add_flag),
.flag_value(add_flag_value),
.sel(sel),
.seg(seg)
);
endmodule
4.功能仿真
`timescale 1ns/1ns
module sel_control_tb();
reg clk;
reg rst_n;
wire[5:0] sel;
wire[7:0] seg;
always #10 clk = ~clk;
initial begin
clk = 1'b0;
rst_n = 1'b0;
#10 rst_n = 1'b1;
end
sel_control_top u_sel_control(
.clk(clk),
.rst_n(rst_n),
.sel(sel),//位选信号
.seg(seg) //段选信号-----该板子六个位公用八个位选信号
);
endmodule
仿真结果
图1:数码管循环播放仿真
三,引脚分配
图2:引脚分配
元件 | 管脚 |
---|---|
SEL0 | A4 |
SEL1 | B4 |
SEL2 | A3 |
SEL3 | B3 |
SEL4 | A2 |
SEL5 | B1 |
DIG0 | B7 |
DIG1 | A8 |
DIG2 | A6 |
DIG3 | B5 |
DIG4 | B6 |
DIG5 | A7 |
DIG6 | B8 |
DIG7 | A5 |
CLOCK(时钟) | E1 |
KEY1 | E15 |
表1. 引脚信息表
四.运行效果
数码管循环播放数字