基於STM32的三軸數字羅盤HMC5883L模塊的測試


       最近買了個數字羅盤模塊,調通后發現很不錯,非常靈敏,測試的時候精度在1°以內。連續測量模式下,最快測量、輸出速率可達75hz,模塊每次測量完畢並將數據更新至寄存器后,其DRDY引腳便產生一個低電平脈沖(可以配置一個外部中斷捕獲DRDY引腳的下降沿,並在中斷服務程序中讀取數據),在STM32中可以設置一個下降沿觸發的外部中斷,並在中斷服務程序中調用角度數據讀取函數。以下為操作該模塊的主要步驟。

一、IIC協議相關操作(單片機作為主機控制時鍾線)

宏定義:

//這里用到了STM32的位帶區操作,方便實現對一個位的操作
//PB13配置為OD輸出,同時外部給上拉電阻,這樣既可輸出信號給從機,也能
//在PB13為漏極開路狀態時接收從機的信號(STM32的IO配置為輸出模式時,
//IO口的電平也會不斷地被捕獲到輸入寄存器中)
//PB14配置為推挽輸出,PB15配置為浮空輸入
#define R_SDA    IPB13          // PB13輸入寄存器
#define W_SDA    OPB13          // PB13輸出寄存器
#define W_SCL    OPB14          // PB14輸出寄存器
#define R_DRDY   IPB15          // PB15輸入寄存器
#define Xmsb 0     //X軸數字量的高8位
#define Xlsb 1       //X軸數字量的低8位
#define Zmsb 2     //Z軸數字量的高8位
#define Zlsb 3       //Z軸數字量的低8位
#define Ymsb 4     //Y軸數字量的高8位
#define Ylsb 5       //Y軸數字量的低8位

 附位帶宏定義:

#define GPIOB_ODR_Addr    (GPIOB_BASE+12) //0x40010C0C 
#define GPIOB_IDR_Addr    (GPIOB_BASE+8) //0x40010C08   

#define BITBAND_Addr(Addr,num)  ((volatile unsigned long *)(0x42000000+32*(Addr-0x40000000)+4*num))

#define IPB13    *BITBAND_Addr(GPIOB_IDR_Addr,13)
#define OPB13   *BITBAND_Addr(GPIOB_ODR_Addr,13)
#define OPB14   *BITBAND_Addr(GPIOB_ODR_Addr,14)
#define IPB15    *BITBAND_Addr(GPIOB_IDR_Addr,15)

 

啟動IIC傳輸:

void _iic_Start()
{
     W_SCL=1;    
     W_SDA=1;
     _delay();
     W_SDA=0;     //SCL高時,拉低SDA,表示開始IIC傳輸,占用總線
     _delay();
     W_SCL=0;     //控制SCL
     _delay();
}

 

停止IIC傳輸:

void _iic_Stop()
{
     W_SCL=1;     //釋放SCL(由於沒有其他主器件,SCL無需開漏)
     W_SDA=0;     
     _delay();
     W_SDA=1;   //SCL為高時,拉高SDA表示結束ICC傳輸,釋放總線
}

發送一個字節:

uint8_t _iic_SendByte(uint8_t dat)          
{
        uint8_t i;
     for(i=0;i<8;i++)
    {
        _delay();
        W_SDA=dat>>7;     //SCL拉高之前寫SDA
        dat=dat<<1;
        _delay();
        W_SCL=1;         //拉高SCL,從器件開始讀取SDA 
        _delay();
        W_SCL=0;         //重新拉低SCL
    }
       W_SDA=1;             //釋放SDA
       W_SCL=1;             //拉高SCL,讀取從器件應答信號
      //   等待應答 
    i=100;
    while(i&&R_SDA)  {i--;_delay();}
    if(i==0)               //無應答
    {
        W_SCL=0;         //重新拉低SCL
        return 0;
    }
    else {                 //有應答
        _delay();
        W_SCL=0;         //重新拉低SCL
        return 1;
}
}            

接收一個字節:

uint8_t _iic_ReadByte(uint8_t Ack)  
{
     uint8_t temp,i;
     W_SDA=1;              //釋放SDA
     _delay();
    for(i=0;i<8;i++)
    {
        _delay();
        W_SCL=1;          //拉高SCL開始讀取SDA          
        temp=temp<<1;      
        temp|=R_SDA;      //SCL拉高之后讀取SDA
        W_SCL=0;              //拉低SCL,從器件開始放置數據
     }
     //發送應答信號
    if(Ack)W_SDA=0;             //拉低SDA表示應答
    W_SCL=1;             //拉高SCL,從器件接收應答信號
    _delay();
    W_SCL=0;             //重新拉低SCL
    W_SDA=1;             //釋放SDA
    return temp;
}

二、配置HMC5883L模塊

 void HMC5883L_Init()
 {     
     _iic_Start();
     _iic_SendByte(0x3c); //寫操作
     _iic_SendByte(0x00); //指針指向00,配置寄存器A 
     _iic_SendByte(0x78);  //數據測量、輸出速率75hz
     _iic_Start();          //指針定位到02,模式寄存器
     _iic_SendByte(0x3c);
     _iic_SendByte(0x02);
     _iic_SendByte(0x00);  //連續測量模式
     _iic_Stop();
 }

三、讀取角度數據

接收三軸數據,處理X,Y軸的數據並計算角度:

 

int16_t HMC5883L_ReadAngle()
{
static uint8_t i; 
static uint8_t XYZ_Data[6]; //用來存儲三個軸輸出的數字量

_iic_Start();
_iic_SendByte(0x3c); // 發送HMC5883L的器件地址0x3c,寫操作
_iic_SendByte(0x03); //指針指向03,X msb寄存器   
_iic_Start();          
_iic_SendByte(0x3d); //改為讀操作

//依次讀取三個軸的數字量
for(i=0;i<5;i++)        //前5次讀取發送應答信號
{
XYZ_Data[i]=_iic_ReadByte(1);
}
XYZ_Data[5] =_iic_ReadByte(0);  //不應答
_iic_Stop();
return atan2( (double)((int16_t)((XYZ_Data[Ymsb]<<8)+XYZ_Data[Ylsb]) ),(double)((int16_t)((XYZ_Data[Xmsb]<<8)+XYZ_Data[Xlsb])))*(180/3.14159265)+180;       //計算角度,需要包含math.h頭文件
}

 

配置好IO口,調用HMC5883L_Init()后,便可調用HMC5883L_ReadAngle()讀取角度值,0~360°。

以下為測試時的截圖:

 

 

測試時,模塊比較靈敏且精確,稍微旋轉模塊便有精確的變化。由於該模塊是基於對地磁場的測量,此模塊容易受到其他磁場的干擾,比如將該模塊靠近直流電機時,

便會因為電機內的磁場而降低精度甚至失靈(之前做智能小車時就遇到這個問題,要將電機內的磁場屏蔽起來才行)。

(完)



 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM