PWM

发布于 2023-08-11  1071 次阅读


内容纲要

PWM笔记

PWM简介

输出比较通道

高级和通用输出比较通道,简单了解即可

输出比较模式


PWM基本结构

打通步骤

以正点原子精英版V2的控制LED灯为例

一、RCC开启时钟

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); // Tim时钟打开
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE); // GPIO口时钟打开

二、配置时基单元

    TIM_InternalClockConfig(TIM3); // 默认打开内部时钟,所以该步骤可省略

    TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct; 
    TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;  // x分频(x为1,2或4)
    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(TIM3,&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 = 0;  // 设置CCR的值
    TIM_OC2Init(TIM3,&TIM_OCInitStruct); // 输出比较通道(根据GPIO口选择)

四、配置GPIO

端口重映射

板子的PB5需要重映射才能在TIM3_CH2上使用

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE); // AFIO口时钟打开
    GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3,ENABLE); // 端口重映射
初始化GPIO口
    GPIO_InitTypeDef GPIO_InitStructure;  //初始化GPIO口
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //采用复用推挽输出
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB,&GPIO_InitStructure);

五、运行控制(启动计数器)

TIM_Cmd(TIM3,ENABLE);

参数计算

其中频率可以控制发光频率

占空比可以控制亮度

部分API

和TIM一样

void TIM_DeInit(TIM_TypeDef* TIMx); // 恢复缺省配置
void TIM_TimeBaseInit(TIM_TypeDef* TIMx, TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct); // 时基单元初始化
void TIM_OC1Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct); // 初始化输出比较模块(选择定时器,结构体)(选择对应GPIO口)
void TIM_OC2Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct); // 初始化输出比较模块
void TIM_OC3Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct); // 初始化输出比较模块
void TIM_OC4Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct); // 初始化输出比较模块
void TIM_ICInit(TIM_TypeDef* TIMx, TIM_ICInitTypeDef* TIM_ICInitStruct); // 结构体配置输入捕获单元
void TIM_PWMIConfig(TIM_TypeDef* TIMx, TIM_ICInitTypeDef* TIM_ICInitStruct); // 快速配置两个通道(配置项PWMI模式)
void TIM_BDTRConfig(TIM_TypeDef* TIMx, TIM_BDTRInitTypeDef *TIM_BDTRInitStruct);
void TIM_TimeBaseStructInit(TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct); // 为结构体变量赋值
void TIM_OCStructInit(TIM_OCInitTypeDef* TIM_OCInitStruct); // 给输出比较结构体赋一个默认值
void TIM_ICStructInit(TIM_ICInitTypeDef* TIM_ICInitStruct); // 给输入捕获结构体赋一个初始值
void TIM_BDTRStructInit(TIM_BDTRInitTypeDef* TIM_BDTRInitStruct);
void TIM_Cmd(TIM_TypeDef* TIMx, FunctionalState NewState); // 使能计数器
void TIM_CtrlPWMOutputs(TIM_TypeDef* TIMx, FunctionalState NewState); // 高级定时器输出PWM时调用该函数使能主输出
void TIM_ITConfig(TIM_TypeDef* TIMx, uint16_t TIM_IT, FunctionalState NewState); // 使能中断输出信号
void TIM_GenerateEvent(TIM_TypeDef* TIMx, uint16_t TIM_EventSource);
void TIM_DMAConfig(TIM_TypeDef* TIMx, uint16_t TIM_DMABase, uint16_t TIM_DMABurstLength);
void TIM_DMACmd(TIM_TypeDef* TIMx, uint16_t TIM_DMASource, FunctionalState NewState);
void TIM_InternalClockConfig(TIM_TypeDef* TIMx); // 选择内部时钟
void TIM_ITRxExternalClockConfig(TIM_TypeDef* TIMx, uint16_t TIM_InputTriggerSource); // 选择ITRX其他定时器时钟(配置定时器和要接入的其他定时器)
void TIM_TIxExternalClockConfig(TIM_TypeDef* TIMx, uint16_t TIM_TIxExternalCLKSource, // 选择TIX捕获通道的时钟 (TIMx,具体引脚,极性,滤波器)
                                uint16_t TIM_ICPolarity, uint16_t ICFilter);
