功能要求
LED,每500ms,状态翻转一次
系统时钟为50MHz,20ns
利用系统时钟进行计数
500ms/20ns
= 500_000_000ns/20ns
= 25_000_000 [二进制25位,定义reg要用]
补充知识
时序逻辑<=赋值
一般情况下使用<=,组合逻辑使用=赋值,时序逻辑使用<=赋值:
举个例子:初始化m=1,n=2,p=3;分别执行以下语句
- begin
m=n;n=p;p=m;
end - begin
m<=n; n<=p; p<=m;
end
- 结果分别是:
-
- m=2,n=3,p=2;(在给p赋值时m=2已经生效)
- m=2,n=3,p=1;(在begin-end过程中,m=2一直无效而是在整体执行完后才生效)
这两种赋值“=”用于阻塞式赋值;“<=”用于非阻塞式赋值中。
**阻塞赋值:**阻塞赋值语句是在这句之后所有语句执行之前执行的,即后边的语句必须在这句执行完毕才能执行,所以称为阻塞,实际上就是顺序执行。
**非阻塞赋值:**非阻塞赋值就是与后边相关语句同时执行,即就是并行执行。
所以一般时序电路使用非阻塞赋值,assign语句一般使用=阻塞赋值;
组合逻辑电路使用阻塞赋值;
数位的表示方法
在Verilog里,当一个变量的类型确定,即已经知道它是寄存器类型或者是线网类型,当把具体的数值赋值给它时,需要利用下面所述的数字表示方法。
数字表达式:<位宽><进制><数字>
位宽是与数据大小相等的对应二进制数的位数加上占位所用0的位数,这个位数需要使用十进制来表示。位宽是可选项,如果没有指明位宽,则默认的数据位宽与仿真器有关(最小32位)。
数制需要用字母来表示
b: 二进du制 //eg.4’b1110 表示4位二进制数1110
h: 十六进zhi制 //eg 8’hef、dao4’ha等
d: 十进制 //eg 2’d3、4‘d15(不能写16,4位宽最大15)等
数字即具体数值
代码
设计文档
module counter(Clk50M,Rst_n,led);//Clk为时钟输入 Rst_n为复位信号,n表示低电平时复位
input Clk50M; //系统时钟 50M
input Rst_n; //全局复位,低电平复位
output reg led; //led 寄存器类型 输出
//定义计数器寄存器
reg [24:0]cnt; //25_000_000 二进制25位
//计数器计数进程
always@(posedge Clk50M or negedge Rst_n)//时序逻辑
if(Rst_n == 1'b0) //如果低电平就复位
cnt <= 25'd0; //时序逻辑 用 <= 赋值
else if (cnt == 25'd24_999_999) //达到了25_000_000次 即 刚好满500ms时
cnt <= 25'd0;
else
cnt <= cnt + 1'b1;
//led输出控制进程
always@(posedge Clk50M or negedge Rst_n)
if(Rst_n == 1'b0)
led <= 1'b1;
else if(cnt == 25'd24_999_999)
led <= ~led;//led取反
else
led <= led; //保持不变
endmodule
仿真文档
- 由于仿真时rst_n信号非常慢,可以直接删掉不看
`timescale 1ns/1ns
`define clock_period 20 //增强代码通用性
module counter_tb;
//定义输入端口激励信号
reg clk;
reg rst_n;
//定义输出端响应
wire led;
counter counter0(
.Clk50M(clk),
.Rst_n(rst_n),
.led(led)
);
initial clk = 1; //初始化 高/低电平均可 但最好是高电平
always #(`clock_period/2) clk = ~clk; //半个周期翻转一次
initial begin
rst_n = 1'b0;
#(`clock_period*200); //规定延时200个时钟周期
rst_n = 1'b1;
#2000_000_000; //持续运行2s
$stop;
end
endmodule