首先了解输出比较的概念:输出比较(OC)的英文全称:Output Compare,通过设置计数器CNT和CCR(捕获/输出比较寄存器),来输出PWM波形。
PWM波形的一些参数:
1:频率 = 1 / Ts(周期)
2:占空比:指高电平的时间在整个高低电平周期中的时间占比,Ton / Ts
3:分辨率:指占空比变化的最低精度(最小幅度)
捕获/比较通道的输出部分:
CNT与CCR进行比较,比较值进入输出模式控制器,输出模式控制器有8种模式可以配置,配置后可以设置OC1REF的输出电平信号,REF输出电平信号在CC1P寄存器可以设置频率和翻转,然后配置输出使能电路完成PWM的输出。
PMW的内部结构和参数设置:形成对周期、占空比、CCR、AAR的基本概念。
这个实验中,我们要有道SG90舵机和130直流电机,我们了解下舵机和直流电机模块的基本知识:
舵机输入信号周期位20ms,也就是50Hz的信号,在20ms周期内,占空比0.5ms舵机为-90°,占空比1ms舵机-45°,占空比1.5ms舵机0°。
130直流电机:
直流电机需要配合驱动电路或者驱动芯片来工作,本次实验使用的是TB6612直流电机驱动芯片
TB6612直流电机驱动芯片的硬件电路和驱动方法如下,通过设置IN1、IN2的电平状态,控制01、02脚的电平状态,达到正转、反转、制动的效果。
PWM驱动LED呼吸灯的实验:
1.在PA0引脚接LED(正极接PA0,负极接地),在此引脚输出PWM实现呼吸灯的效果。
2.新建PWM的模块代码。
3.编写PWM的初始化代码:
①.RCC开启时钟,把TIM外设和GPIO外设的时钟打开
②.时钟源选择配置和时基单元配置。
③.配置输出比较单元,包括CCR(捕获/比较寄存器)的值,输出比较模式、极性选择、输出使能等参数。
④.配置PWM对应的GPIO,初始化为复用推挽输出的配置。
⑤.运行控制,启动计数器输出PWM。
编写代码前,我们先熟悉TIM库函数中关于PWM对应的函数:
#include "stm32f10x.h" // Device header
/**
* 函 数:PWM初始化
* 参 数:无
* 返 回 值:无
*/
void PWM_Init(void)
{
/*开启时钟*/
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE); //开启TIM2的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //开启GPIOA的时钟
/*GPIO重映射*/
// RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); //开启AFIO的时钟,重映射必须先开启AFIO的时钟
// GPIO_PinRemapConfig(GPIO_PartialRemap1_TIM2, ENABLE); //将TIM2的引脚部分重映射,具体的映射方案需查看参考手册
// GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE); //将JTAG引脚失能,作为普通GPIO引脚使用
/*GPIO初始化*/ //将PA0引脚初始化为复用推挽输出
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //只有把GPIO设置成复用推挽输出,引脚的控制权才能交给片上外设定时器
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/*配置时钟源*/
TIM_InternalClockConfig(TIM2); //选择TIM2为内部时钟,若不调用此函数,TIM默认也为内部时钟
/*时基单元初始化*/
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure; //定义结构体变量
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1; //时钟分频,选择不分频,此参数用于配置滤波器时钟,不影响时基单元功能
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; //计数器模式,选择向上计数
TIM_TimeBaseInitStructure.TIM_Period = 100 - 1; //计数周期,即ARR的值
TIM_TimeBaseInitStructure.TIM_Prescaler = 720 - 1; //预分频器,即PSC的值
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0; //重复计数器,高级定时器才会用到
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure); //将结构体变量交给TIM_TimeBaseInit,配置TIM2的时基单元
/*输出比较初始化*/
TIM_OCInitTypeDef TIM_OCInitStructure; //定义结构体变量
TIM_OCStructInit(&TIM_OCInitStructure); //结构体初始化,若结构体没有完整赋值则执行此函数,给结构体成员都赋一个默认值
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //输出比较模式,选择PWM模式1
TIM_OCInitStructure.TIM_Pulse = 0; //初始的CCR值
TIM_OCInitStructure.TIM_OCPolarity =TIM_OCPolarity_High; //输出极性,选择为高,若选择极性为低,则输出高低电平取反
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //输出使能
TIM_OC1Init(TIM2, &TIM_OCInitStructure); //将结构体变量交给TIM_OC1Init,配置TIM2的输出比较通道1
/*TIM使能*/
TIM_Cmd(TIM2,ENABLE); //使能TIM2,定时器开始运行
}
/**
* 函 数:PWM设置CCR
* 参 数:Compare 要写入的CCR的值,范围:0~100
* 返 回 值:无
* 注意事项:CCR和ARR共同决定占空比,此函数仅设置CCR的值,并不直接是占空比
* 占空比Duty = CCR / (ARR + 1)
*/
void PWM_SetCompare1(uint16_t Compare)
{
TIM_SetCompare1(TIM2, Compare); //设置CCR1的值
}
TIM外设引脚和GPIO引脚的复用关系:
只有把GPIO设置成复用推挽输出,引脚的控制权才能交给片上外设定时器:
TIM_SetCompare1函数设置写入CCR的值,注意CCR和ARR共同决定占空比,此函数仅设置CCR的值,并不直接是占空比:
接着在主函数编写代码,调用PWM,实现呼吸灯的效果:
#include "stm32f10x.h" //添加头文件
#include "Delay.h"
#include "LED.h"
#include "KEY.h"
#include "Timer.h"
#include "OLED.h"
#include "PWM.h"
uint8_t i;
int main(void)
{
/*模块初始化*/
OLED_Init(); //OLED初始化
PWM_Init(); //PWM初始化
OLED_ShowString(1, 1, "PWM:"); //OLED显示字符
while(1)
{
for(i = 0; i < 100; i++)
{
PWM_SetCompare1(i); //依次将定时器的CCR寄存器设置为0~100,PWM占空比逐渐增大,LED逐渐变亮
OLED_ShowNum(2, 1, i, 3);
Delay_ms(10);
}
for(i = 100; i > 0; i--)
{
PWM_SetCompare1(i); //依次将定时器的CCR寄存器设置为100~0,PWM占空比逐渐减小,LED逐渐变暗
OLED_ShowNum(2, 1, i, 3);
Delay_ms(10);
}
}
}
接下来介绍引脚重映射的方法:
①.查看引脚配置表可知引脚复用关系:
②.接下来开启AFIO复用IO口的时钟,AFIO是APB2的外设:
③.接下来配置引脚重映射函数:
引脚重映射的第一个参数根据手册的指导来填写,选择部分重映射1就是将TIM2的部分引脚进行重映射;第2个参数填写ENABLE;
GPIO_PinRemapConfig(GPIO_PartialRemap1_TIM2, ENABLE);
④.使用重映射将PA15的JTAG复用解除掉:PA15才可以作为一个普通的IO脚使用:
简单来说,重映射复用IO口需要2步:
1.开启AFIO复用IO口的时钟,
2.配置引脚重映射函数.
如果此IO口用作了其他功能,那么还需要使用重映射函数先解除该引脚的原复用功能。
以上就是定时器输出PWM的笔记。