菜农FPGA助学园地

 找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 2563|回复: 0

时钟分频---计数器

[复制链接]

12

主题

12

帖子

66

积分

超级版主

Rank: 8Rank: 8

积分
66
发表于 2021-5-17 20:48:41 | 显示全部楼层 |阅读模式
本帖最后由 码头小王 于 2021-5-17 21:14 编辑

时钟信号的处理是 FPGA 的特色之一,因此分频器也是 FPGA 设计中使用频率非常高的基本设计之一。一般在 FPGA 中都有集成的锁相环可以实现各种时钟的分频和倍频设计,但是通过语言设计进行时钟分频是最基本的训练,在对时钟要求不高的设计时也能节省锁相环资源。偶数分频:偶数倍分频通过计数器计数是完全可以实现的,例如进行 N 倍偶数分频,那么通过时钟触发计数器计数,当计数器从 0 计数到 N/2-1 (半个周期)时,输出时钟进行翻转,以此循环下去。
奇数分频: 实现占空比为 50%的奇数倍分频,不能同偶数分频一样,当计数器记到一半的时候输出时钟翻转,那样得不到占空比 50%的时钟。以待分频时钟 CLK为例,如果以偶数分频的方法来做奇数分频,在 CLK 上升沿触发,将得到不是 50%占空比的一个时钟信号(正周期比负周期多一个时钟或者少一个时钟);但是如果在CLK 下降沿也触发,又得到另外一个不是 50%占空比的时钟信号,这两个时钟相位正好相差半个CLK 时钟周期。通过这两个时钟信号进行逻辑运算我们可以巧妙的得到 50%占空比的时钟。
新建一个项目 (couter)
divide.v
  1. module divide (        clk,rst_n,clkout);

  2.    input                clk,rst_n;       //输入信号,其中clk连接到FPGA的C1脚,频率为12MHz
  3.         output        clkout;          //输出信号,可以连接到LED观察分频的时钟

  4.     //parameter是verilog里常数语句
  5.         parameter        WIDTH        = 3;     //计数器的位数,计数的最大值为 2**WIDTH-1
  6.         parameter        N        = 5;         //分频系数,请确保 N < 2**WIDTH-1,否则计数会溢出

  7.         reg         [WIDTH-1:0]        cnt_p,cnt_n;     //cnt_p为上升沿触发时的计数器,cnt_n为下降沿触发时的计数器
  8.         reg        clk_p,clk_n;     //clk_p为上升沿触发时分频时钟,clk_n为下降沿触发时分频时钟

  9.         //上升沿触发时计数器的控制
  10.         always @ (posedge clk or negedge rst_n )   //posedge和negedge是verilog表示信号上升沿和下降沿
  11.                                                //当clk上升沿来临或者rst_n变低的时候执行一次always里的语句
  12.                 begin
  13.                         if(!rst_n)
  14.                                 cnt_p<=0;
  15.                         else if (cnt_p==(N-1))
  16.                                 cnt_p<=0;
  17.                         else cnt_p<=cnt_p+1;             //计数器一直计数,当计数到N-1的时候清零,这是一个模N的计数器
  18.                 end

  19.      //上升沿触发的分频时钟输出,如果N为奇数得到的时钟占空比不是50%;如果N为偶数得到的时钟占空比为50%
  20.      always @ (posedge clk or negedge rst_n)
  21.                 begin
  22.                         if(!rst_n)
  23.                                 clk_p<=0;
  24.                         else if (cnt_p<(N>>1))          //N>>1表示右移一位,相当于除以2去掉余数
  25.                                 clk_p<=0;
  26.                         else
  27.                                 clk_p<=1;               //得到的分频时钟正周期比负周期多一个clk时钟
  28.                 end

  29.     //下降沿触发时计数器的控制               
  30.          always @ (negedge clk or negedge rst_n)
  31.                 begin
  32.                         if(!rst_n)
  33.                                 cnt_n<=0;
  34.                         else if (cnt_n==(N-1))
  35.                                 cnt_n<=0;
  36.                         else cnt_n<=cnt_n+1;
  37.                 end

  38.         //下降沿触发的分频时钟输出,和clk_p相差半个时钟
  39.         always @ (negedge clk)
  40.                 begin
  41.                         if(!rst_n)
  42.                                 clk_n<=0;
  43.                         else if (cnt_n<(N>>1))  
  44.                                 clk_n<=0;
  45.                         else
  46.                                 clk_n<=1;                //得到的分频时钟正周期比负周期多一个clk时钟
  47.                 end

  48.     assign clkout = (N==1)?clk:(N[0])?(clk_p&clk_n):clk_p;      //条件判断表达式
  49.                                                                     //当N=1时,直接输出clk
  50.                                                                     //当N为偶数也就是N的最低位为0,N(0)=0,输出clk_p
  51.                                                                     //当N为奇数也就是N最低位为1,N(0)=1,输出clk_p&clk_n。正周期多所以是相与
  52. endmodule   
复制代码
counter.v
  1. module counter
  2. (
  3.         clk                                ,    //时钟
  4.         rst                                ,    //复位
  5.         seg_led_1                ,    //数码管1
  6.         seg_led_2                ,    //数码管2
  7.         led                 //led
  8. );

  9.         input         clk,rst;

  10.         output         [8:0]        seg_led_1,seg_led_2;
  11.         output         reg        [7:0]        led;

  12.         reg                [7:0]cnt;
  13.         wire                clk1h;        //1Hz时钟
  14.         reg                   [6:0]   seg                [15:0];

  15.         // 用于分出一个1Hz的频率        
  16.         divide #(.WIDTH(32),.N(6000000)) U1 (
  17.                         .clk(clk),
  18.                         .rst_n(rst),      
  19.                         .clkout(clk1h)
  20.                         );
  21.                         
  22.         always @ (posedge clk1h or negedge rst) begin
  23.                 if (!rst)
  24.                         begin
  25.                                 seg[0] <= 7'h3f;           //  0
  26.                                 seg[1] <= 7'h06;           //  1
  27.                                 seg[2] <= 7'h5b;           //  2
  28.                                 seg[3] <= 7'h4f;           //  3
  29.                                 seg[4] <= 7'h66;           //  4
  30.                                 seg[5] <= 7'h6d;           //  5
  31.                                 seg[6] <= 7'h7d;           //  6
  32.                                 seg[7] <= 7'h07;           //  7
  33.                                 seg[8] <= 7'h7f;           //  8
  34.                                 seg[9] <= 7'h6f;           //  9
  35.                                 seg[10] <= 7'hf7;           //  A
  36.                                 seg[11] <= 7'h7c;           //  b
  37.                                 seg[12] <= 7'h39;    //  C
  38.                                 seg[13] <= 7'h5e;    //  d
  39.                                 seg[14] <= 7'h79;    //  E
  40.                                 seg[15] <= 7'h71;    //  F
  41.                                 cnt <= 8'b00000000;
  42.                         end
  43.                 else if(cnt == 8'b11111111)
  44.                         cnt <= 0;
  45.                 else
  46.                         begin
  47.                                 cnt <= cnt + 1;
  48.                                 led <= ~cnt;
  49.                         end
  50.         end

  51.         assign seg_led_1[8:0] = {2'b00,seg[cnt[3:0]]};

  52.         assign seg_led_2[8:0] = {2'b00,seg[cnt[7:4]]};


  53. endmodule
复制代码
分析与综合 ---> 管脚配置 ---> 编译 ---> 下载 ---> 上电

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|小黑屋|菜农FPGA助学园地

GMT+8, 2022-1-27 20:08 , Processed in 0.064599 second(s), 3 queries , MemCache On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表