ADS1248驅動及相關總結

七七八八的,畢業設計弄的差不多了。以前遺留的問題也解決的差不多了(雖然有些粗糙)。現在,有點時間來總結畢業設計中的一些內容。
先說點感悟:對於畢業設計做的自動頂空系統來說,我感覺最惱人的要數這個ADS1248的驅動了。對於這個驅動,我他媽差不多整整弄了兩個多月(請原諒我爆句粗口)。(當然,按照導師的說法,我是跨了兩年)。在那差不多兩個月裏,我有很多次找到了以前做OJ題,調試8次改不出來的感覺(氣的牙根癢癢,媽的就是出不來)。當然,也有不少次因爲找到一點點眉目,就高興的能飛的感覺。 最後導師可能怕弄出來個精神病出來,最後給的源碼參考。

好了,言歸正傳。對於ADS1248來說,驅動其工作基本和利用通信協議驅動EEPROM、FLASH差不多,都是發送命令,然後接受模塊的返回信息。只不過對於EEPROM和FLASH’等存儲模塊來說,ADS1248要相對複雜些。總結來說,可以分爲以下步驟:

  1. 芯片復位。將ADS1248的nRESET引腳置低即可進行芯片復位。這裏要注意一點的是芯片在復位之後0.6ms內不能進行SPI通信。如下圖所示。
    芯片復位

  2. 芯片內部初始化設置。在這裏主要是向芯片內的寄存器寫入相關的值,來對芯片進行相應的設置。一般的設置包括:
    (1)、寫入MUX0寄存器,設置正極和負極的輸入端口。如下圖所示。
    MUX0寄存器
    (2)、寫入MUX1寄存器,設置內部晶振時鐘源,是否啓動內部參考電壓,選擇參考電平。如下圖所示。
    MUX1
    (3)、寫入SYS0寄存器,設置ADS的輸出速率和增益。如下圖所示。
    SYS0
    (4)、寫入IDAC0寄存器,設置DOUT/DRDY引腳是否採用複用形式,以及恆流源的電流大小。如下圖所示。
    IDAC0
    (5)、寫入IDAC1寄存器,設置恆流源的輸出引腳(差分輸入和單端輸入就是通過這個寄存器進行設置的)。如下圖所示。
    IIDAC1

3. 芯片校準。包括自偏移校準->偏移校準->增益校準 本質上也就是向MUX1寄存器寫入相關的值。然後等待校準完成。

4 . 開始轉換,並讀取轉換後的值。這裏需要注意兩點。
(1)、轉換是否完成,需要通過nDRDY引腳是否置低(或者是否產生一個脈衝,這個要根據具體的設置)來判斷。即在讀取數據之前要判斷nDRDY引腳是否爲低。
(2)、ADS1248是24位進度的模數轉換器。所以讀出的數據是24位數據,我們如果用int(4個字節)類型來存儲的話,需要進行數據的拼接(接收到的數據是一般是3個單字節的),而且需要符號(正負號)轉換。具體的解釋,見下文。

ADS1248驅動源碼如下:

//寫命令
static void ADS1248_WriteCmd(uint8_t Cmd)  
{   

   AD_nCS_LOW;      //拉低片選線,使能SPI通信

        HAL_SPI_Transmit(&hspi1, &Cmd, 1,HAL_MAX_DELAY);

        AD_nCS_HIGH;        //通信結束,拉高片選

} 



////讀寄存器
void ADS1248_ReadReg(uint8_t RegAddr,uint8_t *Buffer,uint8_t Length)  
{  
    uint8_t Cmd[2];  

    AD_nCS_LOW;

        AD_START_HIGH;      //在寫寄存器時嗎,需要將START拉高(不讓其進入睡眠模式)


    Cmd[0]=ADC_CMD_RREG|RegAddr;  
    Cmd[1]=Length-1;  

        HAL_SPI_Transmit(&hspi1,Cmd,2,HAL_MAX_DELAY);       //發送命令


        HAL_SPI_Receive(&hspi1, Buffer, Length, HAL_MAX_DELAY);     //接收寄存器數據

        Cmd[0]=ADC_CMD_NOP;  
    HAL_SPI_Transmit(&hspi1, Cmd,1,HAL_MAX_DELAY);  //最後在發送一個NOP,強制拉高DOUT


        AD_nCS_HIGH;

}


