文章目录
- 前言
- 一、代码模板
- 二、Verilog程序
- 1、顶层模块
- 2、计数模块
- 3、显示模块
- 三、Testbench程序
- 四、仿真波形
- 五、实测结果
- 总结
前言
又隔了将近一年,学习明德扬编程规范,重新编写模六十计数器程序,使其符合规范,并采用模板化与模块化编程,使程序思路更加清晰。与之前不同,此次编程在Quartus II 13.0中建立项目,在AX530开发板上下载调试,引脚定义与配置需要视情况更改,项目文件将上传到资源中。
一、代码模板
修改明德扬代码模板
:ab Zhushi /***************注释***************/
:ab Shixu always@(posedge clk or negedge rst_n)begin<Enter>if(!rst_n)begin<Enter>end<Enter>else begin<Enter>end<Enter>end
:ab Zuhe always@(*)begin<Enter>end
:ab Module module module_name(<Enter>clk,<Enter>rst_n,<Enter>//<Enter>dout<Enter>);<Enter><Enter>//参数定义<Enter>parameter LENGTH = 8;<Enter>//输入输出<Enter>input clk;<Enter>input rst_n;<Enter>output [7:0] dout;<Enter>reg [7:0] dout;<Enter>//中间信号<Enter>reg signal;<Enter><Enter><Enter>endmodule
:ab Unit module_name Unit(<Enter>.clk(clk),<Enter>.rst_n(rst_n),<Enter>.dout(dout)<Enter>);
:ab Ztj /***************四段式状态机***************/<Enter>//状态更新<Enter>always@(posedge clk or negedge rst_n)begin<Enter>if(!rst_n)<Enter>state_c <= IDLE;<Enter>else<Enter>state_c <= state_n;<Enter>end<Enter>//状态转移<Enter>always@(*)begin<Enter>case(state_c)<Enter>IDLE:begin<Enter>if(idle_s1)<Enter>state_n = S1;<Enter>else <Enter>state_n = state_c;<Enter>end<Enter>S1:begin<Enter>if(s1_s2)<Enter>state_n = S2;<Enter>else <Enter>state_n = state_c;<Enter>end<Enter>S2:begin<Enter>if(s2_s3)<Enter>state_n = S3;<Enter>else <Enter>state_n = state_c;<Enter>end<Enter>default:begin<Enter>state_n = IDLE;<Enter>end<Enter>endcase<Enter>end<Enter>//转移条件<Enter>assign idle_s1 = (state_c == IDLE) && ();<Enter>assign s1_s2 = (state_c == S1) && ();<Enter>assign s2_s3 = (state_c == S2) && ();<Enter>//(寄存器输出)<Enter>always@(posedge clk or negedge rst_n)begin<Enter>if(!rst_n)begin<Enter>out1 <= 1'b0;<Enter>end<Enter>else if(state_c == S1)begin<Enter>out1 <= 1'b1;<Enter>end<Enter>else begin<Enter>out1 <= 1'b0;<Enter>end<Enter>end
:ab Jsq reg [3:0] cnt;<Enter>wire en;<Enter>wire co;<Enter>always@(posedge clk or negedge rst_n)begin<Enter>if(!rst_n)begin<Enter>cnt <= 0;<Enter>end<Enter>else if(en)begin<Enter>if(co)<Enter>cnt <= 0;<Enter>else<Enter>cnt <= cnt + 1;<Enter>end<Enter>end<Enter>assign en = ; <Enter>assign co = (en) && (cnt ==);
二、Verilog程序
1、顶层模块
顶层模块尽量减少逻辑描述,只实现子模块之间的连接
计数模块实现间隔为1s的六十进制计数器
显示模块完成数码管的驱动,可作为基本模块使用
/***************模六十计数器顶层模块***************/
module Mo60(
clk,
rst_n,
smg_sig,
smg_loc
);
//输入输出
input clk;
input rst_n;
output [7:0] smg_sig;
output [5:0] smg_loc;
wire [7:0] smg_sig;
wire [5:0] smg_loc;
//中间信号
wire [7:0] cnt_val;
wire [23:0] data;
/***************计数模块***************/
Count U_count(
.clk(clk),
.rst_n(rst_n),
.cnt_val(cnt_val)
);
assign data = {16'b0, cnt_val};
/***************显示模块***************/
Display U_display(
.clk(clk),
.rst_n(rst_n),
.data(data),
.smg_sig(smg_sig),
.smg_loc(smg_loc)
);
endmodule
2、计数模块
计数器模板额外包括了使能与进位信号,对应于加一条件与结束条件,虽然代码量上升,但思路更加清晰且不容易出错
进位信号需要在使能的条件下输出
/***************计数模块***************/
module Count(
clk,
rst_n,
cnt_val
);
//参数定义
parameter CNT_1S = 26'd49_999_999;
parameter CNT_1US = 26'd49;
//输入输出
input clk;
input rst_n;
output [7:0] cnt_val;
wire [7:0] cnt_val;
/***************分频计数器***************/
reg [25:0] cnt_div;
wire en_div;
wire co_div;
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt_div <= 0;
end
else if(en_div)begin
if(co_div)
cnt_div <= 0;
else
cnt_div <= cnt_div + 1;
end
end
assign en_div = 1;
assign co_div = (en_div) && (cnt_div == CNT_1S);
/***************个位计数器***************/
reg [3:0] cnt0;
wire en0;
wire co0;
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt0 <= 0;
end
else if(en0)begin
if(co0)
cnt0 <= 0;
else
cnt0 <= cnt0 + 1;
end
end
assign en0 = co_div;
assign co0 = (en0) && (cnt0 == 9);
/***************十位计数器***************/
reg [3:0] cnt1;
wire en1;
wire co1;
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt1 <= 0;
end
else if(en1)begin
if(co1)
cnt1 <= 0;
else
cnt1 <= cnt1 + 1;
end
end
assign en1 = co0;
assign co1 = (en1) && (cnt1 == 5);
/***************输出计数***************/
assign cnt_val = {cnt1, cnt0};
endmodule
3、显示模块
和之前一样,分频、扫描、译码、显示
在一个always中只对一个信号进行赋值
/***************显示模块***************/
module Display(
clk,
rst_n,
data,
smg_sig,
smg_loc
);
//参数定义
parameter CNT_2MS = 17'd99_999;
parameter CNT_200NS = 17'd9;
//输入输出
input clk;
input rst_n;
input [23:0] data;
output [7:0] smg_sig;
output [5:0] smg_loc;
reg [7:0] smg_sig;
reg [5:0] smg_loc;
/***************分频***************/
reg [16:0] cnt_div;
wire en_div;
wire co_div;
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt_div <= 0;
end
else if(en_div)begin
if(co_div)
cnt_div <= 0;
else
cnt_div <= cnt_div + 1;
end
end
assign en_div = 1;
assign co_div = (en_div) && (cnt_div == CNT_2MS);
/***************扫描***************/
reg [3:0] cnt_scan;
wire en_scan;
wire co_scan;
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt_scan <= 0;
end
else if(en_scan)begin
if(co_scan)
cnt_scan <= 0;
else
cnt_scan <= cnt_scan + 1;
end
end
assign en_scan = co_div;
assign co_scan = (en_scan) && (cnt_scan == 5);
/***************取数***************/
reg [3:0] smg_data;
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
smg_data <= 0;
end
else begin
case(cnt_scan)
0: smg_data <= data[3:0];
1: smg_data <= data[7:4];
2: smg_data <= data[11:8];
3: smg_data <= data[15:12];
4: smg_data <= data[19:16];
5: smg_data <= data[23:20];
endcase
end
end
/***************显示***************/
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
smg_loc <= 6'b000000;
end
else begin
case(cnt_scan)
0: smg_loc <= 6'b111110;
1: smg_loc <= 6'b111101;
2: smg_loc <= 6'b111011;
3: smg_loc <= 6'b110111;
4: smg_loc <= 6'b101111;
5: smg_loc <= 6'b011111;
endcase
end
end
/***************译码***************/
always@(*)begin
case(smg_data)
0: smg_sig = 8'b00000011;
1: smg_sig = 8'b10011111;
2: smg_sig = 8'b00100101;
3: smg_sig = 8'b00001101;
4: smg_sig = 8'b10011001;
5: smg_sig = 8'b01001001;
6: smg_sig = 8'b01000001;
7: smg_sig = 8'b00011111;
8: smg_sig = 8'b00000001;
9: smg_sig = 8'b00001001;
default: smg_sig = 8'b01100001;//E
endcase
end
endmodule
三、Testbench程序
对Quartus生成的模板文件进行修改
`timescale 1 ns/ 1 ns
module Mo60_tb();
reg clk;
reg rst_n;
// wires
wire [5:0] smg_loc;
wire [7:0] smg_sig;
// assign statements (if any)
Mo60 u1 (
// port map - connection between master ports and signals/registers
.clk(clk),
.rst_n(rst_n),
.smg_loc(smg_loc),
.smg_sig(smg_sig)
);
initial begin
clk = 0;
rst_n = 1;
end
always begin
#10 clk = ~clk;
end
initial begin
#100 rst_n = 0;
#100 rst_n = 1;
end
endmodule
四、仿真波形
在仿真时,将计数间隔设为CNT_1US,扫描间隔设为CNT_200NS,以加快仿真速度
五、实测结果
与之前不同,AX530开发板上有6个数码管
总结
使用模板可以提高编程速度,使逻辑更加清晰,特别是解决了计数器逻辑混乱的问题。