经过几天的测试和使用,APM32M3514点击通用评估板已经使用的比较熟练了;
该源码除了foc和观测器代码不开源,其它的均是开源,整个控制流程与外设的配置开源给玩电驱的同学们一些参考;
先从main函数开始
int main(void)
{
GPIO_BSRET_T bit = Bit_RESET;
__disable_irq();
/* config peripherals */
MC_SystemClockInit();
/* M0CP */
M0CP_Firmware_Init();
RCM_EnableAHBPeriphReset(RCM_AHB_PERIPH_M0CP);
RCM_DisableAHBPeriphReset(RCM_AHB_PERIPH_M0CP);
RCM_EnableAHBPeriphClock(RCM_AHB_PERIPH_M0CP);
M0CP_HardInit();
*(volatile unsigned int*)(0x40024000+0x10) = 0;
/* TIMER1 */
Drv_Pwm_Init(PWM_PERIOD,DEAD_TIME);
PWM_CompareConfig(PWM_PERIOD, PWM_PERIOD, PWM_PERIOD);
/* ADC */
Drv_Adc_Init();
/* OPA */
OPA_Init();
/* COMP */
COMP_Init();
/* GPIO */
IO_Init();
Pilot_uart_init();
/* SYSTICK */
Systick_Init(SystemCoreClock / 1000);
/* Initialize motor control parameters */
Init_Parameter(&Motor_type);
/* Initialize interrupts */
Interrupt_Init();
/* Wait until ADC is ready */
while (!ADC_ReadStatusFlag(ADC_FLAG_ADRDY));
ADC_StartConversion();
WWDTInit();
__enable_irq(); //Enable all interrupts
TMR_EnablePWMOutputs(TMR1);
while (1)
{
//Reads key from demoboard.
NewDIRKey = GPIO_ReadInputBit(GPIOC,GPIO_PIN_13); //PC13 Direction方向按键
if(NewDIRKey == BIT_RESET)
{
/*设定新方向为反转CCW*/
Motor_type.User.s8NewDir = -1;
}
else{
/*设定新方向为正转CW*/
Motor_type.User.s8NewDir = 1;
}
if(Motor_type.User.s8NewDir != Motor_type.User.s8Direction)
{
/*启动转向切换功能*/
Motor_type.User.bDirSwitchEnable = true;
}
if(Motor_type.User.bSlowLoopFlag)
{
WWDTFeedDog();
/* Slow Loop Statemachine */
s_STATE_SLOW[eM1_MainState]();
Motor_type.User.bSlowLoopFlag = 0;
}
if( Get_Systick_Cnt() % 300 == 0)
{
GPIO_WriteBitValue(GPIO_LedErr,GPIO_Pin_LedErr,bit);
bit = !bit;
}
if( Get_Systick_Cnt() % 100 == 0)
{
//speed_rate = 20;
speed_rpm = hall_cnt*20;
hall_cnt = 0;
printf("<plots,%d,%d,%d,%d>\r\n",\
Motor_type.Foc.s16SpdFilt,\
Motor_type.stc_SmoPara.s16q15_Ealpha,\
speed_rpm,\
Motor_type.Foc.stc_Idq.s16q15_Q\
);
// Motor_type.Foc.stc_Idq.s16q15_D,\
// Motor_type.Foc.stc_Idq.s16q15_Q,\
// Motor_type.Foc.stc_IdqCmd.s16q15_D,\
// Motor_type.Foc.stc_IdqCmd.s16q15_Q);
}
}
}
main函数主要是对外设的配置初始化;
主循环是简单的按键识别反向选择、喂狗等;
主要需要看的是PWM和adc的初始化
先看pwm
void Drv_Pwm_Init(uint16_t u16_Period,uint16_t u16_DeadTime)
{
TMR_TimeBase_T TIM_TimeBaseInitStructure;
TMR_OCConfig_T TIM_OCInitStructure;
TMR_BDTInit_T TIM_BDTRInitStructure;
RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_SYSCFG | RCM_APB2_PERIPH_TMR1 );
/* Time Base configuration ,init time1 freq*/
TIM_TimeBaseInitStructure.period = u16_Period; //(SYSTEM_FREQUENCY/2/8000) - 1;
TIM_TimeBaseInitStructure.div = 0;
TIM_TimeBaseInitStructure.counterMode = TMR_COUNTER_MODE_CENTERALIGNED2;
TIM_TimeBaseInitStructure.clockDivision = TMR_CKD_DIV1;
TIM_TimeBaseInitStructure.repetitionCounter = 1;
TMR_ConfigTimeBase(TMR1, &TIM_TimeBaseInitStructure);
/* Automatic Output enable, Break, dead time and lock configuration*/
TIM_BDTRInitStructure.RMOS_State = TMR_RMOS_STATE_ENABLE;//--------
TIM_BDTRInitStructure.IMOS_State = TMR_IMOS_STATE_ENABLE;//--------
TIM_BDTRInitStructure.lockLevel = TMR_LOCK_LEVEL_OFF;//00:锁定关闭,寄存器无写保护;01:锁定级别1,不能写入TIMx_BDTR寄存器的DTG、BKE、BKP、AOE位和TIMx_CR2寄存器的OISx/OISxN位;
TIM_BDTRInitStructure.deadTime = u16_DeadTime;//死区时间
/**
* Brake configuration: enable brake
* Brake input polarity: active in low level
* Auto output enable configuration: Disable MOE bit hardware control
*/
TIM_BDTRInitStructure.breakState = TMR_BREAK_STATE_ENABLE;//TMR_BREAK_STATE_ENABLE TMR_BREAK_STATE_DISABLE;
TIM_BDTRInitStructure.breakPolarity = TMR_BREAK_POLARITY_HIGH;
TIM_BDTRInitStructure.automaticOutput = TMR_AUTOMATIC_OUTPUT_DISABLE;
TMR_ConfigBDT(TMR1, &TIM_BDTRInitStructure);
/*pwm driver set,channel 1,2,3,4set pwm mode*/
TIM_OCInitStructure.OC_Mode = TMR_OC_MODE_PWM2;
TIM_OCInitStructure.OC_OutputState = TMR_OUTPUT_STATE_ENABLE; //TMR_OUTPUT_STATE_DISABLE;
TIM_OCInitStructure.OC_OutputNState = TMR_OUTPUT_NSTATE_ENABLE; //TMR_OUTPUT_NSTATE_DISABLE;//------------
TIM_OCInitStructure.Pulse = u16_Period;
TIM_OCInitStructure.OC_Polarity = TMR_OC_POLARITY_HIGH;
TIM_OCInitStructure.OC_NPolarity = TMR_OC_NPOLARITY_HIGH; //互补输出极性-------
TIM_OCInitStructure.OC_Idlestate = TMR_OCIDLESTATE_RESET; // TMR_OCIDLESTATE_SET; //
TIM_OCInitStructure.OC_NIdlestate = TMR_OCNIDLESTATE_RESET; // TMR_OCNIDLESTATE_SET;//
//set OC1/OC1N
TMR_OC1Config(TMR1, &TIM_OCInitStructure);
//set oc2/oc2N
TIM_OCInitStructure.Pulse = u16_Period;
TMR_OC2Config(TMR1, &TIM_OCInitStructure);
//set OC3/OC3N
TIM_OCInitStructure.Pulse = u16_Period;
TMR_OC3Config(TMR1, &TIM_OCInitStructure);
TIM_OCInitStructure.OC_Mode = TMR_OC_MODE_PWM2; //选择定时器模式:TIM脉冲宽度调制模式2
TIM_OCInitStructure.OC_OutputState = TMR_OUTPUT_STATE_ENABLE; //CH1比较输出使能
TIM_OCInitStructure.OC_OutputNState = TMR_OUTPUT_NSTATE_ENABLE; //CH1N比较输出使能
TIM_OCInitStructure.OC_Polarity = TMR_OC_POLARITY_HIGH; //CH1输出极性:TIM输出比较极性高
TIM_OCInitStructure.OC_NPolarity = TMR_OC_NPOLARITY_HIGH; //CH1N输出极性:TIM输出比较极性高
TIM_OCInitStructure.OC_Idlestate = TMR_OCIDLESTATE_RESET; //CH1输出空闲状态:0
TIM_OCInitStructure.OC_NIdlestate = TMR_OCNIDLESTATE_SET; //CH1N输出空闲状态:0
//set OC4
TIM_OCInitStructure.Pulse = 10;
TMR_OC4Config(TMR1, &TIM_OCInitStructure);//OC4
//enable interrupt
TMR_EnableInterrupt(TMR1, TMR_INT_BRK);
TMR_EnableAUTOReload(TMR1);//TIMx_ARR寄存器被装入缓冲器
TMR_OC1PreloadConfig(TMR1,TMR_OC_PRELOAD_ENABLE);
TMR_OC2PreloadConfig(TMR1,TMR_OC_PRELOAD_ENABLE);//比较值预装载使能
TMR_OC3PreloadConfig(TMR1,TMR_OC_PRELOAD_ENABLE);
TMR_OC4PreloadConfig(TMR1,TMR_OC_PRELOAD_ENABLE);
TMR_EnableAUTOReload(TMR1);
TMR_Enable(TMR1);
TMR1->REPCNT = 1;
/* Main Output Enable */
TMR_EnablePWMOutputs(TMR1);
/* GPIO config */
GPIO_Config_T GPIO_InitStructure;
GPIO_InitStructure.pin = GPIO_PIN_PWM_UH_Mobile;
GPIO_InitStructure.speed = GPIO_SPEED_50MHz;
GPIO_InitStructure.mode = GPIO_MODE_AF;
GPIO_InitStructure.pupd = GPIO_PUPD_PD;
GPIO_Config(GPIO_PWM_UH_Mobile, &GPIO_InitStructure);
GPIO_InitStructure.pin = GPIO_PIN_PWM_VH_Mobile;
GPIO_InitStructure.speed = GPIO_SPEED_50MHz;
GPIO_InitStructure.mode = GPIO_MODE_AF;
GPIO_InitStructure.pupd = GPIO_PUPD_PD;
GPIO_Config(GPIO_PWM_VH_Mobile, &GPIO_InitStructure);
GPIO_InitStructure.pin = GPIO_PIN_PWM_WH_Mobile;
GPIO_InitStructure.speed = GPIO_SPEED_50MHz;
GPIO_InitStructure.mode = GPIO_MODE_AF;
GPIO_InitStructure.pupd = GPIO_PUPD_PD;
GPIO_Config(GPIO_PWM_WH_Mobile, &GPIO_InitStructure);
GPIO_InitStructure.pin = GPIO_PIN_PWM_UL_Mobile;
GPIO_InitStructure.speed = GPIO_SPEED_50MHz;
GPIO_InitStructure.mode = GPIO_MODE_AF;
GPIO_InitStructure.pupd = GPIO_PUPD_PD;
GPIO_Config(GPIO_PWM_UL_Mobile, &GPIO_InitStructure);
GPIO_InitStructure.pin = GPIO_PIN_PWM_VL_Mobile;
GPIO_InitStructure.speed = GPIO_SPEED_50MHz;
GPIO_InitStructure.mode = GPIO_MODE_AF;
GPIO_InitStructure.pupd = GPIO_PUPD_PD;
GPIO_Config(GPIO_PWM_VL_Mobile, &GPIO_InitStructure);
GPIO_InitStructure.pin = GPIO_PIN_PWM_WL_Mobile;
GPIO_InitStructure.speed = GPIO_SPEED_50MHz;
GPIO_InitStructure.mode = GPIO_MODE_AF;
GPIO_InitStructure.pupd = GPIO_PUPD_PD;
GPIO_Config(GPIO_PWM_WL_Mobile, &GPIO_InitStructure);
GPIO_InitStructure.pin = GPIO_PIN_PWM_Break_Mobile;
GPIO_InitStructure.speed = GPIO_SPEED_50MHz;
GPIO_InitStructure.mode = GPIO_MODE_AF;
GPIO_InitStructure.pupd = GPIO_PUPD_PD;
GPIO_Config(GPIO_PWM_Break_Mobile, &GPIO_InitStructure);
//复用映射,需参考文档
GPIO_ConfigPinAF(GPIO_PWM_UH_Mobile,GPIO_PIN_SOURCE_PWM_UH_Mobile,GPIO_AF_PIN2);
GPIO_ConfigPinAF(GPIO_PWM_VH_Mobile,GPIO_PIN_SOURCE_PWM_VH_Mobile,GPIO_AF_PIN2);
GPIO_ConfigPinAF(GPIO_PWM_WH_Mobile,GPIO_PIN_SOURCE_PWM_WH_Mobile,GPIO_AF_PIN2);
GPIO_ConfigPinAF(GPIO_PWM_UL_Mobile,GPIO_PIN_SOURCE_PWM_UL_Mobile,GPIO_AF_PIN2);
GPIO_ConfigPinAF(GPIO_PWM_VL_Mobile,GPIO_PIN_SOURCE_PWM_VL_Mobile,GPIO_AF_PIN2);
GPIO_ConfigPinAF(GPIO_PWM_WL_Mobile,GPIO_PIN_SOURCE_PWM_WL_Mobile,GPIO_AF_PIN2);
GPIO_ConfigPinAF(GPIO_PWM_Break_Mobile,GPIO_PIN_SOURCE_PWM_Break_Mobile,GPIO_AF_PIN3);
}
pwm使用的是timr1,频率为16K,死区时间为1us。
使用高级定时器,产生互补pwm。
其次是ADC的配置:
void Drv_Adc_Init(void)
{
ADC_Config_T ADC_InitStructure;
DMA_Config_T DMA_InitStructure;
DMA_InitStructure.peripheralAddress = (uint32_t)&(ADC->DATA);//ADC地址
DMA_InitStructure.memoryAddress = (uint32_t)&ADC_ConvertedValue[0]; //内存地址
DMA_InitStructure.direction = DMA_DIR_PERIPHERAL; //方向(从外设到内存)
DMA_InitStructure.bufferSize = TOTAL_CHANNEL;//TOTAL_CHANNEL; //传输内容的大小---传输次数
DMA_InitStructure.peripheralInc = DMA_PERIPHERAL_INC_DISABLE; //外设地址固定
DMA_InitStructure.memoryInc = DMA_MEMORY_INC_ENABLE;//DMA_MEMORY_INC_ENABLE; //内存地址固定
DMA_InitStructure.peripheralDataSize = DMA_PERIPHERAL_DATASIZE_HALFWORD ; //外设数据单位
DMA_InitStructure.memoryDataSize = DMA_MEMORY_DATASIZE_HALFWORD ; //内存数据单位
DMA_InitStructure.circular = DMA_CIRCULAR_ENABLE ; //DMA模式:循环传输
DMA_InitStructure.priority = DMA_PRIORITY_LEVEL_VERYHIGH ; //优先级:高
DMA_InitStructure.memoryTomemory = DMA_M2M_DISABLE; //禁止内存到内存的传输
ADC_Reset();
DMA_Config(DMA_CHANNEL_1, &DMA_InitStructure); //配置DMA的1通道
DMA_Enable(DMA_CHANNEL_1);
ADC_ClockMode(ADC_CLOCK_MODE_ASYNCLK);//48M/4=12mADC_CLOCK_MODE_SYNCLKDIV4
ADC_ConfigStructInit(&ADC_InitStructure);
ADC_InitStructure.convMode = ADC_CONVERSION_SINGLE;
ADC_InitStructure.scanDir = ADC_SCAN_DIR_UPWARD;
ADC_InitStructure.extTrigConv1 = ADC_EXT_TRIG_CONV_TRG1; // timer1 CC4
ADC_InitStructure.extTrigEdge1 = ADC_EXT_TRIG_EDGE_RISING;
ADC_InitStructure.dataAlign = ADC_DATA_ALIGN_RIGHT;
ADC_InitStructure.resolution = ADC_RESOLUTION_12B;
ADC_Config(&ADC_InitStructure);
/*ADC_CHANNEL_2 :PA4 IV;ADC_CHANNEL_8:PB0 IU;ADC_CHANNEL_6:PA6 Vbus;ADC_CHANNEL_7:PA7 Handle;ADC_CHANNEL_12:PB10 Ibus*/
ADC_ConfigChannel(ADC_CHANNEL_2 | ADC_CHANNEL_8 | ADC_CHANNEL_6 | ADC_CHANNEL_7| ADC_CHANNEL_12 ,ADC_SAMPLE_TIME_1_5);
ADC->CFG1_B.OVRMAG = 1;
ADC_EnableInterrupt(ADC_INT_CS);
//=========================ADC中断使用=================================================
NVIC_EnableIRQ(ADC_COMP_IRQn);
NVIC_SetPriority(ADC_COMP_IRQn,0);
ADC_DMARequestMode(ADC_DMA_MODE_CIRCULAR);
ADC_EnableDMA();
ADC_Enable();
ADC_StartConversion();//必需要启动一下
/* Config IO */
GPIO_Config_T GPIO_InitStructure;
GPIO_InitStructure.pin = GPIO_Pin_ADC_VDC;
GPIO_InitStructure.speed = GPIO_SPEED_50MHz;
GPIO_InitStructure.mode = GPIO_MODE_AN;
GPIO_InitStructure.pupd = GPIO_PUPD_NO;
GPIO_Config(GPIO_ADC_VDC, &GPIO_InitStructure);
GPIO_InitStructure.pin = GPIO_Pin_ADC_Handle;
GPIO_InitStructure.speed = GPIO_SPEED_50MHz;
GPIO_InitStructure.mode = GPIO_MODE_AN;
GPIO_InitStructure.pupd = GPIO_PUPD_NO;
GPIO_Config(GPIO_ADC_Handle, &GPIO_InitStructure);
GPIO_InitStructure.pin = GPIO_Pin_ADC_IU;
GPIO_InitStructure.speed = GPIO_SPEED_50MHz;
GPIO_InitStructure.mode = GPIO_MODE_AN;
GPIO_InitStructure.pupd = GPIO_PUPD_NO;
GPIO_Config(GPIO_ADC_IU, &GPIO_InitStructure);
GPIO_InitStructure.pin = GPIO_Pin_ADC_IV;
GPIO_InitStructure.speed = GPIO_SPEED_50MHz;
GPIO_InitStructure.mode = GPIO_MODE_AN;
GPIO_InitStructure.pupd = GPIO_PUPD_NO;
GPIO_Config(GPIO_ADC_IV, &GPIO_InitStructure);
GPIO_InitStructure.pin = GPIO_Pin_ADC_IBUS;
GPIO_InitStructure.speed = GPIO_SPEED_50MHz;
GPIO_InitStructure.mode = GPIO_MODE_AN;
GPIO_InitStructure.pupd = GPIO_PUPD_NO;
GPIO_Config(GPIO_ADC_IBUS, &GPIO_InitStructure);
// GPIO_InitStructure.pin = GPIO_Pin_ADC_VOT;
// GPIO_InitStructure.speed = GPIO_SPEED_50MHz;
// GPIO_InitStructure.mode = GPIO_MODE_AN;
// GPIO_InitStructure.pupd = GPIO_PUPD_NO;
// GPIO_Config(GPIO_ADC_VOT, &GPIO_InitStructure);
}
ADC配置为DMA模式,使用TIMER1的CC4的上升沿进行触发,也就是说,TIMER1的通道4,每产生一个PWM的上升沿,就会检测一次ADC的数据;
为什么使用通道4?
因为TIMER1的通道1~3要控制三相桥,通道4空余的作为一个触发源,并不会真正的产生一个PWM信号;
会在ADC的中断内进行数据的读取;
void ADC_COMP_IRQHandler(void)
{
ADC->STS = ADC->STS;//Clear interrupt flag bit
static uint8_t u8ADCTimeCnt = 0;
static uint32_t u32IaSum = 0;
static uint32_t u32IbSum = 0;
static uint16_t u16Cnt = 0;
if(u16Cnt <= 127)
{
u16Cnt++;
u32IbSum += (int16_t)ADC_GetValue(CURR_CHANNEL_V);
u32IaSum += (int16_t)ADC_GetValue(CURR_CHANNEL_U);
}
else if(u16Cnt == 128)
{
u16Cnt++;
u32IbSum = u32IbSum>>7;
u32IaSum = u32IaSum>>7;
Motor_type.Foc.stc_IuvwOffset.s16q15_V = u32IbSum << 3;
Motor_type.Foc.stc_IuvwOffset.s16q15_U = u32IaSum << 3;
u32IbSum = 0;
u32IaSum = 0;
Motor_type.Foc.s16q15IbusOffset = (int16_t)ADC_GetValue(IBUS_CHANNEL) << 3;
}
else
{
/*采样*/
Get_ADC_Result(&Motor_type);
/* Fast Loop Statemachine */
s_STATE_FAST[eM1_MainState]();
if(++u8ADCTimeCnt >= Motor_type.User.u16SlowLoopDiv) //For slow loop state machine
{
u8ADCTimeCnt = 0;
Motor_type.User.bSlowLoopFlag = 1;
}
}
}
在ADC的中断内进行foc算法的控制;
使用Get_ADC_Result(&Motor_type);先获取adc值;
通过s_STATE_FAST[eM1_MainState]();进行foc运算;
foc控制:
static void M1_RunSpinFast(void)
{
Motor_type.Foc.s16CmdTheta += Motor_type.stc_SmoPara.s16q15SpdObs*Motor_type.Foc.s16SpdToTheta >> 15;
Motor_type.Foc.stc_SinCos = sin_cos_cal(Motor_type.Foc.s16CmdTheta);
/*Current loop*/
current_ctrl(&Motor_type);
Motor_type.Foc.u16q15Vdq_sqrt = isqrt32((uint32_t)(Motor_type.Foc.stc_Vdq.s16q15_D * Motor_type.Foc.stc_Vdq.s16q15_D + Motor_type.Foc.stc_Vdq.s16q15_Q * Motor_type.Foc.stc_Vdq.s16q15_Q));
/* observation */
Motor_type.stc_SmoPara.s16q15_Ialpha = Motor_type.Foc.stc_Iab.s16q15_A;
Motor_type.stc_SmoPara.s16q15_Ibeta = Motor_type.Foc.stc_Iab.s16q15_B;
Motor_type.stc_SmoPara.s16q15_Ualpha = Motor_type.Foc.stc_Vab.s16q15_A;
Motor_type.stc_SmoPara.s16q15_Ubeta = Motor_type.Foc.stc_Vab.s16q15_B;
smo_cal(&Motor_type.stc_SmoPara);
/* PLL */
Motor_type.stc_PiPll.s16_Error = ((-Motor_type.stc_SmoPara.s16q15_Ealpha*Motor_type.Foc.stc_SinCos.s16q15_Cos)
- (Motor_type.stc_SmoPara.s16q15_Ebeta*Motor_type.Foc.stc_SinCos.s16q15_Sin)) >> 15;
anti_pi(&Motor_type.stc_PiPll);
Motor_type.stc_SmoPara.s16q15SpdObs = Motor_type.stc_PiPll.s32_Out;
/* svpwm */
Motor_type.Foc.stc_SvpwmPara.s16q15_Vbus = Motor_type.Foc.s16Vbus;
Motor_type.Foc.stc_SvpwmPara.s16q15_Valpha = Motor_type.Foc.stc_Vab.s16q15_A;
Motor_type.Foc.stc_SvpwmPara.s16q15_Vbeta = Motor_type.Foc.stc_Vab.s16q15_B;
svpwm7_cal(&Motor_type.Foc.stc_SvpwmPara);
PWM_Update(&Motor_type);
}
先获取电角度,转换为正弦值,在current_ctrl函数进行clarke变化,再进行park变化,对d轴电流进行pi计算,再对q轴电流进行pi计算,计算除vq和vd值,进行反park变化;
void current_ctrl(Motor_TypeDef *Motor)
{
clarke(&Motor->Foc.stc_Iuvw, &Motor->Foc.stc_Iab);
park(&Motor->Foc.stc_Iab,&Motor->Foc.stc_SinCos, &Motor->Foc.stc_Idq);
/* PI for Id */
Motor->stc_IdPi.s16_Error = Motor->Foc.stc_IdqCmd.s16q15_D-Motor->Foc.stc_Idq.s16q15_D;
anti_pi(&Motor->stc_IdPi);
Motor->Foc.stc_Vdq.s16q15_D = Motor->stc_IdPi.s32_Out;
/* limit the Vq */
uint32_t u32_Temp;
int16_t s16q15Vmax = Motor->Foc.s16Vbus * 18918 >> 15; // Vamx=Vbus/sqrt(3)
u32_Temp = s16q15Vmax*s16q15Vmax
- Motor->Foc.stc_Vdq.s16q15_D*Motor->Foc.stc_Vdq.s16q15_D;
Motor->stc_IqPi.s32_Umax = isqrt32(u32_Temp);
Motor->stc_IqPi.s32_Umin = -Motor->stc_IqPi.s32_Umax;
/* PI for Iq */
Motor->stc_IqPi.s16_Error = Motor->Foc.stc_IdqCmd.s16q15_Q-Motor->Foc.stc_Idq.s16q15_Q;
anti_pi(&Motor->stc_IqPi);
Motor->Foc.stc_Vdq.s16q15_Q = Motor->stc_IqPi.s32_Out;
/* InvPark */
inv_park(&Motor->Foc.stc_Vdq, &Motor->Foc.stc_SinCos, &Motor->Foc.stc_Vab);
}
再将换算除的vd,vq,iq,id赋值到smo滑模观测器参数内进行电角度观测;
使用pi对pll进行整定,能换算出速度值;
最后使用svpwm7_cal(&Motor_type.Foc.stc_SvpwmPara);对不同的角度区域进行换算,得到SVPWM信号,使用PWM_Update(&Motor_type);更新PWM值进行输出;
void PWM_Update(Motor_TypeDef *Motor)
{
if(Motor->User.s8Direction != -1)
{
Motor->PWMx.Timer->CC1 = (32768-Motor->Foc.stc_SvpwmPara.u16q15_DutyU)*PWM_PERIOD >> 15;
Motor->PWMx.Timer->CC2 = (32768-Motor->Foc.stc_SvpwmPara.u16q15_DutyV)*PWM_PERIOD >> 15;
}
else
{
Motor->PWMx.Timer->CC1 = (32768-Motor->Foc.stc_SvpwmPara.u16q15_DutyV)*PWM_PERIOD >> 15;
Motor->PWMx.Timer->CC2 = (32768-Motor->Foc.stc_SvpwmPara.u16q15_DutyU)*PWM_PERIOD >> 15;
}
Motor->PWMx.Timer->CC3 = (32768-Motor->Foc.stc_SvpwmPara.u16q15_DutyW)*PWM_PERIOD >> 15;
}
这个控制是运行快速旋转的控制方法,还有慢速旋转的控制方法,可自行了解学习;
以上是源码的控制流程
|
|