本篇文章我将针对PWM控制电机与编码器读取电机转速的STM32CubeMX配置过程进行详细的讲解,让准备学习HAL库的小伙伴能够更好的理解STM32CubeMX如何配置。
J$ O5 Q# \8 i; W6 x+ \
- w; S+ V& Z) }/ h$ x- `0 m1、硬件准备9 M l% u3 f- M! A" _
(1)所需硬件
% k' O. E9 x, v
' B: v' q& w4 r- F芯片:STM32F103RCT6" o. p3 ^+ G" J
驱动:电机驱动板或TB6612(电机驱动芯片)" @+ Q8 H; g6 M: E$ e. L P
电池:12V Libo电池
' H0 H8 N3 ]7 I& o& T9 X: P1 P: [电机:带编码器电机
. @6 Q0 h4 {8 q& h- O轮子:我用的是麦克纳姆轮$ Q( a% s) s( M! |# m! Z2 J
(2)硬件连接:/ j6 y/ q0 p# g
0 E/ L; A- f# o, A" @3 a, |, v
PA8 —— 电机驱动板PWM13 Y& d8 q- k$ t2 u0 B2 b
GND —— 电机驱动板PWM2
' N" { {7 G4 U6 ~2 E(这里若要反转则PWM1接地,PWM2接PA8;如果在小车中两者都需接PWM引脚,正转:PWM1给一定占空比,PWM2占空比为0)6 I; z$ k, P5 d( E2 t, {4 ]) m G3 P
PA9(USART1_RX) —— 接串口TX9 N' _6 w J6 c" \4 m* T7 H
PA10(USART1_TX) —— 接串口RX' H& w1 U9 ^3 d4 Z
PB6 —— 编码器A
" v- F' ]/ d+ r [# F' sPB7 —— 编码器B. s2 H' W1 {) M3 x/ I
2、STM32CubeMX配置:( t7 E i1 b& i
1.1 所用工具:
* A0 i/ N; }6 c* x' s1 y# l, Q+ f. X: y* Q, E- S+ E
芯片:STM32F103RCT6
& Y& @4 Z8 t# V' D* Q' W$ gIDE:MDK-Keil软件2 y' i4 d0 J5 {
STM32F1xxHAL库$ ]) x6 o( s- d v8 R5 _. D
3 [, q2 P; i1 b8 `+ a1.2 知识概括: ~ Q# R, S6 O; {0 S3 l
4 B6 X5 Q# {- V# I5 B2 k& eSTM32CubeMX创建TIMx、USART例程9 ]7 z# O k Q; t
Keil软件程序编写7 ]3 G- |# K- h0 C! @
7 y( S, N* Z9 E# D
1.3 工程创建
- w9 i% T6 h% n% [1 l9 Y# X8 c1、芯片选择& |9 r/ K& C) R2 d0 C8 [7 `5 C
芯片:STM32F103RCT6(根据自己的板子来进行选择)
! P% F' T. ~$ C) c% U* l; D; Y+ g$ a ~/ Y
% @) r+ C" Z$ r: P9 Q9 {- s5 T7 w, z, O3 ]. Q! k
2、设置RCC3 A6 ^: {# l$ P9 m$ `% u. R
设置高速外部时钟HSE 选择外部时钟源
, h& v1 S$ j6 q, {$ r% ^
1 c' x! w1 j/ k8 N0 |
$ X$ ?& W8 B2 Q% p
+ j2 r8 I- j+ S1 [/ P( G& e$ M. U
3、LED1配置! u1 X+ @( H- G/ O6 }! R
我使用的板子LED1引脚为PD2,初始电平为高电平,目的是通过观察小灯的亮灭判断是否进入定时器中断2 D |0 r, ~- Q4 }/ a8 z
' i, ~9 r I# |' R7 E# V
; y" N5 _* t4 @$ ?) X3 }- c( a
+ Q. M, x7 m' v4、USART1配置
: {8 l2 ^. u( D, i0 N 异步收发,波特率默认:115200 Bit/s( t5 r' t: C2 g- v+ T2 _
7 x: ]. v/ n3 w: t( \* Q) w
" c' B1 O. o9 u- G
) X, U( o# c/ U2 e2 R3 l5、PWM配置' G5 r. y5 Z& N
使用定时器1通道1和通道4(TIM1_CH1和TIM1_CH4),频率10KHz
" v- W( t. O2 p {
" ~' p. s; L3 M5 g
) P2 E7 m- H% E3 } J' E
1 p8 ?0 c8 K; H, W2 G6、定时器中断配置" h: @- N$ {) r1 a: o
使用定时器2(TIM2),周期设为10ms,即10ms进一次定时器中断
% w' T3 s5 d* P3 r6 O
( o, Y' I* d4 P/ `; s
2 \& T+ }7 K+ V' s
2 [! S8 y; @8 k. X- ~
打开更新定时器中断+ l4 A! K, Q' Y$ q6 f+ w. D
4 y- X4 u: [, t( |: w
3 p* _" |) |. A" w9 I( H* T5 q4 S, K
7、编码器配置
7 ^2 J8 \8 u3 W4 H STM32自带编码器配置,使用定时器4(TIM4_CH1和TIM4_CH2),打开更新定时器中断8 Z4 X$ f" T: K' P8 b7 k G9 ?
0 M- J' {: I8 s1 I" w
0 X# [5 w, `+ @; `& q m8 F9 [7 S. y3 D% x
8、中断优先级配置
' ~; i: J: R) a+ c: e) c- q 因为编码器中断要发生在定时10ms中断内,故编码器中断的抢占优先级要大于定时10ms
4 A( ^# G: o3 V( y' s4 o2 y b, d( m* Z* n) c* O X
; G9 J( c8 ?8 O6 b A# A; O) W6 Y! _- n
- R) }+ K; D' o3 L# H0 Z- b8 u9、配置时钟: v. x* M. v8 z$ c' u. y) h
F1系列芯片系统时钟为72MHzs
( j8 J. j3 A$ n: ^3 P2 |
c7 p! u: K2 G1 O' j
6 _, N9 _* d4 S' y0 h! ]5 G- ]
1 L- m' c* ~+ W! ~
10、项目创建最后步骤
8 B- K5 ]8 W) ?/ o: Q) q6 f% z( m: {* V5 u
设置项目名称7 F8 K" A' {7 \" ?6 v8 v% B8 R
选择所用IDE0 f3 h# I" E3 ^7 i
# S# y3 ?# E! t- W6 c" K
7 J0 h% Z( Z' s+ D* p J
4 G- t3 A% g0 B7 E) ]11、输出文件
2 \& Y# A" Y& `! ?1 J
$ B7 h# g8 r! ^$ q②处:复制所用文件的.c和.h
1 s% I: c9 f. V$ n) `+ H③处:每个功能生产独立的.c和.h文件$ m; T+ Q+ ~& O. Q+ u
, Q8 ^: X% K4 }! d( v& O
, y1 L5 R. @' q* A
3 A3 a( \/ O) O$ F12、创建工程文件) ^! d9 S; }; y6 J
点击GENERATE CODE 创建工程" U* d5 `# G1 @; H" u
& R( S4 i, y# Z5 O% Q2 I( j$ n13、配置下载工具
" k8 \# }( F7 r 这里我们需要勾选上下载后直接运行,然后进行一次编译: b# e% C( b8 H% h5 g; R
9 f$ J! r( f! P& R3 Z. {
8 Y2 u; M6 S" C
7 |* y/ N+ _! m' C3、STM32源代码:: K! o0 W/ _+ [
(1)下面的代码之前有用过hal库的小伙伴应该都很容易理解,小政就不过多解释,有不懂的地方欢迎在评论区下方提问。在main.c加上:
" _+ w! ~0 e# d% f9 y/ K, r) f: ^, Q( H1 Q# F% X# b
- /* USER CODE BEGIN Includes */
?6 m$ d# u ^ L - #include "stdio.h"% P! G. r; t: A
- #include "math.h"
0 n9 F1 K, }# R6 j0 V - /* USER CODE END Includes */
复制代码- /* USER CODE BEGIN PV */
: L5 I" u* H# q5 o/ V0 d; G - unsigned int MotorSpeed; // 电机当前速度数值,从编码器中获取
0 T" i$ a* [) ]: N" m }% Y2 F- y - int MotorOutput; // 电机输出! K2 q0 g W* G( Z3 o6 ?, C3 ?
- /* USER CODE END PV */
复制代码- /* USER CODE BEGIN 0 */* {' l8 Z4 _7 k% X0 [3 h7 U/ Q
- int fputc(int ch, FILE *p)
$ e0 N: E/ n( |0 w - {- w8 Q, }0 H4 v; ^# w/ _/ ]( u
- while(!(USART1->SR & (1<<7)));' R I8 ^; b9 Q: ~# w, S
- USART1->DR = ch;/ p& h. Z6 p* W
-
( Z7 D0 n' R! T5 @# F$ q - return ch;' a) y4 p4 F! o( S' l4 d
- }
A5 ]9 T! T8 b6 ~! I1 D9 m - /* USER CODE END 0 */
复制代码- /* USER CODE BEGIN 2 */7 e! [2 f) Z* V3 i& G
- HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1); // TIM1_CH1(pwm)4 b# l$ R$ u1 i& ]& r3 p
- HAL_TIM_Encoder_Start(&htim4, TIM_CHANNEL_1); // 开启编码器A
$ J( l6 k0 B8 I8 |! m+ }; }( } - HAL_TIM_Encoder_Start(&htim4, TIM_CHANNEL_2); // 开启编码器B & i' C4 S! c0 e: h# x& ?
- HAL_TIM_Base_Start_IT(&htim2); // 使能定时器2中断) E8 p. ~( E; i h0 T! S: l9 a( r
- /* USER CODE END 2 */
复制代码- /* USER CODE BEGIN 4 */. M& P2 t# e4 y) V3 V( ` x
- void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)4 ?) b3 r- O# E( }
- {, x4 L C5 a, e9 t
- static unsigned char i = 0;8 A8 Z# Z/ [- y5 F$ `" }
- if (htim == (&htim2))
) {- D. q4 Q6 u2 {& D0 @0 K9 y - {
! ~: V! m/ |& m7 X - //1.获取电机速度
( i6 I& V8 z( o# N5 e. I - MotorSpeed = (short)(__HAL_TIM_GET_COUNTER(&htim4)/18);
% W1 E' {" f u - // TIM4计数器获得电机脉冲,该电机在10ms采样的脉冲/18则为实际转速的rpm
( u3 ]4 E8 o0 ^8 | - __HAL_TIM_SET_COUNTER(&htim4,0); // 计数器清零
) H! y- D [/ E5 M7 u) ^( p; S - + I+ M( Z1 v( p, I
6 ^9 o7 a; t5 q% E- //2.将占空比导入至电机控制函数
2 j2 O7 w7 v+ R* h$ D - MotorOutput=3600; // 3600即为50%的占空比4 X* y F1 U' r$ \6 d3 H" s
- __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, MotorOutput);& ~4 K6 V/ ^1 N0 n
- MotorOutput=MotorOutput*100/7200;
q" j6 ~9 Y$ T; h1 `8 V - // 占空比(按最高100%计算,串口打印)
! B1 V, S/ l i8 D9 m) r! w - i++;
' I4 v# K5 X, @- _! M5 ?; ]- l - if(i>100)
9 u6 @) l4 r8 X; D8 S# w - {
9 p, q J3 F7 L" t1 O4 ` - // 通过观察小灯亮灭来判断是否正确进入定时器中断
4 u* u, f5 Z5 V0 l) L - HAL_GPIO_TogglePin(GPIOD, GPIO_PIN_2);
# u- J# p) G' } - // 打印定时器4的计数值,short(-32768——32767)' D9 U$ g$ Q8 f; r
- printf("Encoder = %d moto = %d \r\n",MotorSpeed,MotorOutput); + k. k! ~4 j8 D8 ~2 s. ^# [
- i=0;
( ]' h o6 ?0 F) b) F* L - }( L' k& o# ?, H! ^7 }
- }" @1 ]! o8 X( d. O7 n
- }) R; V, \) f5 G0 |2 e
- /* USER CODE END 4 */. v, U" \9 X8 L
复制代码
; l' U* \# c* k# V(2)烧入STM32中,串口展示:
0 H3 N+ h" `% u! D& }: X/ d% p0 N9 o+ F" v& i; W3 V
$ L0 p4 T3 Y% n0 z1 f: I0 |' D" i* j$ p' j, s9 }( W) p# [, z
(3)实物展示:
( B3 y9 \' n: C. u* T! D9 _. q m4 X! b$ D
* h+ Y/ M- P4 m3 ?
& Q2 q/ M& I, \4 b: G7 I/ k* Q% I; H6 Q' I( v+ F/ Q
4、总结" v7 w2 I# ]$ {. r9 a3 s
以上就PWM控制电机转速与编码器读取电机速度的HAL库配置与keil编程,后续会推出利用PID算法闭环控制电机转速(HAL库)" {0 I! M1 m8 T8 n6 O/ R. I8 c
f; k0 i. t& U; a3 R
) @# h+ |- _0 r" P |