简介:下面程序基于STM32F103RCT6,部分内容来源于网络。
一、具有互补功能的电机驱动程序
void initPWM()
{
NVIC_InitTypeDef NVIC_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_BDTRInitTypeDef TIM_BDTRInitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB, ENABLE);
//initialize LIHE
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOB, &GPIO_InitStructure);
//initialize Tim1 PWM outputs
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
// Time Base configuration
TIM_TimeBaseStructure.TIM_Prescaler = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseStructure.TIM_Period = BLDC_CHOPPER_PERIOD;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);
// Channel 1, 2, 3 – set to PWM mode - all 6 outputs
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Timing;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;
TIM_OCInitStructure.TIM_Pulse = 0; // initialize to zero output
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;//TIM_OCPolarity_High TIM_OCPolarity_Low
TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_Low;//TIM_OCNPolarity_Low TIM_OCNPolarity_Low
TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;
TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Set;
TIM_OC1Init(TIM1, &TIM_OCInitStructure);
TIM_OC2Init(TIM1, &TIM_OCInitStructure);
TIM_OC3Init(TIM1, &TIM_OCInitStructure);
TIM_OC4Init(TIM1, &TIM_OCInitStructure); //for ADC
TIM_BDTRInitStructure.TIM_OSSRState = TIM_OSSRState_Enable;
TIM_BDTRInitStructure.TIM_OSSIState = TIM_OSSIState_Enable;
TIM_BDTRInitStructure.TIM_LOCKLevel = TIM_LOCKLevel_OFF;
// DeadTime[ns] = value * (1/SystemCoreFreq) (on 72MHz: 7 is 98ns)
TIM_BDTRInitStructure.TIM_DeadTime = BLDC_NOL;
TIM_BDTRInitStructure.TIM_AutomaticOutput = TIM_AutomaticOutput_Enable;
//no break functionality
TIM_BDTRInitStructure.TIM_Break = TIM_Break_Disable;
TIM_BDTRInitStructure.TIM_BreakPolarity = TIM_BreakPolarity_Low;
TIM_BDTRConfig(TIM1, &TIM_BDTRInitStructure);
//Commutation event mapped to TIM4 - We are not using commute event, but interrupt from Hall timer directly to commute.
//Not optimal solution?
//TIM_SelectInputTrigger(TIM1, TIM_TS_ITR3);
TIM_ITConfig(TIM1, TIM_IT_CC4, ENABLE); //adc sampling interrupt
NVIC_InitStructure.NVIC_IRQChannel = TIM1_CC_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x00;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
TIM_Cmd(TIM1, ENABLE);
// enable motor timer main output (the bridge signals)
TIM_CtrlPWMOutputs(TIM1, ENABLE);
pwm_motorStop();
}
void pwm_motorStart()
{
uint16_t newhallpos;
newhallpos = GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_0)? (((GPIO_ReadInputData(GPIOA)>>6)&0x03) | 0x04) : ((GPIO_ReadInputData(GPIOA)>>6)&0x03);
hallpos = newhallpos;
pwm_Hall(hallpos);
TIM_ITConfig(TIM3, TIM_IT_CC1 | TIM_IT_CC2, ENABLE); //enable HALL interrupts
}
void pwm_motorStop()
{
//motor_running=0;
TIM1->CCR1 = 0;
TIM1->CCR2 = 0;
TIM1->CCR3 = 0;
TIM_CCxCmd(TIM1, TIM_Channel_1, TIM_CCx_Disable);
TIM_CCxCmd(TIM1, TIM_Channel_2, TIM_CCx_Disable);
TIM_CCxCmd(TIM1, TIM_Channel_3, TIM_CCx_Disable);
TIM_CCxNCmd(TIM1, TIM_Channel_1, TIM_CCxN_Disable);
TIM_CCxNCmd(TIM1, TIM_Channel_2, TIM_CCxN_Disable);
TIM_CCxNCmd(TIM1, TIM_Channel_3, TIM_CCxN_Disable);
TIM_ITConfig(TIM3, TIM_IT_CC1 | TIM_IT_CC2, DISABLE); //disable HALL interrupts, no commutation!
}
二、霍尔信号接口的对应程序
void initHALL()
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_ICInitTypeDef TIM_ICInitStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
//Hall sensor is connected to TIM3
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOB, &GPIO_InitStructure);
lasthallpos = GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_0)? ((GPIO_ReadInputData(GPIOA)>>6)| 0x04) : (GPIO_ReadInputData(GPIOA)>>6);
hallpos = GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_0)? ((GPIO_ReadInputData(GPIOA)>>6)| 0x04) : (GPIO_ReadInputData(GPIOA)>>6);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
TIM_TimeBaseStructure.TIM_Prescaler = 126;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseStructure.TIM_Period = 65535;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
TIM_SelectHallSensor(TIM3, ENABLE);
TIM_SelectInputTrigger(TIM3, TIM_TS_TI1F_ED);
TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset);
TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
// listen to T1, the HallSensorEvent
TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_TRC;
// Div:1, every edge
TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
// input noise filter
TIM_ICInitStructure.TIM_ICFilter = 0xF;
TIM_ICInit(TIM3, &TIM_ICInitStructure);
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OCInitStructure.TIM_Pulse = BLDC_DELAY; // 1 is no delay; 2000 = 7ms
TIM_OC2Init(TIM3, &TIM_OCInitStructure);
// clear interrupt flag
TIM_ClearFlag(TIM3, TIM_FLAG_CC2);
TIM_SelectOutputTrigger(TIM3, TIM_TRGOSource_OC2Ref);
TIM_ITConfig(TIM3, TIM_IT_CC1 | TIM_IT_CC2, ENABLE);
TIM_Cmd(TIM3, ENABLE);
// we use preemption interrupts here, BLDC Bridge switching and
// Hall has highest priority
NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x00;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 6;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
void TIM3_IRQHandler(void) {
uint16_t newhallpos;
if (TIM_GetITStatus(TIM3, TIM_IT_CC1) != RESET)
{
TIM_ClearITPendingBit(TIM3, TIM_IT_CC1);
// calculate motor speed or else with CCR1 values
}
else if (TIM_GetITStatus(TIM3, TIM_IT_CC2) != RESET)
{
//#ifndef SINUSOID_DRIVE
TIM_ClearITPendingBit(TIM3, TIM_IT_CC2);
newhallpos = GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_0)? (((GPIO_ReadInputData(GPIOA)>>6)&0x03) | 0x04) : ((GPIO_ReadInputData(GPIOA)>>6)&0x03);
if (newhallpos == hallpos) return;
hallpos = newhallpos;
pwm_Hall(hallpos);
}
else if(TIM_GetITStatus(TIM3, TIM_IT_Update) == SET)
{
/* Clear TIM3 Capture compare interrupt pending bit */
TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
// TIM_SetCounter(TIM3,0);
}
}
三、根据霍尔位置进行切换控制
下面程序中“if(fr) hall = 7 - hall;”为后来添加(反转执行),一开始的程序是正反转分别有一组switch不同的语句(根据电机表写的)但正转正常反转有抖动,后来发现只需要一个switch反转时对霍尔数据做处理即可。
void pwm_Hall(uint8_t hall)
{
uint32_t duty=750;
uint8_t fr=1;
duty = BLDC_CHOPPER_PERIOD*500/1000;
if(duty>MAX_DUTY) duty = MAX_DUTY;
if(fr) hall = 7 - hall;
switch(hall)//Õýת ×óÐÐ
{
case 4: //U+ W- Next step: 6
TIM_SetCompare2(TIM1,0);
TIM_CCxCmd(TIM1,TIM_Channel_2,TIM_CCx_Disable);
TIM_CCxNCmd(TIM1,TIM_Channel_2,TIM_CCxN_Disable);
TIM_SelectOCxM(TIM1, TIM_Channel_1, TIM_OCMode_PWM1);
TIM_SetCompare1(TIM1,duty);
TIM_CCxCmd(TIM1,TIM_Channel_1,TIM_CCx_Enable);
TIM_CCxNCmd(TIM1,TIM_Channel_1, TIM_CCxN_Enable);
TIM_SetCompare3(TIM1,0);
TIM_SelectOCxM(TIM1, TIM_Channel_3, TIM_ForcedAction_Active);
TIM_CCxCmd(TIM1,TIM_Channel_3,TIM_CCx_Disable);
TIM_CCxNCmd(TIM1,TIM_Channel_3,TIM_CCxN_Enable);
break;
case 6: //V+ W- Next step: 2
TIM_SetCompare1(TIM1,0);
TIM_CCxCmd(TIM1,TIM_Channel_1,TIM_CCx_Disable);
TIM_CCxNCmd(TIM1,TIM_Channel_1,TIM_CCxN_Disable);
TIM_SelectOCxM(TIM1, TIM_Channel_2, TIM_OCMode_PWM1);
TIM_SetCompare2(TIM1,duty);
TIM_CCxCmd(TIM1,TIM_Channel_2,TIM_CCx_Enable);
TIM_CCxNCmd(TIM1,TIM_Channel_2, TIM_CCxN_Enable);
TIM_SetCompare3(TIM1,0);
TIM_SelectOCxM(TIM1, TIM_Channel_3, TIM_ForcedAction_Active);
TIM_CCxCmd(TIM1,TIM_Channel_3,TIM_CCx_Disable);
TIM_CCxNCmd(TIM1,TIM_Channel_3,TIM_CCxN_Enable);
break;
case 2: //V+ U- Next step: 3
TIM_SetCompare3(TIM1,0);
TIM_CCxCmd(TIM1,TIM_Channel_3,TIM_CCx_Disable);
TIM_CCxNCmd(TIM1,TIM_Channel_3,TIM_CCxN_Disable);
TIM_SelectOCxM(TIM1, TIM_Channel_2, TIM_OCMode_PWM1);
TIM_SetCompare2(TIM1,duty);
TIM_CCxCmd(TIM1,TIM_Channel_2,TIM_CCx_Enable);
TIM_CCxNCmd(TIM1,TIM_Channel_2,TIM_CCxN_Enable);
TIM_SetCompare1(TIM1,0);
TIM_SelectOCxM(TIM1, TIM_Channel_1, TIM_ForcedAction_Active);
TIM_CCxCmd(TIM1,TIM_Channel_1,TIM_CCx_Disable);
TIM_CCxNCmd(TIM1,TIM_Channel_1,TIM_CCxN_Enable);
break;
case 3: //W+ U- Next step: 1
TIM_SetCompare2(TIM1,0);
TIM_CCxCmd(TIM1,TIM_Channel_2,TIM_CCx_Disable);
TIM_CCxNCmd(TIM1,TIM_Channel_2,TIM_CCxN_Disable);
TIM_SelectOCxM(TIM1, TIM_Channel_3, TIM_OCMode_PWM1);
TIM_SetCompare3(TIM1,duty);
TIM_CCxCmd(TIM1,TIM_Channel_3,TIM_CCx_Enable);
TIM_CCxNCmd(TIM1,TIM_Channel_3,TIM_CCxN_Enable);
TIM_SetCompare1(TIM1,0);
TIM_SelectOCxM(TIM1, TIM_Channel_1, TIM_ForcedAction_Active);
TIM_CCxCmd(TIM1,TIM_Channel_1,TIM_CCx_Disable);
TIM_CCxNCmd(TIM1,TIM_Channel_1,TIM_CCxN_Enable);
break;
case 1: //W+ V- Next step: 5
TIM_SetCompare1(TIM1,0);
TIM_CCxCmd(TIM1,TIM_Channel_1,TIM_CCx_Disable); // ¹Ø±Õ U ÉÏÇűÛ
TIM_CCxNCmd(TIM1,TIM_Channel_1,TIM_CCxN_Disable); // ¹Ø±Õ U ÏÂÇűÛ
TIM_SelectOCxM(TIM1, TIM_Channel_3, TIM_OCMode_PWM1);
TIM_SetCompare3(TIM1,duty); // ͨµÀ 3 ÅäÖõÄÕ¼¿Õ±È
TIM_CCxCmd(TIM1,TIM_Channel_3,TIM_CCx_Enable);
TIM_CCxNCmd(TIM1,TIM_Channel_3,TIM_CCxN_Enable); //Ö®ËùÒÔÕ¼¿Õ±È²»ÄÜΪ100%¾ÍÊÇÒòΪÏÂÇűÛÐëÓе¼Í¨Ê±¼äÒÔ¸ø×Ô¾ÙµçÈݳäµç
// ¿ªÆô V ÏÂÇűÛ
TIM_SetCompare2(TIM1,0);
TIM_SelectOCxM(TIM1, TIM_Channel_2, TIM_ForcedAction_Active);
TIM_CCxCmd(TIM1,TIM_Channel_2,TIM_CCx_Disable);
TIM_CCxNCmd(TIM1,TIM_Channel_2,TIM_CCxN_Enable);
break;
case 5: //U+ V- Next step: 4
TIM_SetCompare3(TIM1,0);
TIM_CCxCmd(TIM1,TIM_Channel_3,TIM_CCx_Disable);
TIM_CCxNCmd(TIM1,TIM_Channel_3,TIM_CCxN_Disable);
TIM_SelectOCxM(TIM1, TIM_Channel_1, TIM_OCMode_PWM1);
TIM_SetCompare1(TIM1,duty);
TIM_CCxCmd(TIM1,TIM_Channel_1,TIM_CCx_Enable);
TIM_CCxNCmd(TIM1,TIM_Channel_1,TIM_CCxN_Enable);
TIM_SetCompare2(TIM1,0);
TIM_SelectOCxM(TIM1, TIM_Channel_2, TIM_ForcedAction_Active);
TIM_CCxCmd(TIM1,TIM_Channel_2,TIM_CCx_Disable);
TIM_CCxNCmd(TIM1,TIM_Channel_2,TIM_CCxN_Enable);
break;
default:
TIM_CCxCmd(TIM1,TIM_Channel_1,TIM_CCx_Disable);
TIM_CCxNCmd(TIM1,TIM_Channel_1,TIM_CCxN_Disable);
TIM_CCxCmd(TIM1,TIM_Channel_2,TIM_CCx_Disable);
TIM_CCxNCmd(TIM1,TIM_Channel_2,TIM_CCxN_Disable);
TIM_CCxCmd(TIM1,TIM_Channel_3,TIM_CCx_Disable);
TIM_CCxNCmd(TIM1,TIM_Channel_3,TIM_CCxN_Disable);
break;
}
}
四、电机电流采集
void initADC()
{
GPIO_InitTypeDef GPIO_InitStructure;
ADC_InitTypeDef ADC_InitStructure;
DMA_InitTypeDef DMA_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
//--Enable ADC1 and GPIOA--
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOA, ENABLE);
GPIO_StructInit(&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_Init(GPIOA, &GPIO_InitStructure);
//ADC1 configuration
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
ADC_InitStructure.ADC_ScanConvMode = DISABLE;
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;//!
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfChannel = 1;
//load structure values to control and status registers
ADC_Init(ADC1, &ADC_InitStructure);
ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 1, ADC_SampleTime_41Cycles5);
//Enable ADC1
ADC_Cmd(ADC1, ENABLE);
//enable DMA for ADC
ADC_DMACmd(ADC1, ENABLE);
//Enable ADC1 reset calibration register
ADC_ResetCalibration(ADC1);
//Check the end of ADC1 reset calibration register
while(ADC_GetResetCalibrationStatus(ADC1));
//Start ADC1 calibration
ADC_StartCalibration(ADC1);
//Check the end of ADC1 calibration
while(ADC_GetCalibrationStatus(ADC1));
//enable DMA1 clock
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
//reset DMA1 channe1 to default values;
DMA_DeInit(DMA1_Channel1);
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
DMA_InitStructure.DMA_BufferSize = 1;
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR;
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&ADC_value;
//send values to DMA registers
DMA_Init(DMA1_Channel1, &DMA_InitStructure);
// Enable DMA1 Channel Transfer Complete interrupt
DMA_ITConfig(DMA1_Channel1, DMA_IT_TC, ENABLE);
DMA_Cmd(DMA1_Channel1, ENABLE); //Enable the DMA1 - Channel1
//Enable DMA1 channel IRQ Channel */
NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 5;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
void ADC1_2_IRQHandler(void) {
if (ADC_GetITStatus(ADC1, ADC_IT_EOC) != RESET)
{
ADC_ClearITPendingBit(ADC1, ADC_IT_EOC);
}
}
void DMA1_Channel1_IRQHandler(void) {
uint16_t ADC_temp;
if(DMA_GetITStatus(DMA1_IT_TC1)) {
DMA_ClearITPendingBit(DMA1_IT_GL1);
DMA_Cmd(DMA1_Channel1, ENABLE);
ADC_buf[ADC_index] = ADC_value;
}
}