TIM-有感BLDC实现解析-基于CH32V203

发布时间 2023-09-05 10:10:34作者: WCH_CH32

TIM-有感BLDC实现解析-基于CH32V203

1、BLDC运行基本原理简要介绍

在图1-20(a)中,AB相通电,电流处于转子产生的磁场内,根据左手定则,我们判断线圈AA’中的上半部导线A受到一个顺时针方向的电磁力,而AA’的下半部导线A’也受到一个顺时针方向的电磁力。由于线圈绕组在定子上,定子是固定不动的,故根据作用力与反作用力,定子绕组AA’会施加给转子一个逆时针方向的反作用力,转子在这个力的作用下,就转起来了。同理,与AA’的情况类似,BB’也会对转子产生一个逆时针的反作用力。当转子逆时针转过60°后,到达图1-20(b)的位置,这时线圈BB’已经到达转子磁极的边缘位置了,再转下去就要产生反方向的力了,所以这时就要换相,换成AC相通电,见图1-20(c)。这样,每过60°换相通电,转子就可以一直转下去了。

2、6路PWM互补波形的输出

高级定时器TIM1的相关宏定义-方便后续更换成其它高级定时器

#define BLDC_TIMx TIM1

#define BLDC_TIM_CLK RCC_APB2Periph_TIM1

#define BLDC_TIM_GPIO_CLK (RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB)

#define BLDC_TIM_CH1_PORT GPIOA

#define BLDC_TIM_CH1_PIN GPIO_Pin_8 //通道1

#define BLDC_TIM_CH2_PORT GPIOA

#define BLDC_TIM_CH2_PIN GPIO_Pin_9 //通道2

#define BLDC_TIM_CH3_PORT GPIOA

#define BLDC_TIM_CH3_PIN GPIO_Pin_10 //通道3

#define BLDC_TIM_CH1N_PORT GPIOB

#define BLDC_TIM_CH1N_PIN GPIO_Pin_13 //互补通道1

#define BLDC_TIM_CH2N_PORT GPIOB

#define BLDC_TIM_CH2N_PIN GPIO_Pin_14 //互补通道2

#define BLDC_TIM_CH3N_PORT GPIOB

#define BLDC_TIM_CH3N_PIN GPIO_Pin_15 //互补通道3

#define BLDC_TIM_BKIN_PORT GPIOB

#define BLDC_TIM_BKIN_PIN GPIO_Pin_12 //刹车输入

TIM1高级定时器所使用的6路PWM引脚以及刹车引脚初始化

void TIMx_GPIO_Init(void)

{

GPIO_InitTypeDef GPIO_InitStructure = {0};

RCC_APB2PeriphClockCmd(BLDC_TIM_GPIO_CLK|RCC_APB2Periph_AFIO,ENABLE);

/* TIMx_CH1 */

GPIO_InitStructure.GPIO_Pin = BLDC_TIM_CH1_PIN;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_Init(BLDC_TIM_CH1_PORT, &GPIO_InitStructure);

/* TIMx_CH2 */

GPIO_InitStructure.GPIO_Pin = BLDC_TIM_CH2_PIN;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_Init(BLDC_TIM_CH2_PORT, &GPIO_InitStructure);

/* TIMx_CH3 */

GPIO_InitStructure.GPIO_Pin = BLDC_TIM_CH3_PIN;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_Init(BLDC_TIM_CH3_PORT, &GPIO_InitStructure);

/* TIMx_CH1N */

GPIO_InitStructure.GPIO_Pin = BLDC_TIM_CH1N_PIN;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_Init(BLDC_TIM_CH1N_PORT, &GPIO_InitStructure);

/* TIMx_CH2N */

GPIO_InitStructure.GPIO_Pin = BLDC_TIM_CH2N_PIN;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_Init(BLDC_TIM_CH2N_PORT, &GPIO_InitStructure);

/* TIMx_CH3N */

GPIO_InitStructure.GPIO_Pin = BLDC_TIM_CH3N_PIN;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_Init(BLDC_TIM_CH3N_PORT, &GPIO_InitStructure);

/* TIMx_BKIN */

GPIO_InitStructure.GPIO_Pin = BLDC_TIM_BKIN_PIN;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;

GPIO_Init(BLDC_TIM_BKIN_PORT, &GPIO_InitStructure);

}

