数码管循环播放数字

目录

前言

一,设计思想

二,模块代码

三,引脚分配

四.运行效果

前言

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:引脚分配

元件管脚
SEL0A4
SEL1B4
SEL2A3
SEL3B3
SEL4A2
SEL5B1
DIG0B7
DIG1A8
DIG2A6
DIG3B5
DIG4B6
DIG5A7
DIG6B8
DIG7A5
CLOCK(时钟)E1
KEY1E15

                                                      表1. 引脚信息表

四.运行效果 

数码管循环播放数字

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个基于汇编语言的数码管步进电机闹钟代码,供参考: ``` ORG 0x0000 ; 程序起始地址 ; 定义常量 DELAY EQU 100 ; 延时常量 CLOCK EQU P1 ; 时钟端口 DATA EQU P2 ; 数据端口 STEP EQU 8 ; 步进电机的步数 ; 初始化 INIT: MOV CLOCK, #0 ; 时钟端口清零 MOV DATA, #0 ; 数据端口清零 MOV R0, #STEP ; 设置步数 MOV R1, #0 ; 设置初始值 MOV R2, #0 ; 设置闹钟值 MOV R3, #0 ; 设置当前时间值 CALL DELAY ; 延时 JMP CLOCKWISE ; 开始转动 ; 顺时针转动 CLOCKWISE: MOV A, R1 ; 将当前值保存到累加器 ADD A, #1 ; 加1 MOV R1, A ; 保存结果到寄存器 MOV A, R1 ; 将结果保存到累加器 ANL A, #0x0F ; 屏蔽高4位 MOV P2, A ; 将结果输出到数码管 DJNZ R0, CLOCKWISE ; 循环 ; 计时器中断处理程序 TIMER: PUSH PSW ; 保存现场 MOV A, R3 ; 将当前时间保存到累加器 ADD A, #1 ; 加1 MOV R3, A ; 保存结果到寄存器 MOV A, R3 ; 将结果保存到累加器 ANL A, #0x0F ; 屏蔽高4位 MOV P2, A ; 将结果输出到数码管 CJNE R3, R2, EXIT ; 判断是否到达闹钟时间 CALL ALARM ; 播放闹钟声音 EXIT: POP PSW ; 恢复现场 RETI ; 返回中断 ; 播放闹钟声音 ALARM: MOV DATA, #0xFF ; 发送高电平信号 CALL DELAY ; 延时 MOV DATA, #0x00 ; 发送低电平信号 CALL DELAY ; 延时 RET ; 返回 ; 延时函数 DELAY: MOV R4, #DELAY LOOP: DJNZ R4, LOOP RET ; 中断向量表 ORG 0x0023 AJMP TIMER ; 定时器中断 END ; 程序结束 ``` 这段代码通过轮流输出数码管数字来显示时间,使用步进电机来控制时间的转动,当时间到达闹钟设置的时间时,会触发闹钟响铃。代码中使用了中断处理程序来实现定时器的功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值