void TIM_ETRClockMode1Config(TIM_TypeDef* TIMx, uint16_t TIM_ExtTRGPrescaler, uint16_t TIM_ExtTRGPolarity,
                             uint16_t ExtTRGFilter); // 选择ETR通过外部时钟模式1输入的时钟(TIMx,外部触发预分频器,极性,滤波器)
void TIM_ETRClockMode2Config(TIM_TypeDef* TIMx, uint16_t TIM_ExtTRGPrescaler, 
                             uint16_t TIM_ExtTRGPolarity, uint16_t ExtTRGFilter); // 选择ETR通过外部时钟模式2输入的时钟
void TIM_ETRConfig(TIM_TypeDef* TIMx, uint16_t TIM_ExtTRGPrescaler, uint16_t TIM_ExtTRGPolarity,
                   uint16_t ExtTRGFilter); //单独配置ETR引脚的TIMx,预分频器,极性,滤波器
void TIM_PrescalerConfig(TIM_TypeDef* TIMx, uint16_t Prescaler, uint16_t TIM_PSCReloadMode); // 单独写预分频值和写入模式
void TIM_CounterModeConfig(TIM_TypeDef* TIMx, uint16_t TIM_CounterMode); // 改变计数器的计数模式(TIMx,选择新的计数器模式)
void TIM_SelectInputTrigger(TIM_TypeDef* TIMx, uint16_t TIM_InputTriggerSource); // 选择输入触发源TGRI
void TIM_EncoderInterfaceConfig(TIM_TypeDef* TIMx, uint16_t TIM_EncoderMode,
                                uint16_t TIM_IC1Polarity, uint16_t TIM_IC2Polarity); // 定时器编码器接口配置(选择定时器,选择编码器模式,选择通道1电平极性,选择通道2电平极性)