TIM1高级定时器的参数的初始化

//PWM频率-20KHz

#define BLDC_TIM_PWM_FREQ 20000

// 定时器预分频系数-(2-1)

#define BLDC_TIM_PRESCALER 1

//定时器计数周期-(144000000/2=72000000/20000=3600)

#define BLDC_TIM_PERIOD (uint16_t)(SystemCoreClock/(BLDC_TIM_PRESCALER+1)/BLDC_TIM_PWM_FREQ)

//定时器重复寄存器数值

#define BLDC_TIM_REPETITIONCOUNTER 0 //PWM占空比

void TIMx_Mode_Init(void)//开关频率20K

{

TIM_OCInitTypeDef TIM_OCInitStructure = {0};

TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure = {0};

TIM_BDTRInitTypeDef TIM_BDTRInitStructure = {0};

RCC_APB2PeriphClockCmd(BLDC_TIM_CLK, ENABLE);

TIM_TimeBaseInitStructure.TIM_Period = BLDC_TIM_PERIOD;

TIM_TimeBaseInitStructure.TIM_Prescaler = BLDC_TIM_PRESCALER;

TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;

TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;

TIM_TimeBaseInitStructure.TIM_RepetitionCounter = BLDC_TIM_REPETITIONCOUNTER;

TIM_TimeBaseInit(BLDC_TIMx, &TIM_TimeBaseInitStructure);

TIM_ARRPreloadConfig(BLDC_TIMx, ENABLE);

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 = 0;

TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;

TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;

TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Reset;

TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Reset;

TIM_OC1Init(BLDC_TIMx, &TIM_OCInitStructure);// 初始化通道 1 输出 PWM

TIM_OC2Init(BLDC_TIMx, &TIM_OCInitStructure);// 初始化通道 2 输出 PWM

TIM_OC3Init(BLDC_TIMx, &TIM_OCInitStructure);// 初始化通道 3 输出 PWM

TIM_OC1PreloadConfig(BLDC_TIMx, TIM_OCPreload_Enable);

TIM_OC2PreloadConfig(BLDC_TIMx, TIM_OCPreload_Enable);

TIM_OC3PreloadConfig(BLDC_TIMx, TIM_OCPreload_Enable);

TIM_BDTRInitStructure.TIM_OSSIState = TIM_OSSIState_Enable;

TIM_BDTRInitStructure.TIM_OSSRState = TIM_OSSRState_Enable;

TIM_BDTRInitStructure.TIM_LOCKLevel = TIM_LOCKLevel_OFF;

TIM_BDTRInitStructure.TIM_DeadTime = 10; //死区时间=138.9ns

TIM_BDTRInitStructure.TIM_Break = TIM_Break_Enable;

TIM_BDTRInitStructure.TIM_BreakPolarity = TIM_BreakPolarity_High;

TIM_BDTRInitStructure.TIM_AutomaticOutput = TIM_AutomaticOutput_Disable;

TIM_BDTRConfig(BLDC_TIMx, &TIM_BDTRInitStructure);

//死区以及刹车参数初始化

TIM_SelectInputTrigger( BLDC_TIMx, TIM_TS_ITR3 );

TIM_SelectCOM(BLDC_TIMx,ENABLE);

TIM_CCPreloadControl(BLDC_TIMx,ENABLE);

//设置触发源为TIM4霍尔定时器,并使能COM事件以达到换相时的同步功能

TIM_CtrlPWMOutputs(BLDC_TIMx, ENABLE);

TIM_Cmd(BLDC_TIMx, ENABLE);

TIM_CCxCmd(BLDC_TIMx,TIM_Channel_1,TIM_CCx_Disable);

TIM_CCxNCmd(BLDC_TIMx,TIM_Channel_1,TIM_CCxN_Disable);

TIM_CCxCmd(BLDC_TIMx,TIM_Channel_2,TIM_CCx_Disable);

TIM_CCxNCmd(BLDC_TIMx,TIM_Channel_2,TIM_CCxN_Disable);

TIM_CCxCmd(BLDC_TIMx,TIM_Channel_3,TIM_CCx_Disable);

TIM_CCxNCmd(BLDC_TIMx,TIM_Channel_3,TIM_CCxN_Disable);

}

