前言! j3 |& F% N" u) V+ y
ic-mu基本情况介绍
' K0 V; W3 x) c: N+ `
9 _9 C, v, }' yIC_MU是一款离轴的1.28mm磁编码器,主要用于电机控制居多,当作磁编码器,优势是能使用多种通讯协议(SPI,BISS,SSI),但是目前中文网上使用资料较少,因此我自己写一篇关于IC_MU的SPI通讯读取方式的文章,读取芯片为stm32G4系列,然后代码在stm32G4和stm32F1系列基本通用。
. U( \7 Q! d5 a芯片基本介绍如下
9 L$ E! M% \$ D0 a, ?2 p- b1 [7 I
! r, W1 Q# A. b
$ t* S; g, C' ~: B) v. |提示:以下是本篇文章正文内容,下面案例可供参考2 Y7 s$ w. B1 S
5 J+ [$ f# n3 p7 s
一、硬件连接/ t& ?4 u0 a2 E0 s
按最小系统连接。IC-mu需连接eeprom存储角度,供电为5V. t% P- s2 |+ X* k' O& X- }; G
' n+ A+ F+ h- K1 f9 @( |8 x# F
二、STM32 cubmx配置模式' a+ S7 p- m. ?# h" U2 S. d
STM32G491配置cubemx8 S$ \+ ^% J. S* Z; p( R
) p4 ` Q0 I3 N9 ~" q# r" B. T
- x' p) r: ?3 S/ U1 t z, _# m K1 U
; @; R [9 Z8 ^. _. m* V
; {$ R5 R2 R2 ?; ?2 j如图几个关键点# a/ T! D6 }8 S9 h) G# F* |9 u
1数值格式:可以选8bit,但是我觉得16比特配置更方便,如果要配8bit只需将数据拆分即可
% i" ^) o" x! ~3 v9 c2波特率 没有明确要求,12M以下都可以
8 z0 W/ v6 N% b5 F4 Y3SPI模式,SPI一共4种模式$ {. d9 ~' ?8 I9 i8 \
/ A& F4 v4 M0 S) Y; F, G- A# ?+ t
! y( h, G8 ?+ S2 g: A
0 Z8 k, w: e" \3 D- @9 R1 E; q+ ]
IC_MU只支持模式0和模式3,如上图所示采用模式3 CPOL选择High CPHA选择2Edge. ^- h8 c0 h7 p
% q- q( \: g0 ?8 d i
; X$ |2 Y: y5 s! @4 y; @) Q" W- @9 j
, s0 X2 ^6 q( `# T: s# d- R; u5 r
SPI通道要设置为高速
7 w! Y6 N7 T* v除此之外还需要设置片选信号,默认为高电平# J$ S; i0 Z- D3 d7 u) s
5 K# W, S* \4 \" V2 U( K
+ G2 s) T7 [. d* N
7 F" e; j5 U9 G" R& O+ K0 S4 L
三、软件代码及思路
+ |+ b5 e9 ]# l+ N首先需要对整体进行说明,需要将编码器激活,配置在SPI通讯模式
# v0 }5 A$ v; i# ]8 h
( i1 @0 U; x5 c. t. X1.寄存器指令介绍
9 }8 F5 [9 T5 U# h: X" g* E+ \2 s0xB083 Activate,激活
9 E* C) i6 p1 \" @' I" _, |0xA6FF Position Read 位置读取命令, ^( D1 u! a3 w# y# l* o
0x8A Register Read (Continuous) 寄存器读取(连续)( E! Q$ n# i- e& i& \9 F6 `9 t, r
0xCF Register Write(Continuous) 寄存器写入(连续)
( L0 K0 `1 r1 j% I: ]4 W" S$ ]& q0x9C Read Status 读取状态寄存器 指令
3 U" _3 V6 [' i$ v+ T0x97 Register Read(Single) 寄存器读取(单次)( ^/ I& ]! @/ t+ U
0xD2 Register Write(Single) 寄存器写入(单次)
% D& v9 B- T E6 j5 {) e) \$ S/ n
% y# k8 A& U- l6 ~) i( [
+ q) ~" c7 ~. i+ z1 B# X; e2.代码介绍
1 Z; d7 w+ _( l: u( s对片选进行宏定义,然后对SPI数据传输底层函数进行定义
0 \6 U9 ?" C# V! `* _5 u, c. v+ h( Y2 X
1初始声明和定义- #define SPI_IC_MU_CS_LOW(); HAL_GPIO_WritePin(ABS_ENCODER_CSN_GPIO_Port, ABS_ENCODER_CSN_Pin, GPIO_PIN_RESET); o: b4 Y, v F0 ]; U
- #define SPI_IC_MU_CS_HIGH() ; HAL_GPIO_WritePin(ABS_ENCODER_CSN_GPIO_Port, ABS_ENCODER_CSN_Pin, GPIO_PIN_SET);
' n* m. c. d8 \5 E
; z8 J) S4 F6 s6 q3 h+ |( O# k0 ~- uint16_t SPI_SendHalfWord(uint16_t HalfWord)
$ ^* v$ J* s' B; [ - {8 }( c- x6 u! |$ W
-
- d+ m5 w- p5 g; V6 D - SPITimeout = SPIT_LONG_TIMEOUT;" `, G% d+ e. m
- /* Loop while DR register in not emplty */4 V8 N7 b2 M2 ~1 d7 }" p! D5 `
- while (__HAL_SPI_GET_FLAG( &hspi1, SPI_FLAG_TXE ) == RESET)
& T3 q, o: B& k, T3 C. s - {
) D N* @/ H0 Y% r - if((SPITimeout--) == 0) return 0;
/ A0 }8 n/ e/ r9 q3 D - }# j" T+ f/ x" p4 g+ e; z E5 i
- /* Send Half Word through the SPIx peripheral */
. w: ~1 _6 z$ b# W - WRITE_REG(hspi1.Instance->DR, HalfWord);3 p/ g( z4 u) ^" o0 V( @! k" h3 Q6 ?
- * t9 T0 L% @! ]& T. `
- SPITimeout = SPIT_LONG_TIMEOUT;
4 ~1 t( D; r9 T7 e) t& ~ - /* Wait to receive a Half Word */
7 m$ N2 E7 U A* Q - while (__HAL_SPI_GET_FLAG( &hspi1, SPI_FLAG_RXNE ) == RESET)
, u2 u5 Z8 a5 M - {
; }# z1 o- I. I+ E% W; H D - if((SPITimeout--) == 0) return 0;# ?/ {$ ?. Q# R1 J/ c
- }/ O6 j5 Y" H" n. j8 j/ ?
- /* Return the Half Word read from the SPI bus */+ V7 K5 h1 N0 ?: g9 v5 o7 `& R! Z
- return READ_REG(hspi1.Instance->DR);
8 [& r; c t4 A5 @' h4 { - # A. L2 E( `& b7 j2 U" `
- }! B( E6 h- @ G
复制代码
: m( i% N: K. _0 o: f, w G2激活寄存器
9 f$ L# B. \/ w8 Q) g3 `0 f激活后才能对寄存器有操作1 E- f) q l) ^
- void ACTIVATE_FUN(void); J% G" D7 t. w- t4 b1 p, h
- {3 A& b s; w: h. d! a/ X
- uint32_t ICMU_Temp = 0;* X1 g& W M7 |) {& c
- SPI_IC_MU_CS_LOW();9 f7 z6 w9 _) C% L
- ICMU_Temp= SPI_SendHalfWord(0xB083);" F& ? ^5 H/ C! q; I6 D' D$ { j
- SPI_IC_MU_CS_HIGH(); ?/ N$ O" y2 x H) j5 j
- Delay(100);
/ n0 h2 P: t( J/ |0 n( J" U - }2 L; e: @1 H {1 Q
复制代码 ; D' E0 _0 E3 p! e8 U
3编码器初始化函数
1 c7 C& N1 @6 R N- Z: X, j初始化发送0xB083激活编码器,编码器配置为单圈14位,具体见数据手册+ X) d' t( L% I; V9 Q
初始化完成后可删除函数,状态会固化在配套eeprom种,不会丢失
' `% [3 X9 r! O' [# Q7 {& r- void Init_ICMU(void)! J1 ?1 d% G/ }" b
- {
+ y. }7 m8 q1 S$ T( ]2 B N - ACTIVATE_FUN();
, o' l* c6 K0 j1 P% n% f7 ]& U - uint32_t ICMU_Temp = 0, ICMU_Temp1=0;( w) F' w) F$ A. C' M2 H. {$ J4 M
- SPI_IC_MU_CS_LOW();
% p9 m0 ~9 r) K+ m/ V) n8 J - ICMU_Temp= SPI_SendHalfWord(0xCF00);
4 b n5 u% ^/ V - ICMU_Temp1= SPI_SendHalfWord(0x8E20);9 z' c3 M- W& z1 W0 |( E- }) x
- SPI_IC_MU_CS_HIGH();
9 ?: R7 U4 [7 s+ p - Delay(100);
" X; ]/ d4 X1 H% b. T2 @8 | - }
' k6 ^7 ~$ v% K' ^ a% W( a; @$ e
复制代码 # g* o- {/ C; c$ N& p+ G( I& D4 p
4数据读取
6 g; u5 X, R( b& b' O# V- t编码器数据读取,读取指令为0xA6
( o O. R8 z2 X F# E3 n- uint32_t SPI_SDAD_transmission_Fun ( void)& N6 y; A9 r1 y! O& V; x& q
- {. u2 I1 n& e \# Q* v
-
! ?+ c0 G# G3 L- p$ M - uint32_t Temp = 0 , Temp1 = 0, Temp2 = 0 , Temp3 = 0 ;, @. @/ X% n! ^5 p( T1 X' q% E) l
- ACTIVATE_FUN();( q% b+ c7 r( V( ?: v
- - y' \$ M+ m6 M1 ]
- /* 开始通讯:CS低电平 */ n* Q: i; j0 s+ O1 R8 i( {0 ^* a
- SPI_IC_MU_CS_LOW();
, C" |& [7 _/ U3 z: Y# t. K$ w - Temp1=SPI_SendHalfWord(0xA6FF);8 K* `+ i/ E# L' y/ \& b
- Temp2=SPI_SendHalfWord(0xFFFF);3 o6 |& e3 G" @# W
-
" P1 n1 i5 x2 d4 T9 g/ y. l, v - + ?/ W6 w8 x4 c0 w% @* u
- /* 结束通讯:CS高电平*/: p9 Z/ f- W$ s9 I6 [4 x8 ?5 _
- SPI_IC_MU_CS_HIGH();
- Z4 Q( D( @% Q# s7 [# D - 2 m S. B6 n- {3 ~) F: U! L# Y
- // Temp = ( (Temp1 << 16) | (Temp2 << 8) | Temp3 )>> 5 ; //读出数据,右移5位,共24位,有效位为19位 % J& E( a4 e/ X
- Temp= (Temp1 << 16| Temp2) >> 13; //总体32位 19位的话需右移13位
# g$ L; Q, U! R2 B - Delay(1000);; M2 h, }* S& @
- return Temp;1 @( g+ z$ S( ]6 e; h, x1 U# p, Y
- }" ]. W/ B$ E4 t$ h$ L
复制代码 2 [! o/ s3 B( X2 P
5角度计算
* {0 W( p8 Y' D: t* C1 t: `! b角度我用了11位,初始默认存在一个数值因此将他减掉了,然后按照360度进行划分 F2 j5 v# F8 H/ ~) W, I/ n3 L2 [' W
- float Position_Calce()
% H4 L2 J N8 e* f - {
, N9 d! _# F& t) w/ M5 Z+ Q - uint32_t a ;
$ w' o) g9 x5 v2 V - double b;
! Q: k, f' h1 Y+ d- y) h( o/ y - float c ;
: Y% z( G8 j) C - uint32_t www ;
4 [* s8 N9 C7 M3 K7 e# A0 p# v - double n ;0 Y8 a+ _, X: j7 g+ n$ {
- a=SPI_SDAD_transmission_Fun ();" a5 c! S1 z6 l+ m9 ?
- n=((a-0x00053000)/2047);//计算角度
2 J& }' B; F6 e. t, g - b= 360.000* ((double)(a-0x53000)/2047);
* C! V: `+ _% y$ @ -
9 | ~# K5 N# ` - return b; 0 \% V) U4 N- [5 a- H) M. `4 y# I* s
- ; M2 q5 g4 u2 v3 p1 o
- }
复制代码
- y' b' z& j8 z6主函数读取角度# K2 e. n) f1 i4 C$ ?/ z6 S2 B5 b
- float position_fk_f=0; //位置计算
+ G- l+ G( r3 A - 3 i5 s) j2 N" {
- while (1)
! K0 V! g" c$ Y$ A" t1 T - { `5 G9 _1 a% p# s% A6 Q! z
- position_fk_f= Position_Calce();, T- w, i* F! W, L4 i
- }
! b: ~9 e4 i# Y/ G1 W! |9 b9 A) b2 y
复制代码
% B. X3 N1 ]5 V3 p6 X总结' F( p% h7 K' h) \- B6 n
当你转动电机轴能通过SPI发送0xA6读取到数值变化,基本就算成功了,剩下的就无非是处理一下9 V; X+ g9 }, c k
————————————————' K! \ G- O3 K+ `4 \; X- \! Y
版权声明:超级馒头神; F9 N# H" I4 m* S0 E, L
' A6 T0 _, O- h0 r' J
* |( y8 P; Q. @. B: V5 D |
可以把完整代码发出来嘛