输出比较简介输出比较简介

  • OC(Output Compare)输出比较。
  • 输出比较可以通过比较CNT与CCR寄存器值的关系,来对输出电平进行置1、置0或翻转的操作,用于输出一定频率和占空比的PWM波形。
  • 每个高级定时器和通用定时器都拥有4个输出比较通道。
  • 高级定时器的前3个通道额外拥有死区生成和互补输出的功能。

PWM简介

  • PWM(Pulse Width Modulation)脉冲宽度调制。
  • 在具有惯性的系统中,可以通过对一系列脉冲的宽度进行调制,来等效地获得所需要的模拟参量,常应用于电机控速等领域。
  • PWM参数: 频率= 1 /TS。 占空比= TON / TS 分辨率= 占空比变化步距

输出比较通道(高级)

输出比较通道(通用)

输出比较模式

模式描述
冻结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置无效电平

PWM基本结构

参数计算

PWM频率: Freq= CK_PSC / (PSC+ 1) / (ARR+1)

PWM占空比: Duty= CCR / (ARR+ 1)

PWM分辨率: Reso= 1 / (ARR+ 1)

舵机简介

  • 舵机是一种根据输入PWM信号占空比来控制输出角度的装置
  • 输入PWM信号要求:周期为20ms,高电平宽度为0.5ms~2.5ms

硬件电路

![](https://mulin.fun/usr/uploads/2023/05/260931763.png

)

直流电机及驱动简介

  • 直流电机是一种将电能转换为机械能的装置,有两个电极,当电极正接时,电机正转,当电极反接时,电机反转。
  • 直流电机属于大功率器件,GPIO口无法直接驱动,需要配合电机驱动电路来操作。
  • TB6612是一款双路H桥型的直流电机驱动芯片,可以驱动两个直流电机并且控制其转速和方向。

硬件电路

PWM驱动呼吸灯

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_Set_Compare1(i);
            Delay_ms(10);
        }
        for(i=0;i<=100;i++)
        {
            PWM_Set_Compare1(i);
            Delay_ms(10);
        }

    }

}

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_Initstructre;
    GPIO_Initstructre.GPIO_Mode =GPIO_Mode_AF_PP; 
    GPIO_Initstructre.GPIO_Pin = GPIO_Pin_0;
    GPIO_Initstructre.GPIO_Speed =GPIO_Speed_50MHz;
    GPIO_Init(GPIOA,&GPIO_Initstructre);

    TIM_InternalClockConfig(TIM2);

    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_OCInitTypeDef TIM_OCInitStructure;                    //配置输出比较结构体
    TIM_OCStructInit(&TIM_OCInitStructure);                    //给结构体赋初始值
    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;        //输出比较模式选择---PWM模式一
    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_Set_Compare1(uint16_t Compare)
{
    TIM_SetCompare1(TIM2,Compare);        //设置CCR值

}

PWM.h

#ifndef __PWM_H
#define __PWM_H

void PWM_Init();
void PWM_Set_Compare1(uint16_t Compare);

#endif

PWM驱动舵机

main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "PWM.h"
#include "Servo.h"
#include "Key.h"

uint8_t KeyNum;
float Angle;

int main(void)
{
    OLED_Init();
    PWM_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);
    }

}

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_Initstructre;
    GPIO_Initstructre.GPIO_Mode =GPIO_Mode_AF_PP;
    GPIO_Initstructre.GPIO_Pin = GPIO_Pin_1;
    GPIO_Initstructre.GPIO_Speed =GPIO_Speed_50MHz;
    GPIO_Init(GPIOA,&GPIO_Initstructre);

    TIM_InternalClockConfig(TIM2);

    TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
    TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
    TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInitStructure.TIM_Period = 20000 - 1;    //ARR
    TIM_TimeBaseInitStructure.TIM_Prescaler = 72 - 1;    //PSC
    TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
    TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);

    TIM_OCInitTypeDef TIM_OCInitStructure;                    //配置输出比较结构体
    TIM_OCStructInit(&TIM_OCInitStructure);                    //给结构体赋初始值
    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;        //输出比较模式选择---PWM模式一
    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_Set_Compare2(uint16_t Compare)
{
    TIM_SetCompare2(TIM2,Compare);            //设置CCR值

}

Servo.c

#include "stm32f10x.h"                  // Device header
#include "PWM.h"

void Servo_init(void)
{
    PWM_Init();
}

//0        500
//180        2500

void Servo_SetAngle(float Angle)
{
    PWM_Set_Compare2(Angle / 180 * 2000+500);


}

PWM驱动直流电机

main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "Motor.h"
#include "Key.h"
uint8_t KeyNum;
int8_t Speed;
int main(void)
{
    OLED_Init();
    Motor_Init();

    Key_Init();
    OLED_ShowString(1,1,"Speed");
    while(1)
    {
        KeyNum = Key_GetNum();
        if(KeyNum==1)
        {
            Speed +=20;
            if(Speed>100)
            {
                Speed = -100;
            }
        }
        Motor_SetSpeed(Speed);
        OLED_ShowSignedNum(1,7,Speed,3);
    }

}

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_Initstructre;
    GPIO_Initstructre.GPIO_Mode =GPIO_Mode_AF_PP;
    GPIO_Initstructre.GPIO_Pin = GPIO_Pin_2;
    GPIO_Initstructre.GPIO_Speed =GPIO_Speed_50MHz;
    GPIO_Init(GPIOA,&GPIO_Initstructre);

    TIM_InternalClockConfig(TIM2);

    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 = 36 - 1;    //PSC
    TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
    TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);

    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_OC3Init(TIM2,&TIM_OCInitStructure);

    TIM_Cmd(TIM2, ENABLE);

}

void PWM_SetCompare3(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;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    PWM_Init();
}

void Motor_SetSpeed(int8_t Speed)
{
    if (Speed >= 0)
    {
        GPIO_SetBits(GPIOA, GPIO_Pin_4);
        GPIO_ResetBits(GPIOA, GPIO_Pin_5);
        PWM_SetCompare3(Speed);
    }
    else
    {
        GPIO_ResetBits(GPIOA, GPIO_Pin_4);
        GPIO_SetBits(GPIOA, GPIO_Pin_5);
        PWM_SetCompare3(-Speed);
    }
}

参考资料

STM32入门教程-2023版 细致讲解 中文字幕\_哔哩哔哩\_bilibili

最后修改:2023 年 10 月 21 日
如果觉得我的文章对你有用,请随意赞赏