STM32定时器2使用教程
文章目录
前言
这部分主要了解定时器的输出比较,了解计数器与捕获比较寄存器的关系,了解PWM原理并使用PWM驱动直流电机、舵机。
一、介绍部分
输出比较简介
对应这部分
PWM简介
通用输出比较通道
输出比较模式
PWM基本结构
公式
外设介绍
舵机简介
硬件电路
直流电机简介
硬件电路
引脚及定义
二、实例部分
PWM驱动呼吸灯
连接电路
配置PWM以及定时器
使用了重映射,将原本的PA0端口映射到了PB3端口,相关功能表如下
PWM.c如下:
#include "stm32f10x.h" // Device header
void PWM_Init(void){
// 初始化时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
// RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
// 引脚重映射配置(部分重映射),PA1映射到PB3
GPIO_PinRemapConfig(GPIO_PartialRemap1_TIM2,ENABLE);
// 解除JTA调试功能,使这些端口变为普通IO口
GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);
// 配置LED所在端口
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 服用推挽输出
// GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // 50Hz翻转速度
GPIO_Init(GPIOB, &GPIO_InitStructure);
// 使用内部时钟(默认)
TIM_InternalClockConfig(TIM2);
// 配置事间基础(时基单元)
TIM_TimeBaseInitTypeDef TIM_InitStructure;
// 时钟分频
TIM_InitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
// 计算模式
TIM_InitStructure.TIM_CounterMode = TIM_CounterMode_Up;
// 重载值(有1的偏差)<计数值> ARR
TIM_InitStructure.TIM_Period = 100-1;
// 预分频(有1的偏差)<频率> PSC
TIM_InitStructure.TIM_Prescaler = 720-1;
// 重复计数器(不使用)
TIM_InitStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM2,&TIM_InitStructure);
//初始化输出比较
TIM_OCInitTypeDef TIM_OCInitStruct;
//TIM_OCInitStruct.TIM_OCIdleState = ;
//TIM_OCInitStruct.TIM_OCNIdleState = ;
//TIM_OCInitStruct.TIM_OCNPolarity = ;
//TIM_OCInitStruct.TIM_OutputNState = ;
// 初始这个结构体,以免因为没有配置高级定时器相关的值而产生问题
TIM_OCStructInit(&TIM_OCInitStruct);
// PWM1模式
TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1;
// PWM高电平时有效
TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High;
// 输出使能
TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable;
// CCR,用于控制占空比的值
TIM_OCInitStruct.TIM_Pulse = 10;
TIM_OC2Init(TIM2,&TIM_OCInitStruct);
// 启动定时器
TIM_Cmd(TIM2,ENABLE);
}
// 修改占空比
void PWM_SetCCR(uint16_t Compare){
TIM_SetCompare2(TIM2,Compare);
}
主函数main.c如下:
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "PWM.h"
uint8_t i;
int main(void)
{
OLED_Init();
PWM_Init();
OLED_ShowString(1,3,"better");
while (1)
{
for(i=0;i<100;i++){
PWM_SetCCR(i);
Delay_ms(50);
}
for(i=100;i>0;i--){
PWM_SetCCR(i);
Delay_ms(50);
}
}
}
PWM驱动舵机
连接线路
代码实现
和呼吸灯基本一致,只需要对角度部分设计好适合的分频(PSC)、重载值(ARP)、与PWM比较值(CCR),由于舵机需要的周期为20ms,所以PWM频率应为1/0.002=50Hz(注意单位),然后50 = 7200000 / PSC / ARP,这里设置PSC = 72,所以ARP = 1000000/50 = 20000,舵机的可变输入信号范围为0.5ms~2.5ms,也就是(500 ~ 2500)us,所以CCR的范围设置在500 ~ 2500之间,然后与角度计算
PWM.c内容如下:
#include "stm32f10x.h" // Device header
void PWM_Init(void){
// 初始化时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
// 配置LED所在端口
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 服用推挽输出
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // 50Hz翻转速度
GPIO_Init(GPIOA, &GPIO_InitStructure);
// 使用内部时钟(默认)
TIM_InternalClockConfig(TIM2);
// 配置事间基础(时基单元)
TIM_TimeBaseInitTypeDef TIM_InitStructure;
// 时钟分频
TIM_InitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
// 计算模式
TIM_InitStructure.TIM_CounterMode = TIM_CounterMode_Up;
// 重载值(有1的偏差)<计数值> ARR
TIM_InitStructure.TIM_Period = 20000-1;
// 预分频(有1的偏差)<频率> PSC
TIM_InitStructure.TIM_Prescaler = 72-1;
// 重复计数器(不使用)
TIM_InitStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM2,&TIM_InitStructure);
//初始化输出比较
TIM_OCInitTypeDef TIM_OCInitStruct;
//TIM_OCInitStruct.TIM_OCIdleState = ;
//TIM_OCInitStruct.TIM_OCNIdleState = ;
//TIM_OCInitStruct.TIM_OCNPolarity = ;
//TIM_OCInitStruct.TIM_OutputNState = ;
// 初始这个结构体,以免因为没有配置高级定时器相关的值而产生问题
TIM_OCStructInit(&TIM_OCInitStruct);
// PWM1模式
TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1;
// PWM高电平时有效
TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High;
// 输出使能
TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable;
// CCR,用于控制占空比的值
TIM_OCInitStruct.TIM_Pulse = 0;
TIM_OC2Init(TIM2,&TIM_OCInitStruct);
// 启动定时器
TIM_Cmd(TIM2,ENABLE);
}
// 设置比较值
void PWM_SetCCR(uint16_t Compare){
TIM_SetCompare2(TIM2,Compare);
}
角度转换放在Servo.c
#include "stm32f10x.h" // Device header
#include "PWM.h"
// 初始化
void Servo_Init(void){
PWM_Init();
}
// 角度与CCR的数值转换
void Servo_Set(float Angle){
PWM_SetCCR(Angle/180*2000+500);
}
main.c内容如下:
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "Servo.h"
#include "Button.h"
uint8_t KeyNum;
float Angle;
int main(void)
{
OLED_Init();
Servo_Init();
Button_Init();
OLED_ShowString(1,1,"Angle");
Servo_Set(90);
while (1)
{
KeyNum = Key_Num();
if(KeyNum == 1){
Angle += 30;
if(Angle >= 180){
Angle = 0;
}
Servo_Set(Angle);
}
OLED_ShowNum(1,8,Angle,3);
}
}
PWM驱动直流电机
连接电路
连接USB的5v电压才能驱动直流电机,驱动电源4.5V ~ 10V
代码实现
改变了定时器中断频率,不影响占空比的情况下,提高频率使直流电机产生的杂音无法被人耳听见。
修改PWM.c如下:
#include "stm32f10x.h" // Device header
void PWM_Init(void){
// 初始化时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
// 配置PWM所在端口
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 服用推挽输出
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // 50Hz翻转速度
GPIO_Init(GPIOA, &GPIO_InitStructure);
// 使用内部时钟(默认)
TIM_InternalClockConfig(TIM2);
// 配置事间基础(时基单元)
TIM_TimeBaseInitTypeDef TIM_InitStructure;
// 时钟分频
TIM_InitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
// 计算模式
TIM_InitStructure.TIM_CounterMode = TIM_CounterMode_Up;
// 重载值(有1的偏差)<计数值> ARR
TIM_InitStructure.TIM_Period = 100-1;
// 预分频(有1的偏差)<频率> PSC
TIM_InitStructure.TIM_Prescaler = 36-1;
// 重复计数器(不使用)
TIM_InitStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM2,&TIM_InitStructure);
//初始化输出比较
TIM_OCInitTypeDef TIM_OCInitStruct;
// 初始这个结构体,以免因为没有配置高级定时器相关的值而产生问题
TIM_OCStructInit(&TIM_OCInitStruct);
// PWM1模式
TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1;
// PWM高电平时有效
TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High;
// 输出使能
TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable;
// CCR,用于控制占空比的值
TIM_OCInitStruct.TIM_Pulse = 0;
TIM_OC3Init(TIM2,&TIM_OCInitStruct);
// 启动定时器
TIM_Cmd(TIM2,ENABLE);
}
void PWM_SetCCR(uint16_t Compare){
TIM_SetCompare3(TIM2,Compare);
}
电机驱动函数Motor.c
#include "stm32f10x.h" // Device header
#include "PWM.h"
void Motor_Init(void){
// 控制方向的引脚
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // 50Hz翻转速度
GPIO_Init(GPIOA, &GPIO_InitStructure);
PWM_Init();
}
void Motor_SetSpeed(int16_t Speed){
// 正转
if(Speed>=0){
GPIO_SetBits(GPIOA,GPIO_Pin_4);
GPIO_ResetBits(GPIOA,GPIO_Pin_5);
PWM_SetCCR(Speed);
}
// 反转
else{
GPIO_SetBits(GPIOA,GPIO_Pin_5);
GPIO_ResetBits(GPIOA,GPIO_Pin_4);
PWM_SetCCR(-Speed);
}
}
主函数main.c内容:
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "Motor.h"
#include "Button.h"
uint8_t KeyNum;
int16_t Speed;
int main(void)
{
OLED_Init();
Motor_Init();
Button_Init();
OLED_ShowString(1,1,"Speed");
while (1)
{
KeyNum = Key_Num();
if(KeyNum == 1){
Speed += 20;
if(Speed > 100){
Speed = -100;
}
Motor_SetSpeed(Speed);
}
OLED_ShowSignedNum(1,8,Speed,3);
}
}
重点
PWM公式
直流电机引脚定义以及正反转原理
相关函数
// 初始化输出比较
void TIM_OC1Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
void TIM_OC2Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
void TIM_OC3Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
void TIM_OC4Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
// 重映射,解除端口的调试功能
void GPIO_PinRemapConfig(uint32_t GPIO_Remap, FunctionalState NewState);