本篇文章我将针对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
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
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
# 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 | @
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
( 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
& 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
* 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
, 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
- 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
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
; _ 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 }
, 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
: 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- /* USER CODE BEGIN Includes */# B; l! c' s9 \" A3 _+ N+ t. z' Z/ t
- #include "stdio.h". d; b& q- I; A( C
- #include "math.h"5 m; j. k# A, H
- /* USER CODE END Includes */
复制代码- /* USER CODE BEGIN PV */4 {, ^) U; Y7 A& d! w: V1 T
- unsigned int MotorSpeed; // 电机当前速度数值,从编码器中获取+ ~' @, A) W; u
- int MotorOutput; // 电机输出
( C7 N& u6 ^# e4 f% m - /* USER CODE END PV */
复制代码- /* USER CODE BEGIN 0 */
% H R! C' Q3 g6 N O: H - int fputc(int ch, FILE *p)
% b6 G$ k y" n8 T% v. u - {8 l' c* _6 K" s) W. i! n$ L
- while(!(USART1->SR & (1<<7)));) t* Y- M" T5 k' B. `, g# \
- USART1->DR = ch;
# D# e$ C. q, i; L -
: r5 y; {7 b- C0 u, f# b! K6 S6 C: o - return ch;6 u* Z/ x! ?: B: X
- }: `3 U; A6 g. n6 J
- /* USER CODE END 0 */
复制代码- /* USER CODE BEGIN 2 */8 r" P. V% K6 a# l! ^" F0 z
- HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1); // TIM1_CH1(pwm)
) a5 |" S; N! a% }" u D - HAL_TIM_Encoder_Start(&htim4, TIM_CHANNEL_1); // 开启编码器A
, P, K8 H, {% V# d% _5 \/ J& S - HAL_TIM_Encoder_Start(&htim4, TIM_CHANNEL_2); // 开启编码器B ! ]. H) G- f) @
- HAL_TIM_Base_Start_IT(&htim2); // 使能定时器2中断+ y0 ]0 z8 O [, `% o* M
- /* USER CODE END 2 */
复制代码- /* USER CODE BEGIN 4 */# M/ ?8 ^5 F' L9 H/ n
- void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)$ X- o" [9 m2 ]
- {3 X3 M2 U3 P/ {1 V& P
- static unsigned char i = 0;* m2 H5 Z+ l/ |) z; c K
- if (htim == (&htim2))
9 J/ l* W, [9 [" W2 x- } - {5 r8 B6 p4 A$ r: q
- //1.获取电机速度' I5 T5 C$ T5 V' o1 O, X# q( ?
- MotorSpeed = (short)(__HAL_TIM_GET_COUNTER(&htim4)/18); / J3 w4 M1 Q; ?( t+ L5 z4 a
- // TIM4计数器获得电机脉冲,该电机在10ms采样的脉冲/18则为实际转速的rpm
1 v, e2 b" g+ \7 A7 D! X - __HAL_TIM_SET_COUNTER(&htim4,0); // 计数器清零
4 ^/ E9 E7 C- m$ S$ D+ E
" A) N2 s0 m, i" r7 r7 I$ R8 ~ v
. N m* N( t: s3 ~ ]- //2.将占空比导入至电机控制函数
; D; [) {% g- C+ m - MotorOutput=3600; // 3600即为50%的占空比
r9 X1 F- U( v% K- J: r/ ?% [ - __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, MotorOutput);$ X+ W5 Y& N6 j7 l% c! X
- MotorOutput=MotorOutput*100/7200; 8 ^3 Z9 w; \1 a5 v. W; }
- // 占空比(按最高100%计算,串口打印)
' z" H2 M* t( J2 X - i++;
5 V8 s- Z* O5 z - if(i>100)- u; R! c; j- y
- {" Z4 N$ t5 N; W$ m5 Q& S& G
- // 通过观察小灯亮灭来判断是否正确进入定时器中断
+ ^) F) c0 h* G9 l; K5 ^- |6 E - HAL_GPIO_TogglePin(GPIOD, GPIO_PIN_2);
. Z" D+ y/ H$ C0 m; _2 T3 @ - // 打印定时器4的计数值,short(-32768——32767) w9 _# x5 {% R- q) @9 G
- printf("Encoder = %d moto = %d \r\n",MotorSpeed,MotorOutput);
8 ?4 V- d# |9 a2 T$ [) g4 g1 l. R: T - i=0;
; Y0 ?- x, i/ S, M) ?+ X7 P v) Q - }
& ~3 |2 J- r8 N: q9 P: ~1 y - }
" \7 k2 @3 H9 A# J - }+ i @* X; R8 F
- /* 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
# 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
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 |