Post Go back to editing

AD7682读写数据不对

通过STM32F407的硬件SPI驱动AD7682,根据AD7682中文手册,上面写的是支持伪双极性输入,硬件上,VREF接的是外置ADR4525提供的2.5V,让COM接的是基准2.5V分压后的1.25V,IN0-IN3输入的电压范围是: -1.25 ~ 1.25。SPI配置CPOL = CPHA = 0,波特率预分频值为256,对AD7682读写设置如下,想请教大家这种接法是不是有误?现在程序采样到的AD值根据不对应,而且随意跳动。。。

u16 AD7682_ReadWriteByte(u16 ch)
{
u16 reg=0;
u16 DataL = 0;
u16 DataH = 0;
u16 AD7689_Data = 0;

reg = (1<<13)|(2<<10)|(ch<<7)|(1<<6)|(7<<3)|(1<<0)|(0<<1) ;
reg <<=2; //寄存器只用到了14位,所以要先移出高两位

SPI2_CS = 0;

DataH = SPI_ReadWriteByte(SPI2,(u8)((reg)>>8));
DataL = SPI_ReadWriteByte(SPI2,(u8)reg);

SPI2_CS = 1;

DataH = DataH << 8;
AD7689_Data = DataH | DataL;

return (AD7689_Data);

}

  • 1. 按照你的配置,IN0-IN3输入的电压范围对ADC的地电平范围应该是: 0 ~ 2.5v.

    2. 配置寄存器写操作后,要有一次空转换,即第二次转换后的码值才是有效的。

  • 现在程序通过硬件SPI驱动采不到AD值,想请教程序是不是有误?硬件SPI驱动如下:

    void SPI1_Init(void)//spi初始化

    {      

           GPIO_InitTypeDef  GPIO_InitStructure;

           SPI_InitTypeDef  SPI_InitStructure;

            RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);//使能GPIOB时钟

            RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI3, ENABLE);//使能SPI1时钟  

          //GPIOFB3,4,5初始化设置

          GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5;//PB3~5复用功能输出

          GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用功能

          GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出

          GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz

          GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉

          GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化

          GPIO_PinAFConfig(GPIOB,GPIO_PinSource3,GPIO_AF_SPI3); //PB3复用为 SPI1

          GPIO_PinAFConfig(GPIOB,GPIO_PinSource4,GPIO_AF_SPI3); //PB4复用为 SPI1

          GPIO_PinAFConfig(GPIOB,GPIO_PinSource5,GPIO_AF_SPI3); //PB5复用为 SPI1

          //这里只针对SPI口初始化

          RCC_APB1PeriphResetCmd(RCC_APB1Periph_SPI3,ENABLE);//复位SPI1

          RCC_APB1PeriphResetCmd(RCC_APB1Periph_SPI3,DISABLE);//停止复位SPI1

          SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;  //设置SPI单向或者双向的数据模式:SPI设置为双线双向全双工

          SPI_InitStructure.SPI_Mode = SPI_Mode_Master;         //设置SPI工作模式:设置为主SPI

          SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;            //设置SPI的数据大小:SPI发送接收8位帧结构

          SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;            //串行同步时钟的空闲状态为高电平

          SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;  //串行同步时钟的第二个跳变沿(上升或下降)数据被采样

          SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;         //NSS信号由硬件(NSS管脚)还是软件(使用SSI位)管理:内部NSS信号有SSI位控制

          SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;        //定义波特率预分频的值:波特率预分频值为256

          SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; //指定数据传输从MSB位还是LSB位开始:数据传输从MSB位开始

          SPI_InitStructure.SPI_CRCPolynomial = 7;      //CRC值计算的多项式

          SPI_Init(SPI3, &SPI_InitStructure);  //根据SPI_InitStruct中指定的参数初始化外设SPIx寄存器

          SPI_Cmd(SPI3, ENABLE); //使能SPI外设

    }

    void AD7682_init(void)

    {

        GPIO_InitTypeDef  GPIO_InitStructure;

        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB | RCC_AHB1Periph_GPIOA, ENABLE);//使能GPIOB时钟

        //GPIOB6 片选脚初始化

        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;//PA4

        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_UP;//上拉

        GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化  

        SPI1_Init();           //初始化SPI

        /************************/

        AD7682_spi3(0);

        AD7682_spi3(1);

    }

    u16 AD7682_spi3(u16 ch)//读写AD7682芯片
    {
      u16 reg=0;
      u16 DataL = 0;
      u16 DataH = 0;
      u16 AD7689_Data = 0;

      reg = (1<<13)|(2<<10)|(ch<<7)|(1<<6)|(7<<3)|(1<<0)|(0<<1) ;
      reg <<=2; //寄存器只用到了14位,所以要先移出高两位

      SPI3_CS = 0;

      DataH = SPI_ReadWriteByte(SPI3,(u8)((reg)>>8));
      DataL = SPI_ReadWriteByte(SPI3,(u8)reg);

      SPI3_CS = 1;

      DataH = DataH << 8;
      AD7689_Data = DataH | DataL;

      return (AD7689_Data);

    }

    int main(void)

    {

           u16 SPI_3[4]={0};

        AD7682_init();  //初始化AD7682

            while(1)

            {

                   //AD7682四个通道进行采集数据

                    SPI_3[0] = AD7682_spi3(2);     

             SPI_3[1] = AD7682_spi3(3); 

             SPI_3[2] = AD7682_spi3(0);

                    SPI_3[3] = AD7682_spi3(1);

             }

    }

     

    通过模拟SPI方式驱动程序如下:能采到ADC,但是得到数据波动很大

    void AD7682_init(void)

    {

        GPIO_InitTypeDef  GPIO_InitStructure;

        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB | RCC_AHB1Periph_GPIOA|RCC_AHB1Periph_GPIOG, ENABLE);//使能GPIOB时钟

     

        /////////////////////////////////SPI3初始化/////////////////////////////////////  

     

        //CS片选脚

        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;//PA4

        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_UP;//上拉

        GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化

     

        //MOSISCK

        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3|GPIO_Pin_5;//PB3~5复用功能输出 

        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_UP;//上拉

        GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化

     

        //MISO  

        GPIO_InitStructure.GPIO_Pin =GPIO_Pin_4;//PB3~5复用功能输出

        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;//复用功能

        GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出

        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz

        GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉

        GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化

        /************************/

        SPI3_CS = 1;

        SPI3_MOSI = 1;

        SPI3_SCK = 1;    

        AD7682_spi3(0);

        AD7682_spi3(0);

     

    }

     

    /******************************************************************************

    ** 函数名称:int AD7682_spi(u8 ch)

    **    能: reg寄存器内容,data转换数据

    ** 修改日志:

    *******************************************************************************/

    u16 AD7682_spi3(u16 ch)

    {

        u16 reg=0,i=0;

        u16 DataL = 0;

        u16 DataH = 0;

        u16 AD7689_Data = 0;

     

        reg = (1<<13)|(2<<10)|(ch<<7)|(1<<6)|(6<<3)|(1<<0) | (0<<1) ;

        reg <<=2; //寄存器只用到了14位,所以要先移出高两位  

            SPI3_CS = 0;

        SPI3_SCK = 0;    

        delay_us(1);

        for(i=0;i<16;i++)

        {

             if(reg&0x8000)SPI3_MOSI = 1;

             else SPI3_MOSI = 0;

             delay_us(1);

              reg<<=1;

             SPI3_SCK = 1;

             delay_us(2);

             AD7689_Data<<=1;

             if(SPI3_DOUT_READ) AD7689_Data |=1;

             SPI3_SCK = 0;

             delay_us(2);

            

        }

        SPI3_CS = 1;

        delay_us(2);

     

        return (AD7689_Data);

    }

    综上所述,请教下我的硬件SPI驱动为何不成功,而模拟spi方式能采到数据确波动很大,是否该芯片不支持硬件SPI驱动?谢谢了。

    得到时序图如下,该时序是通过模拟SPI方式采到:

    硬件电路设计如下:

    请教下我的硬件SPI驱动和模拟SPI驱动这两种方式哪里有问题?

  • 1. SPI时序没发现问题。

    2. 原理图从2.5V VREF用1kohm电阻分压产生1.25V电压后,应该再加一级运放驱动一下给到COM。否则,这个1.25V驱动能力太弱,引起误差。

    3. 原理图中VIO短接到VCC, 这个是5V还是3.3V供电?VIO是控制SPI控制线的逻辑电平,应该和控制器I/O电平保持一致。