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

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

[复制链接]
STMCU小助手 发布时间:2022-5-24 11:05
本篇文章我将针对PWM控制电机与编码器读取电机转速的STM32CubeMX配置过程进行详细的讲解,让准备学习HAL库的小伙伴能够更好的理解STM32CubeMX如何配置。
: A, z$ k$ K" j# O' M9 A
2 {" f4 N  L- t# j& V7 D1、硬件准备& {; L8 J4 B% V; \$ x5 ^5 |! k
(1)所需硬件" o/ `8 F+ z% Q# g, |* x' V5 n
. y+ f1 \. j& J- w7 P/ b, ]
芯片:STM32F103RCT6$ {# Q" f1 [5 `8 t
驱动:电机驱动板或TB6612(电机驱动芯片)
6 ?4 b5 p; _3 x4 ]电池:12V Libo电池
* i. B9 R  j) g8 ]/ q电机:带编码器电机( J+ I4 Y! |' E
轮子:我用的是麦克纳姆轮# j" q: m% ~' u
(2)硬件连接:
, i* `/ r( ~$ B  b0 F4 y6 Y# J( {, S) Z7 ~
PA8 —— 电机驱动板PWM1
+ q, }4 n* F, T( P* V2 BGND —— 电机驱动板PWM2, ~; w; z% A3 I) R$ T, p) `1 M& n: k
(这里若要反转则PWM1接地,PWM2接PA8;如果在小车中两者都需接PWM引脚,正转:PWM1给一定占空比,PWM2占空比为0)
% R" L. j4 y% L- M% _PA9(USART1_RX) —— 接串口TX  M, W5 n7 D" a& u$ \
PA10(USART1_TX) —— 接串口RX7 R4 v" c, O% K" a. P% }
PB6 —— 编码器A
. f& }1 E' j+ L* C- f# g, Z; u. WPB7 —— 编码器B
9 F* K3 K& O  U% h2、STM32CubeMX配置:
) e+ `7 R) R6 E4 |, f1.1 所用工具:% ^5 }* W( S* k+ x$ q/ x
  N  u$ \: [1 H/ ?6 A
芯片:STM32F103RCT6
5 j7 V  p) @% p0 H. I1 SIDE:MDK-Keil软件
2 }6 F$ J. T3 V( [4 _: bSTM32F1xxHAL库
; E) P0 I# n# u0 ?- \3 \  p! J& ~' }0 P
1.2 知识概括:
0 V, B+ P. r2 {. @& Y+ f2 C% h5 c0 J4 S8 M. U
STM32CubeMX创建TIMx、USART例程4 o4 |4 L) L! ^6 u3 L/ Y
Keil软件程序编写
4 Q" X/ e- N5 O. o- b0 d/ q% o; u* o' C- z) L0 ?" w
1.3 工程创建
  I+ h9 f" ?, a' C1、芯片选择; R6 H0 Z; o$ ~- s
  芯片:STM32F103RCT6(根据自己的板子来进行选择)
! n+ N. r+ G. q' k( L/ j  G
' Z2 f# j' E' t, W. ^ 23D0~9`L~7GL07(I_[N{KE2.png ( p, I+ }' \- L  o+ x# w

9 z: Q" k4 {- S# T9 F/ R, ~; b5 c2、设置RCC. M& B) W) t; \8 @" B
  设置高速外部时钟HSE 选择外部时钟源4 ~6 a' s$ t# q1 l
/ F. ?  H  A9 B
PW`{J8OBH2[{M@N[5PNQZ79.png - }( E0 b5 s+ n( K+ L7 T
# a7 S9 w5 ~2 h
3、LED1配置
  A! U( S1 Y4 E$ M9 M) }8 C) @  我使用的板子LED1引脚为PD2,初始电平为高电平,目的是通过观察小灯的亮灭判断是否进入定时器中断& f0 j* H0 E# q2 d* [6 F; y+ m

. `( g1 p) ]0 |- w $({RM4FPK)]`4S%9ST`Y2IV.png
+ ~  V' a+ C8 }5 z' M' d, d
! u& x) V! z- G  s. |) f( ]! H9 Z4、USART1配置
4 J# }% P( W8 o) i0 |$ ~% l  异步收发,波特率默认:115200 Bit/s
' q# I9 M2 f: y) y* N8 ]* L( }, z9 \' L9 ?% P0 `3 R% l
H)P`$@T]OH)A_H[{)H(6@YF.png
, H+ m# e+ D* g- a$ q# }) }$ z6 L
, ~8 Y# G. [( h, w# z9 a1 D4 ]5、PWM配置  e# v  e" ], l
  使用定时器1通道1和通道4(TIM1_CH1和TIM1_CH4),频率10KHz8 x. Y& M4 M# |' r) c

* E+ _* H! d# `3 l$ T: f SOU4}_(_UV`NP()~L2RAZ%6.png ; s% \" e+ M, ~* @8 T8 P

) v% h+ S, C" w$ w3 U  A; {6、定时器中断配置5 U7 h  u) o5 {" |. r2 R
  使用定时器2(TIM2),周期设为10ms,即10ms进一次定时器中断
; P$ r6 R- W/ T- z
& l, h" @8 d9 K [6DJT48_KSPB0OWES)C%C.png
- x: B$ m. \  f" e# V0 e  H  [" t9 u& V
  打开更新定时器中断* x+ C' r9 z' ^! U

; x+ q' J: k4 I  \ YOU~W`VS981(97ETMJ_GWQ4.png 5 q% P  ^9 d( Q, {) R* V- q+ b: C+ u

, Q! |2 K# Z) d6 i# [! Z7 ~) t7、编码器配置
" p- x- ]% ?9 I* I& O  STM32自带编码器配置,使用定时器4(TIM4_CH1和TIM4_CH2),打开更新定时器中断
+ D( J1 t$ \/ ^6 R$ U4 c# k
  ?1 d4 p. e/ q8 U0 C& w WWM7WN6[4QEZV49ZC(5FD_V.png
; X; W% L; [0 D$ L' u
0 h1 l( i2 c! |8、中断优先级配置3 V. E. x+ |7 V# O* `. e( d
  因为编码器中断要发生在定时10ms中断内,故编码器中断的抢占优先级要大于定时10ms
' }/ K. h/ m5 D; ~5 O
6 o2 P7 r3 L5 t% A; o }_DSEQOI[MC]KJKD5}(][4V.png
: }" e  J) b, _  F* L) |; D( c
! `2 w, m1 O+ Y# F5 w9、配置时钟
/ J& \6 S- D& z& u5 \  F1系列芯片系统时钟为72MHzs, n/ J5 M- R+ ^( S6 p

/ ?: a" m  u7 e1 Y 4NX{AV$J28BT0`HN2LHC%GC.png
$ u. |2 W/ J0 e
: f! i' a1 X7 T$ ]2 c3 c10、项目创建最后步骤( ^8 @; _) _, v1 T' s
$ p+ f  M2 X1 n$ E* h: M. ]
设置项目名称
7 D  w: v$ d" A2 b/ T* s选择所用IDE# X* K* C1 U4 h
1 Y) @7 h: @3 S9 E2 }0 F
_WFXTK(}2ZE8I8EMBL1)[YC.png   R* `8 W+ L* V4 z

  m& `( O0 ~! B1 T$ U7 m  M11、输出文件
# B; U5 R/ R0 c2 X
9 ^1 z& D+ [% `' J% D②处:复制所用文件的.c和.h
. L- K; p/ {) m: l- m6 n" ^$ b③处:每个功能生产独立的.c和.h文件
& ~3 n) @% A: G6 J0 G' H
7 ~3 X5 E: \) S& q+ V' K5 E# {' E WQR2U9C_7V691HYV7Q$VL96.png 8 J6 F& h- K3 @' r2 F
% ~3 a* x7 \( w; Z  A
12、创建工程文件
* e  l5 ]2 A0 T) |  点击GENERATE CODE 创建工程; i/ i+ r6 v, N5 q6 G
# [  h3 M9 ?! ~  |
13、配置下载工具
; W$ V% X" G- [, M  这里我们需要勾选上下载后直接运行,然后进行一次编译
5 s/ [" `3 E* w' ]6 p0 @0 Z% _4 @
  L& G% s% [' Z8 w 6F5%O4Y~9Y2M[QO1[68RUXP.png ! k# \! v% |0 l' _
/ V( i% p3 B( T1 T2 q
3、STM32源代码:+ B- Y3 ^7 a4 [- e9 e& v' E* w# l
(1)下面的代码之前有用过hal库的小伙伴应该都很容易理解,小政就不过多解释,有不懂的地方欢迎在评论区下方提问。在main.c加上:9 a& n/ G- t" g
1 N+ W/ P* h% w' D6 _+ O
  1. /* USER CODE BEGIN Includes */9 J4 N8 H& \+ U" V: C0 X3 c
  2. #include "stdio.h"
    3 X9 p3 t1 t& N* l5 c
  3. #include "math.h"
    * ]7 B* {* ^4 F
  4. /* USER CODE END Includes */
复制代码
  1. /* USER CODE BEGIN PV */
    4 j3 n$ C9 b/ D! r4 ?  @6 _
  2. unsigned int MotorSpeed;  // 电机当前速度数值,从编码器中获取) E+ Q8 ^% N' e% O: j1 e0 A
  3. int MotorOutput;                  // 电机输出
    / ?2 X( `8 Q/ P+ _
  4. /* USER CODE END PV */
复制代码
  1. /* USER CODE BEGIN 0 */
    + g, v+ H4 K* {' p; r2 I6 z
  2. int fputc(int ch, FILE *p)
    . S0 h5 t' [$ U7 E# F' N4 D
  3. {
    $ Y6 m' L8 z$ C- }* N! Y
  4.         while(!(USART1->SR & (1<<7)));& ^. a- N9 j3 j
  5.         USART1->DR = ch;
    2 ~# Q& b- c2 j+ ?
  6.         7 Y" E  ^) W& r  R- d2 H4 O* W' E
  7.         return ch;
    ' W  x8 D0 |6 {1 S) u
  8. }
    * ~% q& y7 i+ _# j6 A6 `4 M
  9. /* USER CODE END 0 */
复制代码
  1.   /* USER CODE BEGIN 2 */
    & U1 X- n  v! Q" z5 h4 ^9 B
  2.   HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);            // TIM1_CH1(pwm)- c: B5 Y9 C5 w4 P( b! C, }3 g
  3.   HAL_TIM_Encoder_Start(&htim4, TIM_CHANNEL_1); // 开启编码器A
    ( g# A6 R2 m! R, i
  4.   HAL_TIM_Encoder_Start(&htim4, TIM_CHANNEL_2); // 开启编码器B        
    3 z& f' O7 S/ W! j+ [/ u
  5.   HAL_TIM_Base_Start_IT(&htim2);                // 使能定时器2中断. S) n1 u/ T/ U8 n, u/ D, z
  6.   /* USER CODE END 2 */
复制代码
  1. /* USER CODE BEGIN 4 */" U# j3 w3 M  O2 q
  2. void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
    : {$ V* j: b& n- f6 s
  3. {
    # z6 K& C5 F8 L& i9 A# b) Q9 H1 I- I
  4.     static unsigned char i = 0;
    0 O+ R* |" _8 p/ V; {. q
  5.     if (htim == (&htim2))
    . v" z, x% X+ N2 a
  6.     {
    " N1 {7 O2 l# h, |# X) v- y
  7.         //1.获取电机速度
    : N9 ]9 G  }3 m+ i. h! R8 M
  8.         MotorSpeed = (short)(__HAL_TIM_GET_COUNTER(&htim4)/18);   4 }' O( W- k. s* b9 E% u
  9.         // TIM4计数器获得电机脉冲,该电机在10ms采样的脉冲/18则为实际转速的rpm
    , ?! I9 ]2 G5 A7 W; T9 n
  10.         __HAL_TIM_SET_COUNTER(&htim4,0);  // 计数器清零
    # J% K% E7 M  v. x% \" _' p
  11. * H# s4 g1 `0 k5 ~2 j

  12. * z8 X0 P, [+ Y6 G7 P2 Y
  13.         //2.将占空比导入至电机控制函数* A) n9 {& q3 K- A, T" `
  14.         MotorOutput=3600; // 3600即为50%的占空比
    6 t+ q- [8 d! f( g; Z0 q) I6 T1 i
  15.         __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, MotorOutput);* y1 ]( ^# E5 k  t7 L& e5 l
  16.         MotorOutput=MotorOutput*100/7200;
    1 ]/ K% j2 f2 E
  17.         // 占空比(按最高100%计算,串口打印)( {* w* b, l% y' a* @* F* N
  18.         i++;5 v& ~1 T. r1 A% n, F( r
  19.         if(i>100)  k# z- U' M, q: V4 U( I" J4 k& y0 F
  20.         {
    ' ^* e5 o1 @" s
  21.           // 通过观察小灯亮灭来判断是否正确进入定时器中断
    2 B; r; L- ]1 s" f, R+ X4 ^' Q
  22.           HAL_GPIO_TogglePin(GPIOD, GPIO_PIN_2);
    - d" F, X, I+ x$ s$ l' l
  23.           // 打印定时器4的计数值,short(-32768——32767)
    / t( r; Y% v9 w! m1 h! D+ `
  24.           printf("Encoder = %d moto = %d \r\n",MotorSpeed,MotorOutput);        
    2 L. ~  T) u5 B: i$ j
  25.           i=0;
    # a% q8 X$ I8 u) n
  26.         }/ ?5 n" F$ E6 A! {) g
  27.     }
    - [! L" ^, I5 y2 P7 H# l
  28. }8 M! i) M2 s, F1 o. w/ \- Z6 p
  29. /* USER CODE END 4 */
    , p  A$ f: ~& `! ]2 z
复制代码

6 q. ^0 f" e+ k(2)烧入STM32中,串口展示:8 V; Z6 K" f! L2 B* j  P8 V

4 `" _) m: O$ Z4 o O`T47Y5J`LF6UMHK{DLRM]G.png
' z- q. f6 x+ ?+ w, @7 g
" p0 z0 {$ X$ ~9 q( M5 k(3)实物展示:9 X- e7 ~# J0 ?- s0 ?2 h  o
% m, U  `$ O- [& Y/ Z9 a/ [1 W6 C
WO8L63G[V)3I$BYDF]A`T`A.png ) f6 h! A6 q$ D# v) }. |
: u1 V0 o! q6 e' @" ]- N
% H  \6 [4 d2 [( N
4、总结% p' J% l7 c: b7 i) g7 O1 t
  以上就PWM控制电机转速与编码器读取电机速度的HAL库配置与keil编程,后续会推出利用PID算法闭环控制电机转速(HAL库)0 _+ Z1 E+ H  S) N/ c

. [! F& q- z+ t1 W* l4 k! i/ i' H% T7 B% v
收藏 1 评论0 发布时间:2022-5-24 11:05

举报

0个回答

所属标签

相似分享

官网相关资源

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