循序电路第一个应用是拿来做计数器((笔记) 如何设.doc_第1页
循序电路第一个应用是拿来做计数器((笔记) 如何设.doc_第2页
循序电路第一个应用是拿来做计数器((笔记) 如何设.doc_第3页
循序电路第一个应用是拿来做计数器((笔记) 如何设.doc_第4页
循序电路第一个应用是拿来做计数器((笔记) 如何设.doc_第5页
已阅读5页,还剩20页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

Abstract循序电路第一个应用是拿来做计数器(笔记) 如何设计计数器? (SOC) (Verilog) (MegaCore),有了计数器的基础后,就可以拿计数器来设计除频器,最后希望能做出能除N的万用除频器。Introduction使用环境:Quartus II 7.2 SP3 + ModelSim-Altera 6.1g除频器在实务中随时会用到,如DE2只提供50MHz与27MHz的clock,如CMOS用的是25MHz,因此就必须手动作一个除频器产生25MHz,利用计数器的基础,就可以设计一个除频器。Method 1:使用Verilog除2的除频器最简单的除频器,还不需要到计数器就可以完成。div2.v / Verilog (没用到计数器) /* 2 (C) OOMusou 20083 4 Filename : div2.v5 Compiler : Quartus II 7.2 SP3 + ModelSim-Altera 6.1g6 Description : Demo how to write frequency divider by 27 Release : 07/12/2008 1.08 */9 10 module div2 (11 input clk,12 input rst_n,13 output reg o_clk14 );15 16 always(posedge clk or negedge rst_n) begin17 if (!rst_n)18 o_clk= 0;19 else20 o_clk= o_clk;21 end22 23 endmodule频率要变一半,也就是周期要变两倍,也就是本来一个clock的时间,变成半个clock的时间,所以每次clock正源触发时,刚好是0变1、1变0的时机。由于除2的除频器很简单,所以不需要用到记数器就可完成,但更复杂的除频器一定要用到计数器,所以我们也用计数器写一个除2除频器,帮助了解后,才能写更复杂的除频器。div2_v2.v / Verilog (使用计数器)1 /* 2 (C) OOMusou 20083 4 Filename : div2_v2.v5 Compiler : Quartus II 7.2 SP3 + ModelSim-Altera 6.1g6 Description : Demo how to write frequency divider by 27 Release : 07/12/2008 1.08 */9 10 module div2_v2 (11 input clk,12 input rst_n,13 output reg o_clk14 );15 16 reg cnt;17 18 always(posedge clk or negedge rst_n) begin19 if (!rst_n)20 cnt= 0;21 else if (cnt= 1)/ 0 122 cnt= 0;23 else24 cnt= cnt+ 1;25 end26 27 always(posedge clk or negedge rst_n) begin28 if (!rst_n)29 o_clk= 0;30 else if (cnt 1)/ 031 o_clk= 0;32 else / 133 o_clk= 1;34 end35 36 endmodule18行always(posedge clk or negedge rst_n) begin if (!rst_n) cnt= 0; else if (cnt= 1)/ 0 1 cnt= 0; else cnt= cnt+ 1;end一个简单的计数器,从0数到1,然后又重头从0数到1,因为目前要做的是除2的除频器,所以只需0和1两个状态即可。27行always(posedge clk or negedge rst_n) begin if (!rst_n) o_clk= 0; else if (cnt 1)/ 0 o_clk= 0; else / 1 o_clk= 1;end利用计数器产生新的clock,当计数器是0时,输出1,当计数器是1时,输出0。如此就完成duty cycle为50%的除2除频器电路。当然我可以将两个always写在一起,不过好的Verilog coding style建议每个always都短短的,最好一个always只处理一个register,第一个always block处理reg cnt,第二个处理reg o_clk,这样一目了然,对于合成器来说,也较容易合成出好的电路,对于可读性来说,人类也较容易理解,甚至看完code后,自己都可以当合成器,合出一个电路,这也是为什么说写HDL要心中有电路,而不是像写软体一样,只要考虑语法就好,反正编译器会帮你解决,这也是写硬体和写软体另一个差异很大的地方。testbenchdiv2_tb.v / Verilog1 /* 2 (C) OOMusou 20083 4 Filename : div2_tb.v5 Compiler : Quartus II 7.2 SP3 + ModelSim-Altera 6.1g6 Description : Demo how to write frequency divider by 2 testbench7 Release : 07/16/2008 1.08 */9 timescale 1ns/10ps10 module div2_tb;11 reg clk;12 reg rst_n;13 wire o_clk;14 15 div2 u0 (16 .clk(clk),17 .rst_n(rst_n),18 .o_clk(o_clk)19 );20 21 initial begin22 clk = 1b1;23 rst_n= 1b1;24 end25 26 / 50MHz clk27 always #10 clk= clk;28 endmodule除4的除频器除3的除频器因为是奇数,所以较麻烦,我们先看除4的除频器后,再回头看除3的除频器。div4.v / Verilog1 /* 2 (C) OOMusou 20083 4 Filename : div4.v5 Compiler : Quartus II 7.2 SP3 + ModelSim-Altera 6.1g6 Description : Demo how to write frequency divider by 47 Release : 07/16/2008 1.08 */9 10 module div4 (11 input clk,12 input rst_n,13 output reg o_clk14 );15 16 reg 1:0 cnt;17 18 always(posedge clk or negedge rst_n) begin19 if (!rst_n)20 cnt= 0;21 else if (cnt= 3)/ 0 322 cnt= 0;23 else24 cnt= cnt+ 1;25 end26 27 always(posedge clk or negedge rst_n) begin28 if (!rst_n)29 o_clk= 0;30 else if (cnt 2)/ 0 131 o_clk= 0;32 else / 2 333 o_clk= 1; 34 end35 endmodule若已经完全搞懂除2的除频器,这个除4的除频器也很好懂。只是变成计数器从0数到3,当0与1时输出1,而2与3时输出0。testbenchdiv4_tb.v / Verilog1 /* 2 (C) OOMusou 20083 4 Filename : div4_tb.v5 Compiler : Quartus II 7.2 SP3 + ModelSim-Altera 6.1g6 Description : Demo how to write frequency divider by 4 testbench7 Release : 07/16/2008 1.08 */9 10 timescale 1ns/10ps11 module div4_tb;12 reg clk;13 reg rst_n;14 wire o_clk;15 16 div4 u0 (17 .clk(clk),18 .rst_n(rst_n),19 .o_clk(o_clk)20 );21 22 initial begin23 clk = 1b1;24 rst_n= 1b1;25 end26 27 / 50MHz clk28 always #10 clk= clk;29 endmodule 看到这里,你应该会想用parameter打造一个万用(泛型)的除偶数的除频器,不过先别急,等我们看了除3的除频器后,最后一起打造一个除N的万用除频器。除3的除频器根据前面的经验,除2的除频器就是每1个clock就0变1、1变0,除4的除频器就是每2个clock就0变1、1变0,所以除3的除频器应该是每1.5的clock就0变1、1变0,但问题来了,哪来的1.5个clock?计数器并不能产生1.5!回想一下波形,正源触发与负源触发的间隔时间是不是刚好是0.5个clock?所以我们产生两个clock,一个是posedge clk,一个是negedge clk,最后将两个clock做or,这样就可以产生出0.5个clock了,很巧妙吧!div3.v / Verilog1 /* 2 (C) OOMusou 20083 4 Filename : div3.v5 Compiler : Quartus II 7.2 SP3 + ModelSim-Altera 6.1g6 Description : Demo how to write frequency divider by 37 Release : 07/12/2008 1.08 */9 10 module div3 (11 input clk,12 input rst_n,13 output o_clk14 );15 16 reg 1:0 cnt_p;17 reg 1:0 cnt_n;18 reg clk_p;19 reg clk_n;20 21 assign o_clk= clk_p| clk_n;22 23 always(posedge clk or negedge rst_n) begin24 if (!rst_n)25 cnt_p= 0;26 else if (cnt_p= 2)/ 0 227 cnt_p= 0;28 else29 cnt_p= cnt_p+ 1;30 end31 32 always(posedge clk or negedge rst_n) begin33 if (!rst_n)34 clk_p= 1;35 else if (cnt_p 1)/ 036 clk_p= 1;37 else / 1 238 clk_p= 0; 39 end40 41 always(negedge clk or negedge rst_n) begin42 if (!rst_n)43 cnt_n= 0;44 else if (cnt_n= 2)/ 0 245 cnt_n= 0;46 else47 cnt_n= cnt_n+ 1;48 end49 50 always(negedge clk or negedge rst_n) begin51 if (!rst_n)52 clk_n= 1;53 else if (cnt_n 1)/ 054 clk_n= 1;55 else / 1 256 clk_n= 0;57 end58 59 endmodule23行always(posedge clk or negedge rst_n) begin if (!rst_n) cnt_p= 0; else if (cnt_p= 2)/ 0 2 cnt_p= 0; else cnt_p= cnt_p+ 1;end由于要将两个clock做or,cnt_p是前半段clock的计数器,由于是除3,所以需要02三个数。32行always(posedge clk or negedge rst_n) begin if (!rst_n) clk_p= 1; else if (cnt_p 1)/ 0 clk_p= 1; else / 1 2 clk_p= 0; end因为要产生duty cycle为50%的clock,所以一半要1,一半要0,但0、1、2该怎么平分呢?由于前半部的波形1做or会变大,所以就少分一点,也就是当计数器为0产生1,1、2时产生0。41行always(negedge clk or negedge rst_n) begin if (!rst_n) cnt_n= 0; else if (cnt_n= 2)/ 0 2 cnt_n= 0; else cnt_n= cnt_n+ 1;end注意到negedge clk了吗?要不是因为这个0.5 clockk,我们几乎不会这样写程式,cnt_n是后半段clock的计数器,也同样需要02三个数。50行always(negedge clk or negedge rst_n) begin if (!rst_n) clk_n= 1; else if (cnt_n 1)/ 0 clk_n= 1; else / 1 2 clk_n= 0;end因为是后半段clock,所以一样是negedge clk,一样是因为后半部的波形1做or会变大,所以就少分一点,也就是当计数器为0产生1,1、2时产生0。21行assign o_clk= clk_p| clk_n;最后将两个clock做or。testbenchdiv3_tb.v / Verilog1 /* 2 (C) OOMusou 20083 4 Filename : div3_tb.v5 Compiler : Quartus II 7.2 SP3 + ModelSim-Altera 6.1g6 Description : Demo how to write frequency divider by 3 testbench7 Release : 07/12/2008 1.08 */9 10 11 timescale 1ns/10ps12 module div3_tb;13 reg clk;14 reg rst_n;15 wire o_clk;16 17 18 div3 u0 (19 .clk(clk),20 .rst_n(rst_n),21 .o_clk(o_clk)22 );23 24 initial begin25 clk = 1b1;26 rst_n= 1b1;27 end28 29 / 50MHz clk30 always #10 clk= clk;31 endmodule因为将clk_p与clk_n做or产生新的clk的方式实在太特别,所以特别将clk_p与clk_n也用modelsim显示出来,这样可以明显地看到or后产生除3后的波形,神奇吧!除任意正整数除频器若前面的范例都已经彻底了解,要写个除任意整数的除频器就不难了。divn.v / Verilog1 /* 2 (C) OOMusou 20083 4 Filename : divn.v5 Compiler : Quartus II 7.2 SP3 + ModelSim-Altera 6.1g6 Description : Demo how to write frequency divider by n7 Release : 07/16/2008 1.08 */9 10 module divn (11 input clk,12 input rst_n,13 output o_clk14 );15 16 parameter WIDTH= 3;17 parameter N = 6;18 19 reg WIDTH-1:0 cnt_p;20 reg WIDTH-1:0 cnt_n;21 reg clk_p;22 reg clk_n;23 24 assign o_clk= (N= 1)? clk :25 (N0) ? (clk_p| clk_n) : (clk_p);26 27 always(posedge clk or negedge rst_n) begin28 if (!rst_n)29 cnt_p= 0;30 else if (cnt_p= (N-1)31 cnt_p= 0;32 else33 cnt_p= cnt_p+ 1;34 end35 36 always(posedge clk or negedge rst_n) begin37 if (!rst_n)38 clk_p= 1;39 else if (cnt_p1)40 clk_p= 1;41 else42 clk_p= 0; 43 end44 45 always(negedge clk or negedge rst_n) begin46 if (!rst_n)47 cnt_n= 0;48 else if (cnt_n= (N-1)49 cnt_n= 0;50 else51 cnt_n= cnt_n+ 1;52 end53 54 always(negedge clk or negedge rst_n) begin55 if (!rst_n)56 clk_n= 1;57 else if (cnt_n1)58 clk_n= 1;59 else60 clk_n= 0;61 end62 63 endmodule16行parameter WIDTH= 3;parameter N = 6;多加了两个参数,WIDTH代表计数器的宽度,N代表要要除的任意正整数,以后若要产生各种除频器,只要改这两个参数即可。36行always(posedge clk or negedge rst_n) begin if (!rst_n) clk_p= 1; else if (cnt_p1) clk_p= 1; else clk_p= 0; endN1稍微做一下解释,其实就是 N / 2,好吧,我承认是syntax sugar,不过这在Verilog倒很常见。24行assign o_clk= (N= 1)? clk : (N0) ? (clk_p| clk_n) : (clk_p);整个程式的唯一关键在此,若N为1,表示不用除频,直接输出clk即可,N0是Verilog个小技巧,判断N是否为奇数,若为奇数,则clk_p | clk_n,若为偶数,则clk_p即可。这样无论N为奇数或者偶数都没问题。其实C/C+也可以用这个小技巧判断是否为奇数,只要x & 1即可,以后就不要靠x % 2了。testbenchdivn_tb.v / Verilog1 /* 2 (C) OOMusou 20083 4 Filename : divn_tb.v5 Compiler : Quartus II 7.2 SP3 + ModelSim-Altera 6.1g6 Description : Demo how to write frequency divider by n testbench7 Release : 07/16/2008 1.08 */9 10 timescale 1ns/10ps11 module divn_tb;12 reg clk;13 reg rst_n;14 wire o_clk;15 16 divn u0 (17 .clk(clk),18 .rst_n(rst_n),19 .o_clk(o_clk)20 );21 22 23 initial begin24 clk = 1b1;25 rst_n= 1b1;26 end27 28 / 50MHz clk29 always #10 clk= clk;30 endmodule产生除5的除频器 产生除6的除频器Method 2:使用Megafunction1.lpm_counter + lpm_ff前面有归纳一个结论:除2的除频器就是每1个clock就0变1、1变0,除4的除频器就是每2个clock就0变1、1变0,这在除偶数的除频器有效,计数器部分我们使用lpm_counter,0变1、1变0我们就是用lpm_ff这个T-FF。divn_mf.v / Verilog1 /* 2 (C) OOMusou 20083 4 Filename : divn_mf.v5 Compiler : Quartus II 7.2 SP3 + ModelSim-Altera 6.1g6 Description : Demo how to write frequency divider by lpm7 Release : 07/16/2008 1.08 */9 10 module divn_mf (11 input clk,12 input rst_n,13 output o_clk14 );15 16 parameter WIDTH= 3;17 parameter N = 8;18 19 wire w_clk;20 21 lpm_counter # (22 .lpm_width(WIDTH),23 .lpm_direction(UP),24 .lpm_modulus(N1)25 ) u0 (26 .clock(clk),27 .cout(w_clk)28 );29 30 lpm_ff # (31 .lpm_width(1),32 .lpm_fftype(TFF)33 )34 u1 (35 .clock(clk),36 .data(w_clk),37 .q(o_clk)38 );39 40 endmodule22行lpm_counter # ( .lpm_width(WIDTH), .lpm_direction(UP), .lpm_modulus(N1) u0 ( .clock(clk), .cout(w_clk);这是一个计数器,详细参数使用我就不多谈,请参考(转贴) LPM Quick Reference Guide (SOC) (MegaCore)。30行lpm_ff # ( .lpm_width(1), .lpm_fftype(TFF)u1 ( .clock(clk), .data(w_clk), .q(o_clk);这是一个T-FF,负责0变1,1变0。testbenchdivn_mf_tb.v / Verilog1 /* 2

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论