: 本教程基于up主江科大自化协——“STM32入门教程”记录的个人学习笔记
输出比较介绍
OC(Output Compare)输出比较
输出比较可以通过比较CNT与CCR寄存器值的关系,来对输出电平进行置1、置0或翻转的操作,用于输出一定频率和占空比的PWM波形
每个高级定时器和通用定时器都拥有4个输出比较通道
高级定时器的前3个通道额外拥有死区生成和互补输出的功能
PWM简介
PWM(Pulse Width Modulation)脉冲宽度调制
在具有惯性的系统中,可以通过对一系列脉冲的宽度进行调制,来等效地获得所需要的模拟参量,常应用于电机控速等领域
PWM参数:
频率 = 1 / TS 占空比 = TON / TS 分辨率 = 占空比变化步距
Ton表示高电平
Ts表示整个周期
输出比较模式
TIM_OCMode_Timing
TIM_OCMode_Active
TIM_OCMode_Inactive
TIM_OCMode_Toggle
TIM_OCMode_PWM1
TIM_OCMode_PWM2
有效电平:高电平
无效电平:低电平
PWM基本结构
参数计算
其中蓝色线是CNT的值,黄色线是ARR的值,红色线是CCR的值
PWM频率: Freq = CK_PSC / (PSC + 1) / (ARR + 1)
PWM占空比: Duty = CCR / (ARR + 1)
PWM分辨率: Reso = 1 / (ARR + 1) Reso越小越好,越小越细腻
硬件电路
舵机
直流电机及驱动简介
直流电机是一种将电能转换为机械能的装置,有两个电极,当电极正接时,电机正转,当电极反接时,电机反转
直流电机属于大功率器件,GPIO口无法直接驱动,需要配合电机驱动电路来操作
TB6612是一款双路H桥型的直流电机驱动芯片,可以驱动两个直流电机并且控制其转速和方向
VM:与电机的额定电压保持一致
VCC:与控制电路的电压保持一致(一般与控制电路共用)
TIM库函数
用结构体初始化输出比较单元
TIM_OC1Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
TIM_OC2Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
TIM_OC3Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
TIM_OC4Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);//不同的GPIO口对应不同的比较单元(引脚定义表)
TIM_OCStructInit(TIM_OCInitTypeDef* TIM_OCInitStruct);//给输出比较结构体赋一个默认值(防止有些参数没有配置,出现报错)
用来配置强制输出模式(暂停波形并强制高低电平)
TIM_ForcedOC1Config(TIM_TypeDef* TIMx, uint16_t TIM_ForcedAction);
TIM_ForcedOC2Config(TIM_TypeDef* TIMx, uint16_t TIM_ForcedAction);
TIM_ForcedOC3Config(TIM_TypeDef* TIMx, uint16_t TIM_ForcedAction);
TIM_ForcedOC4Config(TIM_TypeDef* TIMx, uint16_t TIM_ForcedAction);
用来配置CCR寄存器的预装功能
TIM_OC1PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload);
TIM_OC2PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload);
TIM_OC3PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload);
TIM_OC4PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload);
用来配置快速使能的
TIM_OC1FastConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCFast);
TIM_OC2FastConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCFast);
TIM_OC3FastConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCFast);
TIM_OC4FastConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCFast);
外部事件清除REP信号
TIM_ClearOC1Ref(TIM_TypeDef* TIMx, uint16_t TIM_OCClear);
TIM_ClearOC2Ref(TIM_TypeDef* TIMx, uint16_t TIM_OCClear);
TIM_ClearOC3Ref(TIM_TypeDef* TIMx, uint16_t TIM_OCClear);
TIM_ClearOC4Ref(TIM_TypeDef* TIMx, uint16_t TIM_OCClear);
//注:TIM_CtrlPWMOutputs(TIM_TypeDef* TIMx, FunctionalState NewState);仅高级定时器使用,在使用高级定时器输出PWM时,需要调用这个函数,使能主输出,否则PWM将不能正常输出
单独更改CCR寄存器值的函数
TIM_SetCompare1(TIM_TypeDef* TIMx, uint16_t Compare1);
TIM_SetCompare2(TIM_TypeDef* TIMx, uint16_t Compare2);
TIM_SetCompare3(TIM_TypeDef* TIMx, uint16_t Compare3);
TIM_SetCompare4(TIM_TypeDef* TIMx, uint16_t Compare4);
TIM1_SetCompare1 设置 TIM1 捕获比较 1 寄存器值 TIM1_SetCompare2 设置 TIM1 捕获比较 2 寄存器值 TIM1_SetCompare3 设置 TIM1 捕获比较 3 寄存器值 TIM1_SetCompare4 设置 TIM1 捕获比较 4 寄存器值 //TIM1_SetCompare1是用来控制CCR寄存器的值,但是占空比跟CCR与ARR都有关
配置流程
1,配置时钟,把TIM外设与GPIO外设时钟打开
2,配置时基单元
3,配置输出比较单元
4,配置GPIO PWM对应的GPIO配置为复用推挽输出
5,控制运行
配置时钟
配置GPIO为复用推挽输出
//因为GPIO的推挽、开漏输出的引脚控制权是来自于输出数据寄存器,如果要用定时器控制引脚,就需要使用复用推挽或者复用开漏
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE); //TIM外设
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //GPIO外设
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
TIM_InternalClockConfig(TIM2);
配置时基单元
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
TIM_TimeBaseInitStruct.TIM_ClockDivision =TIM_CKD_DIV1;
TIM_TimeBaseInitStruct.TIM_CounterMode =TIM_CounterMode_Up;
TIM_TimeBaseInitStruct.TIM_Period =100-1; //ARR
TIM_TimeBaseInitStruct.TIM_Prescaler =720-1; //PSC
TIM_TimeBaseInitStruct.TIM_RepetitionCounter =0;
TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStruct);
配置输出比较单元
TIM_OCInitTypeDef TIM_OCInitStruct;
TIM_OCStructInit(&TIM_OCInitStruct); //给结构体赋予一个默认值
TIM_OCInitStruct.TIM_OCMode=TIM_OCMode_PWM1;
TIM_OCInitStruct.TIM_OCPolarity=TIM_OCPolarity_High;
TIM_OCInitStruct.TIM_OutputState =TIM_OutputState_Enable;
TIM_OCInitStruct.TIM_Pulse=50; //Pulse是CCR的值
TIM_OC1Init(TIM2,&TIM_OCInitStruct);
TIM_Cmd(TIM2,ENABLE); //TIM2-CH1-ETR服用了PA0引脚
TIM1_OCMode 描述 TIM1_OCMode_TIM1ing TIM1 输出比较时间模式 TIM1_OCMode_Active TIM1 输出比较主动模式 TIM1_OCMode_Inactive TIM1 输出比较非主动模式 TIM1_OCMode_Toggle TIM1 输出比较触发模式 TIM1_OCMode_PWM1 TIM1 脉冲宽度调制模式 1 TIM1_OCMode_PWM2 TIM1 脉冲宽度调制模式 2
TIM1_OCPolarity 描述 TIM1_OCPolarity_High TIM1 输出比较极性高 TIM1_OCPolarity_Low TIM1 输出比较极性低
TIM1_OutputState 描述 TIM1_OutputState_Disable 失能输出比较状态 TIM1_OutputState_Enable 使能输出比较状态 TIM1_Pulse
TIM1_Pulse 设置了待装入捕获比较寄存器CCR的脉冲值。它的取值必须在 0x0000 和 0xFFFF 之间。 Pulse表示CCR的值
//由于TIM_OCStructureInit已经给赋予一个默认值了
AAR=100-1;PSC=720-1;CCR=50;
对应的:
分辨率为1%;占空比为50%;频率为100Hz
pwm.c代码
#include "stm32f10x.h" // Device header
void PWM_Init(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
TIM_InternalClockConfig(TIM2);
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
TIM_TimeBaseInitStruct.TIM_ClockDivision =TIM_CKD_DIV1;
TIM_TimeBaseInitStruct.TIM_CounterMode =TIM_CounterMode_Up;
TIM_TimeBaseInitStruct.TIM_Period =100-1; //ARR
TIM_TimeBaseInitStruct.TIM_Prescaler =720-1; //PSC
TIM_TimeBaseInitStruct.TIM_RepetitionCounter =0;
TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStruct);
TIM_OCInitTypeDef TIM_OCInitStruct;
TIM_OCStructInit(&TIM_OCInitStruct);
TIM_OCInitStruct.TIM_OCMode=TIM_OCMode_PWM1;
TIM_OCInitStruct.TIM_OCPolarity=TIM_OCPolarity_High;
TIM_OCInitStruct.TIM_OutputState =TIM_OutputState_Enable;
TIM_OCInitStruct.TIM_Pulse=50; //Pulse是CCR的值
}
void PWM_SetCompare1(uint16_t Compare)
{
TIM_SetCompare1(TIM2,Compare);
}
pwm.h
#ifndef __PWM_H
#define __PWM_H
void PWM_Init(void);
void PWM_SetCompare1(uint16_t Compare);
#endif
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();
while(1)
{
for (i=0;i <= 100; i++)
{
PWM_SetCompare1(i);
Delay_ms(10);
}
for (i=0 ;i<= 100; i++)
{
PWM_SetCompare1(100-i);
Delay_ms(10);
}
}
}
后面使用PWM驱动舵机,直流电机都是基于上述函数进行二次开发,稍微观看视频即可理解
一个定时器有多个输出比较通道(一般是4个),可以对不同的通道调节不同的占空比,但是他们的频率和周期是保持一致的,周期一致指的是起始和结束是一致的