注:本文属博主学习时所作笔记,内容源大参考于野火的《零死角玩转STM32F103》以及部分网络资料,笔记内容仅作为自己参考,免去频繁查询参考手册的麻烦,如有错误,还请指出!
高级定时器(STM32F1 系列中为 TIM1 和 TIM8)和通用定时器在基本定时器的基础上引入了外部引脚,可以实现输入捕获和输出比较功能。高级定时器比通用定时器增加了可编程死区互补输出、重复计数器、带刹车(断路)功能,这些功能都是针对电机控制方面。
由于TIM高级定时器结构复杂,功能众多,可以直接看野火的开发书籍,不做过多详述,文章主要侧重几个常用实验,并在代码中层层递进。
PWM 信号输出控制 SG90 舵机
该例程将通过将使用 STM32 输出 PWM 信号,控制 SG90 舵机进行转动,使用的是 TIM3 的通道1 为 PA6 口,舵机接线如下:
![SG90 舵机实物图](https://cdn.jsdelivr.net/gh/mahoo12138/js-css-cdn/hexo-images/image-20200925162930796.png)
控制原理及 PWM 配置
伺服电机通常被称为舵机,它是一种带有输出轴的小装置。当我们向伺服器发送一个控制信号时,输出轴就可以转到特定的位置。只要控制信号持续不变,伺服机构就会保持轴的角度位置不改变。如果控制信号发生变化,输出轴的位置也会相应发生变化。
舵机的内部结构如上图所示。你可以看到控制电路,马达,一组齿轮和外壳。
![舵机的内部结构](https://cdn.jsdelivr.net/gh/mahoo12138/js-css-cdn/hexo-images/servo_structure.png)
舵机内部的控制电路,电位计(可变电阻器)和电机均被连接到电路板上,如内部结构图的右边部分。控制电路通过电位计可监控舵机的当前角度。
如果轴的位置与控制信号相符,那么电机就会关闭。如果控制电路发现这个角度不正确,它就会控制马达转动,直到它达到指定的角度。舵机角度根据制造商的不同而有所不同。比如,一个180度的舵机,它可以在0度至180度之间运动。由于限位装置被安装在主输出装置上,超出这个范围机械结构就不能再转动了。
舵机的输出功率与它所需要转动的距离成正比。如果输出轴需要转动很长的距离,马达就会全速运转,如果它只需要短距离转动,马达就会以较慢的速度运行,这叫做速度比例控制。
舵机的控制一般需要一个 20ms 的时基脉冲,该脉冲的高电平部分一般为 0.5ms~2.5ms 范围内的角度控制脉冲部分。
![舵机的运动原理](https://cdn.jsdelivr.net/gh/mahoo12138/js-css-cdn/hexo-images/servo_motion.gif)
控制线用于传输角度控制信号。这个角度是由控制信号脉冲的持续时间决定的,这叫做脉冲编码调制(PCM)。舵机的控制一般需要一个20ms左右的时基脉冲,该脉冲的高电平部分一般为 0.5ms-2.5ms 范围,总间隔为 2ms。脉冲的宽度将决定马达转动的距离。例如:1.5毫秒的脉冲,电机将转向90度的位置(通常称为中立位置,对于180°舵机来说,就是90°位置)。如果脉冲宽度小于1.5毫秒,那么电机轴向朝向0度方向。如果脉冲宽度大于1.5毫秒,轴向就朝向180度方向。
![伺服电机时序图](https://cdn.jsdelivr.net/gh/mahoo12138/js-css-cdn/hexo-images/SERVO.gif)
综上,设置PWM周期为20ms = (7200*200)/72000000=0.02,所以TIM_Period = 199,TIM_Prescaler = 7199。
以180度舵机 SG90 为例,对应的控制关系是这样的:
脉冲宽度 |
转动角度 |
设置占空比 |
0.5 ms |
0° |
175 |
1.0 ms |
45° |
180 |
1.5 ms |
90° |
185 |
2.0 ms |
135° |
190 |
2.5 ms |
180° |
195 |
STM32工程目录
很久不接触 STM32 工程,文件结构差点乱了,这里贴个目录树:
├─Doc
│ readme.txt
│
├─Libraries
│ ├─CMSIS
│ │ └─startup
│ │
│ └─FWlib
│ ├─inc
│ └─src
│
├─Listing
│
├─Output
│
├─Project
│ └─RVMDK(uv5)
│ └─DebugConfig
│
└─User
│ main.c
│ stm32f10x_conf.h
│ stm32f10x_it.c
│ stm32f10x_it.h
│
├─PWM
│ bsp_pwm.c
│ bsp_pwm.h
│
└─SysTick
bsp_SysTick.c
bsp_SysTick.h
参考代码
bsp_pwm.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| #ifndef _BSP_PWM_H_ #define _BSP_PWM_H_
#include "stm32f10x.h"
#define GENERAL_TIM TIM3 #define GENERAL_TIM_APBxClock_FUN RCC_APB1PeriphClockCmd #define GENERAL_TIM_CLK RCC_APB1Periph_TIM3 #define GENERAL_TIM_Period 199 #define GENERAL_TIM_Prescaler 7199
#define GENERAL_TIM_CH1_GPIO_CLK RCC_APB2Periph_GPIOA #define GENERAL_TIM_CH1_PORT GPIOA #define GENERAL_TIM_CH1_PIN GPIO_Pin_6
void GENERAL_TIM_Init(void);
#endif
|
bsp_pwm.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
| #include "bsp_pwm.h"
static void GENERAL_TIM_GPIO_Config(void) { GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(GENERAL_TIM_CH1_GPIO_CLK, ENABLE); GPIO_InitStructure.GPIO_Pin = GENERAL_TIM_CH1_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GENERAL_TIM_CH1_PORT, &GPIO_InitStructure); }
static void GENERAL_TIM_Mode_Config(void) { GENERAL_TIM_APBxClock_FUN(GENERAL_TIM_CLK,ENABLE);
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_TimeBaseStructure.TIM_Period = GENERAL_TIM_Period; TIM_TimeBaseStructure.TIM_Prescaler = GENERAL_TIM_Prescaler; TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; TIM_TimeBaseStructure.TIM_RepetitionCounter=0; TIM_TimeBaseInit(GENERAL_TIM, &TIM_TimeBaseStructure);
TIM_OCInitTypeDef TIM_OCInitStructure; TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low; TIM_OC1Init(GENERAL_TIM, &TIM_OCInitStructure); TIM_OC1PreloadConfig(GENERAL_TIM, TIM_OCPreload_Enable);
TIM_Cmd(GENERAL_TIM, ENABLE); }
void GENERAL_TIM_Init(void) { GENERAL_TIM_GPIO_Config(); GENERAL_TIM_Mode_Config(); }
|
main.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| #include "stm32f10x.h" #include "bsp_pwm.h" #include "bsp_SysTick.h"
int main(void) { GENERAL_TIM_Init(); SysTick_Init(); while(1) { SysTick_Delay_Ms( 1000 ); TIM_SetCompare1(TIM3, 175); SysTick_Delay_Ms( 1000 ); TIM_SetCompare1(TIM3, 180); SysTick_Delay_Ms( 1000 ); TIM_SetCompare1(TIM3, 185); SysTick_Delay_Ms( 1000 ); TIM_SetCompare1(TIM3, 190); SysTick_Delay_Ms( 1000 ); TIM_SetCompare1(TIM3, 195); SysTick_Delay_Ms( 1000 ); }
}
|
舵机测试