基于AD9954实现正弦交流信号输出——附原理图、代码

这篇具有很好参考价值的文章主要介绍了基于AD9954实现正弦交流信号输出——附原理图、代码。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

最近本人在做基于Cortex-M4的电阻抗采集系统,正弦信号是由AD9954这一款芯片产生的,由于网上对于该芯片的介绍比较少,这里分享一下自己的使用调试心得,以便大家参考。本人才疏学浅,如果有错误,还请指正。

一、AD9954的电路设计

AD9954是一种直接数字合成器,能够在高达160MHz的频率下生成频率可变的模拟输出正弦波形。芯片手册对于该芯片的介绍已经很是详细了,这里就不再多展开介绍。下面直接干货介绍:

AD9954的芯片手册:AD9954 (Rev. C) (analog.com)

  1. 供电模块设计

首先要先解决AD9954芯片的供电问题,AD9954的供电电压是1.8V,主控芯片我选择的是STM32F407,控制IO口的电压是3.3V,由此我们需要一个5V->3.3V、5V->1.8V的电路,由于DDS是模拟信号,数字电源和模拟电源之间最好隔开,这里选择使用0欧电阻/电感分隔。原理图如下:

基于AD9954实现正弦交流信号输出——附原理图、代码

AMS1117-1.8数据手册:AMS1117-1.8_(AMS)AMS1117-1.8中文资料_价格_PDF手册

AMS1117-3.3数据手册:AMS1117-3.3_(国芯佳品)AMS1117-3.3中文资料_价格_PDF手册

  1. DDS模块设计

AD9954的接线如下,在DDS IOUT-和DDS IOUT+两个端口,可以产生相位相反的正弦直流电源。原理图的设计参考芯片手册的。

基于AD9954实现正弦交流信号输出——附原理图、代码

控制引脚的设置如下:

名称

引脚

名称

定义

IO UPDATE

PE3

DDS CS

PF12

DDS PS1

PE11

DDS SDO

PF11

DDS PS0

PE9

DDS IOSYNC

PF13

DDS OSK

PE7

DDS RESET

PF15

DDS SDIO

PG0

DDS PWR

PG1

DDS SCLK

PF14

  1. 仪表放大电路

经过测试,DDS IOUT-和DDS IOUT+两个端口 输出电压偏移为1.5V,幅值可调(最高0.3V)的直流正弦波信号,两个信号相位相反。我们需要将正弦直流信号转变为交流信号。

基于AD9954实现正弦交流信号输出——附原理图、代码

仪表放大器是非常高增益的差分放大电路,具有高输入阻抗和单端输出。具有高输入阻抗的三运放仪表放大器的典型示例如下:

基于AD9954实现正弦交流信号输出——附原理图、代码

仪表放大器电路的总电压增益的一般表达式为:

基于AD9954实现正弦交流信号输出——附原理图、代码

设计差分放大电路并使用Multisim软件对电路进行仿真,测得稳定的幅值为1V 的正弦电压信号:

基于AD9954实现正弦交流信号输出——附原理图、代码

仪表放大器电路的原理图如下,运算放大器选用AD8002,这里需要-5V供电。

基于AD9954实现正弦交流信号输出——附原理图、代码

AD8002:AD8002 (Rev. E) (analog.com)

二、AD9954的软件设计

上一篇章介绍了AD9954的电路设计,接下来是AD9954的代码,对于AD9954没有深入的了解,代码只能实现正弦频率以及幅值的设定。

使用的主控芯片为STM32F407,该代码引脚的初始化是针对本电路的,参考时,还要按实际情况进行修改。

DDS.c文件如下:

void PhyAD9954_Init(void)
{
    GPIO_AD9954_Init();            //GPIO初始化
    AD9954_RESET();                    //DDS复位
    delay_ms(300);                    //延迟300ms
    AD9954_CS = 0;
    //single tone
    AD9954_SENDBYTE(CFR1);//地址0写操作
    AD9954_SENDBYTE(0x02);//
    AD9954_SENDBYTE(0x10);
    AD9954_SENDBYTE(0x00);
    AD9954_SENDBYTE(0x40);//比较器power down      
//    AD9954_SENDBYTE(0x00);//比较器使能        

    AD9954_SENDBYTE(CFR2);//地址1写操作
    AD9954_SENDBYTE(0x00);//
    AD9954_SENDBYTE(0x08);
    #if fs>400
        #error "系统频率超过芯片最大值"
    #endif
    #if fs>=250
        AD9954_SENDBYTE(PLL_MULTIPLIER<<3|0x04|0X03);
    #else
        AD9954_SENDBYTE(PLL_MULTIPLIER<<3);
    #endif
    AD9954_CS=1;
}


