FPGA中的分频与延时.docx
《FPGA中的分频与延时.docx》由会员分享,可在线阅读,更多相关《FPGA中的分频与延时.docx(15页珍藏版)》请在冰豆网上搜索。
FPGA中的分频与延时
FPGA中的分频
FPGA中的分频是很重要的一个内容,只要涉及时序电路,几乎都会有分频的情况出现。
但分频的语句却各有不同,以下就是不同写法,但不管怎样,分频一句话,就是用计数器来实现的。
下面我就几种不同的写法说说我的看法,在FPGA中是如何实现分频的。
不过再说之前首先的了解时钟。
我这里以系统时钟clk,f=50MH为例。
由此可知其T=20ns,f=50MH也就是说一秒内,时钟高低电平改变50M次。
这里我用verilog为例,对于vhdl类同。
讲解时只取分频部分语句后面附有
完正的程序
第一种写法:
。
。
。
。
。
。
always@(posedgeclkornegedgerst)
begin。
if(!
rst)begin
clk_div1<=0;
end
elsebegin
if(clk_div1!
=11)
clk_div1<=clk_div1+1;
else
clk_div1<=0;
end
end
always@(posedgeclkornegedgerst)
begin
if(!
rst)begin
clk_div2<=0;
state<=0;
cnt<=0;
out<=0;
end
elseif(clk_div1==11)begin
。
。
。
。
//执行什么功能
。
。
。
。
。
注意在这里此语句中,我没有写完整,只是把分频的关键地方写出来了,特别是红色标注的地方。
这里暂时不管定义的rst,state。
。
。
。
这些变量。
关键是此句话
if(clk_div1!
=11)
clk_div1<=clk_div1+1;
else
clk_div1<=0;
此句话可知计数器clk_divl对系统时钟进行计数,并且只计数到11,clk_divl变等于0。
这里有点类似于延时,下面以图形来说明。
由上图可知,clk=5MH的时钟,在计数器clk_divl下计数11,产生约4MH的时钟,此后系统便在4MH的频率下工作。
这里他并未把新时钟提出来,而是在原来的时钟上分出4MH情况来工作。
第二种写法:
。
。
。
。
。
。
。
。
。
。
always@(posedgeclk_50M)
begin
if(count==25000000)//此处也可写成24999999
begin
div_clk<=~div_clk;
end
else
count<=count+1;
led_out<=div_clk;
end
。
。
。
。
。
。
。
。
在这里我们也不去关注分频以外的东西,关键此语句
if(count==25000000)
begin
div_clk<=~div_clk;
end
else
count<=count+1;
我们看到这里实际上定义了一个新时钟名:
div_clk,系统此后便可以以此时钟来工作,在这里只要明白这样的解释就行了。
--
(1)如进行N倍偶数、占空比为50%的分频,那么可以通过由待分频的时钟触发计数,当计数器从0计数到N/2-1时,输出时钟进行翻转,以此循环下去。
--
(2)如进行N倍偶数、占空比为1/N的分频,那么可以通过由待分频的时钟触发计数,当计数器从0计数到N-1时,输出时钟进行翻转,并给计数器一个复位信号,使得一个时钟从零开始计数,以此循环下去。
一个公式就是:
N为分频数,M为计数器的计数值。
N/2-1=M。
。
。
。
。
此时为,进行N倍偶数、占空比为50%的分频。
N-1=M。
。
。
。
。
。
。
此时进行N倍偶数、占空比为1/N的分频。
例如一个50MH的分频其图为:
其计数值M为25000000或24999999
对于基数的分频:
对于实现占空比为50%的N倍奇数分频,首先进行上升沿触发进
行模N计数,计数到(N-1)/2进行输出时钟翻转,然后经过(N-1)/2(即计数到N-1时)再次进行翻转得到一个占空比非50%奇数n分频时钟。
再者同时进行下降沿触发的模N计数,到(N-1)/2时,进行输出时钟时钟翻转,同样经过(N-1)/2(即计数到N-1时)时,输出时钟再次翻转生成占空比非50%的奇数n分频时钟。
两个占空比非50%的n分频时钟相或运算,得到占空比为50%的奇数n分频时钟。
第三种写法:
always@(posedgeclk,negedgeres)
begin
if(!
res)
begin
led<=6'b000000;
end
else
begin
case(count[26:
23])
4'd0:
led<=6'b111110;//Xmiao
4'd1:
led<=6'b111101;//Ymiao
4'd2:
led<=6'b111011;
4'd3:
led<=6'b110111;
4'd4:
led<=6'b101111;
4'd5:
led<=6'b011111;
4'd6:
led<=6'b011111;
4'd7:
led<=6'b101111;
4'd8:
led<=6'b110111;
4'd9:
led<=6'b111011;
4'd10:
led<=6'b111101;
4'd11:
led<=6'b111110;
4'd12:
led<=6'b000000;
4'd13:
led<=6'b111111;
4'd14:
led<=6'b000111;
4'd15:
led<=6'b111000;
default:
led<=6'b000000;
endcase
在这里我们也不去关注分频以外的东西,关键此语句
case(count[26:
23])
实际上这里定义了一个26位的计数器,但实际上为后22位计数,前4位定义状态。
这种分频可用于数码管的动态显示或流水灯跑马灯等。
其具体分析为:
26位:
2524232221。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
0
4'd0:
00000000000000000000000000//第一个状态
00001111111。
。
。
。
。
。
。
。
。
。
。
。
。
。
1X秒//计数满22位为80ms
4'd1:
00010000000000。
。
。
。
。
。
。
。
。
00000//第二个状态
00011111111。
。
。
。
。
。
。
。
。
。
。
。
。
。
11111Y秒//计数满22位为80ms
4’d2:
00100000000。
。
。
。
。
。
。
。
。
。
。
。
。
。
00000
00101111111.。
。
。
。
。
。
。
。
。
。
11111111111Z秒//计数满22位为80ms
4’d3:
00110000000。
。
。
。
。
。
。
。
。
。
。
。
00000000//第三个
001111111111111。
。
。
。
。
。
。
。
1111111111W秒//计数满22位为80ms
。
。
。
。
。
。
4’d15:
111000000000000000000。
。
。
。
。
。
。
000000//第四个
11101111111。
。
。
。
。
。
。
。
。
。
。
。
1111111111//计数满22位为80ms
从面可以看出每个状态停留的时间均为80ms,而每个状态在下一个时钟来时
又加一,从而转到下一个状态。
这样状态连续,而每个状态时间有一样,变可以实现动态显示和流水灯。
附以上三个完整程序:
第一个:
modulebuzzer(clk,rst,out);
inputclk,rst;
outputout;
regout;
reg[3:
0]clk_div1;//基频分频计数器,基频为4M
reg[12:
0]clk_div2;//音阶分频计数器,由基频分频产生各个音阶
reg[21:
0]cnt;//各音阶发声时间长短计数器
reg[2:
0]state;
parameterduo=3822,//各个音调的分频系数
lai=3405,
mi=3034,
fa=2865,
suo=2551,
la=2273,
xi=2024,
duo1=1911;
always@(posedgeclkornegedgerst)//这里采用了,分频的另一种手法,相当于延时。
begin//分频的实现方式有多种。
if(!
rst)begin
clk_div1<=0;
end
elsebegin
if(clk_div1!
=11)//在原来的时钟上分频,并未加入一个新的时钟。
及原来的时钟到11个时钟(波形)//才进行下一步做法。
clk_div1<=clk_div1+1;//相当于每4MH,做一次指令功能。
因为11个时钟为220ns,所以周期为220ns,//频率为
else//4MH。
及原来的时钟到11个时钟(波形)才进行下一步做法(计时11个波形)
clk_div1<=0;
end
end
always@(posedgeclkornegedgerst)
begin
if(!
rst)begin
clk_div2<=0;
state<=0;
cnt<=0;
out<=0;
end
elseif(clk_div1==11)begin
case(state)
3'b000:
begin//发“多”
cnt<=cnt+1;
if(cnt==22'h3fffff)
state<=3'b001;
if(clk_div2!
=duo)//+3822
clk_div2<=clk_div2+1;
elsebegin
clk_div2<=0;
out<=~out;
end
end
3'b001:
begin//发“来”
cnt<=cnt+1;
if(cnt==22'h3fffff)
state<=3'b010;
if(clk_div2!
=lai)
clk_div2<=clk_div2+1;//
elsebegin
clk_div2<=0;
out<=~out;
end
end
3'b010:
begin//发"米“
cnt<=cnt+1;
if(cnt==22'h3fffff)
state<=3'b011;
if(clk_div2!
=mi)
clk_div2<=clk_div2+1;
elsebegin
clk_div2<=0;
out<=~out;
end
end
3'b011:
begin//发"法“
cnt<=cnt+1;
if(cnt==22'h3fffff)
state<=3'b100;
if(clk_div2!
=fa)
clk_div2<=clk_div2+1;
elsebegin
clk_div2<=0;
out<=~out;
end
end
3'b100:
begin//发"梭“
cnt<=cnt+1;
if(cnt==22'h3fffff)
state<=3'b101;
if(clk_div2!
=suo)
clk_div2<=clk_div2+1;
elsebegin
clk_div2<=0;
out<=~out;
end
end
3'b101:
begin//发"拉“
cnt<=cnt+1;
if(cnt==22'h3fffff)
state<=3'b110;
if(clk_div2!
=la)
clk_div2<=clk_div2+1;
elsebegin
clk_div2<=0;
out<=~out;
end
end
3'b110:
begin//发"西“
cnt<=cnt+1;
if(cnt==22'h3fffff)
state<=3'b111;
if(clk_div2!
=xi)
clk_div2<=clk_div2+1;
elsebegin
clk_div2<=0;
out<=~out;
end
end
3'b111:
begin//发"多“(高音)
cnt<=cnt+1;
if(cnt==22'h3fffff)
state<=3'b000;
if(clk_div2!
=duo1)
clk_div2<=clk_div2+1;
elsebegin
clk_div2<=0;
out<=~out;
end
end
endcase
end
end
endmodule
第二个:
moduleledwater(clk_50M,led_out,f_led_out);
inputclk_50M;//系统时钟输入50M
//意味每一秒要变化50,000,000HZ
outputled_out;//每一秒闪烁一下
outputf_led_out;//每二秒闪烁一下
reg[24:
0]count;//分频计数器,25000000分频一秒
reg[24:
0]f_count;//分频计数器,12500000分频0.5秒
regdiv_clk,f_div_clk;
regled_out,f_led_out;
//分频计数器。
得到一秒的频率
always@(posedgeclk_50M)
begin
if(count==25000000)
begin//我们的时钟本身是每一秒要变化50,000,000HZ
//我们现在用count这个计数器让它自加到25,000,000HZ
div_clk<=~div_clk;//在这里我们就得到了0.5秒变化一次的信号。
//所以一个周期就是1Hz也就是一秒。
count<=0;//把计数器清零。
end
else
count<=count+1;//计数器自加。
led_out<=div_clk;//利用分频计数器得到显示一秒的闪烁效果
//在LED灯上面表现出来。
end
//分频计数器。
得到0.5秒的频率
always@(posedgeclk_50M)
begin
if(f_count==12500000)//我们现在用count这个计数器让它自加到12,500,000HZ
begin
f_div_clk<=~f_div_clk;//在这里我们就得到了0.25秒变化一次的信号。
//所以一个周期就是0.5也就是2HZ。
f_count<=0;
end
else
f_count<=f_count+1;//计数器自加。
f_led_out<=f_div_clk;//利用分频计数器得到显示一秒的闪烁效果
//在LED灯上面表现出来。
end
endmodule
第三个:
moduleledsan(clk,led,res);
inputclk;
output[5:
0]led;
inputres;
reg[26:
0]count;
reg[5:
0]led;
always@(posedgeclk)
begin
count<=count+1;
end
always@(posedgeclk,negedgeres)
begin
if(!
res)
begin
led<=6'b000000;
end
else
begin
case(count[26:
23])
4'd0:
led<=6'b111110;//Xmiao
4'd1:
led<=6'b111101;//Ymiao
4'd2:
led<=6'b111011;
4'd3:
led<=6'b110111;
4'd4:
led<=6'b101111;
4'd5:
led<=6'b011111;
4'd6:
led<=6'b011111;
4'd7:
led<=6'b101111;
4'd8:
led<=6'b110111;
4'd9:
led<=6'b111011;
4'd10:
led<=6'b111101;
4'd11:
led<=6'b111110;
4'd12:
led<=6'b000000;
4'd13:
led<=6'b111111;
4'd14:
led<=6'b000111;
4'd15:
led<=6'b111000;
default:
led<=6'b000000;
endcase
end
end
endmodule