前言" y7 X1 R+ {4 z: b5 |+ |
ic-mu基本情况介绍4 e9 d, M( s' z6 U" i
& Y5 l4 a& {# t s/ P, @# N+ f% NIC_MU是一款离轴的1.28mm磁编码器,主要用于电机控制居多,当作磁编码器,优势是能使用多种通讯协议(SPI,BISS,SSI),但是目前中文网上使用资料较少,因此我自己写一篇关于IC_MU的SPI通讯读取方式的文章,读取芯片为stm32G4系列,然后代码在stm32G4和stm32F1系列基本通用。4 d$ B0 b) ]6 L
芯片基本介绍如下$ e3 k" T' _* N% t9 c- @( {
- i6 `' c7 ?' b. Z
; n- \. b* X9 F1 n% I0 \
0 M% h/ z# w" j7 \提示:以下是本篇文章正文内容,下面案例可供参考
: \/ x7 ~$ T o( d1 S2 K: _* |! H! u
一、硬件连接; P/ R( O/ f) P4 a; s5 C
按最小系统连接。IC-mu需连接eeprom存储角度,供电为5V7 A# x' S; r0 |8 `3 A( F
% B/ W$ ]6 f- W7 m! F. q: \2 l
二、STM32 cubmx配置模式
! H4 s, N3 { o3 ]STM32G491配置cubemx+ s+ a! o4 z$ m7 {& D" }( p- i
) R8 t! v7 X: y" n g! U$ b
" Y% ]9 D" V: c1 T+ }; k# Z
) V2 a, d/ {7 P) ^3 H! u. K
1 ~! k& N0 h+ V1 p& R如图几个关键点
; w$ T- ^1 Z* B$ `2 k1数值格式:可以选8bit,但是我觉得16比特配置更方便,如果要配8bit只需将数据拆分即可
/ b; B* w3 _6 T8 @4 p% F; y5 |2波特率 没有明确要求,12M以下都可以9 {5 Z @7 z4 H7 Q- [9 ?
3SPI模式,SPI一共4种模式2 l# {1 d( _- J8 @
' k3 s. \* \* M3 S* R
0 J( w! c* N9 Q% R# e O
& n, m d$ n: \% f }IC_MU只支持模式0和模式3,如上图所示采用模式3 CPOL选择High CPHA选择2Edge, R# N9 s/ q. V' S
! v! E" M+ d2 }6 S; W7 i. z
L8 t+ z' p5 D( C' |
" T0 N+ l2 G/ W+ F7 {
0 e+ y% W- X) a* h/ U
SPI通道要设置为高速' f* {" X, x# X8 q( h) k
除此之外还需要设置片选信号,默认为高电平
h$ e" _2 b. \! i( G; v; S
8 K6 o- A5 y" Y- f. i; u
" _3 F- E+ M" k( X3 m- _3 y: I3 u) w8 Y6 s
三、软件代码及思路6 M4 t. d k- R: i" _) a* x
首先需要对整体进行说明,需要将编码器激活,配置在SPI通讯模式
% n! c8 @1 h+ @) c9 C& L: E7 L4 o8 s( ?: r# g5 b
1.寄存器指令介绍- x6 F4 }6 r- X, O9 {8 W
0xB083 Activate,激活; b) C3 m2 c; j5 s
0xA6FF Position Read 位置读取命令
% W( H1 ^( o0 [ L) h0x8A Register Read (Continuous) 寄存器读取(连续)
/ h8 Y+ h& Z, K- q6 T4 W+ @0xCF Register Write(Continuous) 寄存器写入(连续)
. U/ G3 \0 B# E+ }. C# K: f9 d9 I" i0x9C Read Status 读取状态寄存器 指令 ]- n7 e7 V$ }& p
0x97 Register Read(Single) 寄存器读取(单次)
@3 P/ S7 K8 M$ g2 V0 j0xD2 Register Write(Single) 寄存器写入(单次)
/ U1 V' y! R0 s4 j8 ^
, g' w& m( E1 p' p4 v7 b+ _5 o
2 b3 X K" {+ L2.代码介绍
2 s# X# {" z% y, z+ t+ U C& L对片选进行宏定义,然后对SPI数据传输底层函数进行定义- B: s" \ c* U( t& i# b& d7 X
+ `0 k' K0 c: A- I3 e) o
1初始声明和定义- #define SPI_IC_MU_CS_LOW(); HAL_GPIO_WritePin(ABS_ENCODER_CSN_GPIO_Port, ABS_ENCODER_CSN_Pin, GPIO_PIN_RESET);8 m7 i0 p1 g: U0 H* U; m
- #define SPI_IC_MU_CS_HIGH() ; HAL_GPIO_WritePin(ABS_ENCODER_CSN_GPIO_Port, ABS_ENCODER_CSN_Pin, GPIO_PIN_SET);7 y7 q8 A! Z1 B4 e* k2 ?
$ h. L3 F! v6 @6 [; c6 c% y- uint16_t SPI_SendHalfWord(uint16_t HalfWord)1 f x" C7 {. A4 p
- {
6 ^0 r2 P, d( S - 8 `% W) g h2 u
- SPITimeout = SPIT_LONG_TIMEOUT;5 E7 k ?. I0 R. H
- /* Loop while DR register in not emplty */# V; F; W& x( r; V" F3 Q" Y
- while (__HAL_SPI_GET_FLAG( &hspi1, SPI_FLAG_TXE ) == RESET)4 B0 j( j9 Q$ e7 w1 D: A$ ~
- {% E0 t+ d9 @' g5 ~, a
- if((SPITimeout--) == 0) return 0;. T. V, w& ^! C% T" b
- }
1 j8 T: T& Y* I6 @$ i, o1 K" q5 \. D - /* Send Half Word through the SPIx peripheral */0 u, z8 E% x; z$ E# Z W( Y2 s" v
- WRITE_REG(hspi1.Instance->DR, HalfWord);
# @/ E% E k- }- J+ r, U+ z0 Q* Q - 3 {' z% K1 c6 t& Q' ^
- SPITimeout = SPIT_LONG_TIMEOUT;
! Z2 {- U- l! c; c - /* Wait to receive a Half Word */* L* m# F7 _' l5 z
- while (__HAL_SPI_GET_FLAG( &hspi1, SPI_FLAG_RXNE ) == RESET)
$ ~* }3 O5 }. f) u+ R$ J - {
1 A, V9 x/ f$ f. \5 k - if((SPITimeout--) == 0) return 0;
2 W" q, r3 J* b - }8 }5 F& H- `6 v& w z
- /* Return the Half Word read from the SPI bus */, z. y. _, ]: k h
- return READ_REG(hspi1.Instance->DR);
K3 o: O) O7 H3 q* s! J* ? -
! k% b( [2 S( f, H - }
) z1 Z8 g& ] V8 H
复制代码 7 K/ O# x" `2 E3 D3 I
2激活寄存器
, I# h8 `, A1 p$ P激活后才能对寄存器有操作% G/ ~6 ?7 A; L' ~: E3 ~; Q! s
- void ACTIVATE_FUN(void)
' r9 m) @$ I7 o* l - {
4 d) _$ N; B" y# C }5 d - uint32_t ICMU_Temp = 0;
4 A( S1 c/ s6 a& A - SPI_IC_MU_CS_LOW();. y! E% T4 w" l3 c e! k
- ICMU_Temp= SPI_SendHalfWord(0xB083);1 z( d- C9 b! p$ Q4 a
- SPI_IC_MU_CS_HIGH();; D; _4 f" d3 x4 u/ l
- Delay(100);' {) e( G5 K" x
- }
) [/ M& w1 Q1 M/ F3 }' ~# t6 M
复制代码
+ B" e+ F8 {% e+ P3编码器初始化函数
' R( T8 e( L. C2 L; w初始化发送0xB083激活编码器,编码器配置为单圈14位,具体见数据手册0 ]7 E( J- }9 ^/ R, e3 B
初始化完成后可删除函数,状态会固化在配套eeprom种,不会丢失! B! x1 U- y9 k) m& e: N1 b
- void Init_ICMU(void)$ F2 N" [3 [; g. E( t8 w* j
- {
$ u- r4 r) l/ M. {# S: i# D3 ^ - ACTIVATE_FUN();: Y4 j# S$ [1 T, E$ o
- uint32_t ICMU_Temp = 0, ICMU_Temp1=0;
. v0 L$ b+ J( M ^$ ?/ w - SPI_IC_MU_CS_LOW();/ y* a0 c- o7 {& O
- ICMU_Temp= SPI_SendHalfWord(0xCF00);( C T4 j" Z; g/ F7 q& o
- ICMU_Temp1= SPI_SendHalfWord(0x8E20);0 }' k- `" n# V2 V
- SPI_IC_MU_CS_HIGH();
6 f- Q6 e3 X8 V# p - Delay(100);! y2 U3 Y' F& V; j% A
- }. ?; V- Z5 d& U1 s4 q1 G
复制代码 0 }" o6 u! i, S C. L' m
4数据读取
/ f7 H6 [) X4 K- T3 ~+ F编码器数据读取,读取指令为0xA6
6 s2 h: }2 C6 V- uint32_t SPI_SDAD_transmission_Fun ( void) F: ?% H7 P9 |
- {4 O& S( [, C$ H9 _9 l- x# @3 N _$ ~
- ) F3 s3 p/ g3 z% t
- uint32_t Temp = 0 , Temp1 = 0, Temp2 = 0 , Temp3 = 0 ;1 B" N ^* }6 J: @$ j
- ACTIVATE_FUN();
$ N2 E1 H; k3 o7 r# z - 2 \$ b/ b4 \8 M2 j
- /* 开始通讯:CS低电平 */, W ]. m* g' V% h: B
- SPI_IC_MU_CS_LOW();
# ~# I# l) G* G0 @ - Temp1=SPI_SendHalfWord(0xA6FF);
1 P2 f- p. v- H% L+ K6 ? - Temp2=SPI_SendHalfWord(0xFFFF);4 L6 ]; C, f( h( y
-
' e, C& S6 i7 n: | - 3 q. e) @1 X0 ^* h/ ?
- /* 结束通讯:CS高电平*/
8 S) L+ [6 `) `$ f* c - SPI_IC_MU_CS_HIGH();
4 _$ x4 S: e* o0 v -
; y: a0 F# D2 n7 s3 w. y* P - // Temp = ( (Temp1 << 16) | (Temp2 << 8) | Temp3 )>> 5 ; //读出数据,右移5位,共24位,有效位为19位
2 a8 z3 V# L5 [. A8 T9 T ]) s6 b - Temp= (Temp1 << 16| Temp2) >> 13; //总体32位 19位的话需右移13位
5 s* k9 p. p" y9 @6 Z - Delay(1000);: e' |7 E k3 J U
- return Temp;- ^: H7 @* [ w* P9 l P
- }
# r/ s. S0 |0 v
复制代码 4 H0 b. }$ Z* S r8 p
5角度计算 T. D7 o6 U1 S* v; V, V: V$ [- y& e
角度我用了11位,初始默认存在一个数值因此将他减掉了,然后按照360度进行划分* ~( [4 {/ K& R. Y% q6 @
- float Position_Calce()
, b! F" Z5 T; R6 U7 _1 h# L - {% A- ^3 B }; ~8 \8 G
- uint32_t a ;8 ?4 i0 X3 w8 Q0 z, {4 B6 _
- double b;7 L7 k' b! d/ J3 y: D
- float c ;
8 m9 {; w% @1 [$ B8 j - uint32_t www ;! x5 T3 s7 H2 \+ J3 v; k0 u* I
- double n ;' G; j, y3 t6 n
- a=SPI_SDAD_transmission_Fun ();" ?% M( V9 D1 I: K- Y0 ]
- n=((a-0x00053000)/2047);//计算角度 X! ?4 j- H- Y$ }* ]# E; y! B
- b= 360.000* ((double)(a-0x53000)/2047);
: b( g; F2 \! a- Y" G6 W -
5 Q: D4 W7 I$ C* K% M - return b;
7 v4 H; |2 a& D) c$ {4 } -
, H' o U7 Q$ m8 H) q2 C6 b, D - }
复制代码 6 V6 ~! \6 v, m, F1 d: t
6主函数读取角度
6 b: |2 e: k1 b, U6 p8 N0 b- float position_fk_f=0; //位置计算
- K1 h! ~0 ^* S! i5 e -
( L- T$ J* L1 H - while (1)# l+ t P" `& n& H+ f
- {
4 _- |! |+ _8 b8 c; D# ~; M - position_fk_f= Position_Calce();" ^3 b3 \$ k2 A. j' [# C" r
- }3 p1 i2 o3 X3 M9 ~" F# k5 e
复制代码
+ ~( w/ {! L! y% i1 R总结" K" Q4 ]0 [& |! ]. }
当你转动电机轴能通过SPI发送0xA6读取到数值变化,基本就算成功了,剩下的就无非是处理一下/ ?3 C) r& Q0 n) X6 u7 Z
————————————————
* l4 j, s3 X9 H2 N版权声明:超级馒头神
, e- j# q% d$ z* N0 d( U, Z3 [, \6 w* P/ Z, s( z3 H& _9 N
, j, O* ]7 M* P( v |
可以把完整代码发出来嘛