您好,歡迎來(lái)電子發(fā)燒友網(wǎng)! ,新用戶?[免費(fèi)注冊(cè)]

您的位置:電子發(fā)燒友網(wǎng)>電子元器件>傳感器>

淺談磁傳感器AKM8975驅(qū)動(dòng)和中間層

2018年10月07日 11:49 網(wǎng)絡(luò)整理 作者:工程師譚軍 用戶評(píng)論(0
  磁傳感器
?
  磁傳感器是把磁場(chǎng)、電流、應(yīng)力應(yīng)變、溫度、光等外界因素引起敏感元件磁性能變化轉(zhuǎn)換成電信號(hào),以這種方式來(lái)檢測(cè)相應(yīng)物理量的器件。
?
  磁傳感器廣泛用于現(xiàn)代工業(yè)電子產(chǎn)品中以感應(yīng)磁場(chǎng)強(qiáng)度來(lái)測(cè)量電流、位置、方向等物理參數(shù)。在現(xiàn)有技術(shù)中,有許多不同類型的傳感器用于測(cè)量磁場(chǎng)和其他參數(shù)。
?
  磁傳感器是把磁場(chǎng)、電流、應(yīng)力應(yīng)變、溫度、光等外界因素引起敏感元件磁性能變化轉(zhuǎn)換成電信號(hào),以這種方式來(lái)檢測(cè)相應(yīng)物理量的器件。磁傳感器分為三類:指南針、磁場(chǎng)感應(yīng)器、位置傳感器。指南針:地球會(huì)產(chǎn)生磁場(chǎng),如果你能測(cè)地球表面磁場(chǎng)就可以做指南針。電流傳感器:電流傳感器也是磁場(chǎng)傳感器。電流傳感器可以用在家用電器、智能電網(wǎng)、電動(dòng)車、風(fēng)力發(fā)電等等。位置傳感器: 如果一個(gè)磁體和磁傳感器相互之間有位置變化,這個(gè)位置變化是線性的就是線性傳感器,如果轉(zhuǎn)動(dòng)的就是轉(zhuǎn)動(dòng)傳感器。
?
  大生活中用到很多磁傳感器,比如說(shuō)指南針,電腦硬盤、家用電器等等。
?
  在傳統(tǒng)產(chǎn)業(yè)改造中的應(yīng)用及市場(chǎng)
?
  據(jù)報(bào)道,1995年僅工業(yè)過(guò)程控制傳感器的全球市場(chǎng)已達(dá)到260億美元;2001年計(jì)算機(jī)HDD用SV-GMR磁頭的市場(chǎng)超過(guò)了4000億日元(約合34億美元)。若采用新型微型磁傳感器,既使操作更簡(jiǎn)便,又提高了可靠性,增長(zhǎng)了器件壽命,降低了成本。
?
  使用新型磁傳感器可以顯著提高測(cè)量和控制精度,如使用GMI(巨磁阻抗)磁場(chǎng)傳感器,檢測(cè)分辨率和常用磁通門磁強(qiáng)計(jì)一樣,而響應(yīng)速度卻快了一倍,消耗功率僅為后者的1%;若用霍爾器件,其分辨率僅4A/m,而所需外場(chǎng)比前者高300余倍;在應(yīng)力檢測(cè)中,SI 傳感器的靈敏度是常用電阻絲的2000倍高,是半導(dǎo)體應(yīng)變規(guī)的20~40倍。工業(yè)機(jī)床的油壓或氣壓汽缸活塞位置檢測(cè),廣泛采用套在活塞桿上的永磁環(huán)和AMR元件組成的磁傳感器,檢測(cè)精度達(dá)0.1mm,檢測(cè)速度可在0~500mm/s內(nèi)以高低速度變換;改用GMI或SV-GMR傳感器后,測(cè)量精度至少可以提高1個(gè)數(shù)量級(jí)。在機(jī)床數(shù)控化時(shí)代,數(shù)字磁尺幫助設(shè)計(jì)師們實(shí)現(xiàn)了閉環(huán)控制。使用絕對(duì)信號(hào)輸出的磁尺,則不受噪聲、電源電壓波動(dòng)等干擾,也不必原點(diǎn)復(fù)位。使用工作狀態(tài)磁敏開關(guān),還可以完成手動(dòng)與數(shù)控之間的轉(zhuǎn)換。
?
  旋轉(zhuǎn)磁編碼器在旋轉(zhuǎn)量的檢測(cè)控制中起關(guān)鍵作用,它在數(shù)控機(jī)床、機(jī)器人、工廠自動(dòng)化設(shè)備的位置檢測(cè)、傳輸速度控制,磁盤、打印機(jī)之類的自動(dòng)化設(shè)備通訊設(shè)備的旋轉(zhuǎn)量檢測(cè)中都是不可缺少的重要部件。其檢測(cè)對(duì)象是光磁圖形,不受油霧粉塵的影響,因此比目前最先進(jìn)的光編碼器的可靠性高壽命長(zhǎng),尤其適合于自動(dòng)焊接、油漆機(jī)器人和與鋼鐵有關(guān)的位置檢測(cè)以及各種金屬、木材、塑料等加工行業(yè)的應(yīng)用。而仍大量使用光編碼器,由于這種器件易受粉塵、油污和煙霧的影響,用在自動(dòng)焊接、油漆機(jī)器人、紡織和鋼鐵、木料、塑料等的加工中,可靠性極差。應(yīng)用AMR、GMR 、GMI敏感元件構(gòu)成的旋轉(zhuǎn)磁編碼器,就不存在上述缺點(diǎn),因此,它們的市場(chǎng)需求年增長(zhǎng)率在30%以上。在家用電器和節(jié)能產(chǎn)品中也也有其廣泛的應(yīng)用潛力,在節(jié)能環(huán)保產(chǎn)品中也大有用武之地。若使用微型磁編碼器和控制微機(jī)一體化,更有利于簡(jiǎn)化控制系統(tǒng)結(jié)構(gòu),減少元件數(shù)和占空體積,這在精密制造和加工業(yè)中意義十分重大。
?
  在環(huán)境監(jiān)測(cè)中的應(yīng)用
?
  環(huán)境保護(hù)的前提是對(duì)各個(gè)環(huán)境參數(shù)(溫度、氣壓、大氣成份、噪聲。..。..。)的監(jiān)測(cè),這里需要使用多種大量的傳感器。采用強(qiáng)磁致伸縮非晶磁彈微型磁傳感器,可以同時(shí)測(cè)量真空或密閉空間的溫度和氣壓,而且不用接插件,可以遙測(cè)和遠(yuǎn)距離訪問(wèn)。在食品包裝、環(huán)境科學(xué)實(shí)驗(yàn)等方面,應(yīng)用前景廣闊。
?
  在交通管制中的應(yīng)用
?
  交通事故和交通阻塞是城市中和城市間交通存在的一個(gè)大問(wèn)題。國(guó)內(nèi)外都在加強(qiáng)高速公路行車支持道路系統(tǒng)(AHS)、智能運(yùn)輸系統(tǒng)(ITS)和道路交通信息系統(tǒng)(VICS)等的開發(fā)與建設(shè)。在這些新系統(tǒng)中,高靈敏度、高速響應(yīng)微型磁傳感器大有用武之地。例如,用分辨率可達(dá)1nT的GMI和SI傳感器,可構(gòu)成ITS傳感器(作高速路上的道路標(biāo)志,測(cè)車輪角度,貨車近接距離),汽車通過(guò)記錄儀(測(cè)通行方向、速度、車身長(zhǎng)度、車種識(shí)別),停車場(chǎng)成批車輛傳感器,加速度傳感器(測(cè)車輛通過(guò)時(shí)路橋的振動(dòng)等)。
?
  磁傳感器在電子羅盤中的應(yīng)用
?
  幾個(gè)世紀(jì)以來(lái),人們?cè)趯?dǎo)航中一直使用磁羅盤。有資料顯示早在二千多年前中國(guó)人就開始使用天然磁石-一種磁鐵礦來(lái)指示水平方向。電子羅盤(數(shù)字羅盤,電子指南針,數(shù)字指南針)是測(cè)量方位角(航向角)比較經(jīng)濟(jì)的一種電子儀器。如今電子指南針廣泛應(yīng)用于汽車和手持電子羅盤,手表,手機(jī),對(duì)講機(jī),雷達(dá)探測(cè)器,望遠(yuǎn)鏡,探星儀,穆斯林麥加探測(cè)器(穆斯林鐘),手持 GPS 系統(tǒng),尋路器,武器/導(dǎo)彈導(dǎo)航( 航位推測(cè) ),位置/方位系統(tǒng),安全/定位設(shè)備,汽車、航海和航空的高性能導(dǎo)航設(shè)備,電子游戲機(jī)設(shè)備等需要方向或姿態(tài)顯示的設(shè)備。
