1、输出比较简介
•OC(Output Compare)输出比较
•输出比较可以通过比较CNT与CCR寄存器值的关系,来对输出电平进行置1、置0或翻转的操作,用于输出一定频率和占空比的PWM波形
2、参考通用定时器
CNT时基单元里的计数器。CCR捕获/比较寄存器,CC捕获/比较意思,R是Register,寄存器的意思。两个共用,输入捕获寄存器。输出比较寄存器,比较CNT与CCR的值,CNT计数自增,CCR自己给定。当CNT大于CCR(小于或者等于)时,置1置0,然后输出应该电平不断跳变的PWM波形。
•每个高级定时器和通用定时器都拥有4个输出比较通道共用一个计数器
•高级定时器的前3个通道额外拥有死区生成和互补输出的功能
3、PWM波简介
•PWM(Pulse Width Modulation)脉冲宽度调制
•在具有惯性的系统中,可以通过对一系列脉冲的宽度进行调制,来等效地获得所需要的模拟参量,常应用于电机控速等领域
•PWM参数:
频率 = 1 / TS 占空比 = TON / TS 分辨率 = 占空比变化步距
4、输出比较通道(通用)
CNT与CCR1比较后输出模式控制器改变输出OC1REF的高低电平,REF(reference)参考信号。REF可以映射到主模式TRGO输出上去,主要去向在下一路,来到极性选择,给TIMx_CCER寄存器写0,信号上走,信号电平不翻转,写1向下,通过非门取反,输出使能信号要不要输出。最后到达OC1引脚既CH1通道引脚。
5、输出模式控制器介绍
8种模式
模式 | 描述 |
冻结 | CNT=CCR时,REF保持为原状态 |
匹配时置有效电平 | CNT=CCR时,REF置有效电平 |
匹配时置无效电平 | CNT=CCR时,REF置无效电平 |
匹配时电平翻转 | CNT=CCR时,REF电平翻转 |
强制为无效电平 | CNT与CCR无效,REF强制为无效电平 |
强制为有效电平 | CNT与CCR无效,REF强制为有效电平 |
PWM模式1 | 向上计数:CNT<CCR时,REF置有效电平,CNT≥CCR时,REF置无效电平 向下计数:CNT>CCR时,REF置无效电平,CNT≤CCR时,REF置有效电平 |
PWM模式2 | 向上计数:CNT<CCR时,REF置无效电平,CNT≥CCR时,REF置有效电平 向下计数:CNT>CCR时,REF置有效电平,CNT≤CCR时,REF置无效电平 |
6、PWM波基本结构
以PWM模式1向上计数芯片逻辑图:
7、参数计算
PWM波的频率等于计数器更新的频率,CCR为红线,ARR为黄线。
8、 输出比较通道(高级)
8、舵机简介
•舵机是一种根据输入PWM信号占空比来控制输出角度的装置
•输入PWM信号要求:周期为20ms,高电平宽度为0.5ms~2.5ms
9、直流电机及驱动简介
•直流电机是一种将电能转换为机械能的装置,有两个电极,当电极正接时,电机正转,当电极反接时,电机反转
•直流电机属于大功率器件,GPIO口无法直接驱动,需要配合电机驱动电路来操作
•TB6612是一款双路H桥型的直流电机驱动芯片,可以驱动两个直流电机并且控制其转速和方向
10、 呼吸灯
主程序
#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.C
#include "stm32f10x.h" // Device header
void PWM_Init(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);//开启APB1时钟函数
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
//-------------------重映射改变引脚测试------------------------
// RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);//开启AFIO时钟
// GPIO_PinRemapConfig(GPIO_PartialRemap1_TIM2,ENABLE);//部分重映射,将PA0换成PA15
// GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);//解除JTAG复用
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_TimeBaseStructInit;
TIM_TimeBaseStructInit.TIM_ClockDivision=TIM_CKD_DIV1 ;//选择1分频,主要作用,滤波处理
TIM_TimeBaseStructInit.TIM_CounterMode=TIM_CounterMode_Up;//向上计数
TIM_TimeBaseStructInit.TIM_Period = 100-1;//周期,ARR自动重装器的值(同PSC取值范围0~65535)
TIM_TimeBaseStructInit.TIM_Prescaler= 720 -1;//PSC预分频器的值
TIM_TimeBaseStructInit.TIM_RepetitionCounter=0;//重复计数器的值(高级定时器才有用)
TIM_TimeBaseInit(TIM2,&TIM_TimeBaseStructInit);//初始化时基单元
TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_OCStructInit(&TIM_OCInitStructure);//结构体赋初始值,方便其他变量默认赋值
TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1;//输出比较模式
TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_High;//输出比较极性
TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;//输出状态
TIM_OCInitStructure.TIM_Pulse=0;//CCR的值
TIM_OC1Init(TIM2,&TIM_OCInitStructure);
//启动定时器
TIM_Cmd(TIM2,ENABLE);
}
void PWM_SetCompare1(uint16_t Compare)
{
TIM_SetCompare1(TIM2,Compare);//更改CCR的值
}
其中PSC,ARR,CCR是带人下式算出
•PWM频率: Freq = CK_PSC / (PSC + 1) / (ARR + 1)
•PWM占空比: Duty = CCR / (ARR + 1)
•PWM分辨率: Reso = 1 / (ARR + 1)
实物效果图
舵机主代码
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "Servo.h"
#include "key.h"
uint8_t KeyNum;
float Angle;
int main(void)
{
OLED_Init();
Servo_Init();
Key_Init();
OLED_ShowString(1,1,"Angle:");
while (1)
{
KeyNum=Key_GetNum();
if(KeyNum == 1)
{
Angle += 30;
if(Angle >180)
{
Angle = 0;
}
}
Servo_SetAngle(Angle);
OLED_ShowNum(1,7,Angle,3);
}
}
舵机配置代码"Servo"
#include "stm32f10x.h" // Device header
#include "PWM.h"
void Servo_Init(void)
{
PWM_Init();
}
void Servo_SetAngle(float Angle)
{
PWM_SetCompare2(Angle / 180*2000+500);
}
PWM.C
#include "stm32f10x.h" // Device header
void PWM_Init(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);//开启APB1时钟函数
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
// RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);//开启AFIO时钟
// GPIO_PinRemapConfig(GPIO_PartialRemap1_TIM2,ENABLE);//部分重映射,将PA0换成PA15
// GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);//解除JTAG复用
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;
GPIO_Init(GPIOA, &GPIO_InitStructure);
TIM_InternalClockConfig(TIM2);//选择时基单元的时钟
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructInit;
TIM_TimeBaseStructInit.TIM_ClockDivision=TIM_CKD_DIV1 ;//选择1分频,主要作用,滤波处理
TIM_TimeBaseStructInit.TIM_CounterMode=TIM_CounterMode_Up;//向上计数
TIM_TimeBaseStructInit.TIM_Period = 20000-1;//周期,ARR自动重装器的值(同PSC取值范围0~65535)
TIM_TimeBaseStructInit.TIM_Prescaler= 72 -1;//PSC预分频器的值
TIM_TimeBaseStructInit.TIM_RepetitionCounter=0;//重复计数器的值(高级定时器才有用)
TIM_TimeBaseInit(TIM2,&TIM_TimeBaseStructInit);//初始化时基单元
TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_OCStructInit(&TIM_OCInitStructure);//结构体赋初始值,方便其他变量默认赋值
TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1;//输出比较模式
TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_High;//输出比较极性
TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;//输出状态
TIM_OCInitStructure.TIM_Pulse=0;//CCR的值
TIM_OC2Init(TIM2,&TIM_OCInitStructure);
//启动定时器
TIM_Cmd(TIM2,ENABLE);
}
void PWM_SetCompare2(uint16_t Compare)
{
TIM_SetCompare2(TIM2,Compare);//更改CCR的值
}