3、与霍尔传感器接口-霍尔定时器的配置

霍尔定时器TIM4的相关宏定义-方便后续更换成其它霍尔定时器

#define HALL_TIMx TIM4

#define HALL_TIM_CLK RCC_APB1Periph_TIM4

#define HALL_TIM_PERIOD 0xFFFF //ARR,计数周期,配置为最大65535

#define HALL_TIM_PRESCALER (144-1) //预分频系数为144

#define HALL_TIM_Channel_x TIM_Channel_1 //通道1

#define HALL_TIM_GPIO_CLK RCC_APB2Periph_GPIOB

#define HALL_TIM_CH1_PIN GPIO_Pin_6

#define HALL_TIM_CH1_GPIO GPIOB

#define HALL_TIM_CH2_PIN GPIO_Pin_7

#define HALL_TIM_CH2_GPIO GPIOB

#define HALL_TIM_CH3_PIN GPIO_Pin_8

#define HALL_TIM_CH3_GPIO GPIOB

TIM4霍尔定时器所使用的3路捕获引脚的初始化

void TIMx_HALL_GPIO_Init(void)

{

GPIO_InitTypeDef GPIO_InitStructure = {0};

RCC_APB2PeriphClockCmd(HALL_TIM_GPIO_CLK,ENABLE);

/* TIM4_CH1 */

GPIO_InitStructure.GPIO_Pin = HALL_TIM_CH1_PIN;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;

GPIO_Init(HALL_TIM_CH1_GPIO, &GPIO_InitStructure);

/* TIM4_CH2 */

GPIO_InitStructure.GPIO_Pin = HALL_TIM_CH2_PIN;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;

GPIO_Init(HALL_TIM_CH2_GPIO, &GPIO_InitStructure);

/* TIM4_CH3 */

GPIO_InitStructure.GPIO_Pin = HALL_TIM_CH3_PIN;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;

GPIO_Init(HALL_TIM_CH3_GPIO, &GPIO_InitStructure);

}

void TIMx_HALL_Mode_Init(void)

{

TIM_ICInitTypeDef TIM_ICInitStructure = {0};

TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure = {0};

NVIC_InitTypeDef NVIC_InitStructure={0};

RCC_APB1PeriphClockCmd(HALL_TIM_CLK, ENABLE);

TIM_TimeBaseInitStructure.TIM_Period = HALL_TIM_PERIOD;

TIM_TimeBaseInitStructure.TIM_Prescaler = HALL_TIM_PRESCALER;

TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;

TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;

TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;

TIM_TimeBaseInit(HALL_TIMx, &TIM_TimeBaseInitStructure);

NVIC_InitStructure.NVIC_IRQChannel = HALL_TIM_IRQn;

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;

NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;

NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

NVIC_Init(&NVIC_InitStructure);

TIM_ITConfig( HALL_TIMx, TIM_IT_Trigger, ENABLE );

TIM_ITConfig( HALL_TIMx, TIM_IT_CC1, ENABLE );

TIM_ICInitStructure.TIM_Channel = HALL_TIM_Channel_x;

TIM_ICInitStructure.TIM_ICFilter = 0x00;

TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_BothEdge;

TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;

TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_TRC;

TIM_ICInit(HALL_TIMx,&TIM_ICInitStructure);

//使能霍尔传感器的接口,将三个通道的信号异或输入。

TIM_SelectHallSensor(HALL_TIMx,ENABLE);

//输入触发源选择,选择TI1F_ED

TIM_SelectInputTrigger( HALL_TIMx, TIM_TS_TI1F_ED );

//从模式选择,复位模式

TIM_SelectSlaveMode( HALL_TIMx, TIM_SlaveMode_Reset );

//主从模式使能

TIM_SelectMasterSlaveMode( HALL_TIMx, TIM_MasterSlaveMode_Enable );

//使能霍尔定时器

TIM_Cmd( HALL_TIMx, ENABLE );

//清除中断标志位,防止直接第一次进入中断

TIM_ClearITPendingBit (HALL_TIMx,TIM_IT_Trigger);

}

