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

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

[复制链接]
STMCU小助手 发布时间:2022-5-24 11:05
本篇文章我将针对PWM控制电机与编码器读取电机转速的STM32CubeMX配置过程进行详细的讲解,让准备学习HAL库的小伙伴能够更好的理解STM32CubeMX如何配置。
* t: E9 ?  S. {% `' |- V% q1 t7 x) C& D
1、硬件准备0 g/ N: H3 I& V% T# U! h. P' {
(1)所需硬件* b7 c, q- [! k- p) x1 R: X, e. ~

& U! o' }3 k8 w2 `5 U+ Y( ]/ s芯片:STM32F103RCT6
; O/ {1 C1 x3 ~7 l驱动:电机驱动板或TB6612(电机驱动芯片)
7 }- a1 f5 l+ n6 v电池:12V Libo电池
3 \$ ~, [. |2 ^1 K2 v" S电机:带编码器电机7 r3 c  w( z" \/ X4 Z, G4 \% \# e3 u
轮子:我用的是麦克纳姆轮
" |. }1 E1 z, u; L(2)硬件连接:) R: m# ~* J9 s/ j1 ^9 R; N7 a2 @' X

8 ]" z% ~0 w# V  F+ a, _, wPA8 —— 电机驱动板PWM1
9 T, X' ~' `5 b# B* c/ \' d5 jGND —— 电机驱动板PWM2* x" L% d$ ?; A8 l% _& F
(这里若要反转则PWM1接地,PWM2接PA8;如果在小车中两者都需接PWM引脚,正转:PWM1给一定占空比,PWM2占空比为0)
7 M) Z" J% z# i# z' OPA9(USART1_RX) —— 接串口TX
9 U+ ]) q( B3 m( b6 H" gPA10(USART1_TX) —— 接串口RX% H! o$ m) a3 Z+ `
PB6 —— 编码器A
5 m0 C' u" d$ ^! Q4 ^* jPB7 —— 编码器B
3 |- t, e0 o: H  k6 L2、STM32CubeMX配置:
( z' |7 z7 p8 Q& |% S. a  e; [1.1 所用工具:* P1 F* y9 a' j6 }& z6 p
! a0 M+ G$ ~& H
芯片:STM32F103RCT63 y& y! j. [, C5 G
IDE:MDK-Keil软件
$ M/ u9 \& w1 n9 `) B" eSTM32F1xxHAL库
0 A1 `+ @% q  n! [) Z/ A2 U9 k# l( f! Q* |
1.2 知识概括:
) g2 W; f* P" s
: G) I5 s0 n, h1 O  SSTM32CubeMX创建TIMx、USART例程& C7 V' e& C: f$ j
Keil软件程序编写7 k1 F0 f: ]4 U5 {
$ Y% |. B$ V: J5 ]
1.3 工程创建
) F/ \3 e9 s- k8 M1、芯片选择  o9 W: I& \, ?! _0 [2 T. U
  芯片:STM32F103RCT6(根据自己的板子来进行选择)0 s1 {5 z! ~2 O9 t

+ S9 z& M- q+ I- y+ y6 U 23D0~9`L~7GL07(I_[N{KE2.png 3 a4 ?$ v* P. F. ?0 n
- T8 Q% d( t% y! X: p6 N
2、设置RCC+ W% |) k1 L8 _/ W  @/ u* [5 T
  设置高速外部时钟HSE 选择外部时钟源
3 ?. p' T! |3 b5 O
+ i- k$ Y4 X  S4 h2 |4 e! G PW`{J8OBH2[{M@N[5PNQZ79.png & N: K. }+ _3 l) P( d5 z! X
  h4 q" F1 d8 {% n
3、LED1配置) E# |: Q- s1 p( F  S
  我使用的板子LED1引脚为PD2,初始电平为高电平,目的是通过观察小灯的亮灭判断是否进入定时器中断/ B" D$ K7 i- h8 x, o* z& ~( A6 L8 L

/ R( i& ~0 H3 Q5 _% z $({RM4FPK)]`4S%9ST`Y2IV.png
7 x! e; @: m4 _4 f3 w( K7 e* d: J5 b
4、USART1配置
$ i4 W. D# Q6 |- o  异步收发,波特率默认:115200 Bit/s2 Z4 H% ]3 g) i& M7 y
' `2 n( U# i; K$ v& @
H)P`$@T]OH)A_H[{)H(6@YF.png
0 d9 r& Z' Y$ g% ]
9 i5 `. A" P. c' o6 U( Y: T  c, I5、PWM配置
, h3 {$ F8 R3 v( ?$ E; ?. H  使用定时器1通道1和通道4(TIM1_CH1和TIM1_CH4),频率10KHz
7 v$ d) R; E) e. F8 L4 ~
/ H0 m) _% {2 Q7 C SOU4}_(_UV`NP()~L2RAZ%6.png - W' \/ D' W" \' ]6 p; ]1 `
! j( R* p, X1 H' a! ^/ \( S6 b1 f# k& K3 v
6、定时器中断配置% ]2 q. h3 ?/ G5 b; b. `9 F# d
  使用定时器2(TIM2),周期设为10ms,即10ms进一次定时器中断
/ h( ]) c) d1 k
4 Q4 e2 f% d1 u. r9 z& X: g [6DJT48_KSPB0OWES)C%C.png
7 X4 H5 s# C6 l" C$ U' {. o; ^" e6 b# K' v3 l2 y& j
  打开更新定时器中断
% T" p/ w) T- }  r8 ^6 M/ m' p$ R3 \) V7 |: H# f, V. g6 f) |2 `
YOU~W`VS981(97ETMJ_GWQ4.png ) l* e, D1 p( Z6 g' |" u8 K+ q% N

# [" x9 G! ]- ~% d" j7、编码器配置3 t5 m& H$ B0 `3 {
  STM32自带编码器配置,使用定时器4(TIM4_CH1和TIM4_CH2),打开更新定时器中断
; n3 E5 A' U# r8 L
2 T& p  ~; g- p3 Q$ N+ A WWM7WN6[4QEZV49ZC(5FD_V.png
/ w  _$ N$ P# X, }) W
3 j& G' }* E, u! Z. }8、中断优先级配置8 q3 p8 W/ b. s1 D: _5 ]3 m- T
  因为编码器中断要发生在定时10ms中断内,故编码器中断的抢占优先级要大于定时10ms
5 M# Y  C1 {# _/ M6 `5 H4 @0 }6 W+ e6 X, y0 w" A) E
}_DSEQOI[MC]KJKD5}(][4V.png 0 `6 [* q9 [* I. i
- y6 l5 e1 @' I8 t7 p
9、配置时钟
0 y- s% C1 _4 K4 x, z* w+ T% @( R  F1系列芯片系统时钟为72MHzs0 _, ~' F7 W) y8 W; C+ L( B

2 |- h0 \" N- Z% D" o8 I 4NX{AV$J28BT0`HN2LHC%GC.png
7 t" {5 I/ N2 m& }! [; |" l
8 P! y7 `  Y1 C" w10、项目创建最后步骤7 `; F. A0 f8 X" l7 H

5 Z* w: y1 w# M' V8 u设置项目名称
, Q/ @: O& b+ d* k1 `+ l) F' I0 m选择所用IDE8 o4 j- U9 T0 C

) e% Q/ c6 u$ k/ N9 x _WFXTK(}2ZE8I8EMBL1)[YC.png   Z) {: e! g* z3 ?& F9 e( f( r
( f. B' J% n/ [- f) b
11、输出文件
" _3 @3 {; y, Q2 c. p  R
2 V$ F! c; @; ~1 h6 Z②处:复制所用文件的.c和.h
" Y9 y1 U( u/ ^/ v0 N# l4 @③处:每个功能生产独立的.c和.h文件( K8 ]# \$ N- b  T- Z
7 z, W3 ^/ E5 I) {- M  k7 Y
WQR2U9C_7V691HYV7Q$VL96.png
" ?3 D! v3 i  N  G! j# Y0 S9 Q* W1 W* |# q5 |
12、创建工程文件9 r$ P; ?; b' Q% N; `. c% g
  点击GENERATE CODE 创建工程# V+ j$ Y4 F* N' J
/ [: i6 l& t8 K0 a1 d  W) f& ?
13、配置下载工具
& q6 J9 H2 F% B8 X& N0 p' j4 M+ i& P' \  这里我们需要勾选上下载后直接运行,然后进行一次编译
) J# ~7 [9 {. |7 k$ ~2 c$ f! U, O6 {5 N2 F" t5 ^; Y  K
6F5%O4Y~9Y2M[QO1[68RUXP.png ( Z, v2 d) x& y! j
: h: m) a( g1 a+ N: J) k* ]
3、STM32源代码:  t4 F6 k5 T  o9 V1 g- }
(1)下面的代码之前有用过hal库的小伙伴应该都很容易理解,小政就不过多解释,有不懂的地方欢迎在评论区下方提问。在main.c加上:
1 n3 {' t. n, e+ b7 W* Y* H- y- n
  1. /* USER CODE BEGIN Includes */
    4 n* b+ w8 g" N2 e0 {
  2. #include "stdio.h"
    # Y1 ^. K" H* Y4 ^' a- R
  3. #include "math.h"
    " i7 M8 j% H( ?- k; P
  4. /* USER CODE END Includes */
复制代码
  1. /* USER CODE BEGIN PV */
    ' N! U7 H. y! Z( i0 v8 o
  2. unsigned int MotorSpeed;  // 电机当前速度数值,从编码器中获取
    % k+ o7 n3 Z5 h2 |
  3. int MotorOutput;                  // 电机输出
    3 B5 d7 x: d+ ]0 X/ H1 J
  4. /* USER CODE END PV */
复制代码
  1. /* USER CODE BEGIN 0 */
    " t% E$ \+ J" g& T. j  g
  2. int fputc(int ch, FILE *p)0 z5 Y( U9 u  O. q+ L4 G1 g7 ~& q" S' [
  3. {% f1 \' C- l, Y! z  R7 i
  4.         while(!(USART1->SR & (1<<7)));
    . S$ i2 L& E1 d& ^5 x
  5.         USART1->DR = ch;  E8 ~* P+ _) k2 O! z2 }! x
  6.         
    8 J, ]  e2 c  m. _
  7.         return ch;5 h& I" k5 u4 |1 P) |. q
  8. }" R3 E5 W0 m# I
  9. /* USER CODE END 0 */
复制代码
  1.   /* USER CODE BEGIN 2 */
    1 M) z0 {* C. H1 ~0 D4 m$ E/ h) ]
  2.   HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);            // TIM1_CH1(pwm)
      d) B* _' G+ f5 Q( z& K
  3.   HAL_TIM_Encoder_Start(&htim4, TIM_CHANNEL_1); // 开启编码器A# _! }  B3 `+ A/ k0 u7 ]3 }
  4.   HAL_TIM_Encoder_Start(&htim4, TIM_CHANNEL_2); // 开启编码器B          G4 m. ^+ n1 h! l  j9 [3 z" |- j7 ]5 ~
  5.   HAL_TIM_Base_Start_IT(&htim2);                // 使能定时器2中断* G8 R4 ]$ Z# f: ~+ k+ T
  6.   /* USER CODE END 2 */
