1. 程式人生 > >STM32-24位AD7799驅動之手冊程式碼詳解,支援模擬SPI和硬體SPI

STM32-24位AD7799驅動之手冊程式碼詳解,支援模擬SPI和硬體SPI

1.AD7799介紹

AD7799結構圖如下所示:

 

其中REFIN參考電壓建議為2.5V, REFIN電壓低於0.1V時,則差分輸入ad值就無法檢測了,如下圖所示:

 

注意:

如果REG_CONFIG的REF_DET開啟的話,那麼輸入AD值電壓低於0.5V時,則差分輸入ad值就無法檢測了,如下圖所示:

 

 

2.AD7799差分訊號的輸入模式

如下圖所示,差分輸入電壓有3種模式:

 

注意:

單端輸入電壓(AIN-接地,只有正電壓)則支援任意範圍,比如In-Amp模式下,單端輸入如果為10mv的話,也能檢測到.

 

2.1 Unbuffered Mode非緩衝模式

該模式可測的AD值可以在 -30mV ~ (AVDD+30mv)範圍之間,如果開了雙極型模式(雙極型模式通過將REG_CONFIG的U/B位設0實現),則也可以測-(AVDD+30mv)~30mV之間AD值.

也就是說假如我們要測的AD值位於-100mV~100mV之間,則用這個模式.

該模式優缺點:可測範圍最大,但是精度誤差不是很高

2.2 Buffered Mode緩衝模式

緩衝的作用就是減少測的AD誤差,並且功耗相應地會增高點,該模式主要是測100mV~( AVDD-100mV)之間.

該模式優缺點:可測範圍比Unbuffered小一點,並且精度誤差高一點

2.3 In-Amp 高增益模式

需要將REG_CONFIG的Gain調到4及以上才是該模式,否則的話,就會根據REG_CONFIG的BUF位來自動判斷是Buffered Mode還是Unbuffered Mode.

並且AD值必須位於300mv~(AVDD+1100mv)之間,否則的話該模式是無法檢測AD值的,之前筆者就是測差分輸入的正負20mV,卻一直沒有反應,後來才發現是處於這個模式的原因.

該模式優缺點:可測範圍可以通過設定Gain來設定測試範圍,比如VREF為3V,Gain=4,則可測量程為正負600mv.

 

注意:

當使用Buffered Mode或者In-Amp模式時,需要將REG_CONFIG的BO位開啟,介紹如下圖所示:

 

 

3.程式碼效果

串列埠截圖如下:

 

通過電壓發生器不停修改AD值時,可以看到萬用表和串列埠列印的資料相差不大:

 

PS:由於GIF錄製的畫素位數太低,所以不清晰

 

 

4.程式碼實現

支援硬體SPI1或者GPIO模擬方式

程式碼通過巨集AD7799_INTERFACE_MODE判斷,能夠支援硬體SPI1或者GPIO模擬方式,如下圖所示:

 

通過巨集定義VREF參考電壓,以及GAIN增益值

如下圖所示,只需修改下面巨集,就可以實現轉換電壓資料自動轉換:

 

實現通道1和通道2來回切換

串列埠傳送select 1,表示選擇通道1:

 

傳送select 2,則表示選擇通道2.

 

4.1初始化過程

     /*ad7799初始化*/

         AD7799_gpio_init();
         while(!AD7799_Init())
         {
                          LED0 = !LED0;
                          delay_ms(50);
         }      
         LED0 = 1;
         AD7799_Calibrate();                           //通道校準

         AD7799_SetGain(AD7799_CHIP_GAIN);               
         AD7799_SetBurnoutCurren(0);                  //關閉BO
         AD7799_SetBufMode(0);                        //由於我們要測的電壓低於100mV,所以設定為Unbuffered Mode
         AD7799_SetChannel(ChannelBuf[0]);            //通道設定.
         AD7799_SetMode(AD7799_MODE_CONT,5);          //預設雙極性   頻率為5
         AD7799_SetReference(0);                      //關閉參考檢測,因為我們的 AD7799_RefmV 參考電壓低於0.5V

4.2 上面的函式如下所示:

void AD7799_gpio_init(void)
{
         GPIO_InitTypeDef GPIO_InitStructure;
         GPIO_InitStructure.GPIO_Pin = AD_CS_PIN;
         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;      
         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
         GPIO_Init(AD_CS_GPIO, &GPIO_InitStructure);                              //CS片選

#if ( AD7799_INTERFACE_MODE == AD7799_INTERFACE_SPI1 )
         //spi1 mode
         SPI1_Init();
         SPI1_SetSpeed(SPI_BaudRatePrescaler_2);
#else
         //gpio模擬spi mode
         GPIO_InitStructure.GPIO_Pin = AD_DI_PIN;
         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;      
         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
         GPIO_Init(AD_DI_GPIO, &GPIO_InitStructure);

         GPIO_InitStructure.GPIO_Pin = AD_SCK_PIN;
         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;      
         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
         GPIO_Init(AD_SCK_GPIO, &GPIO_InitStructure);

         GPIO_InitStructure.GPIO_Pin = AD_DO_PIN;
         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;      
         GPIO_Init(AD_DO_GPIO, &GPIO_InitStructure);
         spi_AD7799_init();
#endif  
         AD7799_Reset();
}
void AD7799_SetGain(unsigned long gain)
{
    unsigned long command;
    command = AD7799_GetRegisterValue(AD7799_REG_CONF,2);
    command &= ~AD7799_CONF_GAIN(0xFF);
    command |= AD7799_CONF_GAIN(gain);
    AD7799_SetRegisterValue(
            AD7799_REG_CONF,
            command,
            2
    );
}

