提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
TIM的 OC(Output Compare)输出比较 主要用于输出PWM波形,PWM又是驱动电机的必要条件(智能车、机器人等),所以应用广泛。输出比较功能 可以通过比较 CNT计数器 与 CCR捕获/比较寄存器 的大小,来对输出电平进行置1、置0或翻转的操作,用于输出一定频率和占空比的PWM波形。
PWM是电路中重要的一类知识点。
举个例子,呼吸灯,电风扇的一二三档,等等。都是用到了PWM的知识,也是面试以及工作中最常用的知识点。属于不会不行的。
每个高级定时器和通用定时器都拥有4个输出比较通道
高级定时器的前3个通道额外拥有死区生成和互补输出的功能
一、输出比较是什么?输出比较作用?
用PWM来进行讲解,会使用PWM,会进行设置。基本上就将输出比较理解了!
PWM参数计算
PWM频率: Freq = CK_PSC / (PSC + 1) / (ARR + 1)
PWM占空比: Duty = CCR / (ARR + 1)
PWM分辨率: Reso = 1 / (ARR + 1)
蓝色为CNT计数,根据频率自动计数,黄色为ARR自动重装值。通过设置红色(CCR比较值)来控制一个周期内的高低电平来达到控制PWM占空比的效果
输出比较单元为代码设置,看懂逻辑即可,再结合后续代码,能看懂就算理解。
通用定时器和高级定时器电路原理图如下
二、使用步骤
(1)TIM_OC1Init 【常用】:配置第一路输出比较模块。TIM_OC2Init、TIM_OC3Init、TIM_OC4Init 则分别是配置第二、三、四路。
(2)TIM_OCStructInit 【常用】:给输出比较结构体赋一个默认值。
(3)TIM_CtrlPWMOutputs 【重要】:仅高级定时器使用,使用高级定时器输出PWM波时,必须调用此函数,否则PWM将不能正常输出。
(4)TIM_ForcedOC1Config 【不常用】:配置强制输出模式,但由于占空比100%输出高电平、0%输出低电平,与强制输出高、低电平等价,所以使用不多。第二、三、四路同理。
(5)TIM_OC1PreloadConfig 【不常用】:用于配置CCR寄存器的预装功能,即CCR的影子寄存器。不会立即生效,而是在更新时间后才会生效。第二、三、四路同理。
(6)TIM_CCPreloadControl :一次性设置所有的4路输出比较通道寄存器CCR的预装载方式,也就是是否启用影子寄存器。
(7)TIM_OC1FastConfig 【不常用】:用于配置快速使能,在参考手册“14.3.10单脉冲模式”有介绍。第二、三、四路同理。
(8)TIM_ClearOC1Ref 【不常用】:在参考手册“14.3.11在外部事件时清除OCxREF信号”有介绍。第二、三、四路同理。
(9)TIM_OC1PolarityConfig 、 TIM_OC1NPolarityConfig :用于单独设置输出比较的极性,第二、三、四路同理。带N的函数就是高级定时器里互补通道的配置。这个极性设置与 输
出比较模块结构体 中的设置极性相同。一般来说结构体中的参数都有一个专门的函数用于修改。
(10)TIM_CCxCmd 、 TIM_CCxNCmd :用于单独修改输出使能参数。
(11)TIM_SelectOCxM :用于单独更改输出比较模式的函数。
(12)TIM_SetCompare1 【重要】:用于单独更改CCR寄存器的值,可以更改PWM波的占空比。第二、三、四路同理。
1.主函数控制占空比
代码如下(示例):
#include "stm32f10x.h" // Device header
#include "PWM.h"
#include "Delay.h"
int main(void){
uint16_t pwm_duty = 0;//PWM波的占空比
uint8_t pwm_flag = 1;//占空比变化控制信号,1升0降
//PWM初始化
PWM_Init();
while(1){
Delay_ms(5);//0.5s完成100个占空比变化
//调整占空比
if(pwm_flag==1){
if(pwm_duty<100){
pwm_duty++;
//
}else if(pwm_duty==100){
pwm_flag = 0;
}else{
pwm_duty = 0;
pwm_flag = 1;
}
}else if(pwm_flag == 0){
if(pwm_duty >0 && pwm_duty<=100){
pwm_duty--;
//
}else if(pwm_duty==0){
pwm_flag = 1;
}else{
pwm_duty = 0;
pwm_flag = 1;
}
}else{
pwm_duty = 0;
pwm_flag = 1;
}
//改变占空比
PWM_SetDuty(pwm_duty);
};
}
2.占空比示例(配置输出比较模块)
代码如下(示例):
#include "stm32f10x.h" // Device header
//TIM输出比较模式-PWM初始化
void PWM_Init(void){
//1.配置RCC
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
// //隐:引脚重映射,将PA0映射到PA15
// RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);//引脚重映射会使用AFIO
// GPIO_PinRemapConfig(GPIO_PartialRemap1_TIM2, ENABLE);//参考手册“8.3.7定时器复用功能重映射”
// GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);//PA15、PB3、PB4变成普通IO口
//2.选择时基单元时钟
TIM_InternalClockConfig(TIM2);
//3.配置时基单元-10kHz
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;//向上计数
TIM_TimeBaseInitStructure.TIM_Period = 100-1;//自动重装载值
TIM_TimeBaseInitStructure.TIM_Prescaler = 72-1;//预分频
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0x0000;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);
//4.配置运行控制
TIM_Cmd(TIM2, ENABLE);
//5.配置输出捕获电路
TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_OCStructInit(&TIM_OCInitStructure);//后续即使用到高级定时器初始化,也不会出错
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //PWM模式1
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = 0x0000; //占空比
TIM_OC1Init(TIM2, &TIM_OCInitStructure);
//7.配置GPIO-PA0
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//复用推挽输出
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; //GPIO_Pin_15-引脚重映射
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
//设置PWM波的占空比
//范围是0~100
void PWM_SetDuty(uint16_t pwm_duty){
TIM_SetCompare1(TIM2, pwm_duty);
}```
---
# 总结
1. 在Hardware文件夹创建了PWM.h和PWM.c。
2. 输出比较电路的OC1输出怎么映射到GPIO引脚上呢?
其实在引脚定义表上就已经固定好了,OC1输出固定是PA0。但是配置GPIO时注意配置成“复用推挽输出”模式,因为GPIO输出框图中显示,只有复用输出模式才能使信号来自片上外设。
3. 引脚重映射。进行引脚重映射时,需要不断对照参考手册及引脚定义表。
若对 调试端口 进行引脚重映射,需要三步:
开启AFIO时钟,进行引脚重映射,解除调试端口复用。
4. 若想对 定时器和其他外设的复用引脚 进行重映射,那就只需要前两步即可。
设置出一个正确的占空比电路即可。实际使用中还是要结合当下电路。
放假后第一天,有些敷衍,估计后续会再补充些。