// AD9954接口IO初始化
void GPIO_AD9954_Init(void)
{
    GPIO_InitTypeDef  GPIO_InitStructure;
    
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE);
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE);
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOG, ENABLE);

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7 | GPIO_Pin_9 | GPIO_Pin_11 | GPIO_Pin_13;   
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;               //普通输出模式
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;              //推挽输出
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;          //100MHz
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;                //下拉
    GPIO_Init(GPIOE, &GPIO_InitStructure);                      //初始化GPIO
    
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;   
    GPIO_Init(GPIOF, &GPIO_InitStructure);                      //初始化GPIO
    
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;   
    GPIO_Init(GPIOG, &GPIO_InitStructure);                      //初始化GPIO    
    
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;   
    GPIO_Init(GPIOG, &GPIO_InitStructure);                      //初始化GPIO 

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;   
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;               //普通输出模式
    GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;              //推挽输出
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;          //100MHz
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;                //下拉
    GPIO_Init(GPIOF, &GPIO_InitStructure);                      //初始化GPIO

    AD9954_IOSY=0;
    AD9954_OSK=0;
    AD9954_PWR=0;
}


// 复位AD9954
void AD9954_RESET(void)
{
    AD9954_CS = 1;
    AD9954_RES = 0;
    delay_ms(10);
    AD9954_RES = 1;
    delay_ms(10);
    AD9954_RES = 0;
    delay_ms(10);
    AD9954_CS = 0;
    AD9954_SCLK = 0;
    PS0 = 0;
    PS1 = 0;
    IOUPDATE = 0;
    AD9954_CS = 1;
}


// 往AD9954发送一个字节的内容
void AD9954_SENDBYTE(u8 dat)
{
    u8 i;
    for (i = 0;i<8;i++)
    {
        AD9954_SCLK = 0;
        if (dat & 0x80)
        {
            AD9954_SDIO = 1;
        }
        else
        {
            AD9954_SDIO = 0;
        }
        AD9954_SCLK = 1;
        dat <<= 1;
    }
}


// 往AD9954接收一个字节的内容
u8 AD9954_ReadByte(void)
{
    u8 i,dat=0;
    for (i = 0;i<8;i++)
    {
        AD9954_SCLK = 0;
        dat|=AD9954_SDO;
        AD9954_SCLK = 1;
        dat <<= 1;
    }
    return dat;
}



//产生一个更新信号,更新AD9954内部寄存器
void UPDATE(void)
{
    IOUPDATE=0;
//    delay_us(100); 
    IOUPDATE = 1;
    delay_us(2);
    IOUPDATE = 0;
}

u32 Get_FTW(double Real_fH)
{
        return (u32)(fH_Num*Real_fH);
}


/*********************************************************************************************************
** 函数名称 :void AD9954_SETFRE(float f)
** 函数功能 :设置AD9954当前的频率输出,采用的是单一频率输出
** 函数说明 :因为采用的浮点数进行计算,转换过程中会出现误差,通过调整可以精确到0.1Hz以内
** 入口参数 :欲设置的频率值
** 出口参数 :无
*********************************************************************************************************/
void AD9954_SETFRE(double f)//single tone
{
    u32 date;
    AD9954_CS = 0;
    
    date = Get_FTW(f);//det=(f/fclk)x2^32=10.7374xf
    AD9954_SENDBYTE(FTW0);//FTW0地址
    AD9954_SENDBYTE((u8)(date >> 24));//频率控制字
    AD9954_SENDBYTE((u8)(date >> 16));
    AD9954_SENDBYTE((u8)(date >> 8));
    AD9954_SENDBYTE((u8)date);
    AD9954_CS=1;
    UPDATE();
    
    #ifdef EIT_USART_DEBUG
                printf("\n\r DDS输出频率为:%.2f Hz \n\r" ,f);            
    #endif
}



