STM32的HAL库开发---高级定时器---互补输出带死区实验
一、互补输出简介
互补输出:OCx输出高电平,则互补通道OCxN输出低电平。OCx输出低电平,则互补通道OCxN输出高电平。
带死区控制的互补输出:OCx输出高电平时,则互补通道OCxN过一会再输出输出低电平。这个时间里输出的电平为无效电平。
二、带死区控制的互补输出应用H桥
在H桥中间的是电动机, 电流从左边流向右边为正转,从右边流向左边为反转。正转的时候,Q1和Q4导通,反转的时候,Q2和Q3导通。4个三极管都是NPN型三极管,都需要高电平才能导通。
Q1和Q3连接的OC1,Q2和Q3连接的是互补通道OC1N。当OC1输出高电平时,Q1和Q4导通,电机正转,OC1N输出低电平,Q2和Q3都截止。当OC1N输出高电平时,Q2和Q3导通,电机反转,此时OC1输出低电平,Q1和Q4截止。
如果输出通道OC1和互补输出通道OC1N都为有效电平,在这个图里边有效电平为高电平,都为有效电平则短路。
由于元器件是有延迟特性,所以需要加上死区时间控制。这个电路图的无效电平为低电平。
三、捕获/比较通道的输出部分(通道1至3)
1、OC1RE为输出参考信号,高电平有效。
2、TIMx_CCMR1的OC1M设置输出比较模式,在F1系列有8种比较模式。
3、 ETRF信号,设置了OC1CE为,则ETRF信号来的时候,OC1REF会被强制清0。
4、配置TIMx_CCER寄存器的CC1E和CC1NE位,来设置输出通道使能和输出互补通道使能。当使能输出通道,关闭互补输出通道,则直接走死区发生器上面那个线,经过输出极性选择器,从OC1输出。当关闭输出通道,使能互补输出通道,则经过互补输出极性选择器,从OC1N输出。
死区输出:同时使能输出通道和互补输出通带,OC1REF信号经过死区发生器,然后分别经过各自的极性选择器,来到OC1和OC1N。
MOE位:高级定时器的主输出控制,想输出。必须置1,否则两个通道都无法输出。
四、死区时间计算
1、确定tDTS的值:
其中CKD位在TIMx_CR1寄存器里边设置,Ft为定时器时钟频率,F1系列就是72Mhz。
2、判断DTG[7:5],选择计算公式,在TIMx_BDTR寄存器设置。
3、带入选择的公式计算。
五、刹车(断路)功能
1、使能刹车功能:将TIMx_BDTR的BKE位置1,刹车输入信号极性由BKP位设置
将TIMx_BKIN引脚复用为刹车功能,刹车信号经过极性选择后,来到或门。BI为刹车中断。
使能刹车功能后:由TIMx_BDTR的MOE、OSSI、OSSR位,TIMx_CR2的OISx、OISxN位,TIMx_CCER的CCxE、CCxNE位控制OCx和OCxN输出状态
无论何时,OCx和OCxN输出都不能同时处在有效电平,由硬件强制设置。
2、发生刹车后,会怎么样?
- MOE位被清零,OCx和OCxN为无效、空闲或复位状态(OSSI位选择),MOE为0,被称为空闲模式,为1被称为运行模式。
- OCx和OCxN的状态:由相关控制位状态决定,当使用互补输出时:根据情况自动控制输出电平,参考参考手册使用刹车(断路)功能小节
- BIF位置1,如果使能了BIE位,还会产生刹车中断;如果使能了TDE位,会产生DMA请求
- 如果AOE位置 1,在下一个 更新事件UEV时,MOE位被自动置 1
从图中可以看出,当刹车信号来时,MOE位会被置0,同时输出通道电平由OIS1位决定,OIS1为1,则输出高电平,OIS1为0,则输出低电平。
1、设置输出通道极性为高电平有效,当OCxREF下降沿来的时候,没有延迟,当上升沿来的时候,需要加死区延迟。当刹车信号来的时候,OISx为0,输出低电平,低电平不是有效输出电平,所以没有延迟。
设置互补输出通道为高电平有效,在OCxREF下降沿来的时候,OCxN需要加死区延迟,在OCxREF上升沿来的时候,OCxN变为低电平,不需要加死区延迟。刹车信号来的时候,设置的OCSxN为1,为有效电平,需要加死区延迟。
2、设置输出通道极性为高电平有效,当OCxREF下降沿来的时候,不需要死区延迟,当上升沿来的时候,需要加死区延迟。当刹车信号来的时候,OISx为1,输出高电平,高电平是有效输出电平,需要加死区延迟。
设置互补输出通道为低电平有效,在OCxREF下降沿来的时候,OCxN需要加死区延迟,在OCxREF上升沿来的时候,OCxN变为高电平,不需要加死区延迟。刹车信号来的时候,设置的OCSxN为1,为无效电平,不需要加死区延迟。
3、互补输出没有开启,设置输出通道为高电平有效,输出与OCxREF一样,刹车信号来的时候,OCSx为0,为无效电平,不需要死区延迟。
互补输出通道没有开启,设置的设置互补输出通道为高电平有效,同时OCSxN为1,高电平是有效输出电平,需要加死区延迟。
4、互补输出没有开启,设置输出通道为高电平有效,输出与OCxREF一样,刹车信号来的时候,OCSx为1,为有效电平,需要死区延迟。
互补输出通道没有开启,设置的设置互补输出通道为高电平有效,同时OCSxN为0,低电平不是有效输出电平,不需要加死区延迟。
4、互补输出没有开启,设置输出通道为高电平有效,输出与OCxREF一样,刹车信号来的时候,OCSx为1,为有效电平,需要死区延迟。
互补输出通道没有开启,设置的设置互补输出通道为高电平有效,同时OCSxN为0,低电平不是有效输出电平,不需要加死区延迟。
六、高级定时器互补输出带死区控制实验配置步骤
1、HAL_TIM_PWM_Init()函数,配置定时器基础工作参数。这个函数与HAL_TIM_Base_init()函数功能是一样的。
2、HAL_TIM_PWM_MspInit(),配置NVIC、CLOCK、GPIO等。
3、HAL_TIM_PWM _Configchannel()函数,配置PWM模式/比较值。
4、HAL_TIMEx_ConfigBreakDeadTime()函数,配置刹车功能、死区时间等。
5、HAL_TIM_PWM _Start()函数,使能输出、主输出、计数器。
6、HAL_TIM_PWMN _Start()函数,使能互补输出、主输出、计数器。
七、高级定时器互补输出带死区控制实验
1、寄存器版本
#include "./BSP/TIMER/atim.h"
//配置定时器1的通道1 和 通道1互补输出 PE8 PE9
void Advanced_TIM_Init(void)
{
//开启定时器1时钟
RCC->APB2ENR |= (1 << 11);
//设置CKD分频系数为4
TIM1->CR1 |= (1 << 9);
TIM1->CR1 &= ~(1 << 8);
//设置ARR寄存器缓冲功能
TIM1->CR1 |= (1 << 7);
//注意硬件不允许同时输出有效电平 有效电平在CCxP和CCxNP设置
//设置OIS1 输出空闲状态
//TIM1->CR2 |= (1 << 8);
TIM1->CR2 &= ~(1 << 8);
//设置OIS1N 互补输出空闲状态
TIM1->CR2 |= (1 << 9);
//设置CC1S模式为输出 00
TIM1->CCMR1 &= ~(0X03 << 0);
//OC1M 设置为PWM1模式 110
TIM1->CCMR1 |= (0X03 << 5);
TIM1->CCMR1 &= ~(1 << 4);
//CC1NP 互补输出高电平有效
TIM1->CCER &= ~(1 << 3);
//CC1NE 开启互补输出比较使能
TIM1->CCER |= (1 << 2);
//CC1P 输出高电平有效
TIM1->CCER &= ~(1 << 1);
//CC1E开启输出比较使能
TIM1->CCER |= (1 << 0);
//设置预分频系数为71
TIM1->PSC = 71;
//设置预装载值为999
TIM1->ARR = 999;
//设置CCR1输出比较值 控制占空比
TIM1->CCR1 = 0.3 * (TIM1->ARR + 1) - 1;
//MOE 开启主输出
TIM1->BDTR |= (1 << 15);
//AOE 开启刹车失效之后MOE自动恢复
TIM1->BDTR |= (1 << 14);
//刹车极性高电平有效
TIM1->BDTR |= (1 << 13);
//开启刹车使能
TIM1->BDTR |= (1 << 12);
//CKD分频系数设置为4 72M/4 取倒数为Tdts时间
//然后用100 成这个时间为死区延迟时间 5.56us
//设置DTG死区延时为100
TIM1->BDTR |= 100;
TIM1->EGR |= (1 << 0);
//开启GPIOE1时钟
RCC->APB2ENR |= (1 << 6);
//设置PE8为复用推挽输出
GPIOE->CRH |= (0X03 << 0);
GPIOE->CRH |= (1 << 3);
GPIOE->CRH &= ~(1 << 2);
//设置PE9为复用推挽输出
GPIOE->CRH |= (0X03 << 4);
GPIOE->CRH |= (1 << 7);
GPIOE->CRH &= ~(1 << 6);
//设置PE15为复用推挽输出
GPIOE->CRH |= (0X03 << 28);
GPIOE->CRH |= (1 << 31);
GPIOE->CRH &= ~(1 << 30);
//使能AFIO时钟
RCC->APB2ENR |= (1 << 0);
//设置TIM1完全重映射 将CH1映射到PE9 CH1N映射到PE8 BKIN映射到PE15上
AFIO->MAPR |= (0x03 << 6);
//使能计数器
TIM1->CR1 |= (1 << 0);
}
注意:配置过程中发现刹车输入使能位和刹车极性位设置无效,但是debug的时候通过断点设置便可以,全速运行就不可以 问题还没有找到,有思路的小伙伴可以私信我。
2、库函数版本
atim.h头文件
#ifndef __ATIM_H
#define __ATIM_H
#include "stm32f1xx.h"
void Advanced_TIM_Init(void);
#endif
atim.c源文件
#include "./BSP/TIMER/atim.h"
TIM_HandleTypeDef htim;
void Advanced_TIM_Init(void)
{
htim.Instance = TIM1;
htim.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
htim.Init.ClockDivision = TIM_CLOCKDIVISION_DIV4;
htim.Init.CounterMode = TIM_COUNTERMODE_UP;
htim.Init.Period = 999;
htim.Init.Prescaler = 71;
//配置PWM输出
HAL_TIM_PWM_Init(&htim);
TIM_OC_InitTypeDef sConfig = {0};
sConfig.OCIdleState = TIM_OCIDLESTATE_SET;
sConfig.OCMode = TIM_OCMODE_PWM1;
sConfig.OCNIdleState = TIM_OCNIDLESTATE_RESET;
sConfig.OCNPolarity = TIM_OCNPOLARITY_HIGH;
sConfig.OCPolarity = TIM_OCPOLARITY_HIGH;
sConfig.Pulse = 499;
HAL_TIM_PWM_ConfigChannel(&htim,&sConfig,TIM_CHANNEL_1);
TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0};
sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_ENABLE;
sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_HIGH;
sBreakDeadTimeConfig.BreakState = TIM_BREAK_ENABLE;
sBreakDeadTimeConfig.DeadTime = 100;
sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSI_DISABLE;
sBreakDeadTimeConfig.OffStateRunMode=TIM_OSSR_DISABLE;
//刹车输入及死区时间配置
HAL_TIMEx_ConfigBreakDeadTime(&htim,&sBreakDeadTimeConfig);
HAL_TIM_PWM_Start(&htim,TIM_CHANNEL_1);
HAL_TIMEx_PWMN_Start(&htim,TIM_CHANNEL_1);
}
void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim)
{
//开启定时器1时钟
__HAL_RCC_TIM1_CLK_ENABLE();
//开启GPIOE时钟
__HAL_RCC_GPIOE_CLK_ENABLE();
GPIO_InitTypeDef GPIO_Init = {0};
GPIO_Init.Mode = GPIO_MODE_AF_PP;
GPIO_Init.Pin = GPIO_PIN_8;
GPIO_Init.Speed = GPIO_SPEED_FREQ_HIGH;
//初始化PE8为复用推挽输出
HAL_GPIO_Init(GPIOE, &GPIO_Init);
//初始化PE9为复用推挽输出
GPIO_Init.Pin = GPIO_PIN_9;
HAL_GPIO_Init(GPIOE, &GPIO_Init);
GPIO_Init.Mode = GPIO_MODE_INPUT;
GPIO_Init.Pull = GPIO_PULLDOWN;
GPIO_Init.Pin = GPIO_PIN_15;
HAL_GPIO_Init(GPIOE, &GPIO_Init);
//开启AFIO时钟
__HAL_RCC_AFIO_CLK_ENABLE();
//开启TIM1完全重映射
__HAL_AFIO_REMAP_TIM1_ENABLE();
}
main.c源文件
#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/usart/usart.h"
#include "./SYSTEM/delay/delay.h"
#include "./BSP/LED/led.h"
#include "./BSP/TIMER/atim.h"
int main(void)
{
HAL_Init(); /* 初始化HAL库 */
sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */
delay_init(72); /* 延时初始化 */
led_Init(); /* LED初始化 */
Advanced_TIM_Init();
while(1)
{
LED0(1);
LED1(0);
delay_ms(500);
LED0(0);
LED1(1);
delay_ms(500);
}
}