STM32TIM定时器(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);

根据手册了解不同计数器所含引脚的重映射范围

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值