内容纲要
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)
{
}
}
Comments NOTHING