FPGA 学习之路(六)任意分频技术

本文介绍了如何使用FPGA实现UART波特率115200Hz,通过两种方案对比,详细阐述了直接计数分频法存在的问题,并提出基于DDS技术的任意频率发生器方案,最终实现了精确的波特率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本次我们采用FPGA自带频率100MHZ分频到115200MHZ用于UART波特率的实现。

DDS原理分析

在介绍任意分频技术之前我们先来看一下直接数字频率合成技术DDS的原理以利于后学的程序设计:
这里要介绍以下直接数字频率合成技术DDS的原理:
直接数字频率合成技术DDS的核心是一个N位的相位寄存器(N一般为24~32,N越大,精度越高),在一个固定的参考时钟下,相位寄存器以步长K递增计数。相位寄存器输出结果用于正弦查找表上。正弦查找表中存储一个周期的正弦波幅度量化数据,用于实现从相位累加器输出的相位值到正弦波幅度的转换。

这里写图片描述

相位寄存器每经过 2NK 个参考时钟回到初始状态,即一个周期结束。所以频率控制字K取最小值1时,每 2N 个时钟周期输出一个周期的正弦波,所以此时有**

fo=fc2N

更一般的情况当频率控制字时K时,每经过 2NK 个参考时钟输出一个周期的正弦波。所以此时有:
fo=fck2N

任意分频技术原理分析:

方案一:直接计数分频法
采用最常用的直接计数分频法,所需的计数器上限为

T=fcfo=100106115200=868

计数器上限取整数,将此值反馈带入输出频率计算式。如下所示:
fo=fcT=100106868=115200+7HZ

由公式可以看出,结果值与预期相差大约7HZ,误差如此之大我们难以忍受。

方案二:任意频率发生器。
这个任意频率发生器是根据直接数字频率合成技术DDS演变而来。
根据公式:

fo=fck2N

若根据不同的K和N的值可以将fc分频到不同的值。下面我们看它的误差在多少范围。
我们设定N的值为32即设置一个32位的计数器,首先计算控制字:
k=fo2Nfc=fo232100106=4947802.324992

由于FPGA中不能进行浮点运算,所以取K为整数4947803。将此值反馈代入输出频率计算表达式,如下所示 :

fo=fck2N=115199.99243319

与预期相差在0.007左右,比较符合所需的频率分频。

Verilog程序设计

怎样将上述原理转化为我们的Verilog程序呢?
我们设置一个计数值cnt【31:0】作为相位累加器,k作为步长。在时钟clk下,以k为步长,cnt=cnt+k;

参数选择如下:
1)输出频率为115200,选择k=4947806;
2)占空比50%,我们采用如下操作:
(1)当 cnt<=2N2 时,fo=0,即输出为低电平;
(2)当 cnt>=2N2 时,fo=1,即输出为高电平;

程序设计步骤:
1)设置一个32位寄存器在时钟作用下计数。
2)设置“门限电压”,实现合成频率的方波输出。
3)分频时钟使能信号的产生。
(由于在FPGA中,除了全局时钟以外,不允许用其他的门控时钟来驱动电路,不然不利于综合电路而且也无法保证电路的稳定性。因此为了便于后续模块的调用,我们设计了一个时钟使能信号,采用边沿检测技术。)

Verilog程序:

module  precise_divider
#(
//DEVIDE_CNT = 42.94967296 * fo    步长DEVIDE_CNT 
//  parameter       DEVIDE_CNT = 32'd175921860  //256000bps * 16
//  parameter       DEVIDE_CNT = 32'd87960930   //128000bps * 16
//  parameter       DEVIDE_CNT = 32'd79164837   //115200bps * 16
    parameter       DEVIDE_CNT = 32'd6597070    //9600bps * 16
)
(
    input           clk,
    input           rst_n,
    output          divide_clk, //分频时钟信号
    output          divide_clken   //时钟使能信号
);
reg [31:0]  cnt;                           //设置一个32位相位寄存器cnt
always@(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        cnt <= 0;
    else
        cnt <= cnt + DEVIDE_CNT;    //在参考时钟下以步长DEVIDE_CNT计数
end

reg cnt_equal;                     //输出频率位fo的方波
always@(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        cnt_equal <= 0;
    else if(cnt < 32'h7FFF_FFFF)
        cnt_equal <= 0;
    else
        cnt_equal <= 1;
end

reg cnt_equal_r;                         //边沿(上升沿)检测
always@(posedge clk or negedge rst_n)    
begin
    if(!rst_n)
        cnt_equal_r <= 0;
    else
        cnt_equal_r <= cnt_equal;
end                                     //上升沿检测输出使能信号
assign  divide_clken = (~cnt_equal_r & cnt_equal) ? 1'b1 : 1'b0; 
assign  divide_clk = cnt_equal_r;

endmodule

本文引用地址:http://group.chinaaet.com/116/32518

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值