4、定时器的联动与触发换相

定时器联动概述:

1、高级定时器TIM1设定TIM4为主定时器,即利用TIM4触发TIM1

2、霍尔定时器配置了TIM4_CH1、TIM4_CH2、TIM4_CH3三个通道捕获的电平在经过异或后形成TI1信号,并经过双边沿检测器,形成TI1F_ED的脉冲波形信号。

3、设置定时器内部TRC触发,IC1配置为输入捕获(无论配置为上升沿还是下降沿均可捕获到TI1F_ED的脉冲波形信号),IC1输入源配置为TRC。一旦捕获到此信号即开始换相操作。

4、同时TRC信号生成TRGI信号触发复位更新TIM4的CNT计数值,使得CNT=0,产生一个UPDATE信号,通过此处的更新可以捕获到两个换相之前的延时,从而推算出马达的速度信息。

触发换相:

获取霍尔定时器三个通道的霍尔信号

uint8_t get_hall_state(void)

{

uint8_t state = 0;

if((HALL_TIM_CH1_GPIO->INDR & HALL_TIM_CH1_PIN) != (uint32_t)Bit_RESET)

//CH1状态获取

{

state |= 0x01U << 0;

}

if((HALL_TIM_CH2_GPIO->INDR & HALL_TIM_CH2_PIN) != (uint32_t)Bit_RESET)

//CH2状态获取

{

state |= 0x01U << 1;

}

if((HALL_TIM_CH3_GPIO->INDR & HALL_TIM_CH3_PIN) != (uint32_t)Bit_RESET)

//CH3状态获取

{

state |= 0x01U << 2;

}

return state; // 返回传感器状态

}

霍尔定时器中断换相

void TIM4_IRQHandler(void)