?
  地球本身是一個(gè)大磁鐵,地球表面的磁場(chǎng)大約為0.5Oe,地磁場(chǎng)平行地球表面并始終指向北方。利用GMR薄膜可做成用來(lái)探測(cè)地磁場(chǎng)的傳感器。圖5顯示這種傳感器的具體工作原理。我們可以制出能夠探測(cè)磁場(chǎng)X和Y方向分量的集成GMR傳感器。此傳感器可作為羅盤并應(yīng)用在各種交通工具上作為導(dǎo)航裝置。美國(guó)的NVE公司已經(jīng)把GMR傳感器用在車輛的交通控制系統(tǒng)上。例如,放置在高速公路邊的GMR傳感器可以計(jì)算和區(qū)別通過(guò)傳感器的車輛。如果同時(shí)分開放置兩個(gè)GMR傳感器,還可以探測(cè)出通過(guò)車輛的速度和車輛的長(zhǎng)度,當(dāng)然GMR也可用在公路的收費(fèi)亭,從而實(shí)現(xiàn)收費(fèi)的自動(dòng)控制。另外高靈敏度和低磁場(chǎng)的傳感器可以用在航空、航天及衛(wèi)星通信技術(shù)上。大家知道,在軍事工業(yè)中隨著吸波技術(shù)的發(fā)展,軍事物件可以通過(guò)覆蓋一層吸波材料而隱蔽,但是它們無(wú)論如何都會(huì)產(chǎn)生磁場(chǎng),因此通過(guò)GMR磁場(chǎng)傳感器可以把隱蔽的物體找出來(lái)。當(dāng)然,GMR磁場(chǎng)傳感器可以應(yīng)用在衛(wèi)星上,用來(lái)探測(cè)地球表面上的物體和底下的礦藏分布。
