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

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

[复制链接]
STMCU小助手 发布时间:2022-5-24 11:05
本篇文章我将针对PWM控制电机与编码器读取电机转速的STM32CubeMX配置过程进行详细的讲解,让准备学习HAL库的小伙伴能够更好的理解STM32CubeMX如何配置。$ Z$ h- \, v6 h* L; j; W
. }! |' T$ _9 s  P
1、硬件准备/ D5 g# D$ H/ s$ C3 F
(1)所需硬件
( r$ O0 s6 o  o" M) C$ c0 r* @( ~# C8 j: n' E
芯片:STM32F103RCT63 U. c$ M0 A  e' N! m) a5 q
驱动:电机驱动板或TB6612(电机驱动芯片)
4 p  w3 P5 I. `" z2 {电池:12V Libo电池, I) c1 {. N" M7 |& e
电机:带编码器电机) `' R3 C* E6 F* V" k
轮子:我用的是麦克纳姆轮! A$ D! U7 L3 a9 `4 o* x# a
(2)硬件连接:5 b7 Q% c7 X6 _

. P0 I3 L! D3 Y: C: {* ?% GPA8 —— 电机驱动板PWM1) z7 u; g# z  C* W1 [
GND —— 电机驱动板PWM2: `/ k9 h5 s" d5 z$ y- k8 n
(这里若要反转则PWM1接地,PWM2接PA8;如果在小车中两者都需接PWM引脚,正转:PWM1给一定占空比,PWM2占空比为0)+ f; P/ F+ \& w* J
PA9(USART1_RX) —— 接串口TX$ z8 h3 ^) y7 }' d
PA10(USART1_TX) —— 接串口RX* m+ u8 e. ]* `1 E. l" i2 x
PB6 —— 编码器A4 T) p" J4 X9 H1 }/ n
PB7 —— 编码器B) n2 J6 e8 @1 j0 [
2、STM32CubeMX配置:
' M& q; W( T% v! C1.1 所用工具:
% V  K2 v6 Z1 u% ]4 y3 H
4 N# J( }6 z9 s+ ?  V) [. N$ ~芯片:STM32F103RCT6  b8 K7 a% v! V& n: W, G
IDE:MDK-Keil软件
- Q8 s  @8 f1 P3 k/ jSTM32F1xxHAL库
; F7 n3 L. t5 y( V
, O5 q5 w; H2 o4 X' K1.2 知识概括:
' D1 z9 {2 R9 Y& o6 c  _3 u4 F- o% f: R
STM32CubeMX创建TIMx、USART例程. j" T- T5 b% E4 J1 R) {
Keil软件程序编写2 j) ~* F" i  Q  W4 C! q/ X* y) w
2 v: H) c: o; l7 R2 r+ r! Y# |6 M
1.3 工程创建6 D4 [2 ]% }7 ^; }
1、芯片选择
; z+ l4 [* j8 `9 B4 \' c+ X  芯片:STM32F103RCT6(根据自己的板子来进行选择)4 v; \: R: W3 l- R2 |* v8 P; s
* |5 @3 N( R- ]
23D0~9`L~7GL07(I_[N{KE2.png + E* P6 n4 K7 j0 N; z

- l5 @- N4 ?8 K& l/ @0 |) t( R! O2、设置RCC' T- n1 X( d( G3 q5 ~
  设置高速外部时钟HSE 选择外部时钟源
+ N, P9 f4 F, u9 \/ S3 Y1 W+ L( P# b- \5 g5 x
PW`{J8OBH2[{M@N[5PNQZ79.png
. }1 @, U: U! T+ `* t
2 S: g9 M- B" ^: u$ p  a3、LED1配置
/ f3 p; r) ~2 E5 D. N+ S- ], o/ u  我使用的板子LED1引脚为PD2,初始电平为高电平,目的是通过观察小灯的亮灭判断是否进入定时器中断
0 O+ l6 {5 d1 S7 e# v8 z( J, d% \) [8 j; G" p, a
$({RM4FPK)]`4S%9ST`Y2IV.png
- Z4 p9 ?. L: w1 v! u# F% L
/ a, S, H, j% o  U1 [4、USART1配置* q5 b" i! E- ^( v3 F
  异步收发,波特率默认:115200 Bit/s+ r: U; _( {' h0 X/ E5 a

  H7 c1 u- i$ I9 K. u6 j; J H)P`$@T]OH)A_H[{)H(6@YF.png
: f* ~* n' g; H- _9 F2 o) m( D( g8 w7 n
5、PWM配置
9 @& c$ s- z9 W* d  使用定时器1通道1和通道4(TIM1_CH1和TIM1_CH4),频率10KHz
) v" k- z. M9 \% [8 U0 `
! @( V/ U! T9 b1 N SOU4}_(_UV`NP()~L2RAZ%6.png
9 u7 N4 d& n7 g% O& F( K  r9 z. t8 n5 Z' w0 u
6、定时器中断配置
2 _! N* Q" F+ s  使用定时器2(TIM2),周期设为10ms,即10ms进一次定时器中断
1 f8 ^3 H9 {/ |8 F& X" s0 z' N( V8 d9 b+ B% V2 J! q
[6DJT48_KSPB0OWES)C%C.png / q1 U9 a9 `! x- O7 z" S
5 t( q, u1 `' z+ g- u. u
  打开更新定时器中断! t( {: Y1 c. K" L& d* W

# @2 f" n- N: \8 R% { YOU~W`VS981(97ETMJ_GWQ4.png 7 L  m7 U+ U# f: w# Q: P$ c3 ]. w8 q; r
7 t# a; A: t7 H3 _. m' r5 O
7、编码器配置6 Q8 w- Q* z) X
  STM32自带编码器配置,使用定时器4(TIM4_CH1和TIM4_CH2),打开更新定时器中断2 }/ x$ m" q+ g1 N7 e0 }! u3 Y3 R, I% h
6 N0 B) f" j  e$ j* T  y
WWM7WN6[4QEZV49ZC(5FD_V.png 9 n( M. {7 V! X  ~
/ v. ~; n  \( P5 K
8、中断优先级配置
4 w& ^# U: `4 h4 f" G  因为编码器中断要发生在定时10ms中断内,故编码器中断的抢占优先级要大于定时10ms
7 T& ^8 j4 T- s* H! P. C1 {
8 g: }+ ~# }4 l }_DSEQOI[MC]KJKD5}(][4V.png ' W- w: _9 j0 _/ e. I; l

2 R, n3 U! Z* O, q. n9、配置时钟
) e' ~' G1 \# V7 I# h  F1系列芯片系统时钟为72MHzs
: }. G$ K7 d( u; t: L; `3 X: @5 n- f2 u, E" S
4NX{AV$J28BT0`HN2LHC%GC.png
% c$ Z. A) V. m# S6 C3 T' g
) C% }  O0 _( e& Y; Y10、项目创建最后步骤
( V$ k, u- m) _0 c7 a; ?; t% |( O  Q, s9 L, J4 [1 b" @1 s
设置项目名称
& `/ Z3 \. U# x选择所用IDE
/ j/ z& o, z* A2 M# n8 r2 e
4 X8 Q3 X8 c7 S  e _WFXTK(}2ZE8I8EMBL1)[YC.png
7 X- {' s& ^3 j" C" s7 j; S
* w0 m$ a7 D* B. f11、输出文件/ V4 A! F  k: r; D) }* W8 M

5 y" z# z/ g9 d% B②处:复制所用文件的.c和.h
( L# @" G( E( M+ d+ G3 [  b2 m③处:每个功能生产独立的.c和.h文件
# T6 V! w7 @1 ?; b1 n! j! z* ?% h" i7 o" Z8 z+ W- q* d: a5 U# c( [& W! V
WQR2U9C_7V691HYV7Q$VL96.png
# q, ]: Q' t  Z' e9 W2 r: C4 a# J4 ?4 ]& r  g
12、创建工程文件
+ w) }0 Q; P" _3 R8 o( C0 P  点击GENERATE CODE 创建工程
8 r& {) p$ m& ]2 e7 a7 X" V  j4 C7 @
13、配置下载工具# T, ?4 Z  w; u3 r  Z* j8 y1 `
  这里我们需要勾选上下载后直接运行,然后进行一次编译( _+ e* p5 c) V1 z# f
+ V& K: A7 ^: G0 ]& Y+ w
6F5%O4Y~9Y2M[QO1[68RUXP.png
$ s# V  z4 n8 r! B: g# ?2 D. D) F% W/ e& [( X; r* l6 @' Z# J) J9 I
3、STM32源代码:8 R5 J" G  F% y
(1)下面的代码之前有用过hal库的小伙伴应该都很容易理解,小政就不过多解释,有不懂的地方欢迎在评论区下方提问。在main.c加上:" ^4 b+ Y* |6 q2 I

4 T  Q9 V% ?; _0 b* G; h6 F
  1. /* USER CODE BEGIN Includes */0 n+ t1 q8 v* X$ B4 T
  2. #include "stdio.h"
    $ g* _( U  O2 s7 R
  3. #include "math.h"5 v( w9 w/ S5 _  W+ n
  4. /* USER CODE END Includes */
复制代码
  1. /* USER CODE BEGIN PV */
    * r8 ~4 M0 b1 w
  2. unsigned int MotorSpeed;  // 电机当前速度数值,从编码器中获取+ t3 S- h$ ]3 w) }
  3. int MotorOutput;                  // 电机输出
    & o: d; p: M: v8 \
  4. /* USER CODE END PV */
复制代码
  1. /* USER CODE BEGIN 0 */" l$ o# u% ^% u; {) N+ G0 n
  2. int fputc(int ch, FILE *p)* w' ]$ D- x1 M- ^- o
  3. {  J5 h4 b  v) u! A7 F* e
  4.         while(!(USART1->SR & (1<<7)));5 k, ^! W$ a  i- X1 E
  5.         USART1->DR = ch;
    + U& E+ `0 o% d" e+ Z* q
  6.         % C7 i6 f$ b2 O( O! _
  7.         return ch;
    1 O! |. Y  e% Y. X5 y
  8. }
    1 O, y/ n+ S$ X7 B! ?
  9. /* USER CODE END 0 */
复制代码
  1.   /* USER CODE BEGIN 2 */& u( M: L. C$ N: ?9 j6 l+ E
  2.   HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);            // TIM1_CH1(pwm)% g+ u9 w2 ~; O( a$ |
  3.   HAL_TIM_Encoder_Start(&htim4, TIM_CHANNEL_1); // 开启编码器A
    & r: Z7 [0 C' h4 S6 Q. g/ @
  4.   HAL_TIM_Encoder_Start(&htim4, TIM_CHANNEL_2); // 开启编码器B        6 X( V$ B5 a. Y; _! }/ G4 K* y
  5.   HAL_TIM_Base_Start_IT(&htim2);                // 使能定时器2中断# ^& h$ \% R% A2 @( Z" k
  6.   /* USER CODE END 2 */
复制代码
  1. /* USER CODE BEGIN 4 */
    9 H! h( j; Y1 l8 l; s/ r
  2. void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
    + Y  E% v) w9 ]) \9 t
  3. {! ]4 o( y9 `8 {" I4 d1 G9 T+ O
  4.     static unsigned char i = 0;1 ~$ n6 T3 k# W# {& F  n( a- W- p
  5.     if (htim == (&htim2))
      ~4 N$ B: s; _' A
  6.     {
    6 e6 C% m0 s) E
  7.         //1.获取电机速度" O- f. u5 e- C% P. i
  8.         MotorSpeed = (short)(__HAL_TIM_GET_COUNTER(&htim4)/18);   ! R7 }. _8 k, C# k
  9.         // TIM4计数器获得电机脉冲,该电机在10ms采样的脉冲/18则为实际转速的rpm
    8 X$ _7 x4 u8 N! J
  10.         __HAL_TIM_SET_COUNTER(&htim4,0);  // 计数器清零
    1 b6 D2 d5 b! u: w- N/ n

  11. 6 a) L) @$ H2 \" H

  12. 9 d: b. j, Y5 T& |, z4 M& }! Q% ?
  13.         //2.将占空比导入至电机控制函数
    0 c* R6 ~& W7 l: C- ~1 ^
  14.         MotorOutput=3600; // 3600即为50%的占空比
    2 ^( N$ K6 _/ q
  15.         __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, MotorOutput);9 h7 B! S3 {# z5 @* W( [
  16.         MotorOutput=MotorOutput*100/7200; " A& t( Q( F9 f9 ?4 _/ Y% W
  17.         // 占空比(按最高100%计算,串口打印)* K+ k5 S+ Q6 }
  18.         i++;
    ( L' {. W+ c8 o. p
  19.         if(i>100)
    ) l/ z: u7 o' Z8 ]0 j% W( s9 Q6 M
  20.         {; f8 x# q0 z( Z! B# |8 x
  21.           // 通过观察小灯亮灭来判断是否正确进入定时器中断
    " X# _. r* W. c
  22.           HAL_GPIO_TogglePin(GPIOD, GPIO_PIN_2);- ~8 _  b# h2 B9 K: I/ C! d
  23.           // 打印定时器4的计数值,short(-32768——32767)* \# {3 @# F, Z6 x
  24.           printf("Encoder = %d moto = %d \r\n",MotorSpeed,MotorOutput);        9 r. U( x. _" [. F4 f% k  U. n- L. l* @
  25.           i=0;; K6 s& D. w4 I* a9 @& |
  26.         }
    & w8 I, G. Z  v% J. x$ ]
  27.     }
    # z% n1 s7 w$ q) L( S' b$ `
  28. }
      c% F, J) M3 f
  29. /* USER CODE END 4 */
    % x6 L  C; N% ?3 z+ m
复制代码

; t, M7 n* [+ C; v/ a* T$ f(2)烧入STM32中,串口展示:" ~9 `7 W& }6 q: F" W$ K3 r
6 J5 n$ e$ J  g* J
O`T47Y5J`LF6UMHK{DLRM]G.png
2 z" g! {) h  p1 n9 |" |5 f
0 r- K. `3 i( A# W: J- ]( k(3)实物展示:
5 D9 J+ U% _% Y2 G# Z7 L
# f4 y: f( U3 S+ Z% D' z! `# U WO8L63G[V)3I$BYDF]A`T`A.png - n! |% R. x$ J: E

9 u" q2 f2 `: N" \: |( g, B6 F  s* K8 w" ]
4、总结3 b  G& \/ Q/ |9 J
  以上就PWM控制电机转速与编码器读取电机速度的HAL库配置与keil编程,后续会推出利用PID算法闭环控制电机转速(HAL库)* [+ F$ U- |9 l: K" ?; N

4 r0 w7 r5 {/ Z7 }
4 ]% ?7 q; t! |
收藏 1 评论0 发布时间:2022-5-24 11:05

举报

0个回答

所属标签

相似技术帖

官网相关资源

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