你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【经验分享】STM32 HAL库 PWM控制电机转速与编码器读取(超详解)

[复制链接]
STMCU小助手 发布时间:2022-5-24 11:05
本篇文章我将针对PWM控制电机与编码器读取电机转速的STM32CubeMX配置过程进行详细的讲解,让准备学习HAL库的小伙伴能够更好的理解STM32CubeMX如何配置。
  J$ O5 Q# \8 i; W6 x+ \
- w; S+ V& Z) }/ h$ x- `0 m1、硬件准备9 M  l% u3 f- M! A" _
(1)所需硬件
% k' O. E9 x, v
' B: v' q& w4 r- F芯片:STM32F103RCT6" o. p3 ^+ G" J
驱动:电机驱动板或TB6612(电机驱动芯片)" @+ Q8 H; g6 M: E$ e. L  P
电池:12V Libo电池
' H0 H8 N3 ]7 I& o& T9 X: P1 P: [电机:带编码器电机
. @6 Q0 h4 {8 q& h- O轮子:我用的是麦克纳姆轮$ Q( a% s) s( M! |# m! Z2 J
(2)硬件连接:/ j6 y/ q0 p# g
0 E/ L; A- f# o, A" @3 a, |, v
PA8 —— 电机驱动板PWM13 Y& d8 q- k$ t2 u0 B2 b
GND —— 电机驱动板PWM2
' N" {  {7 G4 U6 ~2 E(这里若要反转则PWM1接地,PWM2接PA8;如果在小车中两者都需接PWM引脚,正转:PWM1给一定占空比,PWM2占空比为0)6 I; z$ k, P5 d( E2 t, {4 ]) m  G3 P
PA9(USART1_RX) —— 接串口TX9 N' _6 w  J6 c" \4 m* T7 H
PA10(USART1_TX) —— 接串口RX' H& w1 U9 ^3 d4 Z
PB6 —— 编码器A
" v- F' ]/ d+ r  [# F' sPB7 —— 编码器B. s2 H' W1 {) M3 x/ I
2、STM32CubeMX配置:( t7 E  i1 b& i
1.1 所用工具:
* A0 i/ N; }6 c* x' s1 y# l, Q+ f. X: y* Q, E- S+ E
芯片:STM32F103RCT6
& Y& @4 Z8 t# V' D* Q' W$ gIDE:MDK-Keil软件2 y' i4 d0 J5 {
STM32F1xxHAL库$ ]) x6 o( s- d  v8 R5 _. D

3 [, q2 P; i1 b8 `+ a1.2 知识概括:  ~  Q# R, S6 O; {0 S3 l

