赞
踩
时隔一年,重新拾起Verilog,对之前写的模六十计数器进行修改,使其尽量符合编写规范,用电路的思想写程序,解决遗留的计数器进位问题,并使用模块化编程增强可读性和扩展性。
模六十计数器顶层模块Mo60:相当于60s计时器
计数分频模块Div_cnt:将系统时钟转为1Hz输入计数模块
计数模块Count:两个计数器级联,通过设置同步置零信号完成60进制
扫描模块Scan:将系统时钟转为2x100Hz,对两个数码管引脚扫描
译码模块Convert:组合逻辑,将计数转为数码管引脚电位
具体原理见上一篇
/* 模六十计数器顶层模块Mo60:相当于60s计时器 计数分频模块Div_cnt:将系统时钟转为1Hz输入计数模块 计数模块Count:两个计数器级联,通过设置进位信号完成60进位 扫描模块Scan:将系统时钟转为2x100Hz,对两个数码管引脚扫描 译码模块Convert:组合逻辑,将计数转为数码管引脚电位 */ module Mo60( input clk,//系统时钟50MHz input rst_n,//异步复位按钮 output [3:0] loc,//被选中数码管的位置 output [7:0] pin//被选中数码管的八个引脚 ); //计数部分 wire clk_cnt;//计数时钟 wire co1, co0;//进位信号 wire [3:0] n1, n0;//十位与个位数据 Div_cnt U0(.clk(clk), .rst_n(rst_n), .clk_cnt(clk_cnt)); Count U1(.clk(clk_cnt), .rst_n(rst_n), .en(1), .set(co0), .cnt(n0)); Count U2(.clk(clk_cnt), .rst_n(rst_n), .en(co0), .set(co1), .cnt(n1)); assign co0 = (n0 == 9); assign co1 = (n1 == 5)&&(n0 == 9);//可实现模任意两位数 //扫描部分 Scan U3(.clk(clk), .loc(loc)); //译码部分 reg [3:0] num;//待译码数字 always @(loc, n1, n0) begin case (loc) 4'b1101: num = n1; 4'b1110: num = n0; default: num = 4'bxxxx;//避免锁存 endcase end Convert U4(.num(num), .pin(pin)); endmodule
/* 计数器分频模块 系统时钟50MHz 仿真时输出1MHz 下载时输出1Hz 上升沿触发计数 CNT_END=50M/(2x计数频率) */ module Div_cnt ( input clk, input rst_n, output reg clk_cnt); reg [24:0] counter; parameter [24:0] CNT_END = 24;//仿真时计数25 //parameter [24:0] CNT_END = 24 999 999;//下载时计数25M always @(posedge clk, negedge rst_n) begin if (!rst_n) begin counter <= 0; clk_cnt <= 1;//上升沿触发计数 end else if (counter == CNT_END) begin counter <= 0; clk_cnt <= !clk_cnt; end else counter <= counter + 1; end endmodule
/* 计数模块 16进制计数器 同步置零在外部电路完成 */ module Count( input clk,//时钟 input rst_n,//异步复位 input en,//使能 input set,//同步置0 output reg [3:0] cnt);//计数值 always @(posedge clk, negedge rst_n) begin if(!rst_n) cnt <= 0; else if(set) cnt <= 0; else if(en) cnt <= cnt + 1; end endmodul
/* 扫描模块 扫描分频,系统时钟50MHz 仿真时5MHz(每计一次数扫描5轮) 下载时100Hz(扫描一轮100Hz) 数码管选择,为0表示被选中 电平触发扫描 CNT_END=50M/(扫描数x扫描频率) */ module Scan( input clk, output reg [3:0] loc); //扫描分频 reg [17:0] counter = 0;//最多计到249999 reg flag = 0;//选择标志 parameter [17:0] CNT_END = 4;//仿真时计数5 //parameter [17:0] CNT_END = 249 999;//下载时计数250 000 always @(posedge clk) begin if (counter == CNT_END) begin counter <= 0; flag <= ~flag; end else counter <= counter + 1; end //数码管选择 always @(flag) begin case(flag) 0: loc = 4'b1110; 1: loc = 4'b1101; default loc = 4'bxxxx; endcase end endmodule
/* 译码模块 将取到的数转换为数码管对应的电平 组合逻辑 */ module Convert( input [3:0] num, output reg [7:0] pin); always @(num) begin case(num) 0: pin = 8'b00000011;//最后一位表示小数点 1: pin = 8'b10011111; 2: pin = 8'b00100101; 3: pin = 8'b00001101; 4: pin = 8'b10011001; 5: pin = 8'b01001001; 6: pin = 8'b01000001; 7: pin = 8'b00011111; 8: pin = 8'b00000001; 9: pin = 8'b00001001; default: pin = 8'b01100001;//其他状态显示E endcase end endmodule
/* 测试文件 */ `timescale 1ns/1ns module Test_mo60; reg clk; reg rst_n; wire [3:0] loc; wire [7:0] pin; parameter PERIOD = 20;//时钟周期20ns Mo60 u_Mo60 ( .clk(clk), .rst_n(rst_n), .loc(loc), .pin(pin)); initial begin clk = 0; rst_n = 1; end always #10 clk = ~clk; initial begin #5000 rst_n = 0; #5000 rst_n = 1; #90000 rst_n = 0; #5000 rst_n = 1; end endmodule
本次修改只对程序进行了简单的仿真而未在FPGA中进行验证,不排除实际使用时可能会出现问题。
1、整体波形
2、进位部分波形
永远不知道学的东西什么时候会用上,这几天抽空把之前写的EDA数字钟再改一下。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。