/*********************************************************************************************************
** 函数名称 :void Write_ASF(u16 factor)
** 函数功能 :改变scale factor数值,改变DAC输出幅度
** 函数说明 :写入最大为0X3FFF,最小为0,最大峰峰值约500mv
** 入口参数 :无
** 出口参数 :无
*********************************************************************************************************/
void Write_ASF(u16 factor)  //
{
    AD9954_CS = 0;

    AD9954_SENDBYTE(0x02);//幅度    
    AD9954_SENDBYTE(factor >> 8);
    AD9954_SENDBYTE(factor);
    AD9954_CS = 1;
    UPDATE();

}

DDS.h文件如下:

#ifndef __PHY_DDS_H
#define __PHY_DDS_H    

#include "Public_Config.h"    //IO口控制

/*  引脚设置
**      AD9954_CS----------PF12         OUT
**      AD9954_SCLK--------PF14         OUT
**      AD9954_SDIO--------PG0         OUT
**      AD9954_OSK---------PE7       OUT
**      PS0----------------PE9        OUT
**        PS1----------------PE11         OUT
**      IOUPDATE-----------PE13          OUT
**        AD9954_SDO---------PF11          IN
**      AD9954_IOSY--------PF13          OUT
**      AD9954_RES---------PF15        OUT
**      AD9954_PWR---------PG1        OUT
*/

#define AD9954_CS     PFout(12)            
#define AD9954_SCLK PFout(14)            
#define AD9954_SDIO PGout(0)            
#define AD9954_OSK     PEout(7)            
#define PS0         PEout(9)        
#define PS1         PEout(11)            
#define IOUPDATE     PEout(13)            
#define AD9954_SDO    PFin(11)        
#define AD9954_IOSY PFout(13)        
#define AD9954_RES     PFout(15)        
#define AD9954_PWR     PGout(1)    


#define CFR1    0X00            
#define CFR2    0X01
#define ASF     0X02
#define ARR1    0X03
#define FTW0    0X04
#define POW0    0X05
#define FTW1    0X06
#define NLSCW   0X07
#define PLSCW   0X08
#define RSCW0   0X07
#define RSCW1   0X08
#define RSCW2   0X09
#define RSCW3   0X0A
#define RAM     0X0B

#define No_Dwell 0X80

typedef enum {
DownScan  =   0,
UpScan,
DoubleScan
}ScanMode;              


void PhyAD9954_Init(void);                 //DDS初始化
void AD9954_SETFRE(double f);               //设置频率
void Write_ASF(u16 data);                  //设置幅值

#endif

DDS.h文件中涉及的IO空控制,封装在 Public_Config.h 文件中:

#ifndef __PUBLIC_CONFIG_H
#define __PUBLIC_CONFIG_H


#define APP_VECT_TAB_OFFSET     0       //中断向量表设置

//IO口操作宏定义
#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2)) 
#define MEM_ADDR(addr)  *((volatile unsigned long  *)(addr)) 
#define BIT_ADDR(addr, bitnum)   MEM_ADDR(BITBAND(addr, bitnum)) 
//IO口地址映射
#define GPIOA_ODR_Addr    (GPIOA_BASE+20) //0x40020014
#define GPIOB_ODR_Addr    (GPIOB_BASE+20) //0x40020414 
#define GPIOC_ODR_Addr    (GPIOC_BASE+20) //0x40020814 
#define GPIOD_ODR_Addr    (GPIOD_BASE+20) //0x40020C14 
#define GPIOE_ODR_Addr    (GPIOE_BASE+20) //0x40021014 
#define GPIOF_ODR_Addr    (GPIOF_BASE+20) //0x40021414    
#define GPIOG_ODR_Addr    (GPIOG_BASE+20) //0x40021814   
#define GPIOH_ODR_Addr    (GPIOH_BASE+20) //0x40021C14    
#define GPIOI_ODR_Addr    (GPIOI_BASE+20) //0x40022014     

