内容介绍
内容介绍
1、项目概况
本设计旨在利用RP2350B核心板+综合训练扩展板建一个DDS信号发生器,主要的需求如下:
- 能够产生正弦波、三角波、方波、直流,可以通过核心板的拨码开关控制波形的切换
- 产生信号的幅度0-3Vpp之间可调,可以通过电位计进行调节
- 产生信号的频率100Hz-200KHz之间可调
- 产生的波形、波形的幅度、波形的频率都实时显示在OLED屏幕上
根据以上需求,可以细化上述需求,主要的DDS信号发生器功能如下:
- 通过R-2R电阻网络和控制GPIO口来模拟DAC输出不同的电压,从而生成不同的波形,
- 通过SPI读出ADS7868 AD采样器,从而可以读出电位计数据,结合波形生成策略,可控制波形赋值
- 核心板AD采样按键电阻网络,从而判断按键的类型。
- 根据按键的类型可以切换波形,也可以调节波形的频率
- 通过SPI控制OLED显示波形的类型、赋值和频率。
- IIC读取姿态传感器数据,可用于控制波形的切换。
- 数码管可用于显示波形类型编码
- LED灯指示按键的按下
主要使用的RP2350B核心板和综合训练扩展板如下:
2、项目总体方案框图
项目总体框图如下:
根据细化的需求,拆分相关的模块如下:
- adc:采集电阻按键网站的电压值,用于检查哪个按键或者拨码开关按下
- ads7868:通过spi采集电位计数据,用于模块波形幅值
- angle:iic读取姿态传感器数据,用于波形类型控制
- blink:led闪烁,系统运行指示灯
- dac:R-2R电阻网络电压输出,用于生成波形
- key:对adc采集的电压进行滤波以及按键值的检查
- oled:spi 协议控制波形、幅值等数据显示
- multi_core:core1处理函数,接收core的数据,用于控制dac数据输出,电位计控制幅值输出,以及频率的控制
- segment_scan:利用74hc595 串转并显示对应的数据,显示波形编码值
- main:core0上运行,用于处理电位计、姿态传感器数据、按键逻辑控制、OLED显示以及core1的通信控制数据传输。
3、硬件使用介绍
使用到的硬件主要有如下图所示:
- OLED:128*64 液晶显示屏
- 数码管:IO驱动数码管和74HC595串转并驱动数码管
- 74HC595:串转并驱动芯片
- 按键:拨码以及点击按键
- ads7868:ad采样芯片,spi协议数据读出
- R-2R电阻网络以及TLV271:运算放大器,
- KXTJ3-1057:姿态传感器,IIC协议总线,x,y,z三轴数据
- LED灯:数量为8个
3.1、R-2R电阻网络DAC
- R-2R无需与并行数据同步的时钟,直接IO口并行数据输出到10个电阻节点即可
- 基准电压为3.3V,因此在R-2R上得到的模拟波形的峰峰值也就是3.3Vpp
- 10个IO口,从DA0-DA9,可看出10位数据,数值越大,则幅值越大,基于此可调整不同的电压生成不同的波形。
R-2R电阻网络DAC电路图如下所示:
3.2、74HC595控制数码管
2个74HC595 来控制2个数码管,主要使用三个管脚,SER,SRCLK,RCLK,时钟频率为40KHZ
- SER:串行数据输入管脚,数据从SER口排着队依次进入。
- SRCLK:移位寄存器的时钟输入
- 数据从SER口排着队等待进入,该管脚输入低电平,则SER接收一位数据。
- RCLK:存储计时器时钟的输入引脚
- 把SER输入的8位数据存储起来,输入高电平,把移位寄存器中的8位数据一次性转存到存储时钟当中。
实验中有2个数码管,则需要2个74HC595芯片控制,一个控制数码管的位置,一个控制数码管的数据。
- 首先初始化管脚状态
- 其次把控制的数码管位置以及数码管封住成整体数据,1个16位数据
- 接着通过sclk时钟,逐位通过SER管脚输出,则点亮单个数码管
- 最后扫描2个数码管,通过状态机逐个数码管显示对应数据
具体电路与时序图如下
3.3、姿态传感器数据读取
KXTJ3-1057姿态传感器:使用IIC总线通信,400KHZ频率,通过读取固寄存器地址,可以分多次将数据读出。寄存器列表如下:
- 首先写0x1B 地址,初始化传感器,主要是控制传感器位数,以及精读量程
- 其次写0x1D地址,传感器输出数据频率
- 最后就通过0x06/07、0x8/09、0xA/B读取接近传感器数值,可以有8/12/16位数值
3.4、ADA采样芯片数据读取
ADS7868 ADA采样芯片:spi协议读取采样数据,其时序图和电路图如下
- 需要三个IO口,其中一个输入SD,用于读取数据,其他IO口用于输出,clk是时钟,cs是片选使能
- cs使能的时候进行读数据
- clk 时钟下拉时,读取sdo数据
- 读取sdo数据时,前三个为0,需要过滤掉,数据总共8位。
3.5、8个LED控制
- 多个IO口控制来确定不同的LED灯亮
- 不需要的IO口需要设置高组态,不然导致其他LED灯亮
3.6、按键控制:
- ADC 采集电压,按键按下电阻不同,则电压不同,根据电压的范围,确定哪个电阻按下
- adc采集的值需要均值滤波,且需要消抖,不然有很大概率出现误触按下情况
4、功能模块设计与展示
4.1、任意波形生成
利用R-2R DAC可生成不同的电压幅值,如果在不同的时刻输出不同的值,则可以用于生成波形。
- 正弦波:查表生成,正弦波属于中心对称以及轴对称,因此只需要生成1/4波形数据,然后通过基础值+逆序的方式就可以生成余下的波形。
uint16_t sine_wave_data[] =
{
0x0, 0xC, 0x19, 0x25, 0x32, 0x3E, 0x4B, 0x57,
0x63, 0x70, 0x7C, 0x88, 0x94, 0xA0, 0xAC, 0xB8,
0xC3, 0xCF, 0xDA, 0XE6, 0xF1, 0XFC, 0x107, 0x111,
0x11C, 0x126, 0x130, 0x13A, 0x144, 0x14E, 0x157, 0x161,
0x16A, 0x172, 0x17B, 0x183, 0x18B, 0x193, 0x19B, 0x1A2,
0x1A9, 0x1B0, 0x1B7, 0x1BD, 0x1C3, 0x1C9, 0x1CE, 0x1D4,
0x1D9, 0x1DD, 0x1E2, 0x1E6, 0x1E9, 0x1ED, 0x1F0, 0x1F3,
0x1F6, 0x1F8, 0x1FA, 0x1FC, 0x1FD, 0x1FE, 0x1FF, 0x1FF,
};
case SINE_WAVE_SEL:
{
int8_t i;
for(i=0;i<64;i++)
{
dac_io_value_set((0x1FF + sine_wave_data[i])*ad_data_g/1024);
sleep_us(fre);
}
for(i=63;i>=0;i--)
{
dac_io_value_set((0x1FF + sine_wave_data[i])*ad_data_g/1024);
sleep_us(fre);
}
for(i=0;i<64;i++)
{
dac_io_value_set((0x1FF - sine_wave_data[i])*ad_data_g/1024);
sleep_us(fre);
}
for(i=63;i>=0;i--)
{
dac_io_value_set((0x1FF - sine_wave_data[i])*ad_data_g/1024);
sleep_us(fre);
}
}break;
- 方波:控制DAC输出0,以及输出有电压幅值,如此循环往复可以生成方波。
case SQUARE_WAVE_SEL:
{
dac_io_value_set(ad_data_g);
sleep_us(fre);
dac_io_value_set(0);
sleep_us(fre);
}break;
- 三角波:控制DAC输出按照阶梯输出到最大值,然后再减小到0值。这里笔者的阶梯值可以根据幅值调控
case TRIANGULAR_WAVE_SEL:
{
int8_t i;
uint16_t value = 0;
uint16_t avg = ad_data_g>>5;
for(i=0;i<32;i++)
{
dac_io_value_set(value);
sleep_us(fre);
value+=avg;
}
for(i=0;i<32;i++)
{
value-=avg;
dac_io_value_set(value);
sleep_us(fre);
}
}break;
- 锯齿波:相比三角波,只需要阶梯式增大即可。
case SAWTOOTH_WAVE_SEL:
{
int8_t i;
uint16_t value = 0;
uint16_t avg = ad_data_g>>5;
for(i=0;i<32;i++)
{
dac_io_value_set(value);
sleep_us(fre);
value+=avg;
}
}break;
- 直流偏置:直接输出电压
case DC_WAVE_SEL:
{
dac_io_value_set(ad_data_g);
}break;
4.2、波形幅值与频率控制
- 电位计由ADS7868 采样,通过SPI协议读出,这里SPI协议通过IO口模拟生成(硬件SPI 与当前口无法对应上)
- 频率由按键控制,可以进行增减。
- 通过拨码开关,可以控制波形的类型
- 通过按键,可以控制波形的频率,通过控制波形数据点位之间的延时,可以控制波形的频率
- 电位计数据通过SPI读出,用于控制波形的幅值,例如对于方波,用于控制高电平的幅值,即可输出不同幅值的方波,对于正弦波,幅值与最大值成比例,然后作为输出系数,对于三角波和锯齿波,幅值可用于控制阶梯式大小,然后就可以控制波形幅值。
void core1_fifo_irq() {
// Just record the latest entry
uint32_t value;
while (multicore_fifo_rvalid())
{
value = multicore_fifo_pop_blocking();
ad_data_g = ((value & 0xFF) << 2);
wave_select = (value >> 8) & 0xFF;
fre = (value>>16);
}
multicore_fifo_clear_irq();
}
- core0 输出的控制波形数据,通过fifo irq获取,共32位数据
- 低16位中的低8位是幅值数据
- 低16位中的高8位是波形选择数据
- 高16位为频率控制数据
4.3、OLED波形信息显示
- OLED显示通过SPI控制,这里同样采样IO口模拟(硬件SPI 与当前口无法对应上)
- OLED的波形通过图案进行显示
- core0发送给core1的波形控制数据同时显示在OLED上面。
- 100HZ利用定时器定时刷新OLED显示数据
void wave_info_show()
{
uint8_t buf[128];
uint32_t ad_data = ad_read_data();
sprintf(buf,"Vol:%.2f V", (float)ad_data*3.0/254);
show_common_string(40, 4, buf, 16);
switch(wave_set)
{
case SQUARE_WAVE_SEL:
{
uint16_t fre = 1000000/wave_fre/2;
if(fre>1000)
sprintf(buf,"Fre:%.1f kHz", (float)fre/1000.0);
else
sprintf(buf,"Fre:%04d Hz", fre);
OLED_DrawBMP(0,0, 40, 64, square_wave);
}break;
case SINE_WAVE_SEL:
{
uint16_t fre = 1000000/wave_fre/256;
sprintf(buf,"Fre:%04d Hz", fre);
OLED_DrawBMP(0,0, 40, 64, sine_wave);
}break;
case TRIANGULAR_WAVE_SEL:
{
uint16_t fre = 1000000/wave_fre/64;
sprintf(buf,"Fre:%04d Hz", fre);
OLED_DrawBMP(0,0, 40, 64, triangular_wave);
}break;
case SAWTOOTH_WAVE_SEL:
{
uint16_t fre = 1000000/wave_fre/32;
sprintf(buf,"Fre:%04d Hz", fre);
OLED_DrawBMP(0,0, 40, 64, sawtooth_wave);
}break;
case DC_WAVE_SEL:
{
sprintf(buf,"Fre:%04d Hz", 1);
OLED_DrawBMP(0,0, 40, 64, dc_wave);
}break;
default:
break;
}
show_common_string(40, 1, buf, 16);
multicore_fifo_push_blocking((wave_fre<<16) | (wave_set<<8) | (ad_data));
}
5、项目实物展示
项目仓库地址为:DDS 信号发生器
项目硬件展示如下图所示:
- 波形:正弦波
- 幅值:1.95V
- 频率:38HZ
- 波形:三角波
- 幅值:1.89V
- 频率:156HZ
- 波形:锯齿波
- 幅值:1.89V
- 频率:312HZ
- 波形:方波
- 幅值:1.97V
- 频率:4.95KHZ
- 波形:直流偏置
- 幅值:1.9V
- 频率:0HZ
6、项目总结与展望
6.1、项目总结与展望
- DDS任意波形发生器总体难度不是很大,核心的控制还是波形的频率控制,单片机不像FPGA那样,频率可以达到很高,且控制相对容易,单片机如果输出相对较高的IO还是相对困难的,因为需要精准的去控制频率,如果有其他程序运行,就会干扰频率范围,笔者采样core1运行DAC,没有其他程序感染,延时精准控制频率,但是频率范围有限,后续考虑DMA控制IO或者PWM控制IO输出。
- DDS信号发生器当前功能还是相对简单,后续考虑串口接收上位机数据来进行频率生成以及显示
- DDS信号发生器如果要生成任意波形,考虑上位机传输波形数据下来生成,定义好相关格式,比如点位数据等等,然后可以显示任意波形。
6.2 、心得与感受
- 本次硬禾推出全新RP2350B核心板内置姿态传感器,数码管,按键以及LED灯,外设功能相对丰富,对于初学者来说,还是相对友好的,且按键以及LED灯控制,电路相对有趣,也可以学到很多基础知识。
- RP2350B核心板相对较小,如果用来做物联网等场景的控制板,还是很有竞争力
- 综合外设扩展板板载OLED,电位计,DAC等外设,满足对基本外设的需求,且相对较小,个人还是比较喜欢这样小巧的扩展板。
7、参考
软硬件
附件下载
dds-project.zip
dds project,在blink文件夹下面有所有的文件,编译好即可运行build下面blink下面的dds.uf2
dds.uf2
RP2350B烧录文件
团队介绍
一名嵌入式工程师,励志做自己喜欢的玩具,喜欢研究芯片底层架构,编程模型,指令集等,热爱去研究使用开源软件,跑步、乒乓球爱好者,个人网站一西站点:http://zyixi.xyz/
评论
0 / 100
查看更多
猜你喜欢
基于小脚丫FPGA实现DDS信号发生器通过板上的高速DAC(10bits/125Msps)配合FPGA内部DDS的逻辑,生成波形可调(正弦波、三角波、方波)、频率可调(DC-)、幅度可调的波形。
枳香清酒
2625
基于RP2350B实现DDS信号发生器该项目使用了RP2350B和综合技能训练板,实现了可调波形、频率、幅度、直流偏移的DDS信号发生器的设计,它的主要功能为:通过DAC输出波形、在显示屏上显示波形、在显示屏上显示波形幅度频率等参数。
该项目使用了RP2350B核心板和circuitpython语言,实现了DDS信号发生器的设计,它的主要功能为:根据按键、拨码开关、电位计状态通过DAC输出特定的频率、幅度、波形,并通过OLED显示这些信息。
derrickcr
42
基于RP2350B实现DDS信号发生器该项目使用了RP2350B,实现了DDS信号发生器的设计,它的主要功能为:方波、正弦波、三角波、直流信号的产生,并且幅值和频率可调。
鲍飞.
29