#今天也是咸鱼的一天~(换口头禅了)
DDS全称直接数字频率合成(Direct Digital Synthesis),系统结构可分为这几个部分,其中相位控制字可调整输出正弦波的相位,频率控制字可以调整输出正弦波的频率。
BUT,我在这里必须吐槽一下,Robei比赛的骚操作(别打我),比赛不允许我们使用除了RISC-V 以外的IP核,如果这个在后面真的不做任何改动的话,这就意味着,我没法使用像DDS,PLL,SPI,ROM,RAM,EEPROM,FIFO的IP核(菜鸡流泪),我可能得全部自己手写,手写各种通信协议和常用IP核。因此,这次介绍的是这样一个常用IP核,DDS。(vivado是有dds的IP,quartus好像是没有的)
DDS是一个在很多地方都有很大的用处的硬件,能够产生多种波形,包括现在的信号源,大多也是用FPGA做的,因为Robei没法使用这些IP核,所以就用源代码写一个。
参考是是这两份博客:
- DDS的FPGA实现
- DDS原理及FPGA实现
————————————————毫无感情的分割线————————————————
方波发生
参考的资料是这个:
Robei 模块图:
绿色的模块是一个16进制的计数器,另两个蓝色的模块,是对计数器的数据进行处理,实现方波的过程。
计数器
Code:
// let's create a 16 bits free-running binary counter
always @(posedge clk or negedge rst)
if(!rst)
cnt <= 16'h0;
else if(cnt == 16'hff)
cnt <= 16'h0;
else
cnt <= cnt + 16'h1;
// and use it to generate the DAC signal output
取位数
assign cnt_tap = cnt[7]; // we take one bit out of the counter (here bit 7 = the 8th bit)
累乘
assign DAC_data = {
10{
cnt_tap}}; // and we duplicate it 10 times to create the 10-bits DAC value
三角波
code:
assign tri_data = cnt_tap [10] ? ~cnt_tap [9:0] : cnt_tap [9:0];
锯齿波
assign saw_data = cnt_tap[9:0];
testbech
initial begin
clk = 0;
rst = 0;
#5 rst = 1;
#5 clk = 1;
#150000 rst = 0;
#5 $finish;
end
always begin
#5 clk =~clk;
end
信号波形
——————菜鸡冷漠的分割线————————
前几个都是很简单的代码,利用计数器就可以实现,这是因为像方波、三角波、锯齿波这类波形,都有很“线性”的关系。方波是边沿陡峭,其它平稳;锯齿波是一个线性上升,再边沿陡峭;三角波是线性上升,线性下降。这些关系都比较容易模拟,但是对于正弦波这样的信号波形,它的函数是sin,这样子在数字量输出上,就比较惨了~
在Quartus的编程里,有Rom可以存储波形数据,直接输出就行,非常方便;更是直接有现成的IP Core 可以调用DDS。但是Robei既没有ROM,也没有IP,所以只能手写数据来输出正弦波。
模块配置
分频counter
Code:
reg [10:0] num;
always@(posedge clk or negedge rst)
begin
if(!rst)
begin
num <= 11'd0;
clk_1 <= 1'b0;
end
else if(num>=1280) //这个是对系统时钟分频,根据想得到正弦波的频率,算这里取多少
begin
clk_1<=~clk_1;
num <=11'd0;
end
else
num <=num+11'b1;
end
这个计数器就是一个简易的分频器,当然,如果有条件,直接用pll 多简单。