#define GPIOA_IDR_Addr    (GPIOA_BASE+16) //0x40020010 
#define GPIOB_IDR_Addr    (GPIOB_BASE+16) //0x40020410 
#define GPIOC_IDR_Addr    (GPIOC_BASE+16) //0x40020810 
#define GPIOD_IDR_Addr    (GPIOD_BASE+16) //0x40020C10 
#define GPIOE_IDR_Addr    (GPIOE_BASE+16) //0x40021010 
#define GPIOF_IDR_Addr    (GPIOF_BASE+16) //0x40021410 
#define GPIOG_IDR_Addr    (GPIOG_BASE+16) //0x40021810 
#define GPIOH_IDR_Addr    (GPIOH_BASE+16) //0x40021C10 
#define GPIOI_IDR_Addr    (GPIOI_BASE+16) //0x40022010 
 
//IO口操作,只对单一的IO口!
//确保n的值小于16!
#define PAout(n)   BIT_ADDR(GPIOA_ODR_Addr,n)  //输出 
#define PAin(n)    BIT_ADDR(GPIOA_IDR_Addr,n)  //输入 

#define PBout(n)   BIT_ADDR(GPIOB_ODR_Addr,n)  //输出 
#define PBin(n)    BIT_ADDR(GPIOB_IDR_Addr,n)  //输入 

#define PCout(n)   BIT_ADDR(GPIOC_ODR_Addr,n)  //输出 
#define PCin(n)    BIT_ADDR(GPIOC_IDR_Addr,n)  //输入 

#define PDout(n)   BIT_ADDR(GPIOD_ODR_Addr,n)  //输出 
#define PDin(n)    BIT_ADDR(GPIOD_IDR_Addr,n)  //输入 

#define PEout(n)   BIT_ADDR(GPIOE_ODR_Addr,n)  //输出 
#define PEin(n)    BIT_ADDR(GPIOE_IDR_Addr,n)  //输入

#define PFout(n)   BIT_ADDR(GPIOF_ODR_Addr,n)  //输出 
#define PFin(n)    BIT_ADDR(GPIOF_IDR_Addr,n)  //输入

#define PGout(n)   BIT_ADDR(GPIOG_ODR_Addr,n)  //输出 
#define PGin(n)    BIT_ADDR(GPIOG_IDR_Addr,n)  //输入

#define PHout(n)   BIT_ADDR(GPIOH_ODR_Addr,n)  //输出 
#define PHin(n)    BIT_ADDR(GPIOH_IDR_Addr,n)  //输入

#define PIout(n)   BIT_ADDR(GPIOI_ODR_Addr,n)  //输出 
#define PIin(n)    BIT_ADDR(GPIOI_IDR_Addr,n)  //输入

#endif

在Main函数中,只需要调用以下三个函数,就可以实现AD9954的初始化和正弦波频率及幅值的修改:文章来源地址https://www.toymoban.com/news/detail-469943.html

    PhyAD9954_Init();                 //DDS初始化
    AD9954_SETFRE(100000);           //设置DDS频率 这里设置为100kHz
    Write_ASF(0X3FFF);        //设置DDS幅值 0X0000~0X3FFF对应峰峰值0mv~500mv(左右)

