最近買(mǎi)了個(gè)數(shù)字羅盤(pán)模塊,調(diào)通后發(fā)現(xiàn)很不錯(cuò),非常靈敏,測(cè)試的時(shí)候精度在1°以?xún)?nèi)。連續(xù)測(cè)量模式下,最快測(cè)量、輸出速率可達(dá)75hz,模塊每次測(cè)量完畢并將數(shù)據(jù)更新至寄存器后,其DRDY引腳便產(chǎn)生一個(gè)低電平脈沖(可以配置一個(gè)外部中斷捕獲DRDY引腳的下降沿,并在中斷服務(wù)程序中讀取數(shù)據(jù)),在STM32中可以設(shè)置一個(gè)下降沿觸發(fā)的外部中斷,并在中斷服務(wù)程序中調(diào)用角度數(shù)據(jù)讀取函數(shù)。以下為操作該模塊的主要步驟。
一、IIC協(xié)議相關(guān)操作(單片機(jī)作為主機(jī)控制時(shí)鐘線(xiàn))
宏定義:
//這里用到了STM32的位帶區(qū)操作,方便實(shí)現(xiàn)對(duì)一個(gè)位的操作
//PB13配置為OD輸出,同時(shí)外部給上拉電阻,這樣既可輸出信號(hào)給從機(jī),也能
//在PB13為漏極開(kāi)路狀態(tài)時(shí)接收從機(jī)的信號(hào)(STM32的IO配置為輸出模式時(shí),
//IO口的電平也會(huì)不斷地被捕獲到輸入寄存器中)
//PB14配置為推挽輸出,PB15配置為浮空輸入
#defineW_SDAOPB13//PB13輸出寄存器
#defineW_SCLOPB14//PB14輸出寄存器
#defineR_DRDYIPB15//PB15輸入寄存器
#defineXmsb0//X軸數(shù)字量的高8位
#defineXlsb1//X軸數(shù)字量的低8位
#defineZmsb2//Z軸數(shù)字量的高8位
#defineZlsb3//Z軸數(shù)字量的低8位
#defineYmsb4//Y軸數(shù)字量的高8位
#defineYlsb5//Y軸數(shù)字量的低8位
附位帶宏定義:
#defineGPIOB_ODR_Addr(GPIOB_BASE+12)//0x40010C0C
#defineGPIOB_IDR_Addr(GPIOB_BASE+8)//0x40010C08
#defineBITBAND_Addr(Addr,num)((volatileunsignedlong*)(0x42000000+32*(Addr-0x40000000)+4*num))
#defineIPB13*BITBAND_Addr(GPIOB_IDR_Addr,13)
#defineOPB13*BITBAND_Addr(GPIOB_ODR_Addr,13)
#defineOPB14*BITBAND_Addr(GPIOB_ODR_Addr,14)
#defineIPB15*BITBAND_Addr(GPIOB_IDR_Addr,15)
啟動(dòng)IIC傳輸:
void_iic_Start()
{
W_SCL=1;
W_SDA=1;
_delay();
W_SDA=0;//SCL高時(shí),拉低SDA,表示開(kāi)始IIC傳輸,占用總線(xiàn)
_delay();
W_SCL=0;//控制SCL
_delay();
}
停止IIC傳輸:
void_iic_Stop()
{
W_SCL=1;//釋放SCL(由于沒(méi)有其他主器件,SCL無(wú)需開(kāi)漏)
W_SDA=0;
發(fā)送一個(gè)字節(jié):
uint8_t_iic_SendByte(uint8_tdat)
{
uint8_ti;
for(i=0;i《8;i++)
{
_delay();
W_SDA=dat》》7;//SCL拉高之前寫(xiě)SDA
dat=dat《《1;
_delay();
W_SCL=1;//拉高SCL,從器件開(kāi)始讀取SDA
_delay();
W_SCL=0;//重新拉低SCL
}
W_SDA=1;//釋放SDA
W_SCL=1;//拉高SCL,讀取從器件應(yīng)答信號(hào)
//等待應(yīng)答
i=100;
while(i&&R_SDA){i--;_delay();}
if(i==0)//無(wú)應(yīng)答
{
W_SCL=0;//重新拉低SCL
return0;
}
else{//有應(yīng)答
_delay();
W_SCL=0;//重新拉低SCL
return1;
}
}
_delay();
W_SDA=1;//SCL為高時(shí),拉高SDA表示結(jié)束ICC傳輸,釋放總線(xiàn)
}
接收一個(gè)字節(jié):
uint8_t_iic_ReadByte(uint8_tAck)
{
uint8_ttemp,i;
W_SDA=1;//釋放SDA
_delay();
for(i=0;i《8;i++)
{
_delay();
W_SCL=1;//拉高SCL開(kāi)始讀取SDA
temp=temp《《1;
temp|=R_SDA;//SCL拉高之后讀取SDA
W_SCL=0;//拉低SCL,從器件開(kāi)始放置數(shù)據(jù)
}
//發(fā)送應(yīng)答信號(hào)
if(Ack)W_SDA=0;//拉低SDA表示應(yīng)答
W_SCL=1;//拉高SCL,從器件接收應(yīng)答信號(hào)
_delay();
W_SCL=0;//重新拉低SCL
W_SDA=1;//釋放SDA
returntemp;
}
二、配置HMC5883L模塊
voidHMC5883L_Init()
{
_iic_Start();
_iic_SendByte(0x3c);//寫(xiě)操作
_iic_SendByte(0x00);//指針指向00,配置寄存器A
_iic_SendByte(0x78);//數(shù)據(jù)測(cè)量、輸出速率75hz
_iic_Start();//指針定位到02,模式寄存器
_iic_SendByte(0x3c);
_iic_SendByte(0x02);
_iic_SendByte(0x00);//連續(xù)測(cè)量模式
_iic_Stop();
}
三、讀取角度數(shù)據(jù)
接收三軸數(shù)據(jù),處理X,Y軸的數(shù)據(jù)并計(jì)算角度:
int16_tHMC5883L_ReadAngle()
{
staticuint8_ti;
staticuint8_tXYZ_Data[6];//用來(lái)存儲(chǔ)三個(gè)軸輸出的數(shù)字量
_iic_Start();
_iic_SendByte(0x3c);//發(fā)送HMC5883L的器件地址0x3c,寫(xiě)操作
_iic_SendByte(0x03);//指針指向03,Xmsb寄存器
_iic_Start();
_iic_SendByte(0x3d);//改為讀操作
//依次讀取三個(gè)軸的數(shù)字量
for(i=0;i《5;i++)//前5次讀取發(fā)送應(yīng)答信號(hào)
{
XYZ_Data[i]=_iic_ReadByte(1);
}
XYZ_Data[5]=_iic_ReadByte(0);//不應(yīng)答
_iic_Stop();
returnatan2((double)((int16_t)((XYZ_Data[Ymsb]《《8)+XYZ_Data[Ylsb])),(double)((int16_t)((XYZ_Data[Xmsb]《《8)+XYZ_Data[Xlsb])))*(180/3.14159265)+180;//計(jì)算角度,需要包含math.h頭文件
}
配置好IO口,調(diào)用HMC5883L_Init()后,便可調(diào)用HMC5883L_ReadAngle()讀取角度值,0~360°。以下為測(cè)試時(shí)的截圖:
測(cè)試時(shí),模塊比較靈敏且精確,稍微旋轉(zhuǎn)模塊便有精確的變化。由于該模塊是基于對(duì)地磁場(chǎng)的測(cè)量,此模塊容易受到其他磁場(chǎng)的干擾,比如將該模塊靠近直流電機(jī)時(shí),便會(huì)因?yàn)殡姍C(jī)內(nèi)的磁場(chǎng)而降低精度甚至失靈(之前做智能小車(chē)時(shí)就遇到這個(gè)問(wèn)題,要將電機(jī)內(nèi)的磁場(chǎng)屏蔽起來(lái)才行)。
評(píng)論
查看更多