FPGA入门实验-基于状态机实现4位共阴极数码管显示超声波模块读数

任务目标

基于状态机实现4位共阴极数码管显示超声波模块读数。最近生产实习的FPGA培训课程内容,还是挺简单的。具体原理其他文章应该都烂大街了,重点是状态机的写法,还是很少博主写,没怎么看到,基本上都是时序机写的模块功能。

实现代码

4位共阴极数码模块代码seg.v:

`timescale 1ns/1ps
module seg
#(
    parameter SYSCLK    =   125_000_000,
    parameter TIME      =   1000,
    parameter MODE      =   0           // 0 gong yin ji; 1 gong yang ji
)(
    input   sysclk,
    input   rst_n,
    input       [4:0]  set,//xian shi jin zhi:8/10/16
    input       [15:0] number,
    output       [3:0] DIG,
    output       [7:0] SEG
    );
reg [3:0]   DIG_t;
reg[7:0]    SEG_t;
reg[31:0]   cnt;
//-------------译码-----------//
function [7:0]  seg_out;
    input [3:0] number_in;
    case(number_in)
        4'd0:  seg_out = 8'hc0; 
        4'd1:  seg_out = 8'hf9; 
        4'd2:  seg_out = 8'ha4; 
        4'd3:  seg_out = 8'hb0; 
        4'd4:  seg_out = 8'h99; 
        4'd5:  seg_out = 8'h92; 
        4'd6:  seg_out = 8'h82; 
        4'd7:  seg_out = 8'hf8; 
        4'd8:  seg_out = 8'h80; 
        4'd9:  seg_out = 8'h90; 
        4'd10: seg_out = 8'h88; 
        4'd11: seg_out = 8'h83; 
        4'd12: seg_out = 8'hc6; 
        4'd13: seg_out = 8'ha1; 
        4'd14: seg_out = 8'h86;  
        4'd15: seg_out = 8'h8e; 
        default:seg_out = 8'hff;
    endcase
endfunction    

/*        wei xuan qie huan            */    
always@(posedge sysclk)
    if(!rst_n) begin
        DIG_t <= 4'b0001;
        cnt <= 32'd0;
        end
    else if(cnt>=TIME-1) begin
        DIG_t <= {DIG_t[2:0],DIG_t[3]};
        cnt <= 32'd0;
        end
    else begin
        DIG_t <= DIG_t;
        cnt <= cnt + 32'd1;
        end

/*shu jv ti qv*/
reg[3:0] num1,num2,num3,num4;
always@(*)begin
    num1 <= number%set;                 // ge wei
    num2 <= (number/set)%set;           //shi wei
    num3 <= (number/(set*set))%set;     //bai wei
    num4 <= (number/(set*set*set))%set; // qian wei
end

/*duan xuan shu chu*/
always@(posedge sysclk)
    if(!rst_n)
        SEG_t <= 8'hff;
    else
        case(DIG_t)
            4'b0001:SEG_t <= seg_out(num1);
            4'b0010:SEG_t <= seg_out(num2);
            4'b0100:SEG_t <= seg_out(num3);
            4'b1000:SEG_t <= seg_out(num4);
            default:SEG_t <= 8'hff;
        endcase
assign SEG = (MODE)?SEG_t:~SEG_t;
assign DIG = (MODE)?DIG_t:~DIG_t;
endmodule

超声波模块代码trasonic.v:

`timescale 1ns / 1ps
module trasonic
#(
    parameter SYSCLK = 125_000_000,
    parameter TIME1  = 5000,//激励时间(大于等于10us)
    parameter TIME2  = 200_000_00 //总周期 (大于等于80ms)
)
(
    input               sysclk      ,
    input               rst_n       ,
    input               Echo        ,
    output reg          Trig        ,
    output reg [15:0]   distence
    );
localparam IDLE = 2'd0;
localparam TRIG = 2'd1;
localparam RECE = 2'd2; 
reg [31:0] cnt;
reg [63:0] number;//距离寄存器 
reg [1:0] cur_state,next_state;
reg [63:0]h_cnt;//记录高电平所在的次数
//____________________state1______________________//
always@(posedge sysclk)
    if(!rst_n)
        cur_state <= IDLE;
    else
        cur_state <= next_state;
