文章摘要:
本文主要描述了数码管扫描电路的实现方案;

知识要点:有限状态机,模块例化;


硬件平台: EP4CE6F17C8
开发环境: Quartus II 13.1


数码管扫描模块:

/*
 *  功能描述:6位数码管扫描模块
 */
module smg_scan(
    input clk,                  // 时钟信号
    input rst_n,                // 复位信号
    output reg[7:0]data_pin,    // 数据引脚,共阳数码管
    output reg[5:0]sel_pin,     // 选通引脚,低电平导通   
    input  [7:0]seg0,           // 数据0
    input  [7:0]seg1,           // 数据1
    input  [7:0]seg2,           // 数据2
    input  [7:0]seg3,           // 数据3
    input  [7:0]seg4,           // 数据4
    input  [7:0]seg5            // 数据5
);
    
//--------------------------------------------------    
// 有限状态机
parameter S_SEG0 = 4'd1;
parameter S_SEG1 = 4'd2;
parameter S_SEG2 = 4'd3;
parameter S_SEG3 = 4'd4;
parameter S_SEG4 = 4'd5;
parameter S_SEG5 = 4'd6;
reg[3:0] state; // 记录当前状态

/*
 * 全部刷新时间不能超过10ms,否则人眼可以感觉到闪烁
 * 如果刷新时间缩短至5ms以内,则低速摄像机也扑捉不到闪烁
 */
parameter FLUSH_COUNT = 50_000; // 单个刷新时间1ms,全部刷新时间为6ms
reg[31:0] count;    // 刷新记数器

always @(posedge clk, negedge rst_n) begin
    if(!rst_n) begin
        sel_pin <= 6'b111111;   // 复位时关闭显示
        state <= S_SEG0;        // 回到初始状态
    end
    
    else if(count >= FLUSH_COUNT) begin  // 定时时间到       
        count <= 0;     // 重新计数      
    
        case(state)     
        S_SEG0: begin
            state    <= S_SEG1;
            sel_pin  <= 6'b111110;  // 片选
            data_pin <= seg0;       // 数据
        end
        
        S_SEG1: begin
            state    <= S_SEG2;
            sel_pin  <= 6'b111101;
            data_pin <= seg1;
        end
        S_SEG2: begin
            state    <= S_SEG3;
            sel_pin  <= 6'b111011;      
            data_pin <= seg2;   
        end
        
        S_SEG3: begin
            state    <= S_SEG4;
            sel_pin  <= 6'b11_0111;     
            data_pin <= seg3;
        end
        
        S_SEG4: begin
            state    <= S_SEG5;
            sel_pin  <= 6'b10_1111;     
            data_pin <= seg4;
        end
        
        S_SEG5: begin
            state    <= S_SEG0; // 最后一个显示完,下一次该显示示第一个了
            sel_pin  <= 6'b01_1111;
            data_pin <= seg5;
        end 
        
        default: begin
            state <= S_SEG0;    // 未知状态,返回第一个状态
        end
        endcase
    end
    
    else begin
        count <= count + 1'b1;     // 最后一个时钟沿其实是没计数的;
    end
    
end
endmodule

译码器计数器模块:

/*
 *  功能描述:异步十进制译码计数器
 */
module decoder(    
    clk,    // 计数时钟
    rst_n,  // 异步复位    
    seg,    // 译码输出
    carry   // 进位(做为下级时钟)
);

input  clk;
input  rst_n;
output reg [7:0] seg; 
output reg carry; 
//------------------------------------------
reg [3:0] count;   // 计数器

// 十进制计数器
always @(posedge clk or negedge rst_n) begin
    if(~rst_n) begin
        count <= 0;
        carry <= 1'b0;  
    end
    else if(count < 9) begin
        count <= count + 1'b1;
        carry <= 1'b0;  
    end
    else begin
        count <= 0;
        carry <= 1'b1;   // 产生进位      
    end        
end

// 组合逻辑
always @(*) begin
    if(~rst_n) begin
        seg <= 8'b1111_1111;    // 全灭
    end
    else begin
        case(count)
        4'd0:
            seg <= 8'b1100_0000;    
        4'd1:
            seg <= 8'b1111_1001;
        4'd2:
            seg <= 8'b1010_0100;
        4'd3:
            seg <= 8'b1011_0000;
        4'd4:
            seg <= 8'b1001_1001;
        4'd5:
            seg <= 8'b1001_0010;
        4'd6:
            seg <= 8'b1000_0010;
        4'd7:
            seg <= 8'b1111_1000;
        4'd8:
            seg <= 8'b1000_0000;
        4'd9:
            seg <= 8'b1001_0000;
        4'd10:
            seg <= 8'b1000_1000;
        default:
            seg <= 8'hff;
        endcase
    end
end
endmodule

建立顶层模块(测试用)

/*
 *  功能描述:数码管测试程序
 */
module smg_test(
    input clk,              // 系统时钟
    input rst_n,            // 系统复位
    output [7:0]data_pin,   // 数据管数据脚
    output [5:0]sel_pin     // 数码管片选脚
);

reg[31:0] timer;    // 定时器
reg tick;

// 模块连接线
wire[7:0]seg0;
wire[7:0]seg1;
wire[7:0]seg2;
wire[7:0]seg3;
wire[7:0]seg4;
wire[7:0]seg5;
wire[7:0]seg6;

wire c0;    // 计数器进位
wire c1;
wire c2;
wire c3;
wire c4;
//-----------------------------------------------    
always @(posedge clk or negedge rst_n) begin
    if(~rst_n)
    begin
        timer <= 0;
        tick  <= 0;
    end    
    else if(timer == 32'd25_000_000)
    begin
        tick  <= 1'b1;
        timer <= 0;         
    end    
    else begin
        tick  <= 0;
        timer <= timer + 1'b1;
    end
end 
// 例化数码管显示模块
smg_scan s0(
    .clk(clk),              // 时钟信号
    .rst_n(rst_n),          // 复位信号
    .data_pin(data_pin),    // 数据引脚,共阳数码管
    .sel_pin(sel_pin),      // 选通信号,低电平导通   
    .seg0(seg0),            // 数据
    .seg1(seg1),            // 数据
    .seg2(seg2),            // 数据
    .seg3(seg3),            // 数据
    .seg4(seg4),            // 数据
    .seg5(seg5)             // 数据
);

// 例化6个显示译码器,用于将数字转化为显示段码;
decoder u0(
    .clk(tick),    // 计数时钟
    .rst_n(rst_n), // 异步复位
    .seg(seg0),    // 译码输出
    .carry(c0)     // 进位
);
decoder u1(
    .clk(c0),      // 计数时钟
    .rst_n(rst_n), // 异步复位
    .seg(seg1),    // 译码输出
    .carry(c1)     // 进位
);
decoder u2(
    .clk(c1),      // 计数时钟
    .rst_n(rst_n), // 异步复位
    .seg(seg2),    // 译码输出
    .carry(c2)     // 进位
);
decoder u3(
    .clk(c2),      // 计数时钟
    .rst_n(rst_n), // 异步复位
    .seg(seg3),    // 译码输出
    .carry(c3)     // 进位
);
decoder u4(
    .clk(c3),      // 计数时钟
    .rst_n(rst_n), // 异步复位
    .seg(seg4),    // 译码输出
    .carry(c4)     // 进位
);
decoder u5(
    .clk(c4),      // 计数时钟
    .rst_n(rst_n), // 异步复位
    .seg(seg5),    // 译码输出
    .carry()       // 进位
);
endmodule