到了这里,关于基于AD9954实现正弦交流信号输出——附原理图、代码的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【正点原子STM32】DAC数模转换器(DAC特性、DAC工作原理、DAC输出实验配置步骤、DAC输出三角波实验、DAC输出正弦波实验配置步骤、PWM + RC滤波器、PWM DAC技术实现原理)

    一、DAC简介 1.1、什么是DAC? 1.2、DAC的特性参数 1.3、STM32各系列DAC的主要特性 二、DAC工作原理 2.1、DAC框图简介(F1/ F4 /F7/H7) 2.2、参考电压/模拟部分电压 2.3、DAC数据格式 2.4、触发源 2.5、DMA请求 2.6、DAC输出电压 三、DAC输出实验 3.1、实验简要 3.2、DAC寄存器介绍 3.3、DAC输出实

    2024年04月16日
    浏览(47)
  • 用FPGA驱动AD9910输出跳频信号

    虽然AD9910芯片老掉牙了,但是还有人在使用。前段时间一直比较忙,又赶上换工作,没时间写博文。最近才慢慢的闲下来,所以又开始分享一下自己工作中的调试经验。 AD9910是一种直接数字合成器(DDS),具有集成的14位DAC,支持高达1 Gsps的采样率。AD9910采用了先进的专有DDS技

    2024年02月02日
    浏览(40)
  • 基于FPGA的信号发生器(三角波、方波、正弦波)

    目录 DDS实现原理 DDS整体设计框图​ Quartus II 仿真​ modelsim仿真 顶层代码 DDS(Direct Digital  Frequency Synthesizer) 直接数字频率合成器 ,也可叫DDFS。  DDS是从相位的概念直接合成所需波形的 一种频率合成技术 。  不仅可以产生不同频率的正弦波,而且可以控制波形的初始相位。  主

    2024年02月04日
    浏览(56)
  • 信号发生器:Intel FPGA DDS(NCO)+双路DAC(AD9767)输出正余弦信号

    Quartus18.1 小梅哥AC620开发板+ACM9767模块 示波器 ACM9767模块使用的是ADI公司的AD9767芯片,14位CMOS 双通道DAC,125Msps转换率。 输出形式为差分电流输出,输出电流满量程范围为可设置为 2~20mA。 AD9767的两路DA输出都为补码形式的电流输出IoutA和IoutB。当AD9767数字输入为满量程时(DAC的

    2024年03月24日
    浏览(59)
  • STM32产生PWM实现正弦输出

    本文使用 STM32-G070RB的定时器TIM1产生PWM波,并外接一阶低通滤波器,实现DAC效果,最终在示波器上显示正弦输出。主要分为两步:实现 PWM 输出,实现DAC功能。 实验用具 STM32-G070RB STM32CubeMX STM32CubeIDE PWM输出正弦波原理 1 个 PWM 波形假设为 500Hz(目标定时器频率) ,等效正弦波

    2024年02月06日
    浏览(41)
  • 可变频率正弦信号发生器的FPGA实现(Quartus)

    实现平台:Quartus17.1、MATLAB2021a和Modelsim SE-64 10.4 1. 产生一个完整周期的正弦波信号,并保存为*.mif文件; 2. 设计一个ROM,将正弦波信号文件初始化如该ROM中; 3. 设计一正弦波信号发生器,按照读取步长,产生频率可变的正弦波信号; 4.编写测试文件,通过modelsim查看波形。 (

    2024年01月16日
    浏览(49)
  • STM32HAL ADC+TIM+DMA采集交流信号 基于cubemx

    本文主要讲解定时器触发ADC去采集交流信号,DMA把数据搬移到内存。 所需工具: 开发板:STM32F103C8T6 STM32CubeMX IDE: Keil-MDK 相关文章: STM32HAL ADC+TIM+DMA采集交流信号 基于cubemx(二) STM32cubemx ADC+TIM+DMA超频采样 ADC+TIM+DMA采集交流信号是电赛中使用范围最为广泛的一个技术。这个模

    2024年02月03日
    浏览(49)
  • 基于AD9833的信号发生器

    本文利用FPGA控制AD9833,实现信号发生器的功能。本文将对AD9833的手册进行详细的解读,并对其配置方法进行解析,最后在Verilog中进行编码,将代码烧录置FPGA中,FPGA通过外部引脚控制AD9833输出所需要的正弦波、方波和三角波。三种波形能够输出的频率范围为0~12.5Mhz。 AD9833是

    2024年02月03日
    浏览(45)
  • STM32F103R8T6 SPWM实现正弦波输出

    PWM合成正弦波,原理什么的不详细说了,概括一下就是 PWM有效面积的积分 = 正弦波的有效面积。PWM的频率越快,细分的越多,锯齿也就越不明显。 做法是:首先利用正弦波取点软件,取点1000个,生成一个正弦波的数组。 PWM波的频率(F_PWM)与正弦波频率(F_SIN)之间的对应关系与

    2024年02月03日
    浏览(56)
  • 基于ESP32与AD9850的信号发生器

    1 .基本理论知识概述 1.1 研究背景及意义 为了给后端电路提供一个理想信号,一般用信号发生器所产生的的信号来替代前端电路的实际信号。为了可以方便的在各种不同条件下所需的不同特性信号,就需要一个特征参数可以被认为设定的信号源。这样的信号源对于产品的研

    2024年02月04日
    浏览(41)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包