你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【经验分享】基于STM32的三轴数字罗盘HMC5883L模块的测试

[复制链接]
STMCU小助手 发布时间:2022-2-9 20:25
     最近买了个数字罗盘模块,调通后发现很不错,非常灵敏,测试的时候精度在1°以内。连续测量模式下,最快测量、输出速率可达75hz,模块每次测量完毕并将数据更新至寄存器后,其DRDY引脚便产生一个低电平脉冲(可以配置一个外部中断捕获DRDY引脚的下降沿,并在中断服务程序中读取数据),在STM32中可以设置一个下降沿触发的外部中断,并在中断服务程序中调用角度数据读取函数。以下为操作该模块的主要步骤。
一、IIC协议相关操作(单片机作为主机控制时钟线)
宏定义:
  1. //这里用到了STM32的位带区操作,方便实现对一个位的操作: ^- Y* D' E* y( j
  2. //PB13配置为OD输出,同时外部给上拉电阻,这样既可输出信号给从机,也能% j+ B0 {% f' J. \% y
  3. //在PB13为漏极开路状态时接收从机的信号(STM32的IO配置为输出模式时,
    + F' W# ?* p! E5 V& R3 u
  4. //IO口的电平也会不断地被捕获到输入寄存器中)
    ; A3 C5 X# T' u/ G' r
  5. //PB14配置为推挽输出,PB15配置为浮空输入
    $ v1 _, J- v! ^9 X8 D" \! A
  6. #define R_SDA    IPB13          // PB13输入寄存器
    % v1 T0 U* \9 K; {' I
  7. #define W_SDA    OPB13          // PB13输出寄存器
    ! q7 k# _! O4 O+ S0 o- j7 i: V
  8. #define W_SCL    OPB14          // PB14输出寄存器4 r* s, |2 b: x
  9. #define R_DRDY   IPB15          // PB15输入寄存器
复制代码
  1. #define Xmsb 0     //X轴数字量的高8位; |. g4 Y: H3 c' c% }% G7 J
  2. #define Xlsb 1       //X轴数字量的低8位0 e6 T% f0 e' c: v$ G' \5 \
  3. #define Zmsb 2     //Z轴数字量的高8位
    * e9 U* n7 D4 q, z
  4. #define Zlsb 3       //Z轴数字量的低8位
    : g0 c( |& p8 [  q: b
  5. #define Ymsb 4     //Y轴数字量的高8位' U& d1 ?, f) g5 H1 [1 T  q
  6. #define Ylsb 5       //Y轴数字量的低8位
复制代码
0 E6 x( e' K, c; B" l9 z
附位带宏定义:
  1. #define GPIOB_ODR_Addr    (GPIOB_BASE+12) //0x40010C0C
    7 |" g/ m' J: o( L! v
  2. #define GPIOB_IDR_Addr    (GPIOB_BASE+8) //0x40010C08   ; \6 E  r' `# G2 \/ A$ A1 ?- l

  3. # S3 V. R9 U0 `% W5 |- k
  4. #define BITBAND_Addr(Addr,num)  ((volatile unsigned long *)(0x42000000+32*(Addr-0x40000000)+4*num))
    4 @) l3 K# V2 G$ U% D
  5. , t/ A- O* q" L0 w& M0 q
  6. #define IPB13    *BITBAND_Addr(GPIOB_IDR_Addr,13)9 \# u0 r+ {3 w" E7 d9 z& R
  7. #define OPB13   *BITBAND_Addr(GPIOB_ODR_Addr,13)
    4 x, j0 R5 K: x4 H
  8. #define OPB14   *BITBAND_Addr(GPIOB_ODR_Addr,14)+ _0 D2 e- }3 z
  9. #define IPB15    *BITBAND_Addr(GPIOB_IDR_Addr,15)
复制代码
" g& Y) S; C4 X) X
启动IIC传输:
  1. void _iic_Start()
    1 K6 C& x/ b3 |+ Q, e' u
  2. {
    # U2 ]. v3 ]& \
  3.      W_SCL=1;   
    2 O$ Q6 Y( x6 s1 ?2 }( x
  4.      W_SDA=1;
    / @+ }9 h  Y3 Y3 o8 _
  5.      _delay();3 m+ I' c  m+ h2 [4 V0 F1 t* V
  6.      W_SDA=0;     //SCL高时,拉低SDA,表示开始IIC传输,占用总线
    6 ]+ b' K$ \) v! J- v
  7.      _delay();
    7 [* e# e; p% c% q5 M" [
  8.      W_SCL=0;     //控制SCL- r- W, b4 s. M5 b4 ?3 w  b
  9.      _delay();3 O* H# X: E! [9 Z7 Y4 R3 h+ H- n
  10. }
复制代码

. S( P3 _0 x3 ~. Z  l
停止IIC传输:
  1. void _iic_Stop()5 U; x& t1 ]$ _% |+ W: T' ^
  2. {9 ^' ^/ f# i4 z; x1 q. M6 S+ b
  3.      W_SCL=1;     //释放SCL(由于没有其他主器件,SCL无需开漏)# H: d! D0 K: m5 w" Y
  4.      W_SDA=0;     
    & ]5 n1 F3 {: }) c& _  `9 Z' r4 U
  5.      _delay();& `% t$ l3 X& G1 o: r5 P# I
  6.      W_SDA=1;   //SCL为高时,拉高SDA表示结束ICC传输,释放总线
    . Z" }, l; C1 o# l
  7. }
复制代码

, y$ c3 E% E  r9 r
发送一个字节:
  1. uint8_t _iic_SendByte(uint8_t dat)            V) H; o5 x# v& l" U
  2. {2 a0 _7 P% E7 n7 `$ M% n: G, w* p
  3.         uint8_t i;: m( i" R" }# Z0 E7 |1 i8 |
  4.      for(i=0;i<8;i++)! u% N: i' U3 k) k% `
  5.     {
    7 k0 _1 o# u1 X/ i
  6.         _delay();# l& ~& h! |% w7 ?1 i7 }' v
  7.         W_SDA=dat>>7;     //SCL拉高之前写SDA
    / y  @# S" n* f
  8.         dat=dat<<1;
    ! D2 n- x- |# l: E2 N! N& D
  9.         _delay();% P: k  p0 j0 R4 o1 y3 y
  10.         W_SCL=1;         //拉高SCL,从器件开始读取SDA / o! K! R9 {6 K: q7 H2 p
  11.         _delay();
    - @3 F6 Q. f* S- P- s5 y% w
  12.         W_SCL=0;         //重新拉低SCL! I1 S2 [6 p1 Q9 Z' p# B
  13.     }
    ) ]8 w5 @" Y+ h) d5 L
  14.        W_SDA=1;             //释放SDA
    , H+ {* [. D: g
  15.        W_SCL=1;             //拉高SCL,读取从器件应答信号  X! V6 y6 R1 n  m; s
  16.       //   等待应答 ) ^7 u. h5 H/ S9 |0 y2 p
  17.     i=100;+ m1 E# n( K0 w/ J' T8 `, p
  18.     while(i&&R_SDA)  {i--;_delay();}4 J5 {: l# [/ ^* {5 \) ?: g! t) P) x# z
  19.     if(i==0)               //无应答2 t3 l: @/ `8 ~/ `' S
  20.     {, u3 f$ f1 c$ K: d: B; \
  21.         W_SCL=0;         //重新拉低SCL8 x& s. r8 [) H# k) m) a
  22.         return 0;6 p! j, Q: ]3 v! |
  23.     }8 K( V% E$ Q' Y, [# T
  24.     else {                 //有应答
    ) e: L2 l$ F- ]# a! O$ `$ z' B* U/ O
  25.         _delay();
    " ~* b1 w+ C6 B! p
  26.         W_SCL=0;         //重新拉低SCL
    6 ~1 z$ z9 f" |- F2 Y5 Y" {
  27.         return 1;9 |5 t5 {* Q6 a" n7 E
  28. }
    $ _5 _2 V0 D) M5 k/ F4 Y2 {2 b9 j
  29. }
复制代码
- f5 N2 }: n/ y' L/ R! w# A% s) t( j
接收一个字节:
  1. uint8_t _iic_ReadByte(uint8_t Ack)  
    7 n3 c/ [4 C6 ?$ e1 l+ ^" W  |2 B
  2. {
    : `# l& ?( y' J( H# M; \
  3.      uint8_t temp,i;
    1 G5 R3 U# e$ k. Q6 V7 Q4 E
  4.      W_SDA=1;              //释放SDA
    - G, ^& i# M. Y/ h4 j" s
  5.      _delay();# J8 }9 \! v  @  c
  6.     for(i=0;i<8;i++)
    ! k- c# E$ R7 D( G
  7.     {0 c; A9 c1 L2 W) U
  8.         _delay();3 d8 A8 E4 ?% e9 u
  9.         W_SCL=1;          //拉高SCL开始读取SDA          9 A2 E8 b9 P8 x9 w. q
  10.         temp=temp<<1;      
    8 ?2 I" f$ q% W4 w. r4 b! T4 K
  11.         temp|=R_SDA;      //SCL拉高之后读取SDA" N8 r, y7 n, O5 z; ]3 G0 C3 t+ Q, |
  12.         W_SCL=0;              //拉低SCL,从器件开始放置数据  `# N* F& u/ K5 G& Y& l! {1 ~8 A
  13.      }
      |: m* o# h7 k8 `& e
  14.      //发送应答信号
    ; z8 |/ f! ?# n' w0 ?0 V0 x
  15.     if(Ack)W_SDA=0;             //拉低SDA表示应答. F1 e# i3 P, ]. T8 c1 x
  16.     W_SCL=1;             //拉高SCL,从器件接收应答信号5 h# D+ `- ~( i" _* i5 |& K7 L
  17.     _delay();' P: K; \  i3 _3 V' Q# a6 T
  18.     W_SCL=0;             //重新拉低SCL
    * m/ m+ g6 h) S# z
  19.     W_SDA=1;             //释放SDA; Q; }( E6 O# T& a
  20.     return temp;" A+ X: z* e! ~& C3 R; i
  21. }
