前言
- c" B7 R3 @! O5 x$ Lic-mu基本情况介绍5 \1 o' L' l8 N N
2 C& S O; L" k! n
IC_MU是一款离轴的1.28mm磁编码器,主要用于电机控制居多,当作磁编码器,优势是能使用多种通讯协议(SPI,BISS,SSI),但是目前中文网上使用资料较少,因此我自己写一篇关于IC_MU的SPI通讯读取方式的文章,读取芯片为stm32G4系列,然后代码在stm32G4和stm32F1系列基本通用。
0 B6 p- H4 U( R: c' j& d/ N+ c芯片基本介绍如下2 K2 j; {5 E1 H+ o$ `5 s
3 C) n" }2 l5 V, g2 E6 ~& F
9 q! h) F# ^! X/ e c
+ n2 S9 L. g m, e5 l4 k提示:以下是本篇文章正文内容,下面案例可供参考! C+ Q, S$ a* X! z' q
. A9 {/ h" c6 I4 ~8 F) t& _一、硬件连接
$ ?* b, w8 W; R- L* P L) Z按最小系统连接。IC-mu需连接eeprom存储角度,供电为5V
) C* p8 ]0 q2 Q" F* U0 h! `' L' \' o( S, B7 ^# L9 j
二、STM32 cubmx配置模式/ |4 M* C6 i2 G$ O2 z* ?
STM32G491配置cubemx
4 J/ a+ e+ ]: v
8 ]# [3 [3 z3 ?
9 ?' |# P% H6 W# s1 K% k% Z+ N% O; u' ^* d- h
6 X. N1 L# D4 ?& b E7 n
如图几个关键点
; p# `8 H" Y8 V( k/ t1数值格式:可以选8bit,但是我觉得16比特配置更方便,如果要配8bit只需将数据拆分即可
/ P% _4 d0 o z8 f* ]" O2波特率 没有明确要求,12M以下都可以
/ O0 i) t+ M% p6 X$ y4 }3SPI模式,SPI一共4种模式! q9 {, q0 h! u
' f& k2 \! }% i0 t# L
/ C) P* O3 }1 e( C8 A; a
" z, N1 c$ e9 W8 L* i+ p3 r
IC_MU只支持模式0和模式3,如上图所示采用模式3 CPOL选择High CPHA选择2Edge
$ r# g, F5 o+ R, U& _( k2 X( M2 r7 S, X3 i8 o: N2 G
; K0 b5 `: g0 h' ?/ [
1 Z9 V/ t7 [. { E+ w# s$ X! _, l1 Z/ C& m: y: S5 I
SPI通道要设置为高速
7 U2 f- T% Q2 f* L* `% Z2 v除此之外还需要设置片选信号,默认为高电平
5 \+ Z" P u; A' h4 @; S7 ^. d6 G0 \/ z% I- S6 A1 N4 b2 N+ R
' R' l6 T( g$ t% l! T
% F7 x9 ^( V* G& T9 i; J: z7 q
三、软件代码及思路
0 ~7 v' l5 q/ k0 |! O @首先需要对整体进行说明,需要将编码器激活,配置在SPI通讯模式
3 G* `8 R" h8 |( E6 L0 p
# @3 e; I( q6 ~0 `5 ^6 W" U1.寄存器指令介绍3 f* ~% s8 g7 c( j) J
0xB083 Activate,激活
% I5 T& G" c$ d, S0xA6FF Position Read 位置读取命令
# H: j" A% l& C0 n# z7 ]( W, [ m& Z0x8A Register Read (Continuous) 寄存器读取(连续)$ z5 b, |) R$ s" t
0xCF Register Write(Continuous) 寄存器写入(连续)- p) Q) m6 W: Z+ S& x' t% z
0x9C Read Status 读取状态寄存器 指令
8 j( M, e2 b! ~, Z: H1 x6 c0x97 Register Read(Single) 寄存器读取(单次): X2 y0 O& z& U2 x3 f
0xD2 Register Write(Single) 寄存器写入(单次)
& l' w4 j% m: c& n1 R- l- b. ]" `+ b9 }+ }; t6 F* q- r5 p7 ^
/ q( q- L6 H, F. L' Q. c2.代码介绍9 E1 P4 n* D1 `" a3 b; g
对片选进行宏定义,然后对SPI数据传输底层函数进行定义
% d4 m8 M7 B. ~ C( Z6 G, W9 K- H/ `) A1 m8 @( r# c7 A
1初始声明和定义- #define SPI_IC_MU_CS_LOW(); HAL_GPIO_WritePin(ABS_ENCODER_CSN_GPIO_Port, ABS_ENCODER_CSN_Pin, GPIO_PIN_RESET);
2 p6 c& n. N0 A5 C - #define SPI_IC_MU_CS_HIGH() ; HAL_GPIO_WritePin(ABS_ENCODER_CSN_GPIO_Port, ABS_ENCODER_CSN_Pin, GPIO_PIN_SET);
! f& T/ u5 R" I9 z$ n - ( W. }9 [* o" y- w' h6 h
- uint16_t SPI_SendHalfWord(uint16_t HalfWord)
5 \5 X1 v. T3 l6 R$ n) z7 { - {
0 t7 o5 o$ h1 J4 R' a1 b! q4 Y - 5 [5 i( w3 B9 {
- SPITimeout = SPIT_LONG_TIMEOUT;
G% _' ~- _" h; h - /* Loop while DR register in not emplty */
, K6 J H8 X% g# J6 M - while (__HAL_SPI_GET_FLAG( &hspi1, SPI_FLAG_TXE ) == RESET)
9 `% J0 }. _3 ?, C7 e - {9 \: Y8 G" }# U7 [
- if((SPITimeout--) == 0) return 0;
* i" c4 O0 s. P/ u8 }) O - }
! W- z9 s' Q( p8 l. l - /* Send Half Word through the SPIx peripheral */9 G& T5 E* K, s
- WRITE_REG(hspi1.Instance->DR, HalfWord);6 t4 u/ m- g% I' R6 V
- . Z7 a7 s3 k! c- R9 J
- SPITimeout = SPIT_LONG_TIMEOUT;$ S( {" q1 f# O4 h* U* }/ u
- /* Wait to receive a Half Word */
/ ?# u9 T0 d L - while (__HAL_SPI_GET_FLAG( &hspi1, SPI_FLAG_RXNE ) == RESET). y) i. Z; C# m4 x3 e% I% g
- {! ~# X5 F* ]% L! M) |$ @
- if((SPITimeout--) == 0) return 0;( ?. u3 l" }/ N9 b$ `9 ]
- }
1 J* @5 C( K0 \5 E/ v+ j - /* Return the Half Word read from the SPI bus */' P {& f0 m( u. G
- return READ_REG(hspi1.Instance->DR);
/ ^3 l+ P+ M8 M - 3 o7 Q9 H* U. ~0 _( A( w9 A
- }4 @2 l8 [; @+ g1 ~* u/ p
复制代码
- h( w# R1 ^/ t( h1 C4 y8 ?2激活寄存器' L( \. L5 F6 Q( i& A" k2 x8 s; B: q
激活后才能对寄存器有操作
+ ^" g! W9 j. v* N- void ACTIVATE_FUN(void)
! h# U9 r9 M4 V+ m - {- L Y6 J6 z" E+ s/ S
- uint32_t ICMU_Temp = 0;- B! C/ G* F2 o4 v
- SPI_IC_MU_CS_LOW();# S1 G2 N4 M7 Y" k
- ICMU_Temp= SPI_SendHalfWord(0xB083); |" f% L0 l% G3 {) {/ y7 x! d
- SPI_IC_MU_CS_HIGH();2 g5 r# z0 W1 |
- Delay(100);8 `. w4 A c/ F6 C) M' g: ]9 E
- }) o6 D# U$ q5 W* {
复制代码 ; d$ ?3 K$ q. y+ N) i- \! f: M
3编码器初始化函数
* S9 h! m7 M3 v6 I初始化发送0xB083激活编码器,编码器配置为单圈14位,具体见数据手册
' g( q% u0 e$ l初始化完成后可删除函数,状态会固化在配套eeprom种,不会丢失6 Y, z2 N# E( U$ u! q: ^
- void Init_ICMU(void) n! U7 ?; ^5 j& u5 e' v" ^
- {9 ?& ]" Q! I: `3 o0 V8 l( |) j$ F
- ACTIVATE_FUN();5 V+ d A* O+ `
- uint32_t ICMU_Temp = 0, ICMU_Temp1=0;" @7 Y6 O7 @$ _; Q- c
- SPI_IC_MU_CS_LOW();2 f9 f" L0 F% D" g; r( J
- ICMU_Temp= SPI_SendHalfWord(0xCF00);
e j2 U9 I* I" c& ~% I1 w4 q$ ^ - ICMU_Temp1= SPI_SendHalfWord(0x8E20);
1 S' Q" x& c" p: f) P8 A5 h5 e0 _6 A - SPI_IC_MU_CS_HIGH();7 c v4 F. P! ^1 s& E) Z
- Delay(100);
7 b/ w$ C- L y5 r4 U; B - }- y# ^, t, f# J) y/ D1 T6 K) k# G# V
复制代码
0 M; a8 X; r) W4 p! U( v4数据读取
W: O& b3 J( M3 x编码器数据读取,读取指令为0xA64 _+ E4 s( ]! S" r9 N$ G3 X- k
- uint32_t SPI_SDAD_transmission_Fun ( void)* Y X4 N1 I9 S$ i2 V7 R2 O( n
- {
1 B3 Z9 d3 T0 g# n3 C3 d -
q: I# c; d* T! Y; _ - uint32_t Temp = 0 , Temp1 = 0, Temp2 = 0 , Temp3 = 0 ;# d, w6 K1 z @* e U
- ACTIVATE_FUN();
. a5 J8 e( c: f -
" g. @, m- p) k9 I# M; h - /* 开始通讯:CS低电平 */0 O4 `+ E, n% W
- SPI_IC_MU_CS_LOW();
! ?$ V# `' U1 z$ q+ M - Temp1=SPI_SendHalfWord(0xA6FF);( |; x! Y |5 x6 e4 m9 ] L( Y
- Temp2=SPI_SendHalfWord(0xFFFF);
6 b8 v$ L) |- z8 o -
% ^7 Q# @, r+ H: p# X0 A9 n - ; U1 b+ D' G/ {9 }! l3 t6 N8 i
- /* 结束通讯:CS高电平*/
1 B) C9 ^# }. k6 \& K - SPI_IC_MU_CS_HIGH();
4 ^% C6 E0 F) S' K) _ \3 p7 z - 2 i' J% Z# H4 [- K
- // Temp = ( (Temp1 << 16) | (Temp2 << 8) | Temp3 )>> 5 ; //读出数据,右移5位,共24位,有效位为19位
* D, |; R1 u( K; i i - Temp= (Temp1 << 16| Temp2) >> 13; //总体32位 19位的话需右移13位
( Z8 f5 D/ @! J1 _ - Delay(1000);2 l+ W' P+ u9 `; C* t8 V+ e, u3 K
- return Temp;
3 g9 S/ b! F4 _! J - }: g6 w9 u0 v* w
复制代码
" _4 Y7 y/ u. P5 \6 @5角度计算8 R" }( B, c$ y: P$ s
角度我用了11位,初始默认存在一个数值因此将他减掉了,然后按照360度进行划分
. U6 V8 B5 E' F1 S0 Z8 _$ X3 m& b( h- float Position_Calce()
$ n( \, h% }& R5 E - {
6 u( K: N3 Y' v - uint32_t a ;9 [# ]9 w& H$ o. o; ?) J+ S) Q
- double b;0 J& h( K) A# U" o7 m: n! R$ Q/ @
- float c ;1 S$ f! {, ~8 B) R: w
- uint32_t www ;
! B, R2 v& O1 E8 A* F! x - double n ;5 \' k- p( q* L' ~
- a=SPI_SDAD_transmission_Fun ();& ?, u0 e# |' v4 Z* k/ I& T
- n=((a-0x00053000)/2047);//计算角度' t2 r2 T" _$ h9 K
- b= 360.000* ((double)(a-0x53000)/2047);" C/ J% {( V1 {9 ]% B+ C5 ]/ h
-
) g* _; o( M& }. f# k - return b;
" y1 \; O& c# L& N( w" M5 K8 I; u -
$ b v3 i+ r( J# b% C! a - }
复制代码
$ q8 W8 l! K8 ] y6主函数读取角度5 W# `. B: d& P2 _1 d
- float position_fk_f=0; //位置计算
1 Z8 K5 x# b7 K6 I3 h+ k$ M -
5 M5 Z/ f- O# F0 @ - while (1)9 n& S+ O1 S& s8 O% q
- {
+ i1 i! c( A M) v - position_fk_f= Position_Calce();
L& Z6 X7 e- N) ~ - }5 C/ c/ Z, x6 Y& j
复制代码
$ Z% d6 _( ^# b总结+ x8 f# S! ~1 S1 Q# l. J) [
当你转动电机轴能通过SPI发送0xA6读取到数值变化,基本就算成功了,剩下的就无非是处理一下
: {, i8 K- ?9 q0 a/ J, a0 x* p————————————————% o+ X9 h: o1 b* ] B& l. `
版权声明:超级馒头神
$ U" n* P: ]6 D. _8 E/ d2 R
: I. N9 u$ W# R0 z! ]) L
" @$ R. `/ N9 L& j/ w |
可以把完整代码发出来嘛