FPGA-计数器的相关应用

FPGA-计数器的相关应用

1. 基础知识-3-8译码器的实现

根据3位拨码开关所显示的数字,判断哪一个灯亮。使用case语句列出不同的拨码开关值。

module decoder_3_8(
	input a,
	input b,
	input c,
	output reg [7:0] out
    );
	
	always@(*) begin
		case({a,b,c})
			3'b000: out = 8'b0000_0001;
			3'b001: out = 8'b0000_0010;
			3'b010: out = 8'b0000_0100;
			3'b011: out = 8'b0000_1000;
			3'b100: out = 8'b0001_0000;
			3'b101: out = 8'b0010_0000;
			3'b110: out = 8'b0100_0000;
			3'b111: out = 8'b1000_0000;
		endcase
	end
	
endmodule

2. 设计一个以1秒频率闪烁的LED灯

  • 1秒频率进行闪烁,即亮灭更500毫秒,对于A7这块开发板,它的时钟周期是20ns。
  • 因为500ms/20ns=25_000_000,即每经过25_000_000个时钟周期,灯反转一下。
  • 每一次上升沿,即检测到posedge clk,则代表一个时钟周期,此时就需要使用到计数器来计数一个闪烁周期。
module led_flash(
	input clk,
	input reset_n,
	output reg led
    );
	
	reg [24:0] count;
	parameter mCount=25'd25000000;
	
	//计数器(一次循环为500ms)
	always @(posedge clk) begin
		if(!reset_n)begin
			count <= 25'b0;
		end else if(count==mCount-1) begin	
			count <= 25'b0;
		end else begin
			count <= count+1'b1;
		end
	end
	
	//计时器(当一次计数器循环结束则led灯翻转)
	always @(posedge clk) begin
		if(!reset_n)begin
			led <= 1'b0;
		end else if(count == mCount-1) begin
			led <= !led;
		end
	end
endmodule

3. 跑马灯

设计让8个LED灯以每个0.5s的速率循环闪烁

  • 8个led灯——>则有8个输出端——>output[7:0] led
  • 因为每个led按照顺序依次点亮,所以可以联想到循环队列,将led初始化为0000_0001,再每一次当计数完0.5s时进行一次循环左移。
  • 循环左移led<={led[6:0],led[7]}

4. 从计数器到可控线性序列机

让LED灯按照灭0.75秒,亮0.25秒的状态循环亮灭

  • 0.25s+0.75s=1s,即一个大的灯闪烁的时间周期为1s。
  • 1s/20ns=5000_0000次检测posedge clk
  • 先将led置为0,一直灭0.75s,再拉高为1。即当5000_0000的3/4时,可以将led置为1。
module counter_led(
	output reg led,
	input clk,
	input reset_n
    );
	reg [25:0] count;
	parameter mCount=5000_0000;
	
	//计数器(1s)
	always @(posedge clk or negedge reset_n) begin
		if(!reset_n) begin
			count<=0;
		end else if(count==mCount-1) begin
			count<=0;
		end else begin
			count<=count+1'b1;
		end
	end
	
	//计时器
	always @(posedge clk or negedge reset_n) begin
		if(!reset_n) begin
			led<=0;
		end else if(count==(mCount*3/4)-1) begin//当在0.75s时变亮
			led<=1;
		end else if(count==mCount-1) begin
			led<=0;
		end
	end
endmodule

让LED等按照亮0.25秒,灭0.5秒,亮0.75秒,灭1秒的状态循环亮灭

  • 0.25+0.5+0.75+1=2.5(秒)
  • mCount=2.5s/20ns=125_000_000次 检测posedge clk
  • 初始 led=1
    当1/10mCount-1时,led=0;—即过了0.25秒灯变暗。
    当3/10
    mCount-1时,led=1;----即过了0.25+0.5秒灯变亮。
    当6/10mCount-1时,led=0;----即过了0.25+0.5+0.75秒灯变暗。
    当10/10
    mCount-1时,led=1;----即过了0.25+0.5+0.75+1秒灯变亮。

让LED灯按照指定的亮灭模式亮灭,亮灭模式未知,由用户随机指定。
以0.25秒为一个变化周期,8个变化状态为一个循环。—>2s为一个循环周期

  • 亮灭模式由用户指定,用[7:0] ctrl来设置
  • i/8个mCount-1时,led<=ctrl[i-1]
  • 由第二条分析得出,可以使用case语句来对8种情况分别进行处理。注意:别忘记default语句。

让LED灯按照指定的亮灭模式亮灭,亮灭模式未知,由用户随机指定。
8个变化状态为一个循环,每个变化状态的时间值可以根据不同的应用场景选择。

  • 前面的几个问题都将每个小单位相加成一个大的灯闪烁的时间周期,再用除法进行计算。
  • 现在由于有不同的应用场景,即根据用户给出的灯闪烁的每一小份时间周期-Time,所以没有办法用灯闪烁的时间周期/时钟周期计算出固定的mCount,那么上面所示的先计数器后计时器的方法也不可用
  • 现在转换思路,我们知道了每一小份的时间周期Time,那么8个Time就是一个大的灯闪烁的时间周期。
  • 综上所述:用一个计数器1算出一小份时间Time,再用一个计数器2算出8个一循环。根据计数器2再使用case语句对led进行赋值。
module counter_led_4(
	output reg led,
	input clk,
	input reset_n,
	input [7:0] ctrl,
	input [31:0] Time
    );
	reg [31:0] count;
	
	//现在不知道设置的单位周期,所以mCount不是一个定值,则不需要使用mCount
	//parameter mCount=100000000;
	
	//计数器1(Time-一份作为一个小的时间单位)
	always @(posedge clk or negedge reset_n) begin
		if(!reset_n) begin
			count<=0;
		end else if(count==Time-1) begin
			count<=0;
		end else begin
			count<=count+1'b1;
		end
	end
	
	reg [2:0] count2;
	
	//计数器2(8个小的时间单位作为一个周期)
	always @(posedge clk or negedge reset_n) begin
		if(!reset_n) begin
			count2<=0;
		end else if(count==Time-1) begin
			count2<=count2+1'b1;
		end 
	end
	
	//计时器
	always @(posedge clk or negedge reset_n) begin
		if(!reset_n) begin
			led<=0;
		end else begin
			case(count2)
				3'd0:led<=ctrl[0];
				3'd1:led<=ctrl[1];
				3'd2:led<=ctrl[2];
				3'd3:led<=ctrl[3];
				3'd4:led<=ctrl[4];
				3'd5:led<=ctrl[5];
				3'd6:led<=ctrl[6];
				3'd7:led<=ctrl[7];
				default:led<=led;
			endcase
		end
	end
endmodule

让多个led灯按照设置的模式各自在一个变化循环内独立亮灭变化。

 output [1:0] led;
 input [7:0] ctrl0,ctrl1;
 .....
 case(count2)
	3'd0:begin led[0]<=ctrl0[0];led[1]<=ctrl1[0];end
 ......

每隔10ms,让LED灯的一个8状态循环执行一次(每个状态的变化时间值小一点,方便测试,比如设置为10us)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值