//寫寄存器
static  void ADS1248_WriteReg(uint8_t RegAddr,uint8_t *Buffer,uint8_t Length)  
{  
    uint8_t Cmd[2];  

    AD_nCS_LOW;

        AD_START_HIGH;      //在寫寄存器時嗎,需要將START拉高(不讓其進入睡眠模式)

     HAL_Delay(20);         //硬件延遲

    Cmd[0]=ADC_CMD_WREG|RegAddr;  
    Cmd[1]=Length-1; 

      HAL_SPI_Transmit(&hspi1, Cmd, 2,HAL_MAX_DELAY);   //指定向指定寄存器寫入指定字節數據
      HAL_SPI_Transmit(&hspi1, Buffer, Length,HAL_MAX_DELAY);   //發送數據字節

         HAL_Delay(20);         //硬件延遲

    AD_nCS_HIGH; 
        AD_START_LOW;       

}




//判斷忙狀態
 uint8_t ADS1248_WaitBusy(uint32_t Timeout)  
{  
    uint32_t i = 0; 
        AD_nCS_LOW;
        while(nAD_DRDY_STATE > 0)
            {
                HAL_Delay(1);
                    i++; 
                if(i>Timeout)
                    return 1;   

            }

        AD_nCS_HIGH;

        return 0;

} 


//ADS1248系統校準  校準順序爲:自偏移校準->偏移校準->增益校準 .
static uint8_t ADS1248_Calibrate(uint8_t Gain)  
{  
        uint8_t R=0;
    uint8_t Cmd;  
    ADS1248_WriteReg(ADC_REG_SYS0,&Gain,1);      // 設置增益值、ADC輸出數據率

        Cmd=0x20;   //0010 0000 
        ADS1248_WriteReg(ADC_REG_MUX1,&Cmd,1);       // 設置系統監測爲自偏移測量 
        ADS1248_WriteCmd(ADC_CMD_SELFOCAL);          // 自偏移校準  
        R |= ADS1248_WaitBusy(500);                              // 等待校準完成 


        Cmd=0x21;  //0010 0001
        ADS1248_WriteReg(ADC_REG_MUX1,&Cmd,1);       // 設置系統監測爲偏移測量  
        ADS1248_WriteCmd(ADC_CMD_SYSOCAL);           // 系統偏移校準  
        R |= ADS1248_WaitBusy(500);                           // 等待校準完成 


        Cmd=0x22;  
        ADS1248_WriteReg(ADC_REG_MUX1,&Cmd,1);       // 設置系統監測爲增益測量  
        ADS1248_WriteCmd(ADC_CMD_SYSGCAL);           // 系統增益校準  
        R |= ADS1248_WaitBusy(500);                              // 等待校準完成  

        return R;
}


//復位ADS1248
 void ADS1248_Reset()
{

      AD_nCS_HIGH;
      AD_START_HIGH;        //START要保持高電平,爲了接下來寫入寄存器

        nADRST_LOW;             //置低nADRST,復位ADS1248
        HAL_Delay(20);
        nADRST_HIGH;
        HAL_Delay(20);

}




//ADS1248初始化
void ADS1248_Init(void)  
{  
        uint8_t Cmd;
        uint8_t Gain;

        ADS1248_Reset();                                                                     //系統復位

        HAL_Delay(100); 

        Gain = ADC_GAIN_16|ADC_SPS_20;


        //初始化MUX0多路複用控制寄存器
        Cmd = 0x17      ;                                       //00 010 111,Bit7-6:傳感器電流源檢測不使用,Bit5-3:正輸入爲AIN2,Bit2-0:負輸入爲AIN7     
        ADS1248_WriteReg(ADC_REG_MUX0,&Cmd,1); 

        Cmd=0x20 ;//0 01 00 000
        ADS1248_WriteReg(ADC_REG_MUX1,&Cmd,1);              // 將MUX1置,(內部晶振時鐘源,啓動內部參考電壓,選擇REF0作爲參考電平,普通操作)                                                                                                              
                                                                  // 校準時MUX1將被重新賦值,因此這裏可以不用對其進行賦值,校準之後再配置內部參考電壓
        ADS1248_WriteReg(ADC_REG_SYS0,&Gain,1);                              // 設置增益值、ADC輸出數據率      

        Cmd=0x07 ;//0000 0111                                                                       // 設置極大恆流源電流值1500uA(1.5mA)
        ADS1248_WriteReg(ADC_REG_IDAC0,&Cmd,1);                 

        Cmd=0x17 ;//0010 0111                                                                   // 選擇第一個恆流源輸出引腳 (AIN2) 選擇第二個電流源輸出引腳(AIN7)
        ADS1248_WriteReg(ADC_REG_IDAC1,&Cmd,1);                     

        Cmd=ADS1248_Calibrate(Gain);                        // 通道校準.配置轉換參數  

        //重新配置MUX1
        Cmd=0x20;  //0011 0000
        ADS1248_WriteReg(ADC_REG_MUX1,&Cmd,1);                          // 啓用內部參考電壓總是開啓

        AD_START_LOW;

} 



