本篇文章我将针对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. ^
( 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
- }( 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
+ ~ 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+ 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
; 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
- x: B$ m. \ f" e# V0 e H [" t9 u& V
打开更新定时器中断* x+ C' r9 z' ^! U
; x+ q' J: k4 I \
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
; 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
: }" 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
$ 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
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
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
! 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
- /* USER CODE BEGIN Includes */9 J4 N8 H& \+ U" V: C0 X3 c
- #include "stdio.h"
3 X9 p3 t1 t& N* l5 c - #include "math.h"
* ]7 B* {* ^4 F - /* USER CODE END Includes */
复制代码- /* USER CODE BEGIN PV */
4 j3 n$ C9 b/ D! r4 ? @6 _ - unsigned int MotorSpeed; // 电机当前速度数值,从编码器中获取) E+ Q8 ^% N' e% O: j1 e0 A
- int MotorOutput; // 电机输出
/ ?2 X( `8 Q/ P+ _ - /* USER CODE END PV */
复制代码- /* USER CODE BEGIN 0 */
+ g, v+ H4 K* {' p; r2 I6 z - int fputc(int ch, FILE *p)
. S0 h5 t' [$ U7 E# F' N4 D - {
$ Y6 m' L8 z$ C- }* N! Y - while(!(USART1->SR & (1<<7)));& ^. a- N9 j3 j
- USART1->DR = ch;
2 ~# Q& b- c2 j+ ? - 7 Y" E ^) W& r R- d2 H4 O* W' E
- return ch;
' W x8 D0 |6 {1 S) u - }
* ~% q& y7 i+ _# j6 A6 `4 M - /* USER CODE END 0 */
复制代码- /* USER CODE BEGIN 2 */
& U1 X- n v! Q" z5 h4 ^9 B - HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1); // TIM1_CH1(pwm)- c: B5 Y9 C5 w4 P( b! C, }3 g
- HAL_TIM_Encoder_Start(&htim4, TIM_CHANNEL_1); // 开启编码器A
( g# A6 R2 m! R, i - HAL_TIM_Encoder_Start(&htim4, TIM_CHANNEL_2); // 开启编码器B
3 z& f' O7 S/ W! j+ [/ u - HAL_TIM_Base_Start_IT(&htim2); // 使能定时器2中断. S) n1 u/ T/ U8 n, u/ D, z
- /* USER CODE END 2 */
复制代码- /* USER CODE BEGIN 4 */" U# j3 w3 M O2 q
- void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
: {$ V* j: b& n- f6 s - {
# z6 K& C5 F8 L& i9 A# b) Q9 H1 I- I - static unsigned char i = 0;
0 O+ R* |" _8 p/ V; {. q - if (htim == (&htim2))
. v" z, x% X+ N2 a - {
" N1 {7 O2 l# h, |# X) v- y - //1.获取电机速度
: N9 ]9 G }3 m+ i. h! R8 M - MotorSpeed = (short)(__HAL_TIM_GET_COUNTER(&htim4)/18); 4 }' O( W- k. s* b9 E% u
- // TIM4计数器获得电机脉冲,该电机在10ms采样的脉冲/18则为实际转速的rpm
, ?! I9 ]2 G5 A7 W; T9 n - __HAL_TIM_SET_COUNTER(&htim4,0); // 计数器清零
# J% K% E7 M v. x% \" _' p - * H# s4 g1 `0 k5 ~2 j
* z8 X0 P, [+ Y6 G7 P2 Y- //2.将占空比导入至电机控制函数* A) n9 {& q3 K- A, T" `
- MotorOutput=3600; // 3600即为50%的占空比
6 t+ q- [8 d! f( g; Z0 q) I6 T1 i - __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, MotorOutput);* y1 ]( ^# E5 k t7 L& e5 l
- MotorOutput=MotorOutput*100/7200;
1 ]/ K% j2 f2 E - // 占空比(按最高100%计算,串口打印)( {* w* b, l% y' a* @* F* N
- i++;5 v& ~1 T. r1 A% n, F( r
- if(i>100) k# z- U' M, q: V4 U( I" J4 k& y0 F
- {
' ^* e5 o1 @" s - // 通过观察小灯亮灭来判断是否正确进入定时器中断
2 B; r; L- ]1 s" f, R+ X4 ^' Q - HAL_GPIO_TogglePin(GPIOD, GPIO_PIN_2);
- d" F, X, I+ x$ s$ l' l - // 打印定时器4的计数值,short(-32768——32767)
/ t( r; Y% v9 w! m1 h! D+ ` - printf("Encoder = %d moto = %d \r\n",MotorSpeed,MotorOutput);
2 L. ~ T) u5 B: i$ j - i=0;
# a% q8 X$ I8 u) n - }/ ?5 n" F$ E6 A! {) g
- }
- [! L" ^, I5 y2 P7 H# l - }8 M! i) M2 s, F1 o. w/ \- Z6 p
- /* 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
' 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
) 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
|