4 B6 X5 Q# {- V# I5 B2 k& eSTM32CubeMX创建TIMx、USART例程9 ]7 z# O  k  Q; t
Keil软件程序编写7 ]3 G- |# K- h0 C! @
7 y( S, N* Z9 E# D
1.3 工程创建
- w9 i% T6 h% n% [1 l9 Y# X8 c1、芯片选择& |9 r/ K& C) R2 d0 C8 [7 `5 C
  芯片:STM32F103RCT6(根据自己的板子来进行选择)
! P% F' T. ~$ C) c% U* l; D; Y+ g$ a  ~/ Y
23D0~9`L~7GL07(I_[N{KE2.png
% @) r+ C" Z$ r: P9 Q9 {- s5 T7 w, z, O3 ]. Q! k
2、设置RCC3 A6 ^: {# l$ P9 m$ `% u. R
  设置高速外部时钟HSE 选择外部时钟源
, h& v1 S$ j6 q, {$ r% ^
1 c' x! w1 j/ k8 N0 | PW`{J8OBH2[{M@N[5PNQZ79.png $ X$ ?& W8 B2 Q% p
+ j2 r8 I- j+ S1 [/ P( G& e$ M. U
3、LED1配置! u1 X+ @( H- G/ O6 }! R
  我使用的板子LED1引脚为PD2,初始电平为高电平,目的是通过观察小灯的亮灭判断是否进入定时器中断2 D  |0 r, ~- Q4 }/ a8 z

' i, ~9 r  I# |' R7 E# V $({RM4FPK)]`4S%9ST`Y2IV.png ; y" N5 _* t4 @$ ?) X3 }- c( a

+ Q. M, x7 m' v4、USART1配置
: {8 l2 ^. u( D, i0 N  异步收发,波特率默认:115200 Bit/s( t5 r' t: C2 g- v+ T2 _
7 x: ]. v/ n3 w: t( \* Q) w
H)P`$@T]OH)A_H[{)H(6@YF.png
" c' B1 O. o9 u- G
) X, U( o# c/ U2 e2 R3 l5、PWM配置' G5 r. y5 Z& N
  使用定时器1通道1和通道4(TIM1_CH1和TIM1_CH4),频率10KHz
" v- W( t. O2 p  {
" ~' p. s; L3 M5 g SOU4}_(_UV`NP()~L2RAZ%6.png ) P2 E7 m- H% E3 }  J' E

1 p8 ?0 c8 K; H, W2 G6、定时器中断配置" h: @- N$ {) r1 a: o
  使用定时器2(TIM2),周期设为10ms,即10ms进一次定时器中断
% w' T3 s5 d* P3 r6 O
( o, Y' I* d4 P/ `; s [6DJT48_KSPB0OWES)C%C.png 2 \& T+ }7 K+ V' s
2 [! S8 y; @8 k. X- ~
  打开更新定时器中断+ l4 A! K, Q' Y$ q6 f+ w. D

4 y- X4 u: [, t( |: w YOU~W`VS981(97ETMJ_GWQ4.png
3 p* _" |) |. A" w9 I( H* T5 q4 S, K
7、编码器配置
7 ^2 J8 \8 u3 W4 H  STM32自带编码器配置,使用定时器4(TIM4_CH1和TIM4_CH2),打开更新定时器中断8 Z4 X$ f" T: K' P8 b7 k  G9 ?

0 M- J' {: I8 s1 I" w WWM7WN6[4QEZV49ZC(5FD_V.png
0 X# [5 w, `+ @; `& q  m8 F9 [7 S. y3 D% x
8、中断优先级配置
' ~; i: J: R) a+ c: e) c- q  因为编码器中断要发生在定时10ms中断内,故编码器中断的抢占优先级要大于定时10ms
4 A( ^# G: o3 V( y' s4 o2 y  b, d( m* Z* n) c* O  X
}_DSEQOI[MC]KJKD5}(][4V.png ; G9 J( c8 ?8 O6 b  A# A; O) W6 Y! _- n

- R) }+ K; D' o3 L# H0 Z- b8 u9、配置时钟: v. x* M. v8 z$ c' u. y) h
  F1系列芯片系统时钟为72MHzs
( j8 J. j3 A$ n: ^3 P2 |
  c7 p! u: K2 G1 O' j 4NX{AV$J28BT0`HN2LHC%GC.png 6 _, N9 _* d4 S' y0 h! ]5 G- ]
1 L- m' c* ~+ W! ~
10、项目创建最后步骤
8 B- K5 ]8 W) ?/ o: Q) q6 f% z( m: {* V5 u
设置项目名称7 F8 K" A' {7 \" ?6 v8 v% B8 R
选择所用IDE0 f3 h# I" E3 ^7 i
# S# y3 ?# E! t- W6 c" K
_WFXTK(}2ZE8I8EMBL1)[YC.png
7 J0 h% Z( Z' s+ D* p  J
4 G- t3 A% g0 B7 E) ]11、输出文件
2 \& Y# A" Y& `! ?1 J
$ B7 h# g8 r! ^$ q②处:复制所用文件的.c和.h
1 s% I: c9 f. V$ n) `+ H③处:每个功能生产独立的.c和.h文件$ m; T+ Q+ ~& O. Q+ u
, Q8 ^: X% K4 }! d( v& O
WQR2U9C_7V691HYV7Q$VL96.png , y1 L5 R. @' q* A

3 A3 a( \/ O) O$ F12、创建工程文件) ^! d9 S; }; y6 J
  点击GENERATE CODE 创建工程" U* d5 `# G1 @; H" u

& R( S4 i, y# Z5 O% Q2 I( j$ n13、配置下载工具
" k8 \# }( F7 r  这里我们需要勾选上下载后直接运行,然后进行一次编译: b# e% C( b8 H% h5 g; R
9 f$ J! r( f! P& R3 Z. {
6F5%O4Y~9Y2M[QO1[68RUXP.png 8 Y2 u; M6 S" C

7 |* y/ N+ _! m' C3、STM32源代码:: K! o0 W/ _+ [
(1)下面的代码之前有用过hal库的小伙伴应该都很容易理解,小政就不过多解释,有不懂的地方欢迎在评论区下方提问。在main.c加上:
" _+ w! ~0 e# d% f9 y/ K, r) f: ^, Q( H1 Q# F% X# b
  1. /* USER CODE BEGIN Includes */
      ?6 m$ d# u  ^  L
  2. #include "stdio.h"% P! G. r; t: A
  3. #include "math.h"
    0 n9 F1 K, }# R6 j0 V
  4. /* USER CODE END Includes */
复制代码
  1. /* USER CODE BEGIN PV */
    : L5 I" u* H# q5 o/ V0 d; G
  2. unsigned int MotorSpeed;  // 电机当前速度数值,从编码器中获取
    0 T" i$ a* [) ]: N" m  }% Y2 F- y
  3. int MotorOutput;                  // 电机输出! K2 q0 g  W* G( Z3 o6 ?, C3 ?
  4. /* USER CODE END PV */
复制代码
  1. /* USER CODE BEGIN 0 */* {' l8 Z4 _7 k% X0 [3 h7 U/ Q
  2. int fputc(int ch, FILE *p)
    $ e0 N: E/ n( |0 w
  3. {- w8 Q, }0 H4 v; ^# w/ _/ ]( u
  4.         while(!(USART1->SR & (1<<7)));' R  I8 ^; b9 Q: ~# w, S
  5.         USART1->DR = ch;/ p& h. Z6 p* W
  6.         
    ( Z7 D0 n' R! T5 @# F$ q
  7.         return ch;' a) y4 p4 F! o( S' l4 d
  8. }
      A5 ]9 T! T8 b6 ~! I1 D9 m
  9. /* USER CODE END 0 */
复制代码
  1.   /* USER CODE BEGIN 2 */7 e! [2 f) Z* V3 i& G
  2.   HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);            // TIM1_CH1(pwm)4 b# l$ R$ u1 i& ]& r3 p
  3.   HAL_TIM_Encoder_Start(&htim4, TIM_CHANNEL_1); // 开启编码器A
    $ J( l6 k0 B8 I8 |! m+ }; }( }
  4.   HAL_TIM_Encoder_Start(&htim4, TIM_CHANNEL_2); // 开启编码器B        & i' C4 S! c0 e: h# x& ?
  5.   HAL_TIM_Base_Start_IT(&htim2);                // 使能定时器2中断) E8 p. ~( E; i  h0 T! S: l9 a( r
  6.   /* USER CODE END 2 */
复制代码
  1. /* USER CODE BEGIN 4 */. M& P2 t# e4 y) V3 V( `  x
  2. void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)4 ?) b3 r- O# E( }
  3. {, x4 L  C5 a, e9 t
  4.     static unsigned char i = 0;8 A8 Z# Z/ [- y5 F$ `" }
  5.     if (htim == (&htim2))
    ) {- D. q4 Q6 u2 {& D0 @0 K9 y
  6.     {
    ! ~: V! m/ |& m7 X
  7.         //1.获取电机速度
    ( i6 I& V8 z( o# N5 e. I
  8.         MotorSpeed = (short)(__HAL_TIM_GET_COUNTER(&htim4)/18);   
    % W1 E' {" f  u
  9.         // TIM4计数器获得电机脉冲,该电机在10ms采样的脉冲/18则为实际转速的rpm
    ( u3 ]4 E8 o0 ^8 |
  10.         __HAL_TIM_SET_COUNTER(&htim4,0);  // 计数器清零
    ) H! y- D  [/ E5 M7 u) ^( p; S
  11. + I+ M( Z1 v( p, I

  12. 6 ^9 o7 a; t5 q% E
  13.         //2.将占空比导入至电机控制函数
    2 j2 O7 w7 v+ R* h$ D
  14.         MotorOutput=3600; // 3600即为50%的占空比4 X* y  F1 U' r$ \6 d3 H" s
  15.         __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, MotorOutput);& ~4 K6 V/ ^1 N0 n
  16.         MotorOutput=MotorOutput*100/7200;
      q" j6 ~9 Y$ T; h1 `8 V
  17.         // 占空比(按最高100%计算,串口打印)
    ! B1 V, S/ l  i8 D9 m) r! w
  18.         i++;
    ' I4 v# K5 X, @- _! M5 ?; ]- l
  19.         if(i>100)
    9 u6 @) l4 r8 X; D8 S# w
  20.         {
    9 p, q  J3 F7 L" t1 O4 `
  21.           // 通过观察小灯亮灭来判断是否正确进入定时器中断
    4 u* u, f5 Z5 V0 l) L
  22.           HAL_GPIO_TogglePin(GPIOD, GPIO_PIN_2);
    # u- J# p) G' }
  23.           // 打印定时器4的计数值,short(-32768——32767)' D9 U$ g$ Q8 f; r
  24.           printf("Encoder = %d moto = %d \r\n",MotorSpeed,MotorOutput);        + k. k! ~4 j8 D8 ~2 s. ^# [
  25.           i=0;
    ( ]' h  o6 ?0 F) b) F* L
  26.         }( L' k& o# ?, H! ^7 }
  27.     }" @1 ]! o8 X( d. O7 n
  28. }) R; V, \) f5 G0 |2 e
  29. /* USER CODE END 4 */. v, U" \9 X8 L
复制代码

; l' U* \# c* k# V(2)烧入STM32中,串口展示:
0 H3 N+ h" `% u! D& }: X/ d% p0 N9 o+ F" v& i; W3 V
O`T47Y5J`LF6UMHK{DLRM]G.png
$ L0 p4 T3 Y% n0 z1 f: I0 |' D" i* j$ p' j, s9 }( W) p# [, z
(3)实物展示:
( B3 y9 \' n: C. u* T! D9 _. q  m4 X! b$ D
WO8L63G[V)3I$BYDF]A`T`A.png
* h+ Y/ M- P4 m3 ?
& Q2 q/ M& I, \4 b: G7 I/ k* Q% I; H6 Q' I( v+ F/ Q
4、总结" v7 w2 I# ]$ {. r9 a3 s
  以上就PWM控制电机转速与编码器读取电机速度的HAL库配置与keil编程,后续会推出利用PID算法闭环控制电机转速(HAL库)" {0 I! M1 m8 T8 n6 O/ R. I8 c

  f; k0 i. t& U; a3 R
) @# h+ |- _0 r" P
赞 收藏 1 评论0 发布时间:2022-5-24 11:05

举报

0个回答

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版