复制代码
  1. /* USER CODE BEGIN 4 */# e4 S2 Z- |: Z$ m. j+ V* x4 K  v
  2. void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
    0 z2 `8 m1 V+ E) b0 a- o% S
  3. {5 O3 X! H% E- M9 U( |- S
  4.     static unsigned char i = 0;/ T# b. O9 T$ `4 ?
  5.     if (htim == (&htim2))
    7 r+ {# l+ B( h# |) a  [4 |
  6.     {7 p" m) _1 |! F+ k. n; t
  7.         //1.获取电机速度. R) [" w+ O3 O8 `+ _
  8.         MotorSpeed = (short)(__HAL_TIM_GET_COUNTER(&htim4)/18);   & N! O* S/ A8 H. `' H$ N8 c
  9.         // TIM4计数器获得电机脉冲,该电机在10ms采样的脉冲/18则为实际转速的rpm, y9 x# b! H1 s  I8 b+ A$ O! r" s
  10.         __HAL_TIM_SET_COUNTER(&htim4,0);  // 计数器清零
    , b+ n/ J) s8 j1 Q# F8 a# j; z1 S

  11. & ]" h. E( N, }" ?- N

  12. 5 a( B( k" M2 j+ k! _* i' z2 s
  13.         //2.将占空比导入至电机控制函数
    ( N7 p; W" h) }  V7 u% r6 u" [
  14.         MotorOutput=3600; // 3600即为50%的占空比! y$ f" [" O$ [/ [( m% V$ y" J3 @
  15.         __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, MotorOutput);
    % Q. N8 O, ~, |5 o
  16.         MotorOutput=MotorOutput*100/7200; & Q: D* R7 i7 f* i# ]% m1 k
  17.         // 占空比(按最高100%计算,串口打印)$ B7 x/ K5 F  Z  `5 J# J
  18.         i++;
    $ B, o& b+ d5 z
  19.         if(i>100)9 m; P2 U, W& B& T5 E
  20.         {$ X) w5 S- P3 v
  21.           // 通过观察小灯亮灭来判断是否正确进入定时器中断
    - N9 q" B" z- q0 Y7 b3 B: L1 g
  22.           HAL_GPIO_TogglePin(GPIOD, GPIO_PIN_2);9 Y% a, e' X7 c" U
  23.           // 打印定时器4的计数值,short(-32768——32767)  z" L, R/ ]5 _  p6 j
  24.           printf("Encoder = %d moto = %d \r\n",MotorSpeed,MotorOutput);        
    4 q# k- T% [$ b0 ]$ x* E
  25.           i=0;
    . Z/ a" m: D2 I, X
  26.         }% h2 D' }3 Z' j# P3 X" R, i
  27.     }0 L' n+ z: M! Q! I' G5 \
  28. }1 s3 u6 ?. g" I
  29. /* USER CODE END 4 */
    ; A" e2 ~3 A/ z2 x2 A+ u( B( U' n# w
复制代码
: `; L9 d' x' I
(2)烧入STM32中,串口展示:
5 F# C/ B2 B  y$ ^& D
% {0 {( N" G+ h: H1 a- s# B# n O`T47Y5J`LF6UMHK{DLRM]G.png
3 M0 |# s: D' l0 p4 S
# M' B9 I) s; D" [" ^: N% E" m$ P(3)实物展示:# j9 o: F% `5 ?, v9 c4 |( n

/ W3 z. G- ^) B2 ^  ]- e  D3 f) I  a; q WO8L63G[V)3I$BYDF]A`T`A.png
, T9 y! Z) `8 [+ o" p2 N; [: J6 G! J8 `! D* A! h) j- O
* }4 T7 v! h8 y, _9 X
4、总结
" |! ?, h9 T7 T0 U9 E  以上就PWM控制电机转速与编码器读取电机速度的HAL库配置与keil编程,后续会推出利用PID算法闭环控制电机转速(HAL库)) y3 W. k1 L( o8 W  j
- ~4 b2 N0 ?4 j, N5 c* M

/ Z- h2 V8 L4 t! x
赞 收藏 1 评论0 发布时间:2022-5-24 11:05

举报

0个回答

所属标签

相似技术帖

官网相关资源

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