2.45 AD9833 DDS模块
2.45.1 模块来源
采购链接:
AD9833模块 DDS模块 提供测试程序 正弦波/方波/三角波信号发生器
资料下载:
https://pan.baidu.com/s/1JZ0ga4uTyXUq5u-Or9BVlg?pwd=GOOD
提取码:GOOD
2.45.2 规格参数
工作电压:2.3 V至5.5 V电源供电
工作电流:12.65 mW(3 V时)
通信方式:3线SPI接口
芯片引脚数量:10引脚MSOP封装
2.45.3 移植过程
我们的目标是在梁山派GD32F470上能够通过模块输出波形的功能。首先要获取资料,查看数据手册应如何实现,再移植至我们的工程。
2.45.3.1 查看资料
模块作用:
可编程波形发生器,能够产生正弦 波、三角波和方波输出。各种类型的检测、信号激励和时 域反射(TDR)应用都需要波形发生器。输出频率和相位可 通过软件进行编程,调整简单。无需外部元件。频率寄存 器为28位:时钟速率为25 MHz时,可以实现0.1 Hz的分辨 率;而时钟速率为1 MHz时,则可以实现0.004 Hz的分辨率。
模块驱动:
AD9833通过一个三线式串行接口写入数据。该串行接口能 够以最高40 MHz的时钟速率工作,并且与DSP和微控制器 标准兼容。该器件采用2.3 V至5.5 V电源供电。注意:在生成方波时会过冲(可以在加入电源滤波电路缓解但不能彻底解决!!!)
2.45.3.2 引脚选择
2.45.3.3 移植至工程
移植步骤中的导入.c和.h文件与上一节相同,只是将.c和.h文件更改为AD9833.c与ccd.h。见2.2.3.3 移植至工程。这里不再过多讲述。移植完成后面修改相关代码。
在文件AD9833.c中,编写如下代码。
/********************************************************************************
* 测试硬件:立创·梁山派开发板GD32F470ZGT6 使用主频200Mhz 晶振25Mhz
* 版 本 号: V1.0
* 修改作者: LCKFB
* 修改日期: 2023年06月12日
* 功能介绍:
******************************************************************************
*********************************************************************************/
#include "AD9833.h"
#include "gd32f4xx.h"
/******************************************************************
* 函 数 名 称:Ad9833GpioConfig
* 函 数 说 明:Ad9833的初始化
* 函 数 形 参:无
* 函 数 返 回:无
* 作 者:LC
* 备 注:软件SPI的配置
******************************************************************/
void AD9833_GpioConfig(void)
{
rcu_periph_clock_enable(RCU_SDATA); //使能SDATA引脚时钟
rcu_periph_clock_enable(RCU_SCLK); //使能SCLK引脚时钟
rcu_periph_clock_enable(RCU_FSNYC); //使能FSNYC引脚时钟
//配置SDATA为上拉推挽输出
gpio_mode_set(PORT_SDATA, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP, GPIO_SDATA);
gpio_output_options_set(PORT_SDATA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_SDATA);
//输出高电平
gpio_bit_set(PORT_SDATA, GPIO_SDATA);
//配置SCLK为上拉推挽输出
gpio_mode_set(PORT_SCLK, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP, GPIO_SCLK);
gpio_output_options_set(PORT_SCLK, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_SCLK);
//输出高电平
gpio_bit_set(PORT_SCLK, GPIO_SCLK);
//配置FSNYC为上拉推挽输出
gpio_mode_set(PORT_FSNYC, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP, GPIO_FSNYC);
gpio_output_options_set(PORT_FSNYC, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_FSNYC);
//输出高电平
gpio_bit_set(PORT_FSNYC, GPIO_FSNYC);
}
/******************************************************************
* 函 数 名 称:AD9833_WriteData
* 函 数 说 明:向AD9833写入16位数据
* 函 数 形 参:txdata=写入的16位数据
* 函 数 返 回:无
* 作 者:LC
* 备 注:FSNYC低电平有效,数据在时钟的下降沿被采集数据,在时钟的上升沿更新数据
******************************************************************/
void AD9833_WriteData(uint16_t txdata)
{
int i;
ADI_FSNYC_OUT(1);
ADI_SCLK_OUT(0);
ADI_SCLK_OUT(1);
ADI_FSNYC_OUT(0);
//写16位数据
for(i=0;i<16;i++)
{
if (txdata & 0x8000)
{
ADI_SDATA_OUT(1);
}
else
{
ADI_SDATA_OUT(0);
}
ADI_SCLK_OUT(0);
txdata<<=1;
ADI_SCLK_OUT(1);
}
ADI_FSNYC_OUT(1);
}
/******************************************************************
* 函 数 名 称:AD9833_SetFrequency
* 函 数 说 明:ad9833设置频率寄存器
* 函 数 形 参:reg=待写入的频率寄存器 fout=频率值
* 函 数 返 回:无
* 作 者:LC
* 备 注:无
******************************************************************/
void AD9833_SetFrequency(unsigned short reg, double fout)
{
int frequence_LSB=0, frequence_MSB=0;
double frequence_mid=0, frequence_DATA=0;
long int frequence_hex=0;
/*********************************计算频率的16进制值***********************************/
//如果时钟频率不为25MHZ,修改该处的频率值,单位MHz ,AD9833最大支持25MHz
frequence_mid = 268435456/25;//适合25M晶振
frequence_DATA = fout;
frequence_DATA = frequence_DATA/1000000;
frequence_DATA = frequence_DATA*frequence_mid;
frequence_hex = frequence_DATA; //这个frequence_hex的值是32位的一个很大的数字,需要拆分成两个14位进行处理;
frequence_LSB = frequence_hex; //frequence_hex低16位送给frequence_LSB
frequence_LSB = frequence_LSB&0x3fff; //去除最高两位,16位数换去掉高位后变成了14位
frequence_MSB = frequence_hex>>14; //frequence_hex高16位送给frequence_HSB
frequence_MSB = frequence_MSB&0x3fff; //去除最高两位,16位数换去掉高位后变成了14位
frequence_LSB = frequence_LSB|reg;
frequence_MSB = frequence_MSB|reg;
AD9833_WriteData(0x2100); //选择数据一次写入,B28位和RESET位为1
AD9833_WriteData(frequence_LSB);
AD9833_WriteData(frequence_MSB);
}
/******************************************************************
* 函 数 名 称:AD9833_SetPhase
* 函 数 说 明:ad9833设置相位寄存器
* 函 数 形 参:reg=待写入的相位寄存器 fout=相位值
* 函 数 返 回:无
* 作 者:LC
* 备 注:无
******************************************************************/
void AD9833_SetPhase(unsigned short reg, unsigned short val)
{
unsigned short phase = reg;
phase |= val;
AD9833_WriteData(phase);
}
/******************************************************************
* 函 数 名 称:AD9833_SetWave
* 函 数 说 明:ad9833设置波形
* 函 数 形 参:WaveMode=输出波形类型
* Freq_SFR=输出的频率寄存器类型
* Phase_SFR=输出的相位寄存器类型
* 函 数 返 回:无
* 作 者:LC
* 备 注:无
******************************************************************/
void AD9833_SetWave(unsigned int WaveMode,unsigned int Freq_SFR,unsigned int Phase_SFR)
{
unsigned int val = 0;
val = (val | WaveMode | Freq_SFR | Phase_SFR);
AD9833_WriteData(val);
}
/******************************************************************
* 函 数 名 称:AD9833_Setup
* 函 数 说 明:设置ad9833的输出
* 函 数 形 参:Freq_SFR = 频率寄存器类型
* Freq = 频率值
* Phase_SFR= 相位寄存器类型
* Phase = 相位值
* WaveMode = 波形类型
* 函 数 返 回:无
* 作 者:LC
* 备 注:无
******************************************************************/
void AD9833_Setup(unsigned int Freq_SFR,double Freq,unsigned int Phase_SFR,unsigned int Phase,unsigned int WaveMode)
{
unsigned int Fsel,Psel;
AD9833_WriteData(0x0100); //复位AD9833,即RESET位为1
AD9833_WriteData(0x2100); //选择数据一次写入,B28位和RESET位为1
AD9833_SetFrequency(Freq_SFR,Freq);
AD9833_SetPhase(Phase_SFR,Phase);
if(Freq_SFR == AD9833_REG_FREQ0)
{
Fsel = AD9833_FSEL0;
}
else
{
Fsel = AD9833_FSEL1;
}
if(Phase_SFR == AD9833_REG_PHASE0)
{
Psel = AD9833_PSEL0;
}
else
{
Psel = AD9833_PSEL1;
}
AD9833_SetWave(WaveMode,Fsel,Psel);
}
在文件AD9833.h中,编写如下代码。
/********************************************************************************
* 测试硬件:立创·梁山派开发板GD32F470ZGT6 使用主频200Mhz 晶振25Mhz
* 版 本 号: V1.0
* 修改作者: LCKFB
* 修改日期: 2023年06月12日
* 功能介绍:
******************************************************************************
*********************************************************************************/
#ifndef _AD9833_H__
#define _AD9833_H__
#include "GD32F4XX.h"
//引脚定义
#define RCU_SDATA RCU_GPIOD
#define PORT_SDATA GPIOD
#define GPIO_SDATA GPIO_PIN_5
#define RCU_SCLK RCU_GPIOD
#define PORT_SCLK GPIOD
#define GPIO_SCLK GPIO_PIN_4
#define RCU_FSNYC RCU_GPIOD
#define PORT_FSNYC GPIOD
#define GPIO_FSNYC GPIO_PIN_1
//端口输出
#define ADI_SDATA_OUT(X) gpio_bit_write(PORT_SDATA, GPIO_SDATA, (X)?SET:RESET)
#define ADI_SCLK_OUT(X) gpio_bit_write(PORT_SCLK, GPIO_SCLK, (X)?SET:RESET)
#define ADI_FSNYC_OUT(X) gpio_bit_write(PORT_FSNYC, GPIO_FSNYC, (X)?SET:RESET)
//输出波形
#define AD9833_OUT_SINUS ((0 << 5) | (0 << 1) | (0 << 3)) //正弦波
#define AD9833_OUT_TRIANGLE ((0 << 5) | (1 << 1) | (0 << 3)) //三角波
#define AD9833_OUT_MSB ((1 << 5) | (0 << 1) | (1 << 3)) //方波
#define AD9833_OUT_MSB2 ((1 << 5) | (0 << 1) | (0 << 3)) //方波
//相关寄存器
#define AD9833_REG_CMD (0 << 14)
#define AD9833_REG_FREQ0 (1 << 14)
#define AD9833_REG_FREQ1 (2 << 14)
#define AD9833_REG_PHASE0 (6 << 13)
#define AD9833_REG_PHASE1 (7 << 13)
//命令控制位
#define AD9833_B28 (1 << 13)
#define AD9833_HLB (1 << 12)
#define AD9833_FSEL0 (0 << 11)
#define AD9833_FSEL1 (1 << 11)
#define AD9833_PSEL0 (0 << 10)
#define AD9833_PSEL1 (1 << 10)
#define AD9833_PIN_SW (1 << 9)
#define AD9833_RESET (1 << 8)
#define AD9833_CLEAR_RESET (0 << 8)
#define AD9833_SLEEP1 (1 << 7)
#define AD9833_SLEEP12 (1 << 6)
#define AD9833_OPBITEN (1 << 5)
#define AD9833_SIGN_PIB (1 << 4)
#define AD9833_DIV2 (1 << 3)
#define AD9833_MODE (1 << 1)
//函数声明
void AD9833_GpioConfig(void);
void AD9833_WriteData(uint16_t txdata);
void AD9833_SetFrequency(unsigned short reg, double fout);
void AD9833_SetPhase(unsigned short reg, unsigned short val);
void AD9833_SetWave(unsigned int WaveMode,unsigned int Freq_SFR,unsigned int Phase_SFR);
void AD9833_Setup(unsigned int Freq_SFR,double Freq,unsigned int Phase_SFR,unsigned int Phase,unsigned int WaveMode);
#endif
2.45.4 移植验证
在自己工程中的main主函数中,编写如下。
/********************************************************************************
* 测试硬件:立创·梁山派开发板GD32F470ZGT6 使用主频200Mhz 晶振25Mhz
* 版 本 号: V1.0
* 修改作者: LCKFB
* 修改日期: 2023年06月12日
* 功能介绍:
******************************************************************************
*********************************************************************************/
#include "gd32f4xx.h"
#include "systick.h"
#include <stdio.h>
#include "main.h"
#include "sys.h"
#include "bsp_usart.h"
#include "AD9833.h"
int main(void)
{
systick_config();
usart_gpio_config(115200U);
AD9833_GpioConfig();
while(1)
{
//输出 2K 三角波
AD9833_Setup(AD9833_REG_FREQ0,2000.0,AD9833_REG_PHASE1,1024,AD9833_OUT_TRIANGLE);
delay_1ms(2000);
delay_1ms(2000);
delay_1ms(2000);
delay_1ms(2000);
//输出 50K 正弦波
AD9833_Setup(AD9833_REG_FREQ0,50000.0,AD9833_REG_PHASE1,1024,AD9833_OUT_SINUS);
delay_1ms(2000);
delay_1ms(2000);
delay_1ms(2000);
delay_1ms(2000);
//输出 1M 方波
AD9833_Setup(AD9833_REG_FREQ0,1000000.0,AD9833_REG_PHASE1,1024,AD9833_OUT_MSB);
delay_1ms(2000);
delay_1ms(2000);
delay_1ms(2000);
delay_1ms(2000);
}
}
移植现象:该实例是产生一个2KHZ的三角波,8秒后产生50K正弦波,8秒后再产生1M方波,将探头连接到示波器上观察!!注意:生成方波有过冲是正常现象。
移植成功示例,见文件2.45.4-1。