FPGA实验1 流水灯

发布时间 2023-03-26 17:13:17作者: CoderEnd

FPGA实验1 流水灯

时钟频率与时钟周期计算

\[f=\frac{1}{T} \]

f是频率 T是周期  时钟周期的计算  1s=1000ms=1000000us=1000000000ns
对于100kHz=100000Hz  f= 1000000000/100000 =10000ns
	8MHz = 8000kHz=8000000Hz f=1000000000/8000000=125ns
时钟频率 时钟周期
100kHz 10_000ns
1MHz 1_000ns
8MHz 125ns
50MHz 20ns
100MHz 10ns
125MHz 8ns
150MHz 6.667ns
200MHz 5ns
led 流水灯 每隔0.2s 闪

20ns对应输入的时钟频率为50MHz (不同开发板,或者硬件设计可能有不同)

0.2s/20ns = 1000_0000

ppD9C5j.md.png

//计数器 counter:0-9999999 (10000000) 通过转换二进制 得到位宽
/*
计数器 counter 一般计数器都是从0开始,例如计数器要计数10000,则需要写成10000-1
计数器 counter-1
‭16b'0010_0111_0001_0000‬ = 16d'1_0000
*/
//‭1001_1000_1001_0110_1000_0000‬   位宽24  reg [23:0]  位宽N  reg [N-1:0]  
reg [23:0] counter;

//电路设计 高电平点亮,低电平熄灭

//计数器对系统时钟计数,计时0.2秒
always @(posedge sys_clk or negedge sys_rst_n) begin //检测时钟的上升沿和复位的下降沿
    if (!sys_rst_n)  //当sys_rst_n 处于复位状态时,计数器重置0  复位信号低有效
        counter <= 24'd0;
    else if (counter < 24'd1000_0000-1'b1) //计数器开始计数,从0-9999999,自加
        counter <= counter + 1'b1;
    else
        counter <= 24'd0;//计数器达到计数值,置0,
end


//通过移位寄存器控制IO口的高低电平,从而改变LED的显示状态
//0001->0010->0100->1000->0001
always @(posedge sys_clk or negedge sys_rst_n) begin //检测时钟的上升沿和复位的下降沿
    if (!sys_rst_n)   //当sys_rst_n 处于复位状态时,led1亮,置1
        led <= 4'b0001;
    else if(counter == 24'd1000_0000-1'b1) //当计数器计数到指定值时,进行操作
        led[3:0] <= {led[2:0],led[3]};  //把高位赋给低位进行交换
    else
        led <= led;
end

计数器模板

always @(posedge clk or negedge rst_n)begin
	if(rst_n==1'b0)begin
		cnt<= 0;
	end
	else if(加 1 条件) begin
		if(结束条件)
			cnt<= 0;
		else
			cnt<= cnt + 1;
		end
	end

assign 加 1 条件 = ;
assign 结束条件 = 加 1 条件&&cnt==(计数个数)-1;

/*
工作时钟是 50MHz,时钟周期即 20ns,当计数器计数到 1_000_000_000/20=50_000_000个 
1s  计数器计数 50_000_000个周期  
*/
parameter Count_MAX = 50_000_000 ; //计数器计数总周期个数

reg [N:0] cnt;//计数变量 N为位宽
//计算 1 秒次数的计数器命名为 cnt0
always @(posedge clk or negedge rst_n)begin
	if(rst_n==1'b0)begin
		cnt<= 0;
	end
    else if(add_cnt) begin
        if(end_cnt)
			cnt<= 0;
		else
			cnt<= cnt + 1;
		end
	end
//加 1 条件  	add_cnt = 1 则默认为加1条件一直有效
//什么是加1条件 触发条件 根据实际情况	
assign add_cnt = 1 ; 
assign end_cnt = add_cnt && cnt==(Count_MAX)-1;
reg [25:0]  cnt0;
//计数器cnt0:计数1s 加1条件add_cnt0,结束条件end_cnt0
wire add_cnt0 ;
wire end_cnt0 ;

reg [2:0]   cnt2;//可以存储8个状态  计数5s
//计数器cnt2:计数5s 加1条件add_cnt2,结束条件end_cnt2
wire add_cnt2 ;
wire end_cnt2 ;

//计数器计数1s
always @(posedge sys_clk or negedge sys_rst_n)begin
    if(!sys_rst_n)  begin
        cnt0 <= 0;
    end
    else if(add_cnt0) begin
    if(end_cnt0)
        cnt0 <= 0;
    else
    cnt0 <= cnt0 + 1;
    end
end

assign add_cnt0 = 1 ; //一直处于加1状态    
assign end_cnt0 = add_cnt0 && cnt0== 50_000_000 - 1 ; //根据时钟频率计算出 1s需要多少个时钟周期


//计数器计数5s 
always @(posedge sys_clk or negedge sys_rst_n)begin
    if(!sys_rst_n)  begin
        cnt2 <= 0;
    end
    else if(add_cnt2) begin
    if(end_cnt2)
        cnt2 <= 0;
    else
    cnt2 <= cnt2 + 1;
    end
end

assign add_cnt2 = end_cnt0;  //该计数器的加1条件是 1s计数器结束 准备进行下一个1s计数器   
assign end_cnt2 = add_cnt2 && cnt2== 5 -1; //根据5s计数器计算出 5s需要多少个1s的计数器