前言) t: J8 _& K6 n6 H
ic-mu基本情况介绍; Y" R. `8 T K. g! Z: p- y( Q4 L
- a9 R- c5 P$ @% d) ~ |
IC_MU是一款离轴的1.28mm磁编码器,主要用于电机控制居多,当作磁编码器,优势是能使用多种通讯协议(SPI,BISS,SSI),但是目前中文网上使用资料较少,因此我自己写一篇关于IC_MU的SPI通讯读取方式的文章,读取芯片为stm32G4系列,然后代码在stm32G4和stm32F1系列基本通用。
0 F" n4 M2 s( W* T* |' E; w+ L芯片基本介绍如下. S) I1 p8 L. l
2 d. V; p1 i3 v1 B9 b; v: t5 Y
) f8 M9 P: w$ V: }, I# ` K$ j
# R: x ^* ^' [7 ?+ [- h6 a, O
提示:以下是本篇文章正文内容,下面案例可供参考
; F, Z! a8 l$ v; b" X/ X6 m+ x2 J9 S `4 {
一、硬件连接. Q9 j5 l4 `- ?7 o0 _4 J
按最小系统连接。IC-mu需连接eeprom存储角度,供电为5V6 A5 T! ?$ v# e8 d
7 s& x9 F' a/ U二、STM32 cubmx配置模式
! G3 l: l! b$ y+ Z4 G! N' uSTM32G491配置cubemx
3 Z' O. q; `6 W
$ _. r( K2 B. \; O$ [9 D; [
: L% ?+ h) O& N: F! c8 o) `+ G: K/ G6 X) {5 D8 p
4 y- e2 }8 X9 m如图几个关键点% M w6 _ H7 e" c2 y1 W) F; K: ?$ H
1数值格式:可以选8bit,但是我觉得16比特配置更方便,如果要配8bit只需将数据拆分即可' }. d: L, B4 i c* E4 K: e9 g
2波特率 没有明确要求,12M以下都可以2 c0 f: Y9 c( H
3SPI模式,SPI一共4种模式
! l) _2 u/ ?" n3 @$ f. X1 r! M b$ p( U" v4 M6 l" K; `
6 N" w4 U, p. G8 R3 G, M
! z2 b6 N; W$ e% Q+ NIC_MU只支持模式0和模式3,如上图所示采用模式3 CPOL选择High CPHA选择2Edge4 b- q: }3 O2 k. W7 R
' o) ]# z( a0 W' }( G/ @+ Y% g# x/ w
9 \# F9 S) Q+ }. l- E% D$ d) H# y" x h; h- i
. j5 `- Y/ \: `3 f0 I3 n' L' J1 `4 u
SPI通道要设置为高速, ~2 z9 j4 |! H+ y* c
除此之外还需要设置片选信号,默认为高电平* I0 p9 `7 Z( x$ h
! t$ i3 \1 l8 g0 w* U6 r- v
! D4 ]: K& a, h2 _1 B, j- n3 i+ f6 x. y" P5 l7 \
三、软件代码及思路# A! t- l) p$ u1 A) ~; L' y
首先需要对整体进行说明,需要将编码器激活,配置在SPI通讯模式2 F7 N* q+ I+ H' }- R
# ?( Q: B, B8 _7 H6 ^
1.寄存器指令介绍: j, O6 U& L! i p. D1 U, [
0xB083 Activate,激活
+ {3 p/ |+ U' d- p. s0xA6FF Position Read 位置读取命令- l+ o9 R- `* f+ K% T/ T
0x8A Register Read (Continuous) 寄存器读取(连续)
& ]) y; |6 \0 G+ k7 u5 g0xCF Register Write(Continuous) 寄存器写入(连续)
: E( F: T( @" Q1 _2 M6 G0x9C Read Status 读取状态寄存器 指令
4 T5 |% {8 V4 l1 d5 W7 V4 }. e0x97 Register Read(Single) 寄存器读取(单次)
2 I9 m; U: B& ?" }3 ^( C- d* _0xD2 Register Write(Single) 寄存器写入(单次) y" |/ I/ N3 v
6 n( L5 r3 _: r, n, ^
$ k2 e& o* @. L+ y% |
2.代码介绍) n5 t! R% R2 ]9 \" X
对片选进行宏定义,然后对SPI数据传输底层函数进行定义
$ z# U5 d" x" J9 M( |- F* u0 Q" \( Z. C# z1 o
1初始声明和定义- #define SPI_IC_MU_CS_LOW(); HAL_GPIO_WritePin(ABS_ENCODER_CSN_GPIO_Port, ABS_ENCODER_CSN_Pin, GPIO_PIN_RESET);
' V* m7 i. d$ Z; [! I5 Z; q - #define SPI_IC_MU_CS_HIGH() ; HAL_GPIO_WritePin(ABS_ENCODER_CSN_GPIO_Port, ABS_ENCODER_CSN_Pin, GPIO_PIN_SET);
9 Y2 N+ M" e& F' t8 `. V- L - ; W% D r# t1 l1 H3 ~% `+ C. } S& d4 D
- uint16_t SPI_SendHalfWord(uint16_t HalfWord)- h% I, E- F, q: m/ c
- {6 o0 I, { G, N) y$ H
-
4 b( Z4 Z' d) J N - SPITimeout = SPIT_LONG_TIMEOUT;6 ?% ^/ u- w1 U1 q
- /* Loop while DR register in not emplty */: w5 C+ q X2 g0 J. i6 ` G
- while (__HAL_SPI_GET_FLAG( &hspi1, SPI_FLAG_TXE ) == RESET)5 K6 x% m U# y, L- b0 Z( c' k$ H
- {
: d2 i) D3 u' d" \ - if((SPITimeout--) == 0) return 0;
( x; f' m9 P$ E - }
7 E5 n, p- B( y( w# U - /* Send Half Word through the SPIx peripheral */( r* a+ e: j4 T' ]: k3 J( M3 Z
- WRITE_REG(hspi1.Instance->DR, HalfWord);( v L: W$ r& v% j: J7 R
- 5 |) F- E. P% J0 X0 U1 S* d
- SPITimeout = SPIT_LONG_TIMEOUT;
) s) I8 X; q% q/ H - /* Wait to receive a Half Word */3 V; p$ z; q8 Z8 E* T& I
- while (__HAL_SPI_GET_FLAG( &hspi1, SPI_FLAG_RXNE ) == RESET)8 {- l% N; T5 l9 {5 N( r) z% N5 q
- {$ T; H. r' h0 R: S. u
- if((SPITimeout--) == 0) return 0; @, L3 W% V0 r- V
- }2 K$ f, y0 k5 i- q+ _* N
- /* Return the Half Word read from the SPI bus */
7 h: }! l) U; ~! p* j% \; _ - return READ_REG(hspi1.Instance->DR);
% E) n. B0 \/ d# s/ L' p -
R, P D. s/ i - }
F, b v, {; ^
复制代码 " M; }9 X: p7 g$ {/ l
2激活寄存器. R8 o% u. j5 g3 z! ]4 x# e s
激活后才能对寄存器有操作2 k3 O# i' X$ [. h, b1 N6 K, \% m' U
- void ACTIVATE_FUN(void)
0 n1 U/ _7 B+ l4 \0 x - {
5 U. C/ n# \% J. W" b. y2 v - uint32_t ICMU_Temp = 0;% z+ \. G6 U6 K0 d7 o% P, g1 q# @
- SPI_IC_MU_CS_LOW();2 |% P, z Z- R0 u
- ICMU_Temp= SPI_SendHalfWord(0xB083);
9 h8 J2 N. E8 W4 Z% N - SPI_IC_MU_CS_HIGH();
; H r. I" ]5 J1 ?9 n - Delay(100);7 ?( U; m8 l" D1 J
- }
& O5 W8 m. f$ c" v
复制代码 5 Y4 r8 P/ @2 l* b
3编码器初始化函数: H. g! b c& W+ W% X
初始化发送0xB083激活编码器,编码器配置为单圈14位,具体见数据手册
& o3 _: h# f' P& t3 S+ O% C初始化完成后可删除函数,状态会固化在配套eeprom种,不会丢失( V& }' v9 x/ i* x9 t& r
- void Init_ICMU(void), b+ F3 I9 [. D1 I+ N% e
- {
) L% @3 _8 b# U; X6 z; b2 J% r - ACTIVATE_FUN();5 T5 M3 J, r2 C$ M; f' J7 b+ A
- uint32_t ICMU_Temp = 0, ICMU_Temp1=0;
! b# T# m5 l7 ~: k- e: _' Z, W - SPI_IC_MU_CS_LOW();+ T- e, R" g# d3 C! W
- ICMU_Temp= SPI_SendHalfWord(0xCF00);3 X4 A2 m( u% X& S1 `& T
- ICMU_Temp1= SPI_SendHalfWord(0x8E20);
6 F( }, Y, q# a8 M - SPI_IC_MU_CS_HIGH();
3 a$ Z$ y( |, V# @, | - Delay(100);8 F8 |% D1 d) A) w
- }# y6 [, V0 V& [: y
复制代码 7 h( @1 X: k: T
4数据读取
6 k( ]1 K1 `0 ]1 C0 r. v T! ?编码器数据读取,读取指令为0xA6
, K# | J1 i+ l! t, ~/ R2 }- uint32_t SPI_SDAD_transmission_Fun ( void)3 f% B+ s* l: B1 d
- {
0 D8 w9 K) P8 L4 S0 g - ! y* G+ l0 F$ w7 J3 r, X7 ~
- uint32_t Temp = 0 , Temp1 = 0, Temp2 = 0 , Temp3 = 0 ;/ I' a, @/ @* a0 R2 i0 m
- ACTIVATE_FUN();
' B9 N5 K4 |; N2 e7 O - + M3 k2 h$ o- s% q! c$ U
- /* 开始通讯:CS低电平 */
6 r$ [0 P6 P# C- v$ i - SPI_IC_MU_CS_LOW();7 v; L. h: W( }5 B" {" H4 b. Q
- Temp1=SPI_SendHalfWord(0xA6FF);7 U5 n) n' e3 O b- u& w9 n
- Temp2=SPI_SendHalfWord(0xFFFF);2 A: o* Y8 V+ w' f5 J2 Y
- 2 t( r, k' ~$ V8 @3 e# x7 I
-
p7 @0 T# g- g2 w - /* 结束通讯:CS高电平*/" C; J; z& g0 z/ y1 \* L
- SPI_IC_MU_CS_HIGH();
, i. c8 D6 q8 O2 \$ s - 5 @& F/ ]/ p" @4 f1 S4 R6 J
- // Temp = ( (Temp1 << 16) | (Temp2 << 8) | Temp3 )>> 5 ; //读出数据,右移5位,共24位,有效位为19位 ! k1 h0 M3 l J ?1 B7 q7 J
- Temp= (Temp1 << 16| Temp2) >> 13; //总体32位 19位的话需右移13位$ B1 n6 V4 |: A' Z& t
- Delay(1000);
% |7 S" ?: ^- B- { - return Temp;
; F& \3 K# v5 H4 e* l$ L; k! f - }
% p1 y4 _2 s7 K# B& S
复制代码 + n) u! W0 [& s: t
5角度计算
* z# E4 A6 I- u. S7 Z, x {) o( q角度我用了11位,初始默认存在一个数值因此将他减掉了,然后按照360度进行划分
( s/ p, l- A3 w# t# |; F- float Position_Calce()
8 G- H6 \( N4 o# ` - {, G2 _1 x0 z7 V9 s8 ~2 P) S+ S
- uint32_t a ;
) U S7 Y, S( E% D. {' v) i4 J3 _ - double b;4 B: V2 D/ B; E8 t4 a: p
- float c ;0 L- V# J/ v% W3 R3 u
- uint32_t www ;
3 n% _6 D$ P) F+ {2 t T, @: ]* @" y - double n ;
0 ?7 y8 E$ M% [2 ]2 g9 q9 v - a=SPI_SDAD_transmission_Fun ();
' s% R) E! m0 x - n=((a-0x00053000)/2047);//计算角度/ G8 \% p9 @: T1 N: `
- b= 360.000* ((double)(a-0x53000)/2047); `6 U! U* O4 @/ r0 i6 n5 N
-
1 R' D; \0 ?2 S4 F6 q - return b;
% A8 M8 G0 N7 z X& N! D7 `, b - : {4 M. |8 o2 Q9 [7 T6 R
- }
复制代码 ! d0 l, C" s, R& m2 _. @0 k
6主函数读取角度% b* Y2 ~/ y$ i& a
- float position_fk_f=0; //位置计算
! B) j% i" T, R: G& j% z. P4 A -
: v' u/ O% B# @ - while (1)
3 W1 c4 z8 l3 e6 Z2 j3 J2 ~ - {
% z" ]; ^# u; ^% }4 o - position_fk_f= Position_Calce();$ ]) m3 Q# F# c
- }
( e' Z% k) p* m1 k( Q6 C6 B
复制代码 . |: T- p, Y2 @7 }3 D' o/ I
总结$ q0 K+ `8 I5 G, e* R+ q r. G- \/ v) y
当你转动电机轴能通过SPI发送0xA6读取到数值变化,基本就算成功了,剩下的就无非是处理一下
( W5 V5 m+ v' V————————————————
7 R! H; H# w+ b. [版权声明:超级馒头神
4 Z5 x2 a& s4 }( X3 I5 S
2 _" U/ M8 r6 `8 S l' I, T, s( K- |) {% v) F1 E$ T
|