本篇文章我将针对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- ]
+ 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
. }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
- 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
: 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
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
/ 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% {
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
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
' 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
% 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
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
# 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
$ 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- /* USER CODE BEGIN Includes */0 n+ t1 q8 v* X$ B4 T
- #include "stdio.h"
$ g* _( U O2 s7 R - #include "math.h"5 v( w9 w/ S5 _ W+ n
- /* USER CODE END Includes */
复制代码- /* USER CODE BEGIN PV */
* r8 ~4 M0 b1 w - unsigned int MotorSpeed; // 电机当前速度数值,从编码器中获取+ t3 S- h$ ]3 w) }
- int MotorOutput; // 电机输出
& o: d; p: M: v8 \ - /* USER CODE END PV */
复制代码- /* USER CODE BEGIN 0 */" l$ o# u% ^% u; {) N+ G0 n
- int fputc(int ch, FILE *p)* w' ]$ D- x1 M- ^- o
- { J5 h4 b v) u! A7 F* e
- while(!(USART1->SR & (1<<7)));5 k, ^! W$ a i- X1 E
- USART1->DR = ch;
+ U& E+ `0 o% d" e+ Z* q - % C7 i6 f$ b2 O( O! _
- return ch;
1 O! |. Y e% Y. X5 y - }
1 O, y/ n+ S$ X7 B! ? - /* USER CODE END 0 */
复制代码- /* USER CODE BEGIN 2 */& u( M: L. C$ N: ?9 j6 l+ E
- HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1); // TIM1_CH1(pwm)% g+ u9 w2 ~; O( a$ |
- HAL_TIM_Encoder_Start(&htim4, TIM_CHANNEL_1); // 开启编码器A
& r: Z7 [0 C' h4 S6 Q. g/ @ - HAL_TIM_Encoder_Start(&htim4, TIM_CHANNEL_2); // 开启编码器B 6 X( V$ B5 a. Y; _! }/ G4 K* y
- HAL_TIM_Base_Start_IT(&htim2); // 使能定时器2中断# ^& h$ \% R% A2 @( Z" k
- /* USER CODE END 2 */
复制代码- /* USER CODE BEGIN 4 */
9 H! h( j; Y1 l8 l; s/ r - void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
+ Y E% v) w9 ]) \9 t - {! ]4 o( y9 `8 {" I4 d1 G9 T+ O
- static unsigned char i = 0;1 ~$ n6 T3 k# W# {& F n( a- W- p
- if (htim == (&htim2))
~4 N$ B: s; _' A - {
6 e6 C% m0 s) E - //1.获取电机速度" O- f. u5 e- C% P. i
- MotorSpeed = (short)(__HAL_TIM_GET_COUNTER(&htim4)/18); ! R7 }. _8 k, C# k
- // TIM4计数器获得电机脉冲,该电机在10ms采样的脉冲/18则为实际转速的rpm
8 X$ _7 x4 u8 N! J - __HAL_TIM_SET_COUNTER(&htim4,0); // 计数器清零
1 b6 D2 d5 b! u: w- N/ n
6 a) L) @$ H2 \" H
9 d: b. j, Y5 T& |, z4 M& }! Q% ?- //2.将占空比导入至电机控制函数
0 c* R6 ~& W7 l: C- ~1 ^ - MotorOutput=3600; // 3600即为50%的占空比
2 ^( N$ K6 _/ q - __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, MotorOutput);9 h7 B! S3 {# z5 @* W( [
- MotorOutput=MotorOutput*100/7200; " A& t( Q( F9 f9 ?4 _/ Y% W
- // 占空比(按最高100%计算,串口打印)* K+ k5 S+ Q6 }
- i++;
( L' {. W+ c8 o. p - if(i>100)
) l/ z: u7 o' Z8 ]0 j% W( s9 Q6 M - {; f8 x# q0 z( Z! B# |8 x
- // 通过观察小灯亮灭来判断是否正确进入定时器中断
" X# _. r* W. c - HAL_GPIO_TogglePin(GPIOD, GPIO_PIN_2);- ~8 _ b# h2 B9 K: I/ C! d
- // 打印定时器4的计数值,short(-32768——32767)* \# {3 @# F, Z6 x
- printf("Encoder = %d moto = %d \r\n",MotorSpeed,MotorOutput); 9 r. U( x. _" [. F4 f% k U. n- L. l* @
- i=0;; K6 s& D. w4 I* a9 @& |
- }
& w8 I, G. Z v% J. x$ ] - }
# z% n1 s7 w$ q) L( S' b$ ` - }
c% F, J) M3 f - /* 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
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
- 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! | |