//啓動轉換
void ADS1248_Start(uint8_t CovMode)  
{  
    AD_START_HIGH ;                          //啓動ADC轉換
    if(CovMode==ADC_MODE_SINGLECOV)
            AD_START_LOW;                                     //產生啓動脈衝  
}     

//停止轉換
void ADS1248_Stop()  
{  
    AD_START_LOW;                            //停止轉換
}  


//讀取ADS1248中的轉換數據
int32_t ADS1248_Read()
{
        uint8_t  Cmd[5]={ADC_CMD_RDATA,ADC_CMD_NOP,ADC_CMD_NOP,ADC_CMD_NOP,ADC_CMD_NOP};  //最後一個字節是爲了強制拉高nDRDY
    uint8_t  Buf[5];
    int32_t  Data = 0;  

    AD_nCS_LOW;
        HAL_SPI_TransmitReceive(&hspi1,Cmd,Buf,5,HAL_MAX_DELAY);        //1個命令,3個空操作接收數據,最後一個拉高nDRDY
    AD_nCS_HIGH;


    Data=Buf[1];
        Data=Data*256+Buf[2];
        Data=Data*256+Buf[3];

        Data = Data*256;                //先乘再除是爲了保留正負號
        return (Data/256); 



}

頭文件既全部源碼見:這兒

相關疑問及解答:
1. 該如何選擇ADS124中的SPI的時鐘極性和時鐘相位。即對於從設備來說,數據在時鐘下降沿移入,在時鐘的上升沿溢出?
答:如下圖所示:

SPI通信
對於SPI協議來說,它的時鐘極性和時鐘相位的設定是爲了兼容不同從設備的要求。其基本的概念就不說了,強調說一下時鐘相位:它指的是在奇數邊沿還是偶數邊沿被採樣。注意是“採樣”。

對於信號傳輸來說,一個是採樣,一個是切換。如上圖所示,信號在奇數邊沿被採樣,那麼它就會在被在偶數邊沿切換。當信號在採樣時,其應該保持穩定狀態,當其處在切換狀態時,其可以發生狀態切換。

如果有這麼個從設備,有這樣的通信規則:它的數據在時鐘下降沿移入,在時鐘的上升沿移出。那麼對於主設備來說,其就需要設置時鐘的極性和相位:使得時鐘下降沿時爲採樣時刻,數據保持在穩定的狀態,這樣從設備就可以再時鐘的下降沿進行採樣,滿足了第一部分(它的數據在時鐘下降沿移入);對於第二部分的規則來說(數據在時鐘的上升沿移出),是處在切換的狀態,此時時鐘處在上升沿過程中,即時鐘上升沿爲切換時刻(也正好對應了時鐘下降沿爲採樣時刻)。
有兩種方式滿足情況:SPOL = 0,CPHA = 1; 或者SPOL = 1,CPHA = 0。

綜上所述,可以有簡單一點的判斷方式,即直接看從設備的的移入時刻。從設備需要下降沿移入,那麼SPI就需要設置成下降沿採樣的狀態。從設備上升沿移入,SPI就需要設置成上升沿採樣的狀態。

2.對於ADS1248來說,爲什麼SPI的時鐘分頻設置成256就可以,設置成4就不行???
答:對於SPI通信來說,兩個設備之間的通信速率受限於速率較低的那個設備。一般來說,主機的通信速率較高,外部設備的通信速率較低。在這裏就是ADS1248的通信速率較低。而對於ADS1248,其最高的通信速率大概在2MHz左右(數據手冊上Tsclk最小爲500ns);而對於STM32主機來說,其通信速率取決於Pclk/分頻率。在這裏採用的是SPI1,它是掛在APB2上的,其設置Pclk的速率爲72MHz,所以最小分頻設置爲64。設置成4的話,一定是不行的了。

2.ADS1248(24位精度)在讀取數據的時候爲什麼要先左移8位,然後在右移8位?

答:這涉及到整數存儲在內存中的問題。在內存中int型整數是32位,其是按照補碼的形式存儲的。即最高位代表符號位,0爲正,1爲負。但是ADS1248是24位精度,這就是說我們只能從ADS1248中讀取24位有效數據。而且這24位有效數據也是按照補碼的形式進行存儲的。如果我們把這24位有效數據放在32位int型的後24位,則會發現其最高位就一直是0,也就是說這樣讀出的數據將一直是正數。(數據應該也是錯誤的,因爲24位的有效數據最高位被當成了普通位)。
鑑於此,我們需要把24位有效數據的最高位移到32位int型的最高位。先左移8位(邏輯移位,低位補零),將最高位放到32位的最高位;再右移8位(算數移位,最高位保留符號位),恢復原值(除去了符號位)。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章