stm32 PWM互补输出
2022-04-05 15:09 jym蒟蒻 阅读(1891) 评论(0) 编辑 收藏 举报stm32高级定时器例子—stm32 PWM互补输出
时基结构体,用于定时器基础参数设置,与TIM_TimeBaseInit函数配合使用,完成配置。
typedef struct
{ TIM_Prescaler /*定时器预分频器设置,时钟源经该预分频器才是定时器计 数时钟CK_CNT,它设定PSC寄存器的值。
计数器时钟频率 (fCK_CNT) 等于
fCK_PSC/(PSC[15:0]+1),可实现1至65536分频。*/
TIM_CounterMode /*定时器计数方式,可设置为
向上计数、向下计数、中心对齐*/
TIM_Period /*定时器周期,设定自动重载寄存器ARR的值
可设置范围为0至65535*/
TIM_ClockDivision /*时钟分频,设置定时器时钟CK_INT频率与死区发生器
以及数字滤波器采样时钟频率分频比。
可以选择 1、2、4 分频。*/
TIM_RepetitionCounter /*重复计数器,只有 8 位,只存在于高级定时器*/
}TIM_TimeBaseInitTypeDef;
输出比较结构体,用于输出比较模式。与TIM_OCxInit函数配合使用,完成指定定时器输出通道初始化配置。
typedef struct
{
uint16_t TIM_OCMode; /*比较输出模式选择,共有八种。
常用的为 PWM1/PWM2。
设定CCMRx寄存器OCxM[2:0]位的值*/
uint16_t TIM_OutputState; /*比较输出使能,决定最终的输出比较信号OCx是否
通过外部引脚输出。
设定TIMx_CCER寄存器CCxE/CCxNE位的值。*/
uint16_t TIM_OutputNState; /*比较互补输出使能,决定OCx的互补信号OCxN
是否通过外部引脚输出。
设定CCER寄存器CCxNE位的值*/
uint16_t TIM_Pulse; /*比较输出脉冲宽度,设定比较寄存器CCR的值,
决定脉冲宽度。可设置范围为0至65535。*/
uint16_t TIM_OCPolarity; /*比较输出极性,
可选OCx为高电平有效或低电平有效。
决定定时器通道有效电平。
设定CCER寄存器的CCxP位的值*/
uint16_t TIM_OCNPolarity; /*比较互补输出极性,
可选OCxN为高电平有效或低电平有效。
设定TIMx_CCER寄存器的CCxNP位的值。*/
uint16_t TIM_OCIdleState; /*空闲状态时,通道输出电平设置,
可选输出1或输出0,
即在空闲状态(BDTR_MOE位为0)时,
经过死区时间后定时器通道输出高电平或低电平。
设定CR2寄存器的OISx位的值*/
uint16_t TIM_OCNIdleState; /*空闲状态时互补通道输出电平设置,
可选输出1或输出0,
即在空闲状态(BDTR_MOE位为0)时,
经过死区时间后定时器互补通道
输出高电平或低电平,
设定值必须与TIM_OCIdleState相反。
设定CR2寄存器的OISxN位的值。*/
} TIM_OCInitTypeDef;
输入捕获结构体,用于输入捕获模式。
与TIM_ICInit函数配合使用,完成定时器输入通道初始化配置。
如果使用PWM输入模式,与TIM_PWMIConfig函数配合使用,完成定时器输入通道初始化配置。
typedef struct
{
uint16_t TIM_Channel; /*捕获通道ICx选择,
可选TIM_Channel_1、2、3、4四个通道。
设定CCMRx寄存器CCxS位的值*/
uint16_t TIM_ICPolarity; /*输入捕获边沿触发选择,
可选上升沿触发、下降沿触发、边沿跳变触发。
设定CCER寄存器CCxP位和CCxNP位的值。*/
uint16_t TIM_ICSelection; /*输入通道选择,
捕获通道ICx的信号可来自三个输入通道,
分别为TIM_ICSelection_DirectTI、
TIM_ICSelection_IndirectTI
TIM_ICSelection_TRC
普通的输入捕获,4个通道都可以使用,
PWM输入,只能使用通道1和通道2。
设定CCRMx寄存器的CCxS[1:0]位的值*/
uint16_t TIM_ICPrescaler; /*输入捕获通道预分频器,
可设置1、2、4、8分频,
设定CCMRx寄存器的ICxPSC[1:0]位的值。
如果需捕获输入信号的每个有效边沿,
则设置1分频。*/
uint16_t TIM_ICFilter; /*输入捕获滤波器设置,
可设置0x0至0x0F。
设定CCMRx寄存器ICxF[3:0]位的值。
一般不使用滤波器,设置为0*/
} TIM_ICInitTypeDef;
关于捕获通道ICx的信号可来自三个输入通道:
断路和死区结构体,用于断路和死区参数的设置,高级定时器专用。
用于配置断路时,通道输出状态、死区时间。
与TIM_BDTRConfig函数配置使用,完成参数配置。
这个结构体的成员只对应BDTR寄存器。
typedef struct
{
uint16_t TIM_OSSRState; /*运行模式下的关闭状态选择,
设定BDTR寄存器OSSR位的值*/
uint16_t TIM_OSSIState; /*空闲模式下的关闭状态选择,
设定BDTR寄存器OSSI位的值。*/
uint16_t TIM_LOCKLevel; /*锁定级别配置,
设定BDTR寄存器LOCK[1:0]位的值*/
uint16_t TIM_DeadTime; /*配置死区发生器,定义死区持续时间,
可选设置范围为0x0至0xFF。
设定BDTR寄存器DTG[7:0]位的值*/
uint16_t TIM_Break; /*断路输入功能选择,
可选使能或禁止。
设定BDTR寄存器BKE位的值*/
uint16_t TIM_BreakPolarity; /*断路输入通道BRK极性选择,
可选高电平有效或低电平有效。
设定BDTR寄存器BKP位的值。*/
uint16_t TIM_AutomaticOutput; /*自动输出使能,可选使能或禁止,
设定BDTR寄存器AOE位的值。*/
} TIM_BDTRInitTypeDef;
在主输出通道输出波形,在互补通道输出与主通道互补的的波形,添加断路和死区功能。
使用高级定时器TIM1的通道1及其互补通道作为本实验的波形输出通道。对应PA8和PB13。
将示波器的两个输入通道分别与PA8和PB13引脚连接,共地,观察波形。
增加断路功能,用到TIM1_BKIN引脚。对应PB12引脚。
设置该引脚为高电平有效,BKIN引脚置高电平时,两路互补的PWM输出就被停止,像是刹车一样。
Main函数,调用ADVANCE_TIM_Init()函数。
该函数调用ADVANCE_TIM_GPIO_Config()和ADVANCE_TIM_Mode_Config()进行定时器GPIO引脚和工作模式的初始化。
相应的GPIO引脚上可以检测到互补输出的PWM信号,而且带死区时间。
程序运行的过程中,如果BKIN引脚被拉高,PWM输出会被禁止,像是断路或者刹车。
#include "stm32f10x.h"
#include "bsp_led.h"
#include "bsp_AdvanceTim.h"
/**
* @brief 主函数
* @param 无
* @retval 无
*/
int main(void)
{
/* 高级定时器初始化 */
ADVANCE_TIM_Init();
while(1)
{
}
}
修改PWM的周期和占空比,只需修改下面的ADVANCE_TIM_PERIOD、ADVANCE_TIM_PSC和ADVANCE_TIM_PULSE这三个宏即可。具体原因,看之前写的文章—高级定时器里面的PWM输出模式。
TIM_CLK等于72MHZ,ARR是自动重装载寄存器的值,对应ADVANCE_TIM_PERIOD;PSC是计数器时钟的分频因子,对应ADVANCE_TIM_PSC。
PWM信号的频率:F = TIM_CLK/{(ARR+1)*(PSC+1)}
计数器时钟CK_CNT:
定时器时钟经过PSC预分频器后,即CK_CNT,用来驱动计数器计数。
PSC是16位的预分频器,可以对定时器时钟TIMxCLK进行1~65536之间的任何一个数进行分频。CK_CNT=TIMxCLK/(PSC+1)。
ARR=8,CCR=4,CNT从0开始计数。
当CNT<CCR,OCxREF为有效的高电平,同时,比较中断寄存器CCxIF置位。
CCR<=CNT<=ARR,OCxREF为无效的低电平。
计数器在CK_CNT的驱动下,计一个数的时间,1/(TIMxCLK/(PSC+1))=1/(CK_CNT)=(PSC+1)/TIMxCLK
计一个数的时间乘上一个波形的计数次数(ARR+1),就是整个波形的所需时间。
时间取倒数就是PWM信号的频率。
由此可知F = TIM_CLK/{(ARR+1)*(PSC+1)}的含义。
ARR :自动重装载寄存器的值
CLK_cnt:计数器的时钟,等于 Fck_int / (psc+1) = 72M/(psc+1)
PWM 信号的周期 T = (ARR+1) * (1/CLK_cnt) = (ARR+1)*(PSC+1) / 72M
占空比P=CCR/(ARR+1)
#ifndef __BSP_ADVANCETIME_H
#define __BSP_ADVANCETIME_H
#include "stm32f10x.h"
/************高级定时器TIM参数定义,只限TIM1和TIM8************/
// 当使用不同的定时器的时候,对应的GPIO是不一样的,这点要注意
// 这里我们使用高级控制定时器TIM1
#define ADVANCE_TIM TIM1
#define ADVANCE_TIM_APBxClock_FUN RCC_APB2PeriphClockCmd
#define ADVANCE_TIM_CLK RCC_APB2Periph_TIM1
// PWM 信号的频率 F = TIM_CLK/{(ARR+1)*(PSC+1)}
#define ADVANCE_TIM_PERIOD (8-1)
#define ADVANCE_TIM_PSC (9-1)
#define ADVANCE_TIM_PULSE 4
#define ADVANCE_TIM_IRQ TIM1_UP_IRQn
#define ADVANCE_TIM_IRQHandler TIM1_UP_IRQHandler
// TIM1 输出比较通道
#define ADVANCE_TIM_CH1_GPIO_CLK RCC_APB2Periph_GPIOA
#define ADVANCE_TIM_CH1_PORT GPIOA
#define ADVANCE_TIM_CH1_PIN GPIO_Pin_8
// TIM1 输出比较通道的互补通道
#define ADVANCE_TIM_CH1N_GPIO_CLK RCC_APB2Periph_GPIOB
#define ADVANCE_TIM_CH1N_PORT GPIOB
#define ADVANCE_TIM_CH1N_PIN GPIO_Pin_13
// TIM1 输出比较通道的刹车通道
#define ADVANCE_TIM_BKIN_GPIO_CLK RCC_APB2Periph_GPIOB
#define ADVANCE_TIM_BKIN_PORT GPIOB
#define ADVANCE_TIM_BKIN_PIN GPIO_Pin_12
/**************************函数声明********************************/
void ADVANCE_TIM_Init(void);
#endif /* __BSP_ADVANCETIME_H */
#include "bsp_AdvanceTim.h"
static void ADVANCE_TIM_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
// 输出比较通道 GPIO 初始化
RCC_APB2PeriphClockCmd(ADVANCE_TIM_CH1_GPIO_CLK, ENABLE);
GPIO_InitStructure.GPIO_Pin = ADVANCE_TIM_CH1_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(ADVANCE_TIM_CH1_PORT, &GPIO_InitStructure);
// 输出比较通道互补通道 GPIO 初始化
RCC_APB2PeriphClockCmd(ADVANCE_TIM_CH1N_GPIO_CLK, ENABLE);
GPIO_InitStructure.GPIO_Pin = ADVANCE_TIM_CH1N_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(ADVANCE_TIM_CH1N_PORT, &GPIO_InitStructure);
// 输出比较通道刹车通道 GPIO 初始化
RCC_APB2PeriphClockCmd(ADVANCE_TIM_BKIN_GPIO_CLK, ENABLE);
GPIO_InitStructure.GPIO_Pin = ADVANCE_TIM_BKIN_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(ADVANCE_TIM_BKIN_PORT, &GPIO_InitStructure);
// BKIN引脚默认先输出低电平
GPIO_ResetBits(ADVANCE_TIM_BKIN_PORT,ADVANCE_TIM_BKIN_PIN);
}
///*
// * 注意:TIM_TimeBaseInitTypeDef结构体里面有5个成员,TIM6和TIM7的寄存器里面只有
// * TIM_Prescaler和TIM_Period,所以使用TIM6和TIM7的时候只需初始化这两个成员即可,
// * 另外三个成员是通用定时器和高级定时器才有.
// *-----------------------------------------------------------------------------
// *typedef struct
// *{ TIM_Prescaler 都有
// * TIM_CounterMode TIMx,x[6,7]没有,其他都有
// * TIM_Period 都有
// * TIM_ClockDivision TIMx,x[6,7]没有,其他都有
// * TIM_RepetitionCounter TIMx,x[1,8,15,16,17]才有
// *}TIM_TimeBaseInitTypeDef;
// *-----------------------------------------------------------------------------
// */
/* ---------------- PWM信号 周期和占空比的计算--------------- */
// ARR :自动重装载寄存器的值
// CLK_cnt:计数器的时钟,等于 Fck_int / (psc+1) = 72M/(psc+1)
// PWM 信号的周期 T = (ARR+1) * (1/CLK_cnt) = (ARR+1)*(PSC+1) / 72M
// 占空比P=CCR/(ARR+1)
static void ADVANCE_TIM_Mode_Config(void)
{
// 开启定时器时钟,即内部时钟CK_INT=72M
ADVANCE_TIM_APBxClock_FUN(ADVANCE_TIM_CLK,ENABLE);
/*--------------------时基结构体初始化-------------------------*/
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
// 自动重装载寄存器的值,累计TIM_Period+1个频率后产生一个更新或者中断
TIM_TimeBaseStructure.TIM_Period=ADVANCE_TIM_PERIOD;
// 驱动CNT计数器的时钟 = Fck_int/(psc+1)
TIM_TimeBaseStructure.TIM_Prescaler= ADVANCE_TIM_PSC;
// 时钟分频因子 ,配置死区时间时需要用到
TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;
// 计数器计数模式,设置为向上计数
TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;
// 重复计数器的值,没用到不用管
TIM_TimeBaseStructure.TIM_RepetitionCounter=0;
// 初始化定时器
TIM_TimeBaseInit(ADVANCE_TIM, &TIM_TimeBaseStructure);
/*--------------------输出比较结构体初始化-------------------*/
TIM_OCInitTypeDef TIM_OCInitStructure;
// 配置为PWM模式1
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
// 输出使能
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
// 互补输出使能
TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;
// 设置占空比大小
TIM_OCInitStructure.TIM_Pulse = ADVANCE_TIM_PULSE;
// 输出通道电平极性配置
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
// 互补输出通道电平极性配置
TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;
// 输出通道空闲电平极性配置
TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;
// 互补输出通道空闲电平极性配置
TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Reset;
TIM_OC1Init(ADVANCE_TIM, &TIM_OCInitStructure);
TIM_OC1PreloadConfig(ADVANCE_TIM, TIM_OCPreload_Enable);
/*-------------------刹车和死区结构体初始化-------------------*/
// 有关刹车和死区结构体的成员具体可参考BDTR寄存器的描述
TIM_BDTRInitTypeDef TIM_BDTRInitStructure;
TIM_BDTRInitStructure.TIM_OSSRState = TIM_OSSRState_Enable;
TIM_BDTRInitStructure.TIM_OSSIState = TIM_OSSIState_Enable;
TIM_BDTRInitStructure.TIM_LOCKLevel = TIM_LOCKLevel_1;
// 输出比较信号死区时间配置,具体如何计算可参考 BDTR:UTG[7:0]的描述
// 这里配置的死区时间为152ns
TIM_BDTRInitStructure.TIM_DeadTime = 11;
TIM_BDTRInitStructure.TIM_Break = TIM_Break_Enable;
// 当BKIN引脚检测到高电平的时候,输出比较信号被禁止,就好像是刹车一样
TIM_BDTRInitStructure.TIM_BreakPolarity = TIM_BreakPolarity_High;
TIM_BDTRInitStructure.TIM_AutomaticOutput = TIM_AutomaticOutput_Enable;
TIM_BDTRConfig(ADVANCE_TIM, &TIM_BDTRInitStructure);
// 使能计数器
TIM_Cmd(ADVANCE_TIM, ENABLE);
// 主输出使能,当使用的是通用定时器时,这句不需要
TIM_CtrlPWMOutputs(ADVANCE_TIM, ENABLE);
}
void ADVANCE_TIM_Init(void)
{
ADVANCE_TIM_GPIO_Config()