前言
* `3 ^( A, S( F, e% R5 Zic-mu基本情况介绍# k/ W5 M% `, _8 u! U$ j. A
' H! e$ k2 [" z5 e, U
IC_MU是一款离轴的1.28mm磁编码器,主要用于电机控制居多,当作磁编码器,优势是能使用多种通讯协议(SPI,BISS,SSI),但是目前中文网上使用资料较少,因此我自己写一篇关于IC_MU的SPI通讯读取方式的文章,读取芯片为stm32G4系列,然后代码在stm32G4和stm32F1系列基本通用。9 s5 z1 T P1 Z/ Q, D! k
芯片基本介绍如下1 b/ f/ q9 v4 e; F. f
: L; k" S2 L0 J' V
' }; R2 [+ y, j/ |2 @/ C- h( e/ U
" s K- p9 @# {3 d
提示:以下是本篇文章正文内容,下面案例可供参考: c$ Z# A. r j, S5 Y T
h3 U. e- M R
一、硬件连接4 w0 F! l5 H7 \3 }
按最小系统连接。IC-mu需连接eeprom存储角度,供电为5V
. a5 S2 n4 e# D6 [2 V4 G& |5 m" q! R r' Z$ c# w
二、STM32 cubmx配置模式
* A; i& a* t9 c6 w( D! x; F& a4 J* RSTM32G491配置cubemx+ [: i, Q8 u: Y) H! k w8 l* x4 K' E7 T
2 ?/ `3 }$ V1 p5 w" T' u
: y. E. m! ?1 _& H* ^/ f# |
7 Q+ j1 f8 X& b% V- j/ O/ @, r( R, s; ]% {& t8 l# |$ b$ u
如图几个关键点" L& l; d( S. J5 N1 c! r
1数值格式:可以选8bit,但是我觉得16比特配置更方便,如果要配8bit只需将数据拆分即可2 }$ B# k: X- K2 I
2波特率 没有明确要求,12M以下都可以
2 ?9 h( J* C" l& A) {3SPI模式,SPI一共4种模式
8 ]$ b) L2 g% ]3 I( X% g: b% o5 o( t4 A2 n
: x% s# G' M' B$ \4 {' @% v- R/ W8 Z X1 B6 g# \$ c# O, R5 f7 s: u
IC_MU只支持模式0和模式3,如上图所示采用模式3 CPOL选择High CPHA选择2Edge- B% U% o6 x8 \% B8 G
5 G# Z$ L4 ^0 d/ q$ L. t0 B
3 O: E" j# ]+ h' q! g% o
5 H: z$ m# {# j& I2 v7 M7 u
6 L# a" n+ Q# d5 s( b- nSPI通道要设置为高速8 x- m1 e) x8 e6 |: E0 Q
除此之外还需要设置片选信号,默认为高电平
! V1 e0 X. Y7 n# J! a) Y! E
& d) v# f. V8 V1 P' u
! D# {( V5 v+ s3 B0 S$ D! y
( n) U! h! A1 P: P' E1 W6 Y
三、软件代码及思路; c8 J7 P4 ?1 y" S5 ?9 p
首先需要对整体进行说明,需要将编码器激活,配置在SPI通讯模式! n# t$ {3 t3 ]2 p; x% k
1 L6 G/ q. n ?* `. R+ i$ O1.寄存器指令介绍
& q; ~1 { K X$ X0xB083 Activate,激活
' x' P6 U; S% W1 I, U% U: x' G0xA6FF Position Read 位置读取命令
: g1 S; b/ ]( m5 m! q5 i0x8A Register Read (Continuous) 寄存器读取(连续)
( Y# f* X9 x* A' V# m0xCF Register Write(Continuous) 寄存器写入(连续)
; D4 M' }* U n V6 w1 D0x9C Read Status 读取状态寄存器 指令* L k3 b# P- _1 |9 z" x, S
0x97 Register Read(Single) 寄存器读取(单次)$ j$ F: B7 d3 |) x7 t$ w; z
0xD2 Register Write(Single) 寄存器写入(单次)
- i1 @& t: x* H/ P2 Q! Z; L8 C/ G5 U; ]6 T$ J: D1 M% L; Y3 X9 }
* S9 G3 @( \1 b* k) u' J
2.代码介绍# J5 w0 f5 y. ^$ X, U" @
对片选进行宏定义,然后对SPI数据传输底层函数进行定义
5 `$ H5 r2 s h" j9 I7 I* }( `; f M5 v
) r# D( P1 _; H3 D& s9 T1初始声明和定义- #define SPI_IC_MU_CS_LOW(); HAL_GPIO_WritePin(ABS_ENCODER_CSN_GPIO_Port, ABS_ENCODER_CSN_Pin, GPIO_PIN_RESET);
% I9 ~, t3 V* N0 U+ ]& O) F8 ?4 D+ L - #define SPI_IC_MU_CS_HIGH() ; HAL_GPIO_WritePin(ABS_ENCODER_CSN_GPIO_Port, ABS_ENCODER_CSN_Pin, GPIO_PIN_SET);
, j, m. E6 ^7 d. \" ] - # r/ L7 w- O: L4 t+ `
- uint16_t SPI_SendHalfWord(uint16_t HalfWord)
* m. J; x; h+ f. N8 x ?9 _) U - {
8 J+ P8 a- Q3 X$ f: ` -
% D% O. d* D' U: _4 x - SPITimeout = SPIT_LONG_TIMEOUT;# z) n) A. `. T, `
- /* Loop while DR register in not emplty */ C3 U" o( f) K B8 q. {
- while (__HAL_SPI_GET_FLAG( &hspi1, SPI_FLAG_TXE ) == RESET)
8 p1 H4 Q9 z( Z T- T - {* H9 L2 R" q/ }! H% B( }
- if((SPITimeout--) == 0) return 0;6 U: t( Z2 t! {; s! h1 a
- }
1 u0 E: s/ L# I5 m3 p, A4 f X7 G - /* Send Half Word through the SPIx peripheral */- r1 V5 y! e& s
- WRITE_REG(hspi1.Instance->DR, HalfWord);
5 o3 ^9 _& p! o8 p - - p& n( O) ~& H% W, _; \( }+ i
- SPITimeout = SPIT_LONG_TIMEOUT;" w+ m8 K) C9 |
- /* Wait to receive a Half Word */1 M0 v _, ^4 Z% o8 m) ?
- while (__HAL_SPI_GET_FLAG( &hspi1, SPI_FLAG_RXNE ) == RESET)
5 A- O5 f8 z) n; U3 c/ ` - {% m0 w1 t! }3 ?; l' Q
- if((SPITimeout--) == 0) return 0;
1 z8 h* F3 k' H; W - }" M$ o5 f6 u# P9 X8 [7 V2 s
- /* Return the Half Word read from the SPI bus */! }% {2 N* L1 |1 a% R* @" \. f
- return READ_REG(hspi1.Instance->DR);
. Y2 a$ u: a9 a0 b' R# w -
, O' h" {% k7 V3 i/ C1 a - }3 N. o e& u. J
复制代码 " u1 T; }/ W" V' p
2激活寄存器( P- p; k$ b' H4 C* Q! ]
激活后才能对寄存器有操作7 C% [! T! R/ v0 b# c; q
- void ACTIVATE_FUN(void)
7 p9 N; e/ q" o - {' U0 ?& N- d/ _/ r& U7 }. T
- uint32_t ICMU_Temp = 0;
) T6 h3 S; S2 D9 g- } - SPI_IC_MU_CS_LOW();
) @( O3 Y9 z+ \1 ]0 H. v* w - ICMU_Temp= SPI_SendHalfWord(0xB083);, B9 d. u, H& e
- SPI_IC_MU_CS_HIGH();) D4 C2 u1 n8 X% Q
- Delay(100);/ x Y6 e, B: o- c
- }5 L( B7 S: W8 E9 m6 R' S9 o* e
复制代码
$ O8 T2 d2 o8 f3 P9 i4 M, M4 |" N2 Y3编码器初始化函数- E8 i+ t( m* i" Q* p
初始化发送0xB083激活编码器,编码器配置为单圈14位,具体见数据手册% L; j- w/ }, x& `4 f2 `
初始化完成后可删除函数,状态会固化在配套eeprom种,不会丢失; x( d) K, X, L, U! x
- void Init_ICMU(void)
! H8 A- }* F- x+ r0 q% t - {
2 V% o- W: Z$ b `1 c - ACTIVATE_FUN();6 [- O i: V: T+ t4 t0 |, l/ k
- uint32_t ICMU_Temp = 0, ICMU_Temp1=0;
3 s/ Z7 `, E- [( u8 r& y - SPI_IC_MU_CS_LOW();, h7 a, Z0 }9 l3 H D$ E! k6 _
- ICMU_Temp= SPI_SendHalfWord(0xCF00);% v# F0 a, m/ c' A; H0 P# X
- ICMU_Temp1= SPI_SendHalfWord(0x8E20);. s" @$ O6 ~: W6 y0 c2 T- _
- SPI_IC_MU_CS_HIGH(); @' f+ l% h2 r+ W+ z/ Q
- Delay(100);5 M1 ^2 `* \$ o5 {
- }
) e! w2 V; ^, k
复制代码 j Q5 d0 m: k6 C
4数据读取, M6 P# S/ T3 X, Q; u; o L4 D
编码器数据读取,读取指令为0xA6- V5 Y$ `* o2 ]4 Z( _ {% j
- uint32_t SPI_SDAD_transmission_Fun ( void)
% G! G, X$ Y9 N1 c% U- S2 e - {& b2 _5 o+ b; I8 w- l' B$ D) L
- , X" d/ l9 p7 O
- uint32_t Temp = 0 , Temp1 = 0, Temp2 = 0 , Temp3 = 0 ;
' x# a: [ C! }! a - ACTIVATE_FUN();+ L5 g( ?" m' D5 W4 M2 }, d
-
# c8 n5 y% }# a2 [% b4 {9 g0 k. U1 Q - /* 开始通讯:CS低电平 */
0 W# J/ L C* L - SPI_IC_MU_CS_LOW();
, T; m5 @& P: b5 {9 R6 A - Temp1=SPI_SendHalfWord(0xA6FF);
, ?6 I& X* H% A, L( p: b5 M0 P - Temp2=SPI_SendHalfWord(0xFFFF);8 g7 F ~" @+ W( g' @. V, [2 v
- ( p3 n0 [3 T' e9 i
- ) K1 m6 e- ^) }6 o' y3 z
- /* 结束通讯:CS高电平*/3 R- O8 A3 `6 f2 A& j( L
- SPI_IC_MU_CS_HIGH();2 W7 }0 A- ?% |! \8 b0 `6 i
-
P# k2 H6 |. V+ ~' H( h# S - // Temp = ( (Temp1 << 16) | (Temp2 << 8) | Temp3 )>> 5 ; //读出数据,右移5位,共24位,有效位为19位
' [6 d& n+ |9 a- j. C - Temp= (Temp1 << 16| Temp2) >> 13; //总体32位 19位的话需右移13位
% [% u. `4 w2 O% f3 A+ [ - Delay(1000);3 a5 k0 t7 B) v# f# N3 L- G
- return Temp;
0 x3 w V3 d' R# a+ B# g7 W3 Z - }
9 H% d4 X% W* ^0 H4 C
复制代码
, {/ {- m7 [) v' t* I/ t5角度计算0 R2 @& c0 g: r- P% z# z
角度我用了11位,初始默认存在一个数值因此将他减掉了,然后按照360度进行划分. x5 x, g B) l5 N
- float Position_Calce() z" I& G- r5 v/ e4 ^8 t
- {% V# N7 k8 m- f% i d" H! _
- uint32_t a ;
3 Y1 S8 t7 j$ ~5 n" G1 N9 F - double b;
3 u/ D& h4 @2 `, L - float c ;
t* d! ?, D A9 I9 C! O/ k - uint32_t www ;
# ~( v3 m9 _2 v3 o" K" q1 s3 \ - double n ;
. [; \& ^6 I: r0 [" s# m" J - a=SPI_SDAD_transmission_Fun ();' T$ r" u8 o- d3 v! Q9 y3 H
- n=((a-0x00053000)/2047);//计算角度
- ] a4 {$ _( r5 R. Y( d - b= 360.000* ((double)(a-0x53000)/2047);$ M L+ O3 l5 x6 q) o
-
! S$ p9 Q; F5 r0 C0 I5 g! N - return b;
* _% D$ W: h j* y# p8 }) v; p+ M! ? -
* w' M2 x5 e: n6 y. Y2 i - }
复制代码
: y" N3 }+ }! c6主函数读取角度
! U' a7 A1 a% o6 I- float position_fk_f=0; //位置计算7 `7 x6 q9 I( [; \0 P( z" j
-
2 Z6 A$ B& y3 X( |; e: i" H! |3 C7 u - while (1)* l q6 _7 ]$ w" M/ p' m
- {
+ W; g0 i+ c' ~0 h - position_fk_f= Position_Calce();
( K5 }7 w' C5 J6 B" b - }! p5 x( H; o Q s8 }& K
复制代码 4 U! S! ]. t9 Q: {
总结
- c, k7 _0 \( a8 c当你转动电机轴能通过SPI发送0xA6读取到数值变化,基本就算成功了,剩下的就无非是处理一下
5 g+ w# T* d$ [! C8 c————————————————9 V9 {2 J4 p1 U6 b5 V3 D+ h
版权声明:超级馒头神8 S& G% o& j8 |8 I
, F' y+ \+ K0 c: g
3 _: W/ a$ G& j( s |
可以把完整代码发出来嘛