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

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

[复制链接]
STMCU小助手 发布时间:2022-5-24 11:05
本篇文章我将针对PWM控制电机与编码器读取电机转速的STM32CubeMX配置过程进行详细的讲解,让准备学习HAL库的小伙伴能够更好的理解STM32CubeMX如何配置。
9 T8 s- Y) w+ Q% o8 w3 W2 s" Q
8 L: Q1 u0 p' j- L  i# V, g: V& H1、硬件准备
0 R8 H& r* r4 K% k& W0 R(1)所需硬件6 x, ?( b9 H' O$ z
+ Y5 C5 _& ?2 W# Z9 [$ D
芯片:STM32F103RCT6
2 g* K1 ]/ W5 `$ d! z驱动:电机驱动板或TB6612(电机驱动芯片)
* a9 A- F% z: h/ h7 }电池:12V Libo电池
. W$ W: d4 S# Q; X* x& X电机:带编码器电机
8 ?& _3 }# ?3 c) q/ _- u: s7 P& ]8 `轮子:我用的是麦克纳姆轮3 g/ F9 i" X) W6 e
(2)硬件连接:
  c. L' B$ l( Z" O6 V0 n0 v- I  L! ]$ b# l0 _/ y2 }
PA8 —— 电机驱动板PWM17 P, }& l( N) v, ^& a
GND —— 电机驱动板PWM2
- B" H3 z& f/ J, H/ s6 q0 O(这里若要反转则PWM1接地,PWM2接PA8;如果在小车中两者都需接PWM引脚,正转:PWM1给一定占空比,PWM2占空比为0)
6 A8 G% S; a: D: o# ]* l* OPA9(USART1_RX) —— 接串口TX% |/ `% T( |# c; a2 F: \/ u- u
PA10(USART1_TX) —— 接串口RX
) _1 J0 y2 m& fPB6 —— 编码器A& g# d& ?0 C: \. k6 m/ l
PB7 —— 编码器B
5 s1 t" u6 ~- V1 U$ x$ B2、STM32CubeMX配置:1 _) w1 B2 A% Y4 J0 b8 E; `
1.1 所用工具:/ f) D! j2 S9 O* t, U$ I7 \! K
. u8 [8 b# {) B
芯片:STM32F103RCT6
7 t: |$ V' F  q% RIDE:MDK-Keil软件/ X6 a2 _2 K! s# g& G1 w
STM32F1xxHAL库
& `! `& M. Q- W( g& D! t; @
/ x3 e; Q# A1 q5 P# A: @1.2 知识概括:
0 [% G9 t9 `8 M* \  @1 A% \, X' t
STM32CubeMX创建TIMx、USART例程$ E! y( F- V. k" |7 \  O  M& ~+ d
Keil软件程序编写9 j9 `; h- b8 U- W- S# F
% q7 D/ r  j: t5 _- p" y1 v
1.3 工程创建5 s6 W' X8 q% G# J1 m8 s5 I8 F$ R4 K
1、芯片选择
! J8 E) N) d' x" K  芯片:STM32F103RCT6(根据自己的板子来进行选择)
9 L. P4 r% ~8 w3 {  D+ f# ^
" M+ O; i: H" x 23D0~9`L~7GL07(I_[N{KE2.png   Y5 _* }$ n* D8 q! b

- R4 O, C: M4 x: c" m4 J2、设置RCC4 @* f9 [( L6 L/ e: ~# k* o* {
  设置高速外部时钟HSE 选择外部时钟源6 ~. `; p2 G' B  y) q1 W& L

/ |7 t' y& I6 d0 Y4 q7 o PW`{J8OBH2[{M@N[5PNQZ79.png 4 W. k! }* D5 I# x- l8 B, I( ~7 I
4 R$ G4 K* M- ?* R" W
3、LED1配置
( G" m% P4 V- v! I* Q6 y, L! X  我使用的板子LED1引脚为PD2,初始电平为高电平,目的是通过观察小灯的亮灭判断是否进入定时器中断
4 Y8 L6 u& o# ~+ u6 W! ]$ F2 e% s4 K% ^( {/ d8 E8 `" w
$({RM4FPK)]`4S%9ST`Y2IV.png
# R* a" `" M( G0 `
  W5 A/ L7 V& c2 m: M4 k4 r5 w( W' c4、USART1配置
+ H8 [* ~8 p5 u8 \. l' T  异步收发,波特率默认:115200 Bit/s7 o% H9 k1 \, R; A+ W$ p/ P" a3 Y

# v9 m. J7 P( Y) v$ F# ]7 |  @ H)P`$@T]OH)A_H[{)H(6@YF.png
  d& ~$ o! W- U) \0 _9 H4 E! B) [4 R4 ~& A& z
5、PWM配置, L' F  ?+ A' V2 o+ {9 x
  使用定时器1通道1和通道4(TIM1_CH1和TIM1_CH4),频率10KHz4 U  h# X: t/ c1 ]7 ~! k9 B& S3 \
$ a+ A- c3 ~4 u- g8 n
SOU4}_(_UV`NP()~L2RAZ%6.png ( s6 b/ V: P+ n* b  x/ g1 I4 d

" Y) a; b2 i+ X" e# c- t$ ?; z# @6、定时器中断配置/ d" \4 S* T% n, i
  使用定时器2(TIM2),周期设为10ms,即10ms进一次定时器中断
- z" H9 w- g  L9 Q; P9 B: A6 H" E% y1 M3 h1 j- H
[6DJT48_KSPB0OWES)C%C.png
& C* ^1 `1 W& K, n2 A4 P1 _5 K4 N: t. d  l7 u0 |
  打开更新定时器中断1 M2 ]' A0 M( r) h5 q. ]0 v

$ P6 {8 K( F7 B6 u YOU~W`VS981(97ETMJ_GWQ4.png
* g" V* j( I& i7 r6 u7 T) j' ?, `& u9 |0 ?( d+ Y" F
7、编码器配置
$ G& B  Z- G0 D0 v. P. X' j  STM32自带编码器配置,使用定时器4(TIM4_CH1和TIM4_CH2),打开更新定时器中断
2 q: ~$ r1 [, g3 w0 S4 o! O. \0 b: e
0 R1 b* L+ [5 }# }: i WWM7WN6[4QEZV49ZC(5FD_V.png
, Q: k: {  K& p$ @" i
: t1 G- @( l$ h6 `& _8、中断优先级配置
/ V) Y* N6 w6 |0 s) u8 i  因为编码器中断要发生在定时10ms中断内,故编码器中断的抢占优先级要大于定时10ms
, M, j' H" Y! X! F! i7 J) ~1 X
. H/ Z6 O+ D! b" t# ]! i: w. J }_DSEQOI[MC]KJKD5}(][4V.png - i! r7 D% A8 j  Q
6 w0 f: d8 M: e" F% i6 I
9、配置时钟
# }3 Z" N" x7 A5 o# s  F1系列芯片系统时钟为72MHzs
8 a& S  _8 r; {, f! _, M0 b
" k# z2 r0 R2 {( h4 m 4NX{AV$J28BT0`HN2LHC%GC.png 4 f& w8 b  f% N8 i3 g* K" U

4 g0 y0 q5 N, M& t& Z10、项目创建最后步骤5 c" |8 _+ L) d: c+ L. t
* G/ C1 m  |% P/ k3 I! B2 w0 H& G2 c
设置项目名称
) Y/ a/ G3 q" m' H' }选择所用IDE: M# k7 w* \+ @4 A% `0 E! M

7 T* M; t! m  P9 E _WFXTK(}2ZE8I8EMBL1)[YC.png ; _  z. J) A; {8 a

8 _( h5 {/ d0 ]9 F3 u8 D11、输出文件
& p9 Z$ |4 h* R; W  L8 j) g' W. @
0 V$ [3 E% }( |: [( k# q# |②处:复制所用文件的.c和.h
! x2 r5 k6 r$ ]3 G1 s③处:每个功能生产独立的.c和.h文件7 J& D: x8 X$ L* ?6 Z
" _, L( _; Z+ S) c8 {6 }
WQR2U9C_7V691HYV7Q$VL96.png , U, M1 i5 G6 J" l1 G. z
( Z+ i0 q# U$ S! c  ^/ P4 ^
12、创建工程文件
% x) L; b/ X% S  点击GENERATE CODE 创建工程
( Y  n5 I  y2 n6 g# z4 C" Q) g  ~6 G" k8 P8 M) H; {
13、配置下载工具5 l7 `3 A" O/ F
  这里我们需要勾选上下载后直接运行,然后进行一次编译
# m- z: T4 ^4 D, b; K3 Q: {8 g( q; z/ N
6F5%O4Y~9Y2M[QO1[68RUXP.png
: W5 i9 ^3 H" |, w8 m( e, H2 Q0 c0 n( r+ F# G5 Y' e9 D
3、STM32源代码:
  E8 a) I% J- e1 _4 c- ?5 ^7 }! `(1)下面的代码之前有用过hal库的小伙伴应该都很容易理解,小政就不过多解释,有不懂的地方欢迎在评论区下方提问。在main.c加上:
5 L9 n3 g/ L; b' }% w
! W( L; S' f1 ]6 u! t
  1. /* USER CODE BEGIN Includes */# B; l! c' s9 \" A3 _+ N+ t. z' Z/ t
  2. #include "stdio.h". d; b& q- I; A( C
  3. #include "math.h"5 m; j. k# A, H
  4. /* USER CODE END Includes */
复制代码
  1. /* USER CODE BEGIN PV */4 {, ^) U; Y7 A& d! w: V1 T
  2. unsigned int MotorSpeed;  // 电机当前速度数值,从编码器中获取+ ~' @, A) W; u
  3. int MotorOutput;                  // 电机输出
    ( C7 N& u6 ^# e4 f% m
  4. /* USER CODE END PV */
复制代码
  1. /* USER CODE BEGIN 0 */
    % H  R! C' Q3 g6 N  O: H
  2. int fputc(int ch, FILE *p)
    % b6 G$ k  y" n8 T% v. u
  3. {8 l' c* _6 K" s) W. i! n$ L
  4.         while(!(USART1->SR & (1<<7)));) t* Y- M" T5 k' B. `, g# \
  5.         USART1->DR = ch;
    # D# e$ C. q, i; L
  6.         
    : r5 y; {7 b- C0 u, f# b! K6 S6 C: o
  7.         return ch;6 u* Z/ x! ?: B: X
  8. }: `3 U; A6 g. n6 J
  9. /* USER CODE END 0 */
复制代码
  1.   /* USER CODE BEGIN 2 */8 r" P. V% K6 a# l! ^" F0 z
  2.   HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);            // TIM1_CH1(pwm)
    ) a5 |" S; N! a% }" u  D
  3.   HAL_TIM_Encoder_Start(&htim4, TIM_CHANNEL_1); // 开启编码器A
    , P, K8 H, {% V# d% _5 \/ J& S
  4.   HAL_TIM_Encoder_Start(&htim4, TIM_CHANNEL_2); // 开启编码器B        ! ]. H) G- f) @
  5.   HAL_TIM_Base_Start_IT(&htim2);                // 使能定时器2中断+ y0 ]0 z8 O  [, `% o* M
  6.   /* USER CODE END 2 */
复制代码
  1. /* USER CODE BEGIN 4 */# M/ ?8 ^5 F' L9 H/ n
  2. void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)$ X- o" [9 m2 ]
  3. {3 X3 M2 U3 P/ {1 V& P
  4.     static unsigned char i = 0;* m2 H5 Z+ l/ |) z; c  K
  5.     if (htim == (&htim2))
    9 J/ l* W, [9 [" W2 x- }
  6.     {5 r8 B6 p4 A$ r: q
  7.         //1.获取电机速度' I5 T5 C$ T5 V' o1 O, X# q( ?
  8.         MotorSpeed = (short)(__HAL_TIM_GET_COUNTER(&htim4)/18);   / J3 w4 M1 Q; ?( t+ L5 z4 a
  9.         // TIM4计数器获得电机脉冲,该电机在10ms采样的脉冲/18则为实际转速的rpm
    1 v, e2 b" g+ \7 A7 D! X
  10.         __HAL_TIM_SET_COUNTER(&htim4,0);  // 计数器清零
    4 ^/ E9 E7 C- m$ S$ D+ E

  11. " A) N2 s0 m, i" r7 r7 I$ R8 ~  v

  12. . N  m* N( t: s3 ~  ]
  13.         //2.将占空比导入至电机控制函数
    ; D; [) {% g- C+ m
  14.         MotorOutput=3600; // 3600即为50%的占空比
      r9 X1 F- U( v% K- J: r/ ?% [
  15.         __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, MotorOutput);$ X+ W5 Y& N6 j7 l% c! X
  16.         MotorOutput=MotorOutput*100/7200; 8 ^3 Z9 w; \1 a5 v. W; }
  17.         // 占空比(按最高100%计算,串口打印)
    ' z" H2 M* t( J2 X
  18.         i++;
    5 V8 s- Z* O5 z
  19.         if(i>100)- u; R! c; j- y
  20.         {" Z4 N$ t5 N; W$ m5 Q& S& G
  21.           // 通过观察小灯亮灭来判断是否正确进入定时器中断
    + ^) F) c0 h* G9 l; K5 ^- |6 E
  22.           HAL_GPIO_TogglePin(GPIOD, GPIO_PIN_2);
    . Z" D+ y/ H$ C0 m; _2 T3 @
  23.           // 打印定时器4的计数值,short(-32768——32767)  w9 _# x5 {% R- q) @9 G
  24.           printf("Encoder = %d moto = %d \r\n",MotorSpeed,MotorOutput);        
    8 ?4 V- d# |9 a2 T$ [) g4 g1 l. R: T
  25.           i=0;
    ; Y0 ?- x, i/ S, M) ?+ X7 P  v) Q
  26.         }
    & ~3 |2 J- r8 N: q9 P: ~1 y
  27.     }
    " \7 k2 @3 H9 A# J
  28. }+ i  @* X; R8 F
  29. /* USER CODE END 4 */3 P( n( F; h) b4 d; K5 R& v
复制代码

3 e+ L, x; j" [& v6 r(2)烧入STM32中,串口展示:; z/ r9 l, h% O3 r
% _  L7 {0 o; d7 H
O`T47Y5J`LF6UMHK{DLRM]G.png
# m9 I  E  D! G! ?4 P- z
% Y7 R/ k* [4 b, k9 t5 g(3)实物展示:1 M: m! U/ v6 X+ O

3 \( z, r- Q: S7 P) J* f$ g WO8L63G[V)3I$BYDF]A`T`A.png
7 R1 q7 o7 P6 [! l" ]) R+ W  ]/ |

& y. X# n) Z- [: Y) m" ]4、总结
; X5 }( V7 L: V% D5 v* m6 Q- g% q  以上就PWM控制电机转速与编码器读取电机速度的HAL库配置与keil编程,后续会推出利用PID算法闭环控制电机转速(HAL库)5 F, p1 w% c# C" @8 t# Q- x, o2 Q: q4 z
* J" _  f3 D! ]4 u7 Q7 z4 ^8 S

% Q- C: P4 G5 v* Q# g/ T
收藏 1 评论0 发布时间:2022-5-24 11:05

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版