【FPGA】高云FPGA之数字钟实验->HC595驱动数码管(二)

简介: 【FPGA】高云FPGA之数字钟实验->HC595驱动数码管

【FPGA】高云FPGA之数字钟实验->HC595驱动数码管(一)https://developer.aliyun.com/article/1472641


2.2 74HC595驱动

为了节省IO引脚开发板数码管设计采用了74HC595来扩展IO,该芯片的作用是位移位寄存器,FPGA 只需要输出 3 个管脚,即可达到发

送数码管数据的目的,与传统段选、位选方式相比,大大节省了 IO 设计资源,在该原理图下,将第一片74HC595的Q7‘串行输出端接到第二片的数据输入端Ds,实现级联功能。经过14个时钟SHcp上升沿后,数据已经全部移位进入移位寄存器,一次共输入14位数据,那么第一位输入的串行数据会在第二片74HC595芯片的Q5输出,此时给一个上升沿的STcp信号就可以将信号移入存储寄存器,OE信号持续给低, 即可输出。这里贴一个博主做的很好理解的gif图。

设计代码如下

module hc595(
  input clk,
    input reset_n,
    input [15:0]data,
    input s_en,
    output reg sh_cp,
    output reg st_cp,
    output reg ds
);
assign reset=~reset_n;
/*******************时钟模块*********************************/
parameter CNT_MAX = 2;
reg [15:0]r_data; //数据寄存器
reg [7:0]clk_count;//分频计数器;
always@(posedge clk)
begin
    if(s_en)
        r_data <= data;