void TIM_ForcedOC1Config(TIM_TypeDef* TIMx, uint16_t TIM_ForcedAction); // 配置强制输出模式
void TIM_ForcedOC2Config(TIM_TypeDef* TIMx, uint16_t TIM_ForcedAction); // 配置强制输出模式
void TIM_ForcedOC3Config(TIM_TypeDef* TIMx, uint16_t TIM_ForcedAction); // 配置强制输出模式
void TIM_ForcedOC4Config(TIM_TypeDef* TIMx, uint16_t TIM_ForcedAction); // 配置强制输出模式
void TIM_ARRPreloadConfig(TIM_TypeDef* TIMx, FunctionalState NewState); // 自动重装器预装功能配置
void TIM_SelectCOM(TIM_TypeDef* TIMx, FunctionalState NewState);
void TIM_SelectCCDMA(TIM_TypeDef* TIMx, FunctionalState NewState);
void TIM_CCPreloadControl(TIM_TypeDef* TIMx, FunctionalState NewState);
void TIM_OC1PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload); // 配置CCR寄存器(影子寄存器)预装功能
void TIM_OC2PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload); // 配置CCR寄存器(影子寄存器)预装功能
void TIM_OC3PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload); // 配置CCR寄存器(影子寄存器)预装功能
void TIM_OC4PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload); // 配置CCR寄存器(影子寄存器)预装功能
void TIM_OC1FastConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCFast); // 配置快速使能
void TIM_OC2FastConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCFast); // 配置快速使能
void TIM_OC3FastConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCFast); // 配置快速使能
void TIM_OC4FastConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCFast); // 配置快速使能
void TIM_ClearOC1Ref(TIM_TypeDef* TIMx, uint16_t TIM_OCClear); // 外部事件时清除REF信号
void TIM_ClearOC2Ref(TIM_TypeDef* TIMx, uint16_t TIM_OCClear); // 外部事件时清除REF信号
void TIM_ClearOC3Ref(TIM_TypeDef* TIMx, uint16_t TIM_OCClear); // 外部事件时清除REF信号
void TIM_ClearOC4Ref(TIM_TypeDef* TIMx, uint16_t TIM_OCClear); // 外部事件时清除REF信号
void TIM_OC1PolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPolarity); // 单独设置输出比较的极性
void TIM_OC1NPolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCNPolarity); // 高级定时器里互补通道的配置
void TIM_OC2PolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPolarity); // 单独设置输出比较的极性
void TIM_OC2NPolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCNPolarity); // 高级定时器里互补通道的配置
void TIM_OC3PolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPolarity); // 单独设置输出比较的极性
void TIM_OC3NPolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCNPolarity); // 高级定时器里互补通道的配置
void TIM_OC4PolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPolarity); //(无互补通道)
void TIM_CCxCmd(TIM_TypeDef* TIMx, uint16_t TIM_Channel, uint16_t TIM_CCx); // 单独修改输出使能参数
void TIM_CCxNCmd(TIM_TypeDef* TIMx, uint16_t TIM_Channel, uint16_t TIM_CCxN); // 单独修改输出使能参数
void TIM_SelectOCxM(TIM_TypeDef* TIMx, uint16_t TIM_Channel, uint16_t TIM_OCMode); // 单独更改输出比较模式
void TIM_UpdateDisableConfig(TIM_TypeDef* TIMx, FunctionalState NewState);
void TIM_UpdateRequestConfig(TIM_TypeDef* TIMx, uint16_t TIM_UpdateSource);
void TIM_SelectHallSensor(TIM_TypeDef* TIMx, FunctionalState NewState);
void TIM_SelectOnePulseMode(TIM_TypeDef* TIMx, uint16_t TIM_OPMode);
void TIM_SelectOutputTrigger(TIM_TypeDef* TIMx, uint16_t TIM_TRGOSource); // 选择输出触发源TRGO 
void TIM_SelectSlaveMode(TIM_TypeDef* TIMx, uint16_t TIM_SlaveMode); // 选择从模式
void TIM_SelectMasterSlaveMode(TIM_TypeDef* TIMx, uint16_t TIM_MasterSlaveMode);
void TIM_SetCounter(TIM_TypeDef* TIMx, uint16_t Counter); // 给计数器写入一个值
void TIM_SetAutoreload(TIM_TypeDef* TIMx, uint16_t Autoreload); // 给自动重装器写入一个值
void TIM_SetCompare1(TIM_TypeDef* TIMx, uint16_t Compare1); // 单独修改CCR寄存器值(运行时更改占空比)(选择对应OCInit里的通道)
void TIM_SetCompare2(TIM_TypeDef* TIMx, uint16_t Compare2); // 单独修改CCR寄存器值(运行时更改占空比)
void TIM_SetCompare3(TIM_TypeDef* TIMx, uint16_t Compare3); // 单独修改CCR寄存器值(运行时更改占空比)
void TIM_SetCompare4(TIM_TypeDef* TIMx, uint16_t Compare4); // 单独修改CCR寄存器值(运行时更改占空比)
void TIM_SetIC1Prescaler(TIM_TypeDef* TIMx, uint16_t TIM_ICPSC); // 单独配置通道1的分频器
void TIM_SetIC2Prescaler(TIM_TypeDef* TIMx, uint16_t TIM_ICPSC); // 单独配置通道1的分频器
void TIM_SetIC3Prescaler(TIM_TypeDef* TIMx, uint16_t TIM_ICPSC); // 单独配置通道1的分频器
void TIM_SetIC4Prescaler(TIM_TypeDef* TIMx, uint16_t TIM_ICPSC); // 单独配置通道1的分频器
void TIM_SetClockDivision(TIM_TypeDef* TIMx, uint16_t TIM_CKD);
uint16_t TIM_GetCapture1(TIM_TypeDef* TIMx); // 读取通道1的CCR
uint16_t TIM_GetCapture2(TIM_TypeDef* TIMx); // 读取通道1的CCR
uint16_t TIM_GetCapture3(TIM_TypeDef* TIMx); // 读取通道1的CCR
uint16_t TIM_GetCapture4(TIM_TypeDef* TIMx); // 读取通道1的CCR
uint16_t TIM_GetCounter(TIM_TypeDef* TIMx); // 获取当前计数器的值
uint16_t TIM_GetPrescaler(TIM_TypeDef* TIMx); // 获取当前预分频器的值
FlagStatus TIM_GetFlagStatus(TIM_TypeDef* TIMx, uint16_t TIM_FLAG); // 获取标志位
void TIM_ClearFlag(TIM_TypeDef* TIMx, uint16_t TIM_FLAG); // 清除标志位
ITStatus TIM_GetITStatus(TIM_TypeDef* TIMx, uint16_t TIM_IT); // 获取标志位
void TIM_ClearITPendingBit(TIM_TypeDef* TIMx, uint16_t TIM_IT); // 清除标志位

