分频器
我们知道串口常用的波特率为300,600, 1200, 2400, 4800, 9600, 19200, 38400, 43000, 56000, 57600, 115200。在用FPGA实现UART协议时,我们期望最好有上述波特率整数倍的系统时钟,但这样的时钟频率不常见。不过,我们可以通过分数分频的方法实现这一功能。为清晰阐明分数分频,在此先不考虑4300bps的波特率。
假设FPGA系统时钟为80M,如果我们能通过分数分频实现64.512M的时钟,那么除43000外其他所有波特率值均可以整除64.512M。再分别实现各个波特率,接下来就只剩下整数分频的问题了。由于64512 / 80000 = 504 / 625,那么在80M时钟下每625个时钟取504个时钟则等效为64.512M时钟了。
进一步分析,625=125×5而504=125×4 + 4。设计两个计数器parts和share,share按照80M时钟节拍模5计数,而parts以share=4为节拍模125计数。那么parts和share的组合625个时钟周期重复一次。每个share为5个时钟周期,取4个周期,这样在625个时钟周期中获得了500个周期。再从125个parts中选择4个,在这4个选出的parts中share的第5个周期也被选择使能,那么就获得了125×4 + 4 = 504个周期。程序代码如下:
--fraction_div.vhdLibrary ieee;Useieee.std_logic_1164.all,ieee.std_logic_unsigned.all;Library ucxLib; Use ucxLib.ucx_2008pkg.all;
Entity fraction_div is port( clock :in std_logic; q :out std_logic );End fraction_div;
Architecture myFavor of fraction_div is signal parts : std_vector(0to 6); signal share : std_vector(0to 2); signalclk32256K,clk_en : std_logic :='0';BeginProcess(clock) begin if rising_edge(clock)then RstIncDec(share,share(0), '1'); RstIncDec(parts,share(0) and parts=124, share(0)); clk_en <=not share(0) or parts=0 or parts=31 or parts=62 or parts=93; end if;End process;Process(clock, clk_en) begin if rising_edge(clock)and clk_en then clk32256K<= not clk32256K; end if;End process;q <= clk32256K;End myFavor;
fraction_div.vhd实现的功能是输入clock为80MHz,输出q为32.256M。即表明程序中rising_edge(clock) and clk_en实现64.512M时钟功能。不过q的占空比不是固定50%。
代码行18表明parts在parts=124和share >=4时清零,否则在share>=4条件下增1计数。行19中not share(0)表示share=0,1,2,3四个周期,parts=0or parts=31 or parts=62 or parts=93表示均匀选取4个parts。行18中与运算share(0)and parts=124第一个参数share(0)是std_logic型,第二个参数parts=124是boolean。这样书写可以编译通过,因为在ucx_2008pkg.vhd中重载了and运算符。
Function"and"(bL: std_logic; bR:boolean) return std_logic is begin return bLand STDZ(bR); End; Function"and"(bL: boolean; bR:std_logic) return boolean is begin return bLand bR='1'; End;运算符and重载后,boolean和std_logic两个不同类型的变量运算后结果同第一个变量。类似地可以重载or,xor,nand,nor和xnor。并加入到自定义库中。
一周热门 更多>