复制代码

6 G5 N. ]9 A9 O: M; O, W7 M
0 h0 T5 \; r: `* G( q5 ~二、配置HMC5883L模块& t+ {, Q0 Y/ g- \- N: l9 D
  1. void HMC5883L_Init()7 R  o' x$ w+ I6 o0 y4 b! J4 M
  2. {     
    # y5 }5 x  E" h0 S
  3.      _iic_Start();
    9 `- l/ g7 X2 r
  4.      _iic_SendByte(0x3c); //写操作  N/ c* V9 ?# q! W1 }
  5.      _iic_SendByte(0x00); //指针指向00,配置寄存器A ' M6 G8 a8 j9 _2 I, j$ |) Y
  6.      _iic_SendByte(0x78);  //数据测量、输出速率75hz8 V7 _) U" a# c0 n" J2 B
  7.      _iic_Start();          //指针定位到02,模式寄存器
    # S! O, x5 U2 b* A! ?& j9 R' u
  8.      _iic_SendByte(0x3c);
    $ k3 r4 X( M- b* r# U8 ]
  9.      _iic_SendByte(0x02);
    " `6 a- T7 M# R$ U5 L6 I6 B. v
  10.      _iic_SendByte(0x00);  //连续测量模式( m% }* J" _( z! D' a0 ?  H
  11.      _iic_Stop();
    3 c) [( B3 z/ E% f  [( Y
  12. }
复制代码
# ~# ], m" F# f
三、读取角度数据
接收三轴数据,处理X,Y轴的数据并计算角度:
  1. int16_t HMC5883L_ReadAngle()( w/ B$ l) a3 L9 e5 E
  2. {
    : j0 Z9 m- B8 {* ?& M0 }! K
  3. static uint8_t i; . v0 W4 h( U, \, J( p0 \) X- c
  4. static uint8_t XYZ_Data[6]; //用来存储三个轴输出的数字量
    ' F! d0 Q7 |% ]6 q- g4 K7 S3 N  l

  5. / [/ ^' d$ W6 u: c3 F" i" s% y
  6. _iic_Start();# o5 L+ p: [- {% I% f
  7. _iic_SendByte(0x3c); // 发送HMC5883L的器件地址0x3c,写操作* S8 [+ q5 Y  f* A+ D3 V
  8. _iic_SendByte(0x03); //指针指向03,X msb寄存器   0 u, H$ E5 i9 V! Q" ?
  9. _iic_Start();          ( D9 E0 I0 Y5 H$ T, w& w$ c: e
  10. _iic_SendByte(0x3d); //改为读操作! Q, ]* k% p  G; E8 T; ?8 r/ F( D
  11. - V0 n% J6 u4 P3 E! Y, M
  12. //依次读取三个轴的数字量
    ; S  W9 D1 X, h1 g% N* z
  13. for(i=0;i<5;i++)        //前5次读取发送应答信号
    9 y. A1 u6 Z: Z
  14. {
    , g/ [# o" ?& D# `% c
  15. XYZ_Data[i]=_iic_ReadByte(1);" J5 V5 O" H4 Z% P6 B
  16. }
    ) o- J/ e: B4 c$ H- p# Y) N6 o. g5 I
  17. XYZ_Data[5] =_iic_ReadByte(0);  //不应答
    $ \8 |: a7 d7 ~4 x' U7 @+ P
  18. _iic_Stop();9 H6 K) {) l9 \" N5 V* ~
  19. 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头文件) R+ j- b5 p4 p
  20. }
复制代码

  f1 q; a% ]8 T
) Y% J$ `* w- q) E" n0 V: a0 T# t
配置好IO口,调用HMC5883L_Init()后,便可调用HMC5883L_ReadAngle()读取角度值,0~360°。
以下为测试时的截图:
272324479545732.png
( T6 e0 B" A( r7 {( K
7 c' J& z) H* D% P
测试时,模块比较灵敏且精确,稍微旋转模块便有精确的变化。由于该模块是基于对地磁场的测量,此模块容易受到其他磁场的干扰,比如将该模块靠近直流电机时,
便会因为电机内的磁场而降低精度甚至失灵(之前做智能小车时就遇到这个问题,要将电机内的磁场屏蔽起来才行)。

# Z2 x/ D! E$ y( ~: a5 v! d
收藏 评论0 发布时间:2022-2-9 20:25

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版