代码部分

LED呼吸灯实验

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

void PWM_Init(void)
{
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); // Tim时钟打开
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE); // GPIO口时钟打开

    TIM_InternalClockConfig(TIM3); // 默认打开内部时钟,所以该步骤可省略

    TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct; 
    TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;  // x分频(x为1,2或4)
    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(TIM3,&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 = 0;  // 设置CCR的值
    TIM_OC2Init(TIM3,&TIM_OCInitStruct); // 输出比较通道(根据GPIO口选择)

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE); // AFIO口时钟打开
    GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3,ENABLE); // 端口重映射

    GPIO_InitTypeDef GPIO_InitStructure; //初始化GPIO口
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //采用复用推挽输出
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB,&GPIO_InitStructure);

    TIM_Cmd(TIM3,ENABLE); // 启动计时器

}

void PWM_SetCompare1(uint16_t Compare)
{
    TIM_SetCompare2(TIM3,Compare); // 单独更改通道2的CCR值
}
主函数
#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "PWM.h"

int main(void){

    PWM_Init();

    while(1)
    {
        uint8_t i; // 通过循环改变i的值实现LED呼吸灯
        for( i = 0 ; i <= 100 ; i++ )
        {
            PWM_SetCompare1(i); // 调用函数改变CCR的值,即用于控制亮度
            Delay_ms(10); // 延时便于观测现象
        }
        for( i = 0 ; i <= 100 ; i++ )
        {
            PWM_SetCompare1(100-i);
            Delay_ms(10);
        }
    }
}

PWM驱动舵机旋转实验

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

void PWM_Init(void)
{
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); // Tim时钟打开
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); // GPIO口时钟打开

    TIM_InternalClockConfig(TIM2); // 默认打开内部时钟,所以该步骤可省略

    TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct; 
    TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;  // 1分频
    TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up; // 向上计数
    TIM_TimeBaseInitStruct.TIM_Period = 20000 - 1;   // ARR的值
    TIM_TimeBaseInitStruct.TIM_Prescaler = 72 - 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 = 0;  // 设置CCR的值
    TIM_OC2Init(TIM2,&TIM_OCInitStruct); // 设置输出比较通道

    GPIO_InitTypeDef GPIO_InitStructure; //初始化GPIO口
    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_Cmd(TIM2,ENABLE); // 启动计时器

}

void PWM_SetCompare2(uint16_t Compare)
{
    TIM_SetCompare2(TIM2,Compare); // 单独更改通道2的CCR值
}
舵机模块
#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); // 舵机角度为0到180,对应CCR值为500到2500,得出角度换算公式
}
主函数
#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "Servo.h"

int main(void){

    Servo_Init();
    Servo_SetAngle(90);

    while(1)
    {

    }
}
世界のネズミは彼らが望むものに依存し、彼らは彼ら自身から誰も求めません
最后更新于 2023-08-27