这里用第一篇用到的数码管做个简单的秒表,这里说“简单的”,因为初学,就只循环从0到9。完成这个有个准备工作:
1.时钟分频
因为板子的时钟信号不是1s,而是远小于1s,所以要累加多个周期,周期变大,则频率变小,所以叫“分频”。这样的话,就知道要设一个计数器,道理很简单,从0开始,累加到n-1,再加就变回0,同时让新周期信号取反,循环下去,得到的半个周期就变成原来一个周期的n倍,那一个周期就是原来2n倍。
1. 试写变成4倍
开始时写代码如下:
module myclk(
input clk_in,
input rst,
output reg clk_out
);
parameter CNT_4=2;//n=2,2n倍就是4倍
reg [25:0] counter=0;
always @ (posedge clk_in or negedge rst)
if(~rst)
counter<=0;
else
if(counter<CNT_4-1)
counter<=counter+1;
else begin
counter<=0;
clk_out<=~clk_out;
end
endmodule
这里用到一个rst(即reset重置),先说一下rst,rst按键按下后rst=0,否则为1。
另外,同步复位和异步复位其实很简单,想一下如果我按下rst,必然此时是从1到0,是下降沿negedge rst,如果写成always @ (posedge clk or negedge rst),按下按键后肯定是rst=0,即~rst,这时不用管clk,肯定执行if( ~rst)条件下的,这叫异步;而如果写成always @ (posedge clk),虽然按下按键后rst=0,但我clk的上升沿还没到,所以不会立刻有反应,必须等到clk上升沿,这叫同步;
仿真波形图,测试时给定周期变换的clk_in,先给rst一个周期的0相当于按下按键来初始化,之后都为1。关于时钟分频,详细请看:verilog时钟分频设计https://blog.csdn.net/moon9999/article/details/75020355
2.写1s的代码
我这里用板子为50MHz,自然就是50M倍,如下:
module myclk(
input clk_in,
input rst,
output reg clk_1s
);
parameter CNT_1S=25_000_000;//n=25M,2n倍即是50M倍
reg [25:0] counter;
always @ (posedge clk_in or negedge rst)
if(~rst) begin
counter<=0;
clk_1s<=0;
end
else
if(counter<CNT_1S-1)
counter<=counter+1;
else begin
counter<=0;
clk_1s<=~clk_1s;
end
endmodule
2.写秒表
有了上述思想,接下来就按照这个来写秒表:
module shumaguan_jishi(
input clk,
input rst,
output [6:0] light,
output com0
);
assign com0=1;
reg [3:0] num;
myclk myclk(
.clk_in(clk),
.rst(rst),
.clk_1s(clk_1s)
);
always @ (posedge clk_1s or negedge rst)
if(~rst)
num<=0;
else begin
if(num<9)
num<=num+1;
else
num<=0;
end
shumaguan shumaguan(
.num(num),
.light(light)
);
endmodule
module myclk(
input clk_in,
input rst,
output reg clk_1s
);
parameter CNT_1S=25_000_000;//n=25M,2n倍即是50M倍
reg [25:0] counter;
always @ (posedge clk_in or negedge rst)
if(~rst) begin
counter<=0;
clk_1s<=0;
end
else
if(counter<CNT_1S-1)
counter<=counter+1;
else begin
counter<=0;
clk_1s<=~clk_1s;
end
endmodule
module shumaguan(
input [3:0] num,
output reg [6:0] light
);
always @ (num)
case(num)
4'h0: light<=7'b1111110;
4'h1: light<=7'b0110000;
4'h2: light<=7'b1101101;
4'h3: light<=7'b1111001;
4'h4: light<=7'b0110011;
4'h5: light<=7'b1011011;
4'h6: light<=7'b1011111;
4'h7: light<=7'b1110000;
4'h8: light<=7'b1111111;
4'h9: light<=7'b1111011;
default: light<=7'b1111110;
endcase
endmodule
我这里为了练习模块化以及参数传入,把模块分开写了,下面给出一个不分开的,看起来少一些,道理是一样的:
module shumaguan_jishi(
input clk,
input rst,
output reg [6:0] light,
output com0
);
assign com0=1;
parameter CNT_1S=50_000_000;
reg [25:0] counter;
reg [3:0] num;
always @ (posedge clk_in or negedge rst)
if(~rst) begin
counter<=0;
num<=0;
end
begin
else
if(counter<CNT_1S-1)
counter<=counter+1;
else begin
counter<=0;
num<=num+1;
end
end
always @ (num)
case(num)
4'h0: light<=7'b1111110;
4'h1: light<=7'b0110000;
4'h2: light<=7'b1101101;
4'h3: light<=7'b1111001;
4'h4: light<=7'b0110011;
4'h5: light<=7'b1011011;
4'h6: light<=7'b1011111;
4'h7: light<=7'b1110000;
4'h8: light<=7'b1111111;
4'h9: light<=7'b1111011;
default: light<=7'b1111110;
endcase
endmodule
这里为什么用CNT_1S=50_000_000?因为上面时钟分频取反再取反才是一个周期,才让数加1,这里我直接让数加1,所以就是50M。
第二篇完