{

if( TIM_GetITStatus( TIM4, TIM_IT_Trigger|TIM_IT_CC1 ) != RESET )

{

uint8_t step = 0;

step = get_hall_state();

switch(step)

{

case 3: //V+ W-

//输出比较通道1配置

TIM_CCxCmd(BLDC_TIMx,TIM_Channel_1,TIM_CCx_Disable);

TIM_CCxNCmd(BLDC_TIMx,TIM_Channel_1,TIM_CCxN_Disable);

//输出比较通道2配置

TIM_SetCompare2(BLDC_TIMx,BLDC_TIM_PERIOD*speed_duty/100);

TIM_CCxCmd(BLDC_TIMx,TIM_Channel_2,TIM_CCx_Enable);

//输出比较通道3配置

TIM_SetCompare3(BLDC_TIMx,BLDC_TIM_PERIOD);

TIM_CCxNCmd(BLDC_TIMx,TIM_Channel_3,TIM_CCxN_Enable);

break;

case 2: //V+ U-

//输出比较通道3配置

TIM_CCxCmd(BLDC_TIMx,TIM_Channel_3,TIM_CCx_Disable);

TIM_CCxNCmd(BLDC_TIMx,TIM_Channel_3,TIM_CCxN_Disable);

//输出比较通道1配置

TIM_SetCompare1(BLDC_TIMx,BLDC_TIM_PERIOD);

TIM_CCxNCmd(BLDC_TIMx,TIM_Channel_1,TIM_CCxN_Enable);

//输出比较通道2配置

TIM_SetCompare2(BLDC_TIMx,BLDC_TIM_PERIOD*speed_duty/100);

TIM_CCxCmd(BLDC_TIMx,TIM_Channel_2,TIM_CCx_Enable);

break;

case 6: //W+ U-

//输出比较通道2配置

TIM_CCxCmd(BLDC_TIMx,TIM_Channel_2,TIM_CCx_Disable);

TIM_CCxNCmd(BLDC_TIMx,TIM_Channel_2,TIM_CCxN_Disable);

//输出比较通道1配置

TIM_SetCompare1(BLDC_TIMx,BLDC_TIM_PERIOD);

TIM_CCxNCmd(BLDC_TIMx,TIM_Channel_1,TIM_CCxN_Enable);

//输出比较通道3配置

TIM_SetCompare3(BLDC_TIMx,BLDC_TIM_PERIOD*speed_duty/100);

TIM_CCxCmd(BLDC_TIMx,TIM_Channel_3,TIM_CCx_Enable);

break;

case 4: //W+ V-

//输出比较通道1配置

TIM_CCxCmd(BLDC_TIMx,TIM_Channel_1,TIM_CCx_Disable);

TIM_CCxNCmd(BLDC_TIMx,TIM_Channel_1,TIM_CCxN_Disable);

//输出比较通道2配置

TIM_SetCompare2(BLDC_TIMx,BLDC_TIM_PERIOD);

TIM_CCxNCmd(BLDC_TIMx,TIM_Channel_2,TIM_CCxN_Enable);

//输出比较通道3配置

TIM_SetCompare3(BLDC_TIMx,BLDC_TIM_PERIOD*speed_duty/100);

TIM_CCxCmd(BLDC_TIMx,TIM_Channel_3,TIM_CCx_Enable);

break;

case 5: //U+ V-

//输出比较通道3配置

TIM_CCxCmd(BLDC_TIMx,TIM_Channel_3,TIM_CCx_Disable);

TIM_CCxNCmd(BLDC_TIMx,TIM_Channel_3,TIM_CCxN_Disable);

//输出比较通道1配置

TIM_SetCompare1(BLDC_TIMx,BLDC_TIM_PERIOD*speed_duty/100);

TIM_CCxCmd(BLDC_TIMx,TIM_Channel_1,TIM_CCx_Enable);

//输出比较通道2配置

TIM_SetCompare2(BLDC_TIMx,BLDC_TIM_PERIOD);

TIM_CCxNCmd(BLDC_TIMx,TIM_Channel_2,TIM_CCxN_Enable);

break;

case 1: //U+ W-

//输出比较通道2配置

TIM_CCxCmd(BLDC_TIMx,TIM_Channel_2,TIM_CCx_Disable);

TIM_CCxNCmd(BLDC_TIMx,TIM_Channel_2,TIM_CCxN_Disable);

//输出比较通道1配置

TIM_SetCompare1(BLDC_TIMx,BLDC_TIM_PERIOD*speed_duty/100);

TIM_CCxCmd(BLDC_TIMx,TIM_Channel_1,TIM_CCx_Enable);

//输出比较通道3配置

TIM_SetCompare3(BLDC_TIMx,BLDC_TIM_PERIOD);

TIM_CCxNCmd(BLDC_TIMx,TIM_Channel_3,TIM_CCxN_Enable);

break;

default: //关闭输出

TIM_CCxCmd(BLDC_TIMx,TIM_Channel_1,TIM_CCx_Disable);

TIM_CCxNCmd(BLDC_TIMx,TIM_Channel_1,TIM_CCxN_Disable);

TIM_CCxCmd(BLDC_TIMx,TIM_Channel_2,TIM_CCx_Disable);

TIM_CCxNCmd(BLDC_TIMx,TIM_Channel_2,TIM_CCxN_Disable);

TIM_CCxCmd(BLDC_TIMx,TIM_Channel_3,TIM_CCx_Disable);

TIM_CCxNCmd(BLDC_TIMx,TIM_Channel_3,TIM_CCxN_Disable);

break;

}

TIM_GenerateEvent(TIM1,TIM_EventSource_COM);//软件产生COM事件将配置写入

}

TIM_ClearITPendingBit( TIM4, TIM_IT_Trigger );

TIM_ClearITPendingBit( TIM4, TIM_IT_CC1 );

}