end
always@(posedge clk or posedge reset)
begin
    if(reset)
        clk_count <= 0;
    else if(clk_count == CNT_MAX - 1'b1)
        clk_count <= 0;
    else
        clk_count <= clk_count + 1'b1;
end    
wire sck_plus;
assign sck_plus = (clk_count == CNT_MAX - 1'b1);
//对 sck_pluse进行计数, 用于查找表实现数据的串行输入以及移位时钟 sh_cp与存储时钟 st_cp 的产生
reg [5:0]SHCP_EDGE_CNT;
always@(posedge clk or posedge reset)
begin
    if(reset)
        SHCP_EDGE_CNT <= 0;
    else if(sck_plus)begin
        if(SHCP_EDGE_CNT == 6'd32)
            SHCP_EDGE_CNT <= 0;
        else
            SHCP_EDGE_CNT <= SHCP_EDGE_CNT + 1'b1;
    end
    else
        SHCP_EDGE_CNT <= SHCP_EDGE_CNT;
end
    
// 查找表实现状态输出
always@(posedge clk or posedge reset)
begin
    if(reset)begin
        st_cp <= 1'b0;
        ds <= 1'b0;
        sh_cp <= 1'd0;
    end 
    else begin
        case(SHCP_EDGE_CNT)
            0: begin sh_cp <= 0; st_cp <= 1'd0;ds <= r_data[15];end
            1: begin sh_cp <= 1; st_cp <= 1'd0;end
            2: begin sh_cp <= 0; ds <= r_data[14];end
            3: begin sh_cp <= 1; end
            4: begin sh_cp <= 0; ds <= r_data[13];end 
            5: begin sh_cp <= 1; end
            6: begin sh_cp <= 0; ds <= r_data[12];end 
            7: begin sh_cp <= 1; end
            8: begin sh_cp <= 0; ds <= r_data[11];end 
            9: begin sh_cp <= 1; end
            10: begin sh_cp <= 0; ds <= r_data[10];end  
            11: begin sh_cp <= 1; end
            12: begin sh_cp <= 0; ds <= r_data[9];end 
            13: begin sh_cp <= 1; end
            14: begin sh_cp <= 0; ds <= r_data[8];end 
            15: begin sh_cp <= 1; end
            16: begin sh_cp <= 0; ds <= r_data[7];end 
            17: begin sh_cp <= 1; end
            18: begin sh_cp <= 0; ds <= r_data[6];end 
            19: begin sh_cp <= 1; end
            20: begin sh_cp <= 0; ds <= r_data[5];end 
            21: begin sh_cp <= 1; end
            22: begin sh_cp <= 0; ds <= r_data[4];end 
            23: begin sh_cp <= 1; end
            24: begin sh_cp <= 0; ds <= r_data[3];end 
            25: begin sh_cp <= 1; end
            26: begin sh_cp <= 0; ds <= r_data[2];end 
            27: begin sh_cp <= 1; end
            28: begin sh_cp <= 0; ds <= r_data[1];end     
            29: begin sh_cp <= 1; end
            30: begin sh_cp <= 0; ds <= r_data[0];end
            31: begin sh_cp <= 1; end
            32: st_cp <= 1'd1;
            default:    
                begin
                    st_cp <= 1'b0;
                    ds <= 1'b0;
                    sh_cp <= 1'd0;
                end
        endcase
    end
end
endmodule

2.3 主模块设计

完成了数码管驱动的显示,要实现计时的功能我们需要在主模块中设计一个1秒定时器来实现计数,然后在调用我们写好的模块将计数值传入到数码管中进行显示,为了更简单的理解这里没有添加更多的功能,但接口都是比较完整的可以自行DIY优化设计属于自己的数值钟,这里开拓一些功能(按键调整时间,设置定时器闹钟,轮流显示日期温度和时间,网络对时,掉点保存等等),好下面开始设计我们的简单计时代码;

module seg_top(
  input clk, // system 50m
  input reset_n,
  output sh_cp,
  output st_cp,
  output ds
);
parameter MCNT = 49_999_999; // 一秒计数器 
wire [31:0]disp_data;
wire [7:0] sel;//数码管位选(选择当前要显示的数码管)
wire [7:0] seg;//数码管段选(当前要显示的内容)
wire [7:0]dp_data;//数码管小数点(某位点亮某位置1)
reg dp_flag;  // 小数点寄存器
reg [31:0]disp_data_reg = 32'h00000000; // 显示数据寄存器
reg [25:0]cnt; //定义计数器寄存器
reg[3:0] hour_reg_h;
reg[3:0] hour_reg_l;
reg[3:0] min_reg_h;
reg[3:0] min_reg_l;
reg[3:0] sec_reg_h;
reg[3:0] sec_reg_l;
  
//assign disp_data = disp_data_reg;
assign disp_data = {4'h2,4'h4,hour_reg_h,hour_reg_l,min_reg_h,min_reg_l,sec_reg_h,sec_reg_l};
assign dp_data = (dp_flag) ? 8'b0101_0100 : 8'b0101_0000;
hc595 hc595_mod(
    .clk(clk),
    .reset_n(reset_n),
    .data({seg,sel}),
    .s_en(1'b1),
    .sh_cp(sh_cp),
    .st_cp(st_cp),
    .ds(ds)
);
hex8 hex8_mod(
    .clk(clk),
    .reset_n(reset_n),
    .en(1'b1), 
    .disp_data(disp_data),
    .sel(sel),
    .seg(seg),
    .dp(dp_data)
);
assign reset=~reset_n;
//计数器计数进程
always@(posedge clk or posedge reset)
begin
    if(reset)
        cnt <= 25'd0;
    else if(cnt == MCNT)
        cnt <= 25'd0;
    else
        cnt <= cnt + 1'b1;
end
//时钟 输出控制进程
always@(posedge clk or posedge reset)
begin
    if(reset)
        begin
            dp_flag <= 1'b1;
            disp_data_reg = 0;
        end
    else if(cnt == 24_999_999) // 0.5反转一次dp点
        dp_flag <= ~dp_flag;
    else if(cnt == MCNT) // 一秒计时
        begin
            dp_flag <= ~dp_flag;
            disp_data_reg = disp_data_reg+1;
            sec_reg_l = sec_reg_l+1;
            if(sec_reg_l == 4'd9)
            begin
                sec_reg_l <= 0;
                sec_reg_h <= sec_reg_h + 1;
                if(sec_reg_h == 4'd5)
                begin
                    sec_reg_h <= 0;
                    min_reg_l <= min_reg_l + 1;
                    if(min_reg_l == 4'd9)
                    begin
                        min_reg_l <= 0;
                        min_reg_h <= min_reg_h + 1;
                        if(min_reg_h == 4'd5)
                        begin
                            min_reg_h <= 0;
                            hour_reg_l <= hour_reg_l + 1;
                            if((hour_reg_h==4'd2) && (hour_reg_l==4'd3))
                            begin
                                hour_reg_l <=0;
                                hour_reg_h <=0;
                            end
                            if(hour_reg_l == 4'd9)
                            begin
                                hour_reg_l <= 0;
                                hour_reg_h <= hour_reg_h + 1;
                            end
                        end
                    end
                end
            end
        end
    else
        dp_flag <= dp_flag;
end
  
endmodule


【FPGA】高云FPGA之数字钟实验->HC595驱动数码管(三)https://developer.aliyun.com/article/1472644

相关文章
|
2天前
|
芯片 异构计算
【FPGA】高云FPGA之数字钟实验->HC595驱动数码管(一)
【FPGA】高云FPGA之数字钟实验->HC595驱动数码管
|
2天前
|
芯片 异构计算
【FPGA】高云FPGA之数字钟实验->HC595驱动数码管(三)
【FPGA】高云FPGA之数字钟实验->HC595驱动数码管
|
2天前
|
机器学习/深度学习 算法 异构计算
m基于FPGA的多通道FIR滤波器verilog实现,包含testbench测试文件
本文介绍了使用VIVADO 2019.2仿真的多通道FIR滤波器设计。展示了系统RTL结构图,并简述了FIR滤波器的基本理论,包括单通道和多通道的概念、常见结构及设计方法,如窗函数法、频率采样法、优化算法和机器学习方法。此外,还提供了Verilog核心程序代码,用于实现4通道滤波器模块,包含时钟、复位信号及输入输出接口的定义。
41 7
|
2天前
|
算法 异构计算
基于FPGA的ECG信号滤波与心率计算verilog实现,包含testbench
基于FPGA的ECG信号滤波与心率计算verilog实现,包含testbench
|
2天前
|
算法 异构计算
m基于FPGA的电子钟verilog实现,可设置闹钟,包含testbench测试文件
该文介绍了基于FPGA的电子钟设计,利用Vivado2019.2平台进行开发并展示测试结果。电子钟设计采用Verilog硬件描述语言,核心包括振荡器、分频器和计数器。时间显示为2个十进制格式,闹钟功能通过存储器和比较器实现,当当前时间等于设定时间时触发。文中给出了Verilog核心程序示例,展示了时钟信号、设置信号及输出的交互。
39 2
|
2天前
|
算法 5G 数据处理
m基于FPGA的PPM光学脉位调制解调系统verilog实现,包含testbench
m基于FPGA的PPM光学脉位调制解调系统verilog实现,包含testbench
59 0
|
2天前
|
算法 异构计算 索引
m基于FPGA的Hamming汉明编译码verilog实现,包含testbench测试文件,不使用IP核
m基于FPGA的Hamming汉明编译码verilog实现,包含testbench测试文件,不使用IP核
52 1
|
2天前
|
算法 异构计算
m基于FPGA的MPPT最大功率跟踪算法verilog实现,包含testbench
该内容包括三部分:1) 展示了Vivado 2019.2和Matlab中关于某种算法的仿真结果图像,可能与太阳能光伏系统的最大功率点跟踪(MPPT)相关。2) 简述了MPPT中的爬山法原理,通过调整光伏电池工作点以找到最大功率输出。3) 提供了一个Verilog程序模块`MPPT_test_tops`,用于测试MPPT算法,其中包含`UI_test`和`MPPT_module_U`两个子模块,处理光伏电流和电压信号。
8 1
|
2天前
|
算法 异构计算
m基于FPGA的RS+卷积级联编译码实现,RS用IP核实现,卷积用verilog实现,包含testbench测试文件
m基于FPGA的RS+卷积级联编译码实现,RS用IP核实现,卷积用verilog实现,包含testbench测试文件
17 0
|
2天前
|
存储 算法 异构计算
m基于FPGA的多功能信号发生器verilog实现,包含testbench,可以调整波形类型,幅度,频率,初始相位等
使用Vivado 2019.2仿真的DDS信号发生器展示了正弦、方波、锯齿波和三角波的输出,并能调整幅度和频率。DDS技术基于高速累加器、查找表和DAC,通过频率控制字和初始相位调整产生各种波形。Verilog程序提供了一个TEST模块,包含时钟、复位、信号选择、幅度和频率控制输入,以生成不同波形。
39 18

热门文章

最新文章