void AD7799_SetBurnoutCurren(u8 enable)//設定BO
{
    unsigned long command;
    command = AD7799_GetRegisterValue(AD7799_REG_CONF,2);
    command &= ~0X2000;
    if(enable)
       command |= 0X2000;
    AD7799_SetRegisterValue(
            AD7799_REG_CONF,
            command,
            2
    );
 
}

void AD7799_SetBufMode(u8 enable)           //設定buf      
{
    unsigned long command;
    command = AD7799_GetRegisterValue(AD7799_REG_CONF,2);
    command &= ~0X10;
    if(enable)
       command |= 0X10;
    AD7799_SetRegisterValue(
            AD7799_REG_CONF,
            command,
            2
    );
}

void AD7799_SetChannel(unsigned long channel)
{
    unsigned long command;
    command = AD7799_GetRegisterValue(AD7799_REG_CONF,2);
    command &= ~AD7799_CONF_CHAN(0xFF);
    command |= AD7799_CONF_CHAN(channel);
    AD7799_SetRegisterValue(
            AD7799_REG_CONF,
            command,
            2
    );
}

void AD7799_SetMode(unsigned long mode,u8  rate)
{
    unsigned long command;
    command = AD7799_GetRegisterValue(AD7799_REG_MODE,2);
    command &= ~AD7799_MODE_SEL(0xFF);
    command |= AD7799_MODE_SEL(mode);
    command &= 0XFFF0;
    command |= rate;                   //設定頻率

    AD7799_SetRegisterValue(
            AD7799_REG_MODE,
            command,
            2
    );
}
void AD7799_SetReference(unsigned char state)
{
    unsigned long command = 0;
    command = AD7799_GetRegisterValue(AD7799_REG_CONF,2);
    command &= ~AD7799_CONF_REFDET(1);
    command |= AD7799_CONF_REFDET(state);
    AD7799_SetRegisterValue(AD7799_REG_CONF,  command, 2);

}

void AD7799_SetRegisterValue(unsigned char regAddress,
                             unsigned long regValue,
                             unsigned char size)
{
    unsigned char data[5] = {0x03, 0x00, 0x00, 0x00, 0x00};   
    data[0] = AD7799_COMM_WRITE |  AD7799_COMM_ADDR(regAddress);
    if(size == 1)
    {
        data[1] = (unsigned char)regValue;
    }
    if(size == 2)
    {
        data[2] = (unsigned char)((regValue & 0x0000FF) >> 0);
        data[1] = (unsigned char)((regValue & 0x00FF00) >> 8);
    }
    if(size == 3)
    {
        data[3] = (unsigned char)((regValue & 0x0000FF) >> 0);
        data[2] = (unsigned char)((regValue & 0x00FF00) >> 8);
        data[1] = (unsigned char)((regValue & 0xFF0000) >> 16);
    }
         AD7799_CS_LOW;     
         SPI_Write(data,(1 + size));
         AD7799_CS_HIGH;
}

unsigned long AD7799_GetRegisterValue(unsigned char regAddress, unsigned char size)
{
         unsigned char data[5] = {0x00, 0x00, 0x00, 0x00, 0x00};
         unsigned long receivedData = 0x00;    
         data[0] = AD7799_COMM_READ |  AD7799_COMM_ADDR(regAddress);
         AD7799_CS_LOW; 
         SPI_Write(data,1);
         SPI_Read(data,size);
         AD7799_CS_HIGH;
         if(size == 1)
         {
                  receivedData += (data[0] << 0);
         }
         if(size == 2)
         {
                  receivedData += (data[0] << 8);
                  receivedData += (data[1] << 0);
         }
         if(size == 3)
         {
                  receivedData += (data[0] << 16);
                  receivedData += (data[1] << 8);
                  receivedData += (data[2] << 0);
         }
    return receivedData;
}

4.3 獲取通道電壓程式碼如下所示:

      while(1)
         {
                  if(Serial_Post_ChannelValue!=0XFF)              //0:不選擇   1~2:更改通道
                  {
                          CurrentChannelValue = Serial_Post_ChannelValue;
                          Serial_Post_ChannelValue =0XFF;

                          if(CurrentChannelValue && CurrentChannelValue<=2)        //1~2
                          {
                                   AD7799_SetChannel(ChannelBuf[CurrentChannelValue-1]);//通道設定.          0~1
                                   delay_ms(10);
                                   AD7799_GetRegisterValue(AD7799_REG_DATA,3);//清空之前的AD
                          }
                          else if(CurrentChannelValue == 0)
                          {
                                   printf("%s value0 0 0 \r\n",Board_Name);
                          }
                  }

                 
                  if(CurrentChannelValue)                  //選擇了通道?
                  {
                          for(i=0;i<2;i++)                 //獲取每個通道資料
                          if(CurrentChannelValue == (i+1))
                          {
                                   while( !AD7799_Ready())                //1~2
                                   {
                                            delay_ms(5);
                                   }
                                   ADValues[i]=  analyzeAD7799_Data(AD7799_GetRegisterValue(AD7799_REG_DATA,3));
                          }
                          else
                                   ADValues[i] = 0.0000;    

                          printf("%s 當前通道為:%d %.3fmV %.3fmV \r\n",Board_Name,CurrentChannelValue,ADValues[0],ADValues[1]);
                  }      
                  LED0 =!LED0;
                  delay_ms(100);
         }

 

 

如果您有收穫,不妨點個讚唄~

&n