//______________________state2_____________________//
always@(*)begin
    next_state = IDLE;
    case(cur_state)
        IDLE:begin
            next_state = TRIG;
        end
        TRIG:begin
            if(cnt >= TIME1 - 1)
                next_state = RECE;
            else
                next_state = cur_state;
        end
        RECE:begin
            if(cnt >= TIME2 - 1)
                next_state = IDLE;
            else
                next_state = cur_state;
        end
        default:next_state = IDLE;
    endcase
end
//________________________state3______________________//
always@(posedge sysclk)
    if(!rst_n)begin
        cnt <= 32'd0;
        Trig <= 0;
        h_cnt <= 64'd0;
    end
    else
        case(cur_state)
            IDLE:begin
                cnt <= 32'd0;
                Trig <= 0;
                h_cnt <= 64'd0; 
            end
            TRIG:begin
                Trig <= 1;
                cnt <= cnt + 32'd1;
                h_cnt <= 64'd0; 
            end
            RECE:begin
                Trig <= 0;
                cnt <= cnt + 32'd1;
                if(Echo)
                    h_cnt <= h_cnt + 64'd1;
                else
                    h_cnt <= h_cnt;
            end
            default:begin
                cnt <= 32'd0;
                Trig <= 0;
                h_cnt <= 64'd0; 
            end
        endcase
//_____________________数据处理_____________________//
localparam t = 1000_000_000;
localparam T = t/SYSCLK;//(8ns)
always@(*)
    number = (cnt == (TIME2 - 1)) ? ((h_cnt*T)/58/1000):number;
    //保证数据稳定传输
always@(*)
    distence = number;
endmodule

顶层文件top.v:

module top(
    input sysclk                ,
    input rst_n                 ,
    input               Echo    ,
    output              Trig    ,
    output  [7:0]   SEG         ,
    output  [3:0]   DIG
    );

wire [15:0] num;

seg
#(
     .SYSCLK    (125_000_000)   ,
     .TIME      (1000)          ,
     .MODE      (0)
)a(
       .sysclk  (sysclk)    ,
       .rst_n   (rst_n)     ,
       .set     (10)        ,
       .number  (num)      ,
       .DIG     (DIG)       ,
       .SEG     (SEG)
    );

trasonic
#(
    .SYSCLK  (125_000_000)      ,
    .TIME1   (5000       )      ,
    .TIME2   (20_000_000 )
)b(
    .sysclk  (sysclk)  ,
    .rst_n   (rst_n)   ,
    .Echo    (Echo)    ,
    .Trig    (Trig)    ,
    .distence(num)
    );


endmodule

结语

这个需要的引脚挺多的——14个pin,在引脚配置的时候别重复了哦。不然生成二进制文件流的时候会报错。

  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
这是一个比较典型的FPGA数字电路设计问题。下面是一个简单的设计原理: 1. 时钟信号:计数器需要一个时钟信号来进行计数。时钟信号可通过一个需要计数的高速时钟信号分频得到。可以使用FPGA内部的时钟分频器模块实现。 2. 同步复位和使能控制端:计数器需要一个同步复位信号和一个使能控制信号。同步复位信号可以通过按键或外部信号触发,使计数器重新从0开始计数。使能控制信号可以通过开关或外部信号控制,使计数器在特定时间段内停止计数。 3. 4位二进制加1计数器:设计一个4位二进制加1计数器,可以使用FPGA内部的计数器模块实现。计数器根据时钟信号进行计数,每计数到15时,需要将计数值清零。 4. 共阴极数码管显示:将计数器的输出值转换为七段显示的信号,将信号驱动共阴极数码管显示。可以使用FPGA内部的七段译码器模块和数码管驱动模块实现。 5. 可逆计数和可装载预置数:如果需要实现可逆计数和可装载预置数功能,可以在计数器模块中添加控制逻辑。例如,当计数器需要逆向计数时,可以在控制逻辑中将计数器的计数方向反转。当需要装载预置数时,可以在控制逻辑中将预置数值加载到计数器中。 6. 两位共阴极数码管显示十进制数:如果需要实现位共阴极数码管显示十进制数的功能,可以在计数器模块中添加BCD码转换器。将计数器的输出值转换为BCD码,然后将BCD码转换为两个七段信号,分别驱动两位共阴极数码管显示。可以使用FPGA内部的BCD码转换器模块实现
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

星羽空间

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值