?
  門磁傳感器在智能家居中的應(yīng)用
?
  在智能家居門禁系統(tǒng)中門磁開關(guān)的作用是負(fù)責(zé)門磁通電否,通電帶磁(閉門),斷電消磁(開門),門磁安裝于門與門套上,開關(guān)安裝于屋內(nèi),配合自動(dòng)閉門器使用,一般可承受150公斤的拉力。
?
  有線門磁為嵌入式安裝更加隱蔽,感應(yīng)門窗的開合,適用于木質(zhì)或鋁合金門窗發(fā)出有線常閉/常開開關(guān)信號(hào)。門磁是用來(lái)探測(cè)門、窗、抽屜等是否被非法打開或移動(dòng)。它由無(wú)線發(fā)射器和磁塊兩部分組成。門磁系統(tǒng)其實(shí)和床磁等原理相同。

  以屏幕的左下方為原點(diǎn)(2d編程的時(shí)候,是以屏幕左上方為原點(diǎn)的,這個(gè)值得注意一下),箭頭指向的方向?yàn)檎?。?10到10,以浮點(diǎn)數(shù)為等級(jí)單位,想象一下以下情形:

  手機(jī)屏幕向上(z軸朝天)水平放置的時(shí)侯,(x,y,z)的值分別為(0,0,10);

  手機(jī)屏幕向下(z軸朝地)水平放置的時(shí)侯,(x,y,z)的值分別為(0,0,-10);

  手機(jī)屏幕向左側(cè)放(x軸朝天)的時(shí)候,(x,y,z)的值分別為(10,0,0);

  手機(jī)豎直(y軸朝天)向上的時(shí)候,(x,y,z)的值分別為(0,10,0);

  2013.4.2,今天提交完代碼,指南針的調(diào)試工作可以告一段落了。這段時(shí)間主要做了2項(xiàng)工作,1、寫了一個(gè)自己的函數(shù),在.c文件中去讀acc的input event,因?yàn)樵瓉?lái)的讀值函數(shù)會(huì)引起驅(qū)動(dòng)資源搶占。2、寫了一個(gè)有效的濾波函數(shù)。濾波函數(shù)我前前后后寫了4個(gè),之前想的很復(fù)雜,今天下午看了一篇論文,試了下,發(fā)現(xiàn)原來(lái)有效的濾波函數(shù)如此簡(jiǎn)單,完全沒(méi)有技術(shù)含量(取9次、報(bào)一次,去掉最大最小,取平均),如下(其它函數(shù)在分割下之前的版本中已經(jīng)列出,見下文):

  //daiyyr add @2013.4.2

  int acount, myx[9], myy[9];

  //return 0 for collect; 1 for report

  int Mean_filter(int16 *bData){

  signed short i, x, y, z;

  x = bData[1] + (bData[2] 《《 8);

  y = bData[3] + (bData[4] 《《 8);

  z = bData[5] + (bData[6] 《《 8);//don‘t do this

  // printf(“x:%d, y:%d, z:%d\n”,x,y,z);//no z

  myx[acount] = x;

  myy[acount] = y;

  acount++;

  if (acount == 9){

  signed short maxx = -1000, minx = 1000, maxy = -1000, miny = 1000, avgx = 0, avgy = 0;

  acount = 0;

  //do sort and average

  for (i=0; i《9; i++){

  if (maxx 《 myx[i])

  maxx = myx[i];

  else if (minx 》 myx[i])

  minx = myx[i];

  avgx += myx[i];

  if (maxy 《 myy[i])

  maxy = myy[i];

  else if (miny 》 myy[i])

  miny = myy[i];

  avgy += myy[i];

  // printf(“avgx:%d, myx[i]:%d, avgy:%d, myy[i]:%d\n”, avgx, myx[i], avgy, myy[i]);

  }

  avgx = (avgx - maxx - minx) / 7;

  avgy = (avgy - maxy - miny) / 7;

  // printf(“bdata1:%x, bdata2:%x\n”, bData[1], bData[2]);

  bData[1] = avgx & ((int16)255);

  bData[2] = avgx 》》 8;

  bData[3] = avgy & ((int16)255);

  bData[4] = avgy 》》 8;

  // printf(“maxx:%d, minx:%d, avgx:%d,avgy:%d; bdata1:%x, bdata2:%x,report!*********************\n”,maxx, minx, avgx, avgy, bData[1], bData[2]);

  return 0;

  }

  return 1;

  }

  ----------------------------下面內(nèi)容為2013.4.2之前--------------------------------------------------------------------------------------

  7023Q

  https://192.168.0.220:8443/svn/coffee/trunk

  驅(qū)動(dòng) coffee/kernel/drivers/misc/akm8975.c

  HAL device/cct/common/libsku7sensors/AkmSensor.cpp

  HAL特殊線層 device/cct/common/libsku7sensors/ak8975/

  在此開啟線程system/core/rootdir

  編譯生成的守護(hù)進(jìn)程的可執(zhí)行文件在手機(jī)中的位置:/system/bin/akmd8975

  8000R

  驅(qū)動(dòng) \\cts-server\sourcecode\rockchip-update\kernel\drivers\input\sensors\compass

  sensors/sensor-dev.c

  HAL:hardware/rk29/sensor/st/ak8975/…

  開啟線程:device/rockchip/rk30sdk/init.rk30board.rc

  板子的GPIO腳變了,所以先修改板子配置源文件:

  HAL層向服務(wù)層上報(bào)數(shù)據(jù)之前,經(jīng)過(guò)以下幾個(gè)流程:

  A:開機(jī)運(yùn)行一個(gè)叫akm8975的進(jìn)程。這個(gè)進(jìn)程源代碼位于HAL層。8000R是hardware/rk29/sensor/st/;7023Q是device/cct/common/libsku7sensors/ak8975/

  B:當(dāng)指南針應(yīng)用被打開后,通過(guò)HAL調(diào)用到驅(qū)動(dòng)的enable函數(shù),設(shè)備開始產(chǎn)生中斷。

  C:此時(shí),akm8975這個(gè)進(jìn)程捕獲這個(gè)中斷,讀取驅(qū)動(dòng)獲得的原始數(shù)據(jù),并作一番神秘的修改,具體的修改函數(shù)被封裝于HAL層的…。/ak8975/libak8975/libak8975.a這個(gè)令人蛋疼菊緊的文件中,該文件的存在褻瀆了自由軟件精神,使業(yè)界良心蕩然無(wú)存,讓代碼民工情何以堪。

  D:之后這個(gè)進(jìn)程呼叫ioctl與內(nèi)核文件搞基,驅(qū)動(dòng)的ioctl去調(diào)用驅(qū)動(dòng)的報(bào)值函數(shù)AKECS_SetYPR,該函數(shù)通過(guò)input_report_abs上報(bào)。

  E:HAL層通過(guò)讀文件/dev/input/compass獲取上報(bào)的值,并作最后的處理,最后報(bào)給服務(wù)層

  rbuf[0] = prms-》m_theta; // yaw 航向

  rbuf[1] = prms-》m_phi180; // pitch 俯仰角

  rbuf[2] = prms-》m_eta90; // roll 翻滾角

  該器件最終輸出到應(yīng)用層的大約是這六個(gè)值:

  磁場(chǎng)強(qiáng)度X軸、y軸、z軸、航向、俯仰角、翻滾角。其中俯仰角和翻滾角是依據(jù)重力傳感器的值計(jì)算出的結(jié)果

  最后調(diào)通的方法是,利用已經(jīng)由可執(zhí)行文件中的秘密函數(shù)計(jì)算出的x和y軸磁感強(qiáng)度值(即磁感線在水平面的投影值的分解值)

  rbuf[9] = prms-》m_hvec.u.x; // M_x

  rbuf[10] = prms-》m_hvec.u.y; // M_y

  用arctan三角函數(shù)算出正北方向與手機(jī)的某個(gè)軸(x或y)的偏移角(實(shí)際上.a文件內(nèi)部也是這樣運(yùn)算的),把角度值賦予:rbuf[0] // yaw,當(dāng)設(shè)備處于水平面的時(shí)候,頂層就是憑借這一個(gè)值來(lái)判斷方向的!而設(shè)備若存在俯仰和翻滾角,則根據(jù)另外幾個(gè)數(shù)據(jù)計(jì)算補(bǔ)償。

  下面是幾個(gè)可執(zhí)行文件中的關(guān)鍵函數(shù),我用它們架空了.a文件,即自己通過(guò)磁感設(shè)備和加速度感應(yīng)設(shè)備計(jì)算6個(gè)上報(bào)的值:三軸磁數(shù)據(jù),航向、俯仰、翻滾三個(gè)方位數(shù)據(jù)。

  同時(shí)注意值得正負(fù),習(xí)慣上,確定了設(shè)備的“底部”后,將底部抬起,俯仰角pitch為正,反之為負(fù);將設(shè)備右側(cè)抬起,翻滾角roll為正,反之為負(fù);航向?yàn)樵O(shè)備“縱軸”與正北方向的順時(shí)針偏離角度(yaw小于360°時(shí)順時(shí)針旋轉(zhuǎn)設(shè)備,yaw遞增)。

  現(xiàn)在的問(wèn)題是我的Gsensor——bma020會(huì)頻繁出現(xiàn)大的尖波,這樣造成俯仰角和翻滾角也出現(xiàn)尖波。我在嘗試使用卡曼濾波算法過(guò)濾尖波。

  頻繁大尖波的原因找到了。我之前一直納悶,為什么當(dāng)我運(yùn)行akmd守護(hù)進(jìn)程時(shí),ACC本身的報(bào)值會(huì)出現(xiàn)尖波影響,硬件上,AKM影響ACC的可能性可以立刻排除。那就是軟件了,我看了ACC的驅(qū)動(dòng),原來(lái),通過(guò)input event報(bào)值和open dev/bma020 ioctl()報(bào)值,這兩個(gè)報(bào)值方式調(diào)用的是同一個(gè)函數(shù):int bma020_read_accel_xyz(bma020acc_t * acc)。而這個(gè)函數(shù)沒(méi)有用自旋鎖鎖住,所以幾乎可以肯定,當(dāng)兩個(gè)通過(guò)不同方式讀acc值的進(jìn)程同時(shí)運(yùn)行時(shí)(ACC本身使用input報(bào)值,AKM通過(guò)ioctl讀值),在上述函數(shù)里發(fā)生了內(nèi)存搶占。

  解決的方式有兩個(gè),1、給驅(qū)動(dòng)函數(shù)bma020_read_accel_xyz加自旋鎖;2、改變akmd讀acc值的方式,通過(guò)input方式讀值。

  這個(gè)系統(tǒng)的設(shè)定是,不輪AKMD是否運(yùn)行,ACC驅(qū)動(dòng)不停地向input報(bào)值,所以相比用ioctl去讀值,akmd去讀ACC的input不會(huì)增加內(nèi)核負(fù)擔(dān)。

  下面兩個(gè)函數(shù)是用c語(yǔ)言寫的讀取acc的input event值的函數(shù):

  //daiyyr add @2013.03.30, to getting acc data by input. begin

  static int accOpened = 0, fd;

  extern int16_t acc_data[3]; //defined in main.c

  int getAccData(void){

  float fData[3];

  int err = 1;

  if (!accOpened){

  fd = openAccInputEvent();

  if (fd 《 0){

  printf(“open acc input event failed\n”);

  return -1;

  }

  accOpened = 1;

  }

  struct input_event event;

  while(err 》 0){

  err = read(fd, &event, sizeof(event));

  if (err 《 0){

  printf(“read err, fd=%d,err=%d\n”, fd, err);

  return -2;

  }

  printf(“dy-code:%d, value:%d\n”,event.code, event.value);

  if(event.type == 0){

  printf(“dy-data[0]:%d, data[1]:%d, data[2]:%d\n”,acc_data[0], acc_data[1], acc_data[2]);

  return 0;

  }

  if(event.type == 2){

  switch (event.code){

  case 3:

  acc_data[0] = event.value;

  continue;

  case 4:

  acc_data[1] = event.value;

  continue;

  case 5:

  acc_data[2] = event.value;

  continue;

  }

  }

  }

  return 0;

  }

  int openAccInputEvent(void){

  char *str, *p, dev[60];

  int i, fd = -1;

  str = “/dev/input/event”;

  strcpy(dev, str);

  for(i=0;i《20;i++){

  p = dev + strlen(dev);

  *p++ = i+48;

  *p = ’\0‘;

  // printf(“mybuffer:%s\n”, dev);

  fd = open(dev,0);

  if (fd》=0) {

  char name[80];

  if (ioctl(fd, EVIOCGNAME(sizeof(name) - 1), &name) 《 1) {

  name[0] = ’\0‘;

  }

  if (!strcmp(name, “acc”)) {

  printf(“open dev succeed\n”);

  return fd;

  } else {

  close(fd);

  p--;

  *p = ’\0‘;

  fd = -1;

  }

  }

  else{

  printf(“err:open dev failed dev:%s\n”, dev);

  return -1;

  }

  }

  return fd;

  }

  //daiyyr add end

  主循環(huán):

  void MeasureSNGLoop(AK8975PRMS* prms)

  {

  BYTE i2cData[AKSC_BDATA_SIZE];

  int16 i;

  int16 bData[AKSC_BDATA_SIZE]; // Measuring block data

  int16 ret;

  int32 ch;

  int32 doze;

  int32_t delay;

  AKMD_INTERVAL interval;

  struct timespec tsstart, tsend;

  if (openKey() 《 0) {

  DBGPRINT(DBG_LEVEL1,

  “%s:%d Error.\n”, __FUNCTION__, __LINE__);

  return;

  }

  if (openFormation() 《 0) {

  DBGPRINT(DBG_LEVEL1,

  “%s:%d Error.\n”, __FUNCTION__, __LINE__);

  return;

  }

  // Get initial interval

  GetValidInterval(CSPEC_INTERVAL_SNG, &interval);

  // Initialize

  if(InitAK8975_Measure(prms) != AKD_SUCCESS){

  return;

  }

  while(TRUE){

  // Get start time

  if (clock_gettime(CLOCK_REALTIME, &tsstart) 《 0) {

  DBGPRINT(DBG_LEVEL1,

  “%s:%d Error.\n”, __FUNCTION__, __LINE__);

  return;

  }

  // Set to SNG measurement pattern (Set CNTL register)

  if (AKD_SetMode(AK8975_MODE_SNG_MEASURE) != AKD_SUCCESS) {

  DBGPRINT(DBG_LEVEL1,

  “%s:%d Error.\n”, __FUNCTION__, __LINE__);

  return;

  }

  // 。! : 獲取 M snesor 的原始數(shù)據(jù)。 這里可能阻塞。

  // Get measurement data from AK8975

  // ST1 + (HXL + HXH) + (HYL + HYH) + (HZL + HZH) + ST2

  // = 1 + (1 + 1) + (1 + 1) + (1 + 1) + 1 = 8 bytes

  if (AKD_GetMagneticData(i2cData) != AKD_SUCCESS) {

  DBGPRINT(DBG_LEVEL1,

  “%s:%d Error.\n”, __FUNCTION__, __LINE__);

  return;

  }

  // Copy to local variable

  // DBGPRINT(DBG_LEVEL3, “%s: bData(Hex)=”, __FUNCTION__);

  printf(“dyyr-”);

  for(i=0; i《AKSC_BDATA_SIZE; i++){

  bData[i] = i2cData[i];

  // DBGPRINT(DBG_LEVEL3, “%02x,”, bData[i]);

  printf(“%02x,”, bData[i]);

  }

  printf(“\n”);

  // DBGPRINT(DBG_LEVEL3, “\n”);

  D_WHEN_REPEAT(100,

  “raw mag x : %d, raw mag y : %d, raw mag z : %d.”,

  (signed short)(bData[1] + (bData[2] 《《 8) ),

 ?。╯igned short)(bData[3] + (bData[4] 《《 8) ),

 ?。╯igned short)(bData[5] + (bData[6] 《《 8) ) );

  // 。! :

  // Get acceelration sensor’s measurement data.

  if (GetAccVec(prms) != AKRET_PROC_SUCCEED) {

  return;

  }

  /*

  DBGPRINT(DBG_LEVEL3,

  “%s: acc(Hex)=%02x,%02x,%02x\n”, __FUNCTION__,

  prms-》m_avec.u.x, prms-》m_avec.u.y, prms-》m_avec.u.z);

  */

  //printf(“dyyr-MeasuringEventProcess”);

  ret = MeasuringEventProcess(

  bData,

  prms,

  getFormation(),

  interval.decimator,

  CSPEC_CNTSUSPEND_SNG

 ?。?

  // Check the return value

  if(ret == AKRET_PROC_SUCCEED){

  if(prms-》m_cntSuspend 》 0){

  // Show message

  DBGPRINT(DBG_LEVEL2,

  “Suspend cycle count = %d\n”, prms-》m_cntSuspend);

  }

  else if (prms-》m_callcnt 《= 1){

  // Check interval

  if (AKD_GetDelay(&delay) != AKD_SUCCESS) {

  DBGPRINT(DBG_LEVEL1,

  “%s:%d Error.\n”, __FUNCTION__, __LINE__);

  } else {

  GetValidInterval(delay, &interval);

  }

  }

  //printf(“dyyr- measureresulthook\n”);

  // Display(or dispatch) the result.

  Disp_MeasurementResultHook(prms);

  }

  //下面幾個(gè)是位于main.c 的報(bào)值函數(shù)和我的數(shù)值處理函數(shù)

  /*!

  Daiyyr@2013.03.29

  Get acc data and convert to pitch and roll orientation

  acc_data: acc data.

  pitch: pitch orientation to report

  roll: roll orientation to report

  獲取加速度數(shù)據(jù)并轉(zhuǎn)換為俯仰角和翻滾角

  acc_data:存儲(chǔ)加速度數(shù)據(jù)

  pitch:將上報(bào)的俯仰角

  roll:將上報(bào)的翻滾角

  */

  int16_t acc_data[3];

  int acc2pitch_roll(int *pitch, int *roll)

  {

  if(getAccData() 《 0)

  return -1;

  *pitch = acc_data[2] 》 0 ? (acc_data[0] 》 0 ? -11520+acc_data[0]*64/264*90 : 11520+acc_data[0]*64/248*90) : (acc_data[0] 》 0 ? -acc_data[0]*64/264*90 : -acc_data[0]*64/248*90);

  *roll = acc_data[1] 》 0 ? acc_data[1]*64/242*90 : acc_data[1]*64/273*90;

  return 0;

  }

  /*!

  Daiyyr@2013.03.29

  Calibration for x & y axis magnetic data.

  */

  int xmax = 1, ymax = 1, xmin = 0, ymin = 0;

  int mag_x_y_calibration(int *x, int *y){

  int xsf, ysf, xoff, yoff;

  // printf(“xy:%d,%d\n”, *x, *y);

  if(*x 》 xmax)

  xmax = *x;

  else if(*x 《 xmin)

  xmin = *x;

  if(*y 》 ymax)

  ymax = *y;

  else if(*y 《 ymin)

  ymin = *y;

  xsf = 1 》 (ymax-ymin)/(2*(xmax-ymin)) ? 1 : (ymax-ymin)/(2*(xmax-ymin));

  ysf = 1 》 (xmax-ymin)/(2*(ymax-ymin)) ? 1 : (xmax-ymin)/(2*(ymax-ymin));

  xoff = ((xmax-xmin)/2-xmax)*xsf;

  yoff = ((ymax-ymin)/2-ymax)*ysf;

  // printf(“xoff:%d, xsf:%d\n”, xoff, xsf);

  *x = xsf + *x + xoff;

  *y = ysf + *y + yoff;

  // printf(“hhll:%d,%d,%d,%d\n”, xmax, ymax, xmin, ymin);

  return 0;

  }

  int16_t acc_data[3];

  void Disp_MeasurementResultHook(AK8975PRMS * prms)

  {

  int err;

  int16 acc[3]; /* 將緩存 acc sensor 返回的數(shù)據(jù)。 */

  if (!s_opmode) {

  int rbuf[12] = { 0 };

  // rbuf[0] = prms-》m_theta; // yaw

  // rbuf[1] = prms-》m_phi180; // pitch

  // rbuf[2] = prms-》m_eta90; // roll

  // rbuf[6] = prms-》m_avec.u.x; // G_Sensor x

  // rbuf[7] = prms-》m_avec.u.y; // G_Sensor y

  // rbuf[8] = prms-》m_avec.u.z; // G_Sensor z

  acc2pitch_roll(&rbuf[1], &rbuf[2]);

  rbuf[3] = 25; // tmp (AK8975 doesn‘t have temperature sensor)

  rbuf[4] = prms-》m_hdst; // m_stat

  rbuf[5] = 3; // g_stat

  rbuf[9] = prms-》m_hvec.u.x; // M_x

  rbuf[10] = prms-》m_hvec.u.y; // M_y

  mag_x_y_calibration(&rbuf[9], &rbuf[10]);

  rbuf[11] = prms-》m_hvec.u.z; // M_z

  rbuf[0] = axis2angle(rbuf[10], -rbuf[9]); // yaw

  //printf(“pitch=%d, roll=%d,\n”, rbuf[1]/64, rbuf[2]/64);

  /* 。! : 將計(jì)算得到的結(jié)果回寫到驅(qū)動(dòng)。 */

  err=ioctl(g_file, ECS_IOCTL_SET_YPR, &rbuf); // 之后, 驅(qū)動(dòng)會(huì)將該數(shù)據(jù)上報(bào) sensor HAL.

  }

  /* 否則, 。.. */

  else {

  Disp_MeasurementResult(prms);

  }

  }

  下面是用三角函數(shù)求偏移角度的函數(shù)

  /*!

  返回地磁感線在水平面的投影與【設(shè)備水平放置時(shí)y軸】的夾角 Daiyyr@2013.02.23

  */

  int axis2angle(int x, int y)

  {

  double dx = x, dy = y;

  double angle = 180/3.1415*atan2(dx, dy);

  angle = angle 》= 0 ? angle : (angle+360);

  // printf(“dyyr-angle: %f\n”, angle);

  return (int)(angle*64);

  }


非常好我支持^.^

(0) 0%

不好我反對(duì)

(0) 0%

( 發(fā)表人:金巧 )

      發(fā)表評(píng)論

      用戶評(píng)論
      評(píng)價(jià):好評(píng)中評(píng)差評(píng)

      發(fā)表評(píng)論,獲取積分! 請(qǐng)遵守相關(guān)規(guī)定!

      ?