static void TIM1_GPIO_Config(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB, ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9| GPIO_Pin_10 | GPIO_Pin_11; //CH1--A8 CH2--A9 CH3--A10 CH4-A11 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出 CH1N-B13 CH2N-B14 CH3N-B15 BKIN-B12 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12 | GPIO_Pin_13| GPIO_Pin_14 | GPIO_Pin_15; GPIO_Init(GPIOB, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12; //BKIN-B12 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB, &GPIO_InitStructure); GPIO_PinLockConfig(GPIOA, GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 ); //锁住高侧IO口的配置寄存器,避免后面误修改 } #define CKTIM ((u32)72000000uL) //主频 #define PWM_PRSC ((u8)0) //TIM1分频系数 #define PWM_FREQ ((u16) 15000) //PWM频率(Hz) #define PWM_PERIOD ((u16) (CKTIM / (u32)(2 * PWM_FREQ *(PWM_PRSC+1)))) #define REP_RATE (1) //该参数可以调整电流环的刷新频率,刷新周期:(REP_RATE + 1)/(2*PWM_FREQ) 秒 //因为电流环的采样是靠TIM1来触发的 #define DEADTIME_NS ((u16)1000) //死区时间(ns),范围:0-3500 #define DEADTIME (u16)((unsigned long long)CKTIM/2 * (unsigned long long)DEADTIME_NS/1000000000uL) static void TIM1_Mode_Config(void) { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_OCInitTypeDef TIM_OCInitStructure; TIM_BDTRInitTypeDef TIM1_BDTRInitStructure; NVIC_InitTypeDef NVIC_InitStructure; TIM_TimeBaseStructure.TIM_Period = PWM_PERIOD; //计数周期 TIM_TimeBaseStructure.TIM_Prescaler = PWM_PRSC; //分频系数 TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV2; //设置外部时钟TIM1ETR的滤波时间 TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_CenterAligned1; //中央对齐模式1,从0计数到 TIM_Period 然后开始减到0,循环 TIM_TimeBaseStructure.TIM_RepetitionCounter = REP_RATE; //重复计数,就是重复溢出多少次才产生一个溢出中断(产生更新事件,用来触发ADC采样) TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure); TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //配置为PWM模式1 TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //使能CHx的PWM输出 TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;//互补输出使能,使能CHxN的PWM输出 TIM_OCInitStructure.TIM_Pulse = 800; //设置跳变值,当计数器计数到这个值时,电平发生跳变 TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //CHx有效电平的极性为高电平(高侧) TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High; //CHxN有效电平的极性为高电平(低侧) TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Reset; //在空闲时CHx输出低(高侧), 调用TIM_CtrlPWMOutputs(TIM1, DISABLE)后就是空闲状态。 TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Set; //在空闲时CHxN输出高(低侧),打开低侧管子可以用来锁电机 //TIM_OCIdleState 和 TIM_OCNIdleState不能同时为高 TIM_OC1Init(TIM1, &TIM_OCInitStructure); //配置CH1 TIM_OCInitStructure.TIM_Pulse = 800; TIM_OC2Init(TIM1, &TIM_OCInitStructure); //配置CH2 TIM_OCInitStructure.TIM_Pulse = 800; TIM_OC3Init(TIM1, &TIM_OCInitStructure); //配置CH3 //设置刹车特性,死区时间,锁电平,OSSI,OSSR状态和AOE(自动输出使能) TIM1_BDTRInitStructure.TIM_OSSRState = TIM_OSSRState_Enable; //MOE=1且定时器不工作时,CHx和CHxN的输出状态 TIM1_BDTRInitStructure.TIM_OSSIState = TIM_OSSIState_Enable; //MOE=0且定时器不工作时,CHx和CHxN的输出状态(详情看用户手册,一般都是ENABLE,不用深究) TIM1_BDTRInitStructure.TIM_LOCKLevel = TIM_LOCKLevel_1; //BDTR寄存器写保护等级,防止软件错误误写。 TIM1_BDTRInitStructure.TIM_DeadTime = DEADTIME; //设置死区时间 TIM1_BDTRInitStructure.TIM_Break = TIM_Break_Enable; //使能TIM1刹车输入(BKIN),要把BKIN引脚拉低才有PWM输出 TIM1_BDTRInitStructure.TIM_BreakPolarity = TIM_BreakPolarity_High; //刹车输入(BKIN)输入高电平有效 TIM1_BDTRInitStructure.TIM_AutomaticOutput = TIM_AutomaticOutput_Disable; //刹车有效标志只能被软件清除,不能被自动清除 TIM_BDTRConfig(TIM1, &TIM1_BDTRInitStructure); NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //4个抢先级、4个子优先级 /* Enable the TIM1 BRK Interrupt */ NVIC_InitStructure.NVIC_IRQChannel = TIM1_BRK_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); TIM_SelectOutputTrigger(TIM1, TIM_TRGOSource_Update); //使用TIM1的更新事件作为触发输出,这个输出可以触发ADC进行采样,电流环的采样 TIM_ClearITPendingBit(TIM1, TIM_IT_Break); //清除刹车中断,BKIN输入导致的中断 TIM_ITConfig(TIM1, TIM_IT_Break, ENABLE); //使能刹车中断 TIM_CtrlPWMOutputs(TIM1, ENABLE); //PWM输出使能 TIM_Cmd(TIM1, ENABLE); //使能TIM1 } void TIM1_PWM_Init(void) { TIM1_GPIO_Config(); TIM1_Mode_Config(); } /******************************************************************************* * Function Name : TIM1_BRK_IRQHandler * Description : This function handles TIM1 Break interrupt request. *******************************************************************************/ void TIM1_BRK_IRQHandler(void) { //关闭IGBT,并报错 TIM_ClearITPendingBit(TIM1, TIM_IT_Break); }
//A相电流采样 #define PHASE_A_ADC_CHANNEL ADC_Channel_11 #define PHASE_A_GPIO_PORT GPIOC #define PHASE_A_GPIO_PIN GPIO_Pin_1 //B相电流采样 #define PHASE_B_ADC_CHANNEL ADC_Channel_10 #define PHASE_B_GPIO_PORT GPIOC #define PHASE_B_GPIO_PIN GPIO_Pin_0 //读取散热器温度(过热保护) #define TEMP_FDBK_CHANNEL ADC_Channel_13 #define TEMP_FDBK_CHANNEL_GPIO_PORT GPIOC #define TEMP_FDBK_CHANNEL_GPIO_PIN GPIO_Pin_3 //读取总线电压值(过压、欠压保护) #define BUS_VOLT_FDBK_CHANNEL ADC_Channel_14 #define BUS_VOLT_FDBK_CHANNEL_GPIO_PORT GPIOC #define BUS_VOLT_FDBK_CHANNEL_GPIO_PIN GPIO_Pin_4 //读取电位器值,可以用来调速等 #define POT1_VOLT_FDBK_CHANNEL ADC_Channel_12 #define POT1_VOLT_FDBK_CHANNEL_GPIO_PORT GPIOC #define POT1_VOLT_FDBK_CHANNEL_GPIO_PIN GPIO_Pin_2 //读取母线电流值(过流保护) #define BUS_SHUNT_CURR_CHANNEL ADC_Channel_15 #define BUS_SHUNT_CURR_CHANNEL_GPIO_PORT GPIOC #define BUS_SHUNT_CURR_CHANNEL_GPIO_PIN GPIO_Pin_5 //读取刹车电阻电流(刹车电阻过流保护) #define BRK_SHUNT_CURR_CHANNEL ADC_Channel_7 #define BRK_SHUNT_CURR_CHANNEL_GPIO_PORT GPIOA #define BRK_SHUNT_CURR_CHANNEL_GPIO_PIN GPIO_Pin_7 //备用通道 #define AIN0_VOLT_FDBK_CHANNEL ADC_Channel_8 #define AIN0_VOLT_FDBK_CHANNEL_GPIO_PORT GPIOB #define AIN0_VOLT_FDBK_CHANNEL_GPIO_PIN GPIO_Pin_0 //备用导通 #define AIN1_VOLT_FDBK_CHANNEL ADC_Channel_9 #define AIN1_VOLT_FDBK_CHANNEL_GPIO_PORT GPIOB #define AIN1_VOLT_FDBK_CHANNEL_GPIO_PIN GPIO_Pin_1 #define ADC1_DR_Address ((uint32_t)0x4001244C) //ADC数据寄存器地址 #define BufferLenght 36 volatile u32 ADC_DualConvertedValueTab[BufferLenght]; volatile u16 ADC1_RegularConvertedValueTab[BufferLenght]; volatile u16 ADC2_RegularConvertedValueTab[BufferLenght]; static u16 hPhaseAOffset; static u16 hPhaseBOffset; void ADC_DMA_Init(void) { u8 bIndex; GPIO_InitTypeDef GPIO_InitStructure; ADC_InitTypeDef ADC_InitStructure; DMA_InitTypeDef DMA_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; RCC_ADCCLKConfig(RCC_PCLK2_Div6); //ADCCLK = PCLK2/6=72M/6=12MHz,ADC最大频率不能超过14MHz RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); //DMA1 RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC2, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOE, ENABLE); GPIO_StructInit(&GPIO_InitStructure); //Fills each GPIO_InitStruct member with its default value GPIO_InitStructure.GPIO_Pin = PHASE_A_GPIO_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; GPIO_Init(PHASE_A_GPIO_PORT, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = PHASE_B_GPIO_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; GPIO_Init(PHASE_B_GPIO_PORT, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = TEMP_FDBK_CHANNEL_GPIO_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; GPIO_Init(TEMP_FDBK_CHANNEL_GPIO_PORT, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = BUS_VOLT_FDBK_CHANNEL_GPIO_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; GPIO_Init(BUS_VOLT_FDBK_CHANNEL_GPIO_PORT, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = POT1_VOLT_FDBK_CHANNEL_GPIO_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; GPIO_Init(POT1_VOLT_FDBK_CHANNEL_GPIO_PORT, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = BUS_SHUNT_CURR_CHANNEL_GPIO_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; GPIO_Init(BUS_SHUNT_CURR_CHANNEL_GPIO_PORT, &GPIO_InitStructure); GPIO_StructInit(&GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = BRK_SHUNT_CURR_CHANNEL_GPIO_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; GPIO_Init(BRK_SHUNT_CURR_CHANNEL_GPIO_PORT, &GPIO_InitStructure); GPIO_StructInit(&GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = AIN0_VOLT_FDBK_CHANNEL_GPIO_PIN | AIN1_VOLT_FDBK_CHANNEL_GPIO_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; GPIO_Init(AIN0_VOLT_FDBK_CHANNEL_GPIO_PORT, &GPIO_InitStructure); //设置DMA1,用于自动存储ADC1和ADC2规则通道的转换值 DMA_DeInit(DMA1_Channel1); DMA_StructInit(&DMA_InitStructure); DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address; //ADC数据寄存器地址(源地址) DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)ADC_DualConvertedValueTab; //转换值存储地址(目标地址) DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; //从外设到内存 DMA_InitStructure.DMA_BufferSize = BufferLenght; //传输大小 DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设地址不增 DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //内存地址自增 DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word; //外设数据单位(每次传输32位) DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word; //内存数据单位(每次传输32位) DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; //循环模式 DMA_InitStructure.DMA_Priority = DMA_Priority_High; //本DMA通道优先级(用了多个通道时,本参数才有效果) DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //没有使用内存到内存的传输 DMA_Init(DMA1_Channel1, &DMA_InitStructure); DMA_ClearITPendingBit(DMA1_IT_TC1); //清除通道1传输完成中断 DMA_ITConfig(DMA1_Channel1, DMA_IT_TC, ENABLE); //打开通道1传输完成中断 DMA_Cmd(DMA1_Channel1, ENABLE); //使能DMA1 /****使用双ADC模式,ADC1为主,ADC2为从。当ADC转换配置成由外部事件触发时,用户必须设置成仅触发主ADC,从ADC设置成软件触发,这样可以防止意外的触发从转换。 但是,主和从ADC的外部触发必须同时被激活,要调用 ADC_ExternalTrigConvCmd(ADC2, ENABLE);//ADC2外部触发使能****/ ADC_DeInit(ADC1); ADC_DeInit(ADC2); ADC_StructInit(&ADC_InitStructure); ADC_InitStructure.ADC_Mode = ADC_Mode_RegInjecSimult; //ADC1工作在混合同步规则及注入模式 ADC_InitStructure.ADC_ScanConvMode = ENABLE; //轮流采集各个通道的值 ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; //连续转换模式,触发后就会一直转换 ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //转换触发信号选择,使用一个软件信号触发ADC1 ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Left; //数据左对齐,ADC是12位,要存到DR寄存器的高16位或低16位,就有左右对齐问题,决定了高4位无效或低4位无效 ADC_InitStructure.ADC_NbrOfChannel = 3; //要进行ADC转换的通道数:BUS_SHUNT(母线电压)+BREAK_SHUNT(刹车电阻电流)+Chip Temp(MCU温度) ADC_Init(ADC1, &ADC_InitStructure); ADC_DMACmd(ADC1, ENABLE); //使能ADC1的DMA ADC_StructInit(&ADC_InitStructure); ADC_InitStructure.ADC_Mode = ADC_Mode_RegInjecSimult; //ADC2工作在混合同步规则及注入模式 ADC_InitStructure.ADC_ScanConvMode = ENABLE; ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; //连续转换模式,触发后就会一直转换 ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //转换触发信号选择,由软件给信号触发,双ADC模式的从ADC必须设置为软件触发 ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Left; ADC_InitStructure.ADC_NbrOfChannel = 3; //要进行ADC转换的通道数:POT1(电位器)+AIN0(备用)+AIN1(备用) ADC_Init(ADC2, &ADC_InitStructure); ADC_ExternalTrigConvCmd(ADC2, ENABLE); //ADC2外部触发使能,双ADC模式的从ADC必须要用这条语句 ADC_RegularChannelConfig(ADC1, ADC_Channel_16, 1, ADC_SampleTime_239Cycles5); //MCU温度 ADC_RegularChannelConfig(ADC1, BRK_SHUNT_CURR_CHANNEL, 2, ADC_SampleTime_239Cycles5); //刹车电阻电流 ADC_RegularChannelConfig(ADC1, BUS_SHUNT_CURR_CHANNEL, 3, ADC_SampleTime_239Cycles5); //母线电流 ADC_RegularChannelConfig(ADC2, POT1_VOLT_FDBK_CHANNEL, 1, ADC_SampleTime_239Cycles5); //电位器 ADC_RegularChannelConfig(ADC2, AIN0_VOLT_FDBK_CHANNEL, 2, ADC_SampleTime_239Cycles5); //备用 ADC_RegularChannelConfig(ADC2, AIN1_VOLT_FDBK_CHANNEL, 3, ADC_SampleTime_239Cycles5); //备用 ADC_Cmd(ADC1, ENABLE); //ADC1使能 ADC_TempSensorVrefintCmd(ENABLE); //开启MCU内存温度传感器及Vref通道 ADC_ResetCalibration(ADC1); //复位校准寄存器 while(ADC_GetResetCalibrationStatus(ADC1)); //等待校准寄存器复位完成 ADC_StartCalibration(ADC1); //ADC1开始校准 while(ADC_GetCalibrationStatus(ADC1)); //等待校准完成 ADC_Cmd(ADC2, ENABLE); //ADC2使能 ADC_ResetCalibration(ADC2); //复位校准寄存器 while(ADC_GetResetCalibrationStatus(ADC2)); //等待校准寄存器复位完成 ADC_StartCalibration(ADC2); //ADC2开始校准 while(ADC_GetCalibrationStatus(ADC2)); //等待校准完成 /**** 获取A、B相零电流值,下面是临时配置 ****/ ADC_InjectedSequencerLengthConfig(ADC1,2); //设置ADC1注入组通道数量 ADC_ITConfig(ADC1, ADC_IT_JEOC, DISABLE); //关闭注入组转换完成中断 hPhaseAOffset=0; //A相零电流值 hPhaseBOffset=0; //B相零电流值 ADC_ExternalTrigInjectedConvConfig(ADC1, ADC_ExternalTrigInjecConv_None); //ADC1注入组转换的触发信号选择,注入组转换由软件触发 ADC_ExternalTrigInjectedConvCmd(ADC1,ENABLE); //使能外部信号触发注入组转换的功能 ADC_InjectedChannelConfig(ADC1, PHASE_A_ADC_CHANNEL,1,ADC_SampleTime_7Cycles5); //配置ADC1的注入组通道,设置它们的转化顺序和采样时间 ADC_InjectedChannelConfig(ADC1, PHASE_B_ADC_CHANNEL,2,ADC_SampleTime_7Cycles5); //A相电流和B相电流 ADC_ClearFlag(ADC1, ADC_FLAG_JEOC); //清除注入组转换完成中断标志 ADC_SoftwareStartInjectedConvCmd(ADC1,ENABLE); //给一个软件触发信号,开始注入组转换 for(bIndex=16; bIndex !=0; bIndex--) { while(!ADC_GetFlagStatus(ADC1,ADC_FLAG_JEOC)) { } //等待注入组转换完成 //求Q1.15格式的零电流值,16个(零电流值/8)的累加,把最高符号位溢出。 hPhaseAOffset += (ADC_GetInjectedConversionValue(ADC1,ADC_InjectedChannel_1)>>3); //注入组左对齐,数据要右移3位才是真实数据 hPhaseBOffset += (ADC_GetInjectedConversionValue(ADC1,ADC_InjectedChannel_2)>>3); ADC_ClearFlag(ADC1, ADC_FLAG_JEOC); //清除注入组转换完成中断标志 ADC_SoftwareStartInjectedConvCmd(ADC1,ENABLE); //给一个软件触发信号,开始注入组转换 } /**** 获取A、B相零电流值的临时配置使用结束,下面恢复ADC1的正常配置 ****/ ADC_InjectedChannelConfig(ADC1, PHASE_A_ADC_CHANNEL, 1, ADC_SampleTime_7Cycles5); //A相电流 ADC_InjectedChannelConfig(ADC1, BUS_VOLT_FDBK_CHANNEL,2, ADC_SampleTime_7Cycles5); //母线电压值 ADC_ExternalTrigInjectedConvConfig(ADC1, ADC_ExternalTrigInjecConv_T1_TRGO); //ADC1注入组转换的触发信号选择,注入组转换由TIM1的TRGO触发 ADC_ITConfig(ADC1, ADC_IT_JEOC, ENABLE); //这里才能打开注入组转换完成中断 ADC_InjectedSequencerLengthConfig(ADC2,2); //设置ADC2注入组通道数量 ADC_InjectedChannelConfig(ADC2, PHASE_B_ADC_CHANNEL, 1,ADC_SampleTime_7Cycles5); //B相电流 ADC_InjectedChannelConfig(ADC2, TEMP_FDBK_CHANNEL, 2,ADC_SampleTime_7Cycles5); //散热器温度 ADC_ExternalTrigInjectedConvCmd(ADC2,ENABLE); //使能外部信号触发注入组转换的功能 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //4个抢先级、4个子优先级 NVIC_InitStructure.NVIC_IRQChannel = ADC1_2_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel1_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); // ADC_ExternalTrigConvCmd(ADC1, ENABLE); //ADC1外部触发使能,如果ADC的触发信号是外部就要调用 // ADC_ExternalTrigConvCmd(ADC2, ENABLE); //ADC2外部触发使能 ADC_SoftwareStartConvCmd(ADC1, ENABLE); //给主ADC一个软件触发信号,之后ADC就会一直转换下去 } u16 h_ADCBusvolt; u16 h_ADCTemp; u16 h_ADCPhase_A; u16 h_ADCPhase_B; void ADC1_2_IRQHandler(void) //AD中断有三种情况:AD_EOC、AD_JEOC、AD_AWD { if((ADC1->SR & ADC_FLAG_JEOC) == ADC_FLAG_JEOC) { ADC1->SR = ~(u32)ADC_FLAG_JEOC; //清除注入组转换完成中断标志 //获取散热器温度和母线电压值,做出相应的处理 h_ADCTemp=ADC_GetInjectedConversionValue(ADC2,ADC_InjectedChannel_2); //散热器温度 h_ADCBusvolt=ADC_GetInjectedConversionValue(ADC1,ADC_InjectedChannel_2); //母线电压 //获取两相电流值,进行FOC运算 h_ADCPhase_A=ADC_GetInjectedConversionValue(ADC1,ADC_InjectedChannel_1); //散热器温度 h_ADCPhase_B=ADC_GetInjectedConversionValue(ADC2,ADC_InjectedChannel_1); //母线电压 } } void DMA1_Channel1_IRQHandler(void) { u8 i,j=0; if(DMA_GetITStatus(DMA1_IT_TC1)) { DMA_ClearITPendingBit(DMA1_IT_GL1); //清除DMA通道1传输完成中断 for(i=0;i<BufferLenght;i++) { ADC1_RegularConvertedValueTab[j++] = (uint16_t)(ADC_DualConvertedValueTab[i]>>4); //ADC1规则组左对齐,要右移4位 } //ADC1_RegularConvertedValueTab[0]是MCU温度,ADC1_RegularConvertedValueTab[1]是刹车电阻电流,ADC1_RegularConvertedValueTab[2]是母线电流 j = 0; for(i=0;i<BufferLenght;i++) { ADC2_RegularConvertedValueTab[j++] = (uint16_t)(ADC_DualConvertedValueTab[i] >> 20);//ADC2规则组左对齐,要右移20位 } //ADC2_RegularConvertedValueTab[0]是电位器,ADC2_RegularConvertedValueTab[1]是备用,ADC2_RegularConvertedValueTab[2]是备用 } }
#define U32_MAX ((u32)4294967295uL) #define POLE_PAIR_NUM (u8)2 //电机的极对数 #define ENCODER_PPR (u16)(1000) //编码器线数,即转一圈,编码器输出的脉冲数 #define ALIGNMENT_ANGLE (u16)90 //上电时,电机转子的初始电角度,范围:0-359 #define COUNTER_RESET (u16)((((s32)(ALIGNMENT_ANGLE)*4*ENCODER_PPR/360)-1)/POLE_PAIR_NUM) //根据初始电角度计算TIM2_CNT值 #define ICx_FILTER (u8) 8 // 8<-> 670nsec void ENC_Init(void) { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_ICInitTypeDef TIM_ICInitStructure; GPIO_InitTypeDef GPIO_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); GPIO_StructInit(&GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1; //TIM2_CH1--PA0 TIM2_CH2--PA1 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //设定浮空模式 GPIO_Init(GPIOA, &GPIO_InitStructure); /* Enable the TIM2 Update Interrupt */ NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); TIM_DeInit(TIM2); TIM_TimeBaseStructInit(&TIM_TimeBaseStructure); TIM_TimeBaseStructure.TIM_Prescaler = 0x0; //No prescaling ,可以改变编码器计数对于脉冲输入个数的倍数 //即当TIM_Prescaler=0,输入一个脉冲,CNT增加4.当TIM_Prescaler=1,输入一个脉冲,CNT只增加2 TIM_TimeBaseStructure.TIM_Period = (4*ENCODER_PPR)-1; //ARR值,当CNT增加到ARR会溢出,产生更新中断 TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //向上计数 TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); TIM_EncoderInterfaceConfig(TIM2,TIM_EncoderMode_TI12,TIM_ICPolarity_Rising,TIM_ICPolarity_Rising); //4倍计数,输入A、B信号不反相 TIM_ICStructInit(&TIM_ICInitStructure); TIM_ICInitStructure.TIM_Channel = TIM_Channel_1; TIM_ICInitStructure.TIM_ICFilter = ICx_FILTER; //滤波值是1-15,看情况设定,是用来滤除编码器信号干扰 TIM_ICInit(TIM2, &TIM_ICInitStructure); //配置通道1的滤波值 TIM_ICInitStructure.TIM_Channel = TIM_Channel_2; TIM_ICInit(TIM2, &TIM_ICInitStructure); //配置通道2的滤波值 TIM_ClearFlag(TIM2, TIM_FLAG_Update); TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE); TIM2->CNT = COUNTER_RESET; //设定电机转子初始电角度,一般电机校零后,掉电时要把电角度保存下来,再次上电时直接使用,就不用再校零了 TIM_Cmd(TIM2, ENABLE); } void TIM2_IRQHandler(void) { TIM_ClearFlag(TIM2, TIM_FLAG_Update); //TIM2->CNT向上溢出或向下溢出,都会触发此中断,即3999加一到0,或0减一到3999 } /******************************************************************************* * Description : 返回电机转子的电角度 * Return : Rotor electrical angle: 0 -> 0 degrees, * S16_MAX-> 180 degrees, * S16_MIN-> -180 degrees *******************************************************************************/ s16 ENC_Get_Electrical_Angle(void) { s32 temp; temp = (s32)(TIM_GetCounter(TIM2)) * (s32)(U32_MAX / (4*ENCODER_PPR)); temp *= POLE_PAIR_NUM; return((s16)(temp/65536)); //s16 result }
/* Set the TI1 and the TI2 Polarities */ tmpccer &= (uint16_t)(((uint16_t)~((uint16_t)TIM_CCER_CC1P)) & ((uint16_t)~((uint16_t)TIM_CCER_CC2P))); tmpccer |= (uint16_t)(TIM_IC1Polarity | (uint16_t)(TIM_IC2Polarity << (uint16_t)4)); /* Write to TIMx CCER */ TIMx->CCER = tmpccer;
#define TIM_ICPolarity_Rising ((uint16_t)0x0000) #define TIM_ICPolarity_Falling ((uint16_t)0x0002) #define TIM_ICPolarity_BothEdge ((uint16_t)0x000A)
typedef struct { s16 qI_Component1; s16 qI_Component2; } Curr_Components; //电流值结构体 typedef struct { s16 qV_Component1; s16 qV_Component2; } Volt_Components; typedef struct //电压值结构体 { s16 hCos; s16 hSin; } Trig_Components; //存放角度sin和cos函数值的结构体 #define S16_MAX ((s16)32767) #define S16_MIN ((s16)-32768) /********************************************************************************************************** 在注入组采样完成中断中调用,获取相电流的采样值。返回(电流采样值-零电流值),Q15格式 **********************************************************************************************************/ Curr_Components GET_PHASE_CURRENTS(void) { Curr_Components Local_Stator_Currents; s32 wAux; wAux = ((ADC1->JDR1)<<1)-(s32)(hPhaseAOffset); //把电流采样值转换为Q1.15格式,再减去零电流值 if (wAux < S16_MIN) Local_Stator_Currents.qI_Component1= S16_MIN; //下限幅 else if (wAux > S16_MAX) Local_Stator_Currents.qI_Component1= S16_MAX; //上限幅 else Local_Stator_Currents.qI_Component1= wAux; wAux = ((ADC2->JDR1)<<1)-(s32)(hPhaseBOffset); //B相电流 if (wAux < S16_MIN) Local_Stator_Currents.qI_Component2= S16_MIN; else if (wAux > S16_MAX) Local_Stator_Currents.qI_Component2= S16_MAX; else Local_Stator_Currents.qI_Component2= wAux; return(Local_Stator_Currents); } #define divSQRT_3 (s16)0x49E6 //1/sqrt(3)的Q15格式,1/sqrt(3)*2^15=18918=0x49E6 /********************************************************************************************************** Clarke变换,输入Ia,Ib,得到Ialpha和Ibeta **********************************************************************************************************/ Curr_Components Clarke(Curr_Components Curr_Input) { Curr_Components Curr_Output; s32 qIa_divSQRT3_tmp; s32 qIb_divSQRT3_tmp; //定义32位有符号数,用来暂存Q30格式 s16 qIa_divSQRT3; s16 qIb_divSQRT3 ; Curr_Output.qI_Component1 = Curr_Input.qI_Component1; //Ialpha = Ia qIa_divSQRT3_tmp = divSQRT_3 * Curr_Input.qI_Component1; //计算Ia/√3 qIa_divSQRT3_tmp /=32768; //两个Q15数相乘,会变成Q30,因此要右移15位,变回Q15 qIb_divSQRT3_tmp = divSQRT_3 * Curr_Input.qI_Component2; //计算Ib/√3 qIb_divSQRT3_tmp /=32768; qIa_divSQRT3=((s16)(qIa_divSQRT3_tmp)); //s32赋值给s16 qIb_divSQRT3=((s16)(qIb_divSQRT3_tmp)); Curr_Output.qI_Component2=(-(qIa_divSQRT3)-(qIb_divSQRT3)-(qIb_divSQRT3)); //Ibeta = -(2*Ib+Ia)/sqrt(3) return(Curr_Output); } #define SIN_MASK 0x0300 #define U0_90 0x0200 #define U90_180 0x0300 #define U180_270 0x0000 #define U270_360 0x0100 const s16 hSin_Cos_Table[256] = {\ 0x0000,0x00C9,0x0192,0x025B,0x0324,0x03ED,0x04B6,0x057F,\ 0x0648,0x0711,0x07D9,0x08A2,0x096A,0x0A33,0x0AFB,0x0BC4,\ 0x0C8C,0x0D54,0x0E1C,0x0EE3,0x0FAB,0x1072,0x113A,0x1201,\ 0x12C8,0x138F,0x1455,0x151C,0x15E2,0x16A8,0x176E,0x1833,\ 0x18F9,0x19BE,0x1A82,0x1B47,0x1C0B,0x1CCF,0x1D93,0x1E57,\ 0x1F1A,0x1FDD,0x209F,0x2161,0x2223,0x22E5,0x23A6,0x2467,\ 0x2528,0x25E8,0x26A8,0x2767,0x2826,0x28E5,0x29A3,0x2A61,\ 0x2B1F,0x2BDC,0x2C99,0x2D55,0x2E11,0x2ECC,0x2F87,0x3041,\ 0x30FB,0x31B5,0x326E,0x3326,0x33DF,0x3496,0x354D,0x3604,\ 0x36BA,0x376F,0x3824,0x38D9,0x398C,0x3A40,0x3AF2,0x3BA5,\ 0x3C56,0x3D07,0x3DB8,0x3E68,0x3F17,0x3FC5,0x4073,0x4121,\ 0x41CE,0x427A,0x4325,0x43D0,0x447A,0x4524,0x45CD,0x4675,\ 0x471C,0x47C3,0x4869,0x490F,0x49B4,0x4A58,0x4AFB,0x4B9D,\ 0x4C3F,0x4CE0,0x4D81,0x4E20,0x4EBF,0x4F5D,0x4FFB,0x5097,\ 0x5133,0x51CE,0x5268,0x5302,0x539B,0x5432,0x54C9,0x5560,\ 0x55F5,0x568A,0x571D,0x57B0,0x5842,0x58D3,0x5964,0x59F3,\ 0x5A82,0x5B0F,0x5B9C,0x5C28,0x5CB3,0x5D3E,0x5DC7,0x5E4F,\ 0x5ED7,0x5F5D,0x5FE3,0x6068,0x60EB,0x616E,0x61F0,0x6271,\ 0x62F1,0x6370,0x63EE,0x646C,0x64E8,0x6563,0x65DD,0x6656,\ 0x66CF,0x6746,0x67BC,0x6832,0x68A6,0x6919,0x698B,0x69FD,\ 0x6A6D,0x6ADC,0x6B4A,0x6BB7,0x6C23,0x6C8E,0x6CF8,0x6D61,\ 0x6DC9,0x6E30,0x6E96,0x6EFB,0x6F5E,0x6FC1,0x7022,0x7083,\ 0x70E2,0x7140,0x719D,0x71F9,0x7254,0x72AE,0x7307,0x735E,\ 0x73B5,0x740A,0x745F,0x74B2,0x7504,0x7555,0x75A5,0x75F3,\ 0x7641,0x768D,0x76D8,0x7722,0x776B,0x77B3,0x77FA,0x783F,\ 0x7884,0x78C7,0x7909,0x794A,0x7989,0x79C8,0x7A05,0x7A41,\ 0x7A7C,0x7AB6,0x7AEE,0x7B26,0x7B5C,0x7B91,0x7BC5,0x7BF8,\ 0x7C29,0x7C59,0x7C88,0x7CB6,0x7CE3,0x7D0E,0x7D39,0x7D62,\ 0x7D89,0x7DB0,0x7DD5,0x7DFA,0x7E1D,0x7E3E,0x7E5F,0x7E7E,\ 0x7E9C,0x7EB9,0x7ED5,0x7EEF,0x7F09,0x7F21,0x7F37,0x7F4D,\ 0x7F61,0x7F74,0x7F86,0x7F97,0x7FA6,0x7FB4,0x7FC1,0x7FCD,\ 0x7FD8,0x7FE1,0x7FE9,0x7FF0,0x7FF5,0x7FF9,0x7FFD,0x7FFE}; /******************************************************************************* * Function Name : Trig_Functions * Description : 本函数返回输入角度的cos和sin函数值 * Input : angle in s16 format * Output : Cosine and Sine in s16 format *******************************************************************************/ Trig_Components Trig_Functions(s16 hAngle) //hAngle=0,转子电角度=0度。hAngle=S16_MAX,转子电角度=180度。hAngle=S16_MIN,转子电角度=-180度 { u16 hindex; Trig_Components Local_Components; /* 10 bit index computation */ hindex = (u16)(hAngle + 32768); hindex /= 64; switch (hindex & SIN_MASK) { case U0_90: Local_Components.hSin = hSin_Cos_Table[(u8)(hindex)]; Local_Components.hCos = hSin_Cos_Table[(u8)(0xFF-(u8)(hindex))]; break; case U90_180: Local_Components.hSin = hSin_Cos_Table[(u8)(0xFF-(u8)(hindex))]; Local_Components.hCos = -hSin_Cos_Table[(u8)(hindex)]; break; case U180_270: Local_Components.hSin = -hSin_Cos_Table[(u8)(hindex)]; Local_Components.hCos = -hSin_Cos_Table[(u8)(0xFF-(u8)(hindex))]; break; case U270_360: Local_Components.hSin = -hSin_Cos_Table[(u8)(0xFF-(u8)(hindex))]; Local_Components.hCos = hSin_Cos_Table[(u8)(hindex)]; break; default: break; } return (Local_Components); } Trig_Components Vector_Components; /********************************************************************************************************** Park变换,输入电角度、Ialpha和Ibeta,经过Park变换得到Iq、Id **********************************************************************************************************/ Curr_Components Park(Curr_Components Curr_Input, s16 Theta) { Curr_Components Curr_Output; s32 qId_tmp_1, qId_tmp_2; s32 qIq_tmp_1, qIq_tmp_2; s16 qId_1, qId_2; s16 qIq_1, qIq_2; Vector_Components = Trig_Functions(Theta); //计算电角度的cos和sin qIq_tmp_1 = Curr_Input.qI_Component1 * Vector_Components.hCos; //计算Ialpha*cosθ qIq_tmp_1 /= 32768; qIq_tmp_2 = Curr_Input.qI_Component2 *Vector_Components.hSin; //计算Ibeta*sinθ qIq_tmp_2 /= 32768; qIq_1 = ((s16)(qIq_tmp_1)); qIq_2 = ((s16)(qIq_tmp_2)); Curr_Output.qI_Component1 = ((qIq_1)-(qIq_2)); //Iq=Ialpha*cosθ- Ibeta*sinθ qId_tmp_1 = Curr_Input.qI_Component1 * Vector_Components.hSin; //计算Ialpha*sinθ qId_tmp_1 /= 32768; qId_tmp_2 = Curr_Input.qI_Component2 * Vector_Components.hCos; //计算Ibeta*cosθ qId_tmp_2 /= 32768; qId_1 = (s16)(qId_tmp_1); qId_2 = (s16)(qId_tmp_2); Curr_Output.qI_Component2 = ((qId_1)+(qId_2)); //Id=Ialpha*sinθ+ Ibeta*cosθ return (Curr_Output); } /********************************************************************************************************** 反park变换,输入Uq、Ud得到Ualpha、Ubeta **********************************************************************************************************/ Volt_Components Rev_Park(Volt_Components Volt_Input) { s32 qValpha_tmp1,qValpha_tmp2,qVbeta_tmp1,qVbeta_tmp2; s16 qValpha_1,qValpha_2,qVbeta_1,qVbeta_2; Volt_Components Volt_Output; qValpha_tmp1 = Volt_Input.qV_Component1 * Vector_Components.hCos; //Uq*cosθ qValpha_tmp1 /= 32768; qValpha_tmp2 = Volt_Input.qV_Component2 * Vector_Components.hSin; //Ud*sinθ qValpha_tmp2 /= 32768; qValpha_1 = (s16)(qValpha_tmp1); qValpha_2 = (s16)(qValpha_tmp2); Volt_Output.qV_Component1 = ((qValpha_1)+(qValpha_2)); //Ualpha=Uq*cosθ+ Ud*sinθ qVbeta_tmp1 = Volt_Input.qV_Component1 * Vector_Components.hSin; //Uq*sinθ qVbeta_tmp1 /= 32768; qVbeta_tmp2 = Volt_Input.qV_Component2 * Vector_Components.hCos; //Ud*cosθ qVbeta_tmp2 /= 32768; qVbeta_1 = (s16)(qVbeta_tmp1); qVbeta_2 = (s16)(qVbeta_tmp2); Volt_Output.qV_Component2 = -(qVbeta_1)+(qVbeta_2); //Ubeta=Ud*cosθ- Uq*sinθ return(Volt_Output); }
typedef struct { s16 hKp_Gain; //比例系数 u16 hKp_Divisor; //比例系数因子 s16 hKi_Gain; //积分系数 u16 hKi_Divisor; //积分系数因子 s16 hLower_Limit_Output; //总输出下限 s16 hUpper_Limit_Output; //总输出上限 s32 wLower_Limit_Integral; //积分项下限 s32 wUpper_Limit_Integral; //积分项上限 s32 wIntegral; //积分累积和 s16 hKd_Gain; //微分系数 u16 hKd_Divisor; //微分系数因子 s32 wPreviousError; //上次误差 } PID_Struct_t; /****************************** 扭矩的PID参数,即q轴 *******************************************************/ #define PID_TORQUE_REFERENCE (s16)3000 //q轴的设定值,PID的目的就是要让测量的q轴值与设定值误差为0 #define PID_TORQUE_KP_DEFAULT (s16)1578 //Kp默认值 #define PID_TORQUE_KI_DEFAULT (s16)676 //Ki默认值 #define PID_TORQUE_KD_DEFAULT (s16)100 //Kd默认值 /****************************** 转子磁通的PID参数,即d轴 *******************************************************/ #define PID_FLUX_REFERENCE (s16)0 //d轴的设定值 #define PID_FLUX_KP_DEFAULT (s16)1578 #define PID_FLUX_KI_DEFAULT (s16)676 #define PID_FLUX_KD_DEFAULT (s16)100 /****************************** q轴和d轴PID参数的放大倍数 *******************************************************/ #define TF_KPDIV ((u16)(1024)) //因为Kp、Ki、Kd值很小,而我们需要整数计算,所以需要放大。得出计算结果之后,再缩小。 #define TF_KIDIV ((u16)(16384)) #define TF_KDDIV ((u16)(8192)) /****************************** 速度环的PID参数 *******************************************************/ #define PID_SPEED_REFERENCE_RPM (s16)1500 //电机的设定转速 #define PID_SPEED_REFERENCE (u16)(PID_SPEED_REFERENCE_RPM/6) //电机转速和速度环的设定值一般都不相等,电机不同,它们的关系也不同 #define PID_SPEED_KP_DEFAULT (s16)300 #define PID_SPEED_KI_DEFAULT (s16)100 #define PID_SPEED_KD_DEFAULT (s16)0000 #define NOMINAL_CURRENT (s16)5289 //motor nominal current (0-pk),3倍的额定电流 #define IQMAX NOMINAL_CURRENT //速度环输出最大值 /****************************** 速度环PID参数的放大倍数 *******************************************************/ #define SP_KPDIV ((u16)(16)) #define SP_KIDIV ((u16)(256)) #define SP_KDDIV ((u16)(16)) volatile s16 hTorque_Reference; //q轴设定值 volatile s16 hFlux_Reference; //d轴设定值 volatile s16 hSpeed_Reference; //速度环设定值 void PID_Init (PID_Struct_t *PID_Torque, PID_Struct_t *PID_Flux, PID_Struct_t *PID_Speed) { hTorque_Reference = PID_TORQUE_REFERENCE; //q轴设定值初始化 /******************************************* 下面是控制扭矩的PID参数,即q轴大小 **************************************************************/ PID_Torque->hKp_Gain = PID_TORQUE_KP_DEFAULT; //Kp参数,放大了hKp_Divisor倍。调节结果除以hKp_Divisor才是真实结果 PID_Torque->hKp_Divisor = TF_KPDIV; //Kp参数分数因子 PID_Torque->hKi_Gain = PID_TORQUE_KI_DEFAULT; //Ki参数 PID_Torque->hKi_Divisor = TF_KIDIV; //Ki参数分数因子 PID_Torque->hKd_Gain = PID_TORQUE_KD_DEFAULT; //Kd参数 PID_Torque->hKd_Divisor = TF_KDDIV; //Kd参数分数因子 PID_Torque->wPreviousError = 0; //上次计算的误差值,用于D调节 PID_Torque->hLower_Limit_Output=S16_MIN; //PID输出下限幅 PID_Torque->hUpper_Limit_Output= S16_MAX; //PID输出上限幅 PID_Torque->wLower_Limit_Integral = S16_MIN * TF_KIDIV; //I调节的下限福 PID_Torque->wUpper_Limit_Integral = S16_MAX * TF_KIDIV; //I调节的上限幅 PID_Torque->wIntegral = 0; //I调节的结果,因为是积分,所以要一直累积 /******************************************* 上面是控制扭矩的PID参数,即q轴大小 **************************************************************/ hFlux_Reference = PID_FLUX_REFERENCE; //对于SM-PMSM电机,Id = 0 /******************************************* 下面是控制转子磁通的PID参数,即d轴大小 **************************************************************/ PID_Flux->hKp_Gain = PID_FLUX_KP_DEFAULT; PID_Flux->hKp_Divisor = TF_KPDIV; PID_Flux->hKi_Gain = PID_FLUX_KI_DEFAULT; PID_Flux->hKi_Divisor = TF_KIDIV; PID_Flux->hKd_Gain = PID_FLUX_KD_DEFAULT; PID_Flux->hKd_Divisor = TF_KDDIV; PID_Flux->wPreviousError = 0; PID_Flux->hLower_Limit_Output=S16_MIN; PID_Flux->hUpper_Limit_Output= S16_MAX; PID_Flux->wLower_Limit_Integral = S16_MIN * TF_KIDIV; PID_Flux->wUpper_Limit_Integral = S16_MAX * TF_KIDIV; PID_Flux->wIntegral = 0; /******************************************* 上面是控制转子磁通的PID参数,即d轴大小 **************************************************************/ hSpeed_Reference = PID_SPEED_REFERENCE; /******************************************* 下面是速度环的PID参数 **************************************************************/ PID_Speed->hKp_Gain = PID_SPEED_KP_DEFAULT; PID_Speed->hKp_Divisor = SP_KPDIV; PID_Speed->hKi_Gain = PID_SPEED_KI_DEFAULT; PID_Speed->hKi_Divisor = SP_KIDIV; PID_Speed->hKd_Gain = PID_SPEED_KD_DEFAULT; PID_Speed->hKd_Divisor = SP_KDDIV; PID_Speed->wPreviousError = 0; PID_Speed->hLower_Limit_Output= -IQMAX; PID_Speed->hUpper_Limit_Output= IQMAX; PID_Speed->wLower_Limit_Integral = -IQMAX * SP_KIDIV; PID_Speed->wUpper_Limit_Integral = IQMAX * SP_KIDIV; PID_Speed->wIntegral = 0; /******************************************* 上面是速度环的PID参数 **************************************************************/ } //#define DIFFERENTIAL_TERM_ENABLED //不使用PID的D调节 typedef signed long long s64; s16 PID_Regulator(s16 hReference, s16 hPresentFeedback, PID_Struct_t *PID_Struct) { s32 wError, wProportional_Term,wIntegral_Term, houtput_32; s64 dwAux; #ifdef DIFFERENTIAL_TERM_ENABLED //如果使能了D调节 s32 wDifferential_Term; #endif wError= (s32)(hReference - hPresentFeedback); //设定值-反馈值,取得需要误差量delta_e wProportional_Term = PID_Struct->hKp_Gain * wError; //PID的P调节,即比例放大调节:wP = Kp * delta_e if (PID_Struct->hKi_Gain == 0) //下面进行PID的I调节,即误差的累积调节 { PID_Struct->wIntegral = 0; //如果I参数=0,I调节就=0 } else { wIntegral_Term = PID_Struct->hKi_Gain * wError; //wI = Ki * delta_e ,本次积分项 dwAux = PID_Struct->wIntegral + (s64)(wIntegral_Term); //积分累积的调节量 = 以前的积分累积量 + 本次的积分项 if (dwAux > PID_Struct->wUpper_Limit_Integral) //对PID的I调节做限幅 { PID_Struct->wIntegral = PID_Struct->wUpper_Limit_Integral; //上限 } else if (dwAux < PID_Struct->wLower_Limit_Integral) //下限 { PID_Struct->wIntegral = PID_Struct->wLower_Limit_Integral; } else { PID_Struct->wIntegral = (s32)(dwAux); //不超限, 更新积分累积项为dwAux } } #ifdef DIFFERENTIAL_TERM_ENABLED //如果使能了D调节 { s32 wtemp; wtemp = wError - PID_Struct->wPreviousError; //取得上次和这次的误差之差 wDifferential_Term = PID_Struct->hKd_Gain * wtemp; //D调节结果,wD = Kd * delta_d PID_Struct->wPreviousError = wError; //更新上次误差,用于下次运算 } houtput_32 = (wProportional_Term/PID_Struct->hKp_Divisor+ //输出总的调节量 = 比例调节量/分数因子 + PID_Struct->wIntegral/PID_Struct->hKi_Divisor + // + 积分调节量/分数因子 wDifferential_Term/PID_Struct->hKd_Divisor); // + 微分调节量/分数因子 #else //把P调节和I调节结果除以分数因子再相加,得到PI控制的结果 houtput_32 = (wProportional_Term/PID_Struct->hKp_Divisor + PID_Struct->wIntegral/PID_Struct->hKi_Divisor); #endif if (houtput_32 >= PID_Struct->hUpper_Limit_Output) //PI控制结果限幅 { return(PID_Struct->hUpper_Limit_Output); } else if (houtput_32 < PID_Struct->hLower_Limit_Output) //下限 { return(PID_Struct->hLower_Limit_Output); } else { return((s16)(houtput_32)); //不超限。输出结果 houtput_32 } }
/**** 根据载波频率来选择调制系数,频率越大,调制系数越小(实质是控制的最大占空比) ****/ //#define MAX_MODULATION_100_PER_CENT // up to 11.4 kHz PWM frequency //#define MAX_MODULATION_99_PER_CENT // up to 11.8 kHz //#define MAX_MODULATION_98_PER_CENT // up to 12.2 kHz //#define MAX_MODULATION_97_PER_CENT // up to 12.9 kHz //#define MAX_MODULATION_96_PER_CENT // up to 14.4 kHz #define MAX_MODULATION_95_PER_CENT // up to 14.8 kHz //#define MAX_MODULATION_94_PER_CENT // up to 15.2 kHz //#define MAX_MODULATION_93_PER_CENT // up to 16.7 kHz //#define MAX_MODULATION_92_PER_CENT // up to 17.1 kHz //#define MAX_MODULATION_89_PER_CENT // up to 17.5 kHz /**** 以下是根据选择的调制系数,计算d、q轴合成矢量模的最大值。用宏定义,优化计算速度 ****/ #ifdef MAX_MODULATION_77_PER_CENT #define MAX_MODULE 25230 // root(Vd^2+Vq^2) <= MAX_MODULE = 32767*77% #endif #ifdef MAX_MODULATION_79_PER_CENT #define MAX_MODULE 25885 // root(Vd^2+Vq^2) <= MAX_MODULE = 32767*79% #endif #ifdef MAX_MODULATION_81_PER_CENT #define MAX_MODULE 26541 // root(Vd^2+Vq^2) <= MAX_MODULE = 32767*81% #endif #ifdef MAX_MODULATION_83_PER_CENT #define MAX_MODULE 27196 // root(Vd^2+Vq^2) <= MAX_MODULE = 32767*83% #endif #ifdef MAX_MODULATION_85_PER_CENT #define MAX_MODULE 27851 // root(Vd^2+Vq^2) <= MAX_MODULE = 32767*85% #endif #ifdef MAX_MODULATION_87_PER_CENT #define MAX_MODULE 28507 // root(Vd^2+Vq^2) <= MAX_MODULE = 32767*87% #endif #ifdef MAX_MODULATION_89_PER_CENT #define MAX_MODULE 29162 // root(Vd^2+Vq^2) <= MAX_MODULE = 32767*89% #endif #ifdef MAX_MODULATION_91_PER_CENT #define MAX_MODULE 29817 // root(Vd^2+Vq^2) <= MAX_MODULE = 32767*91% #endif #ifdef MAX_MODULATION_92_PER_CENT #define MAX_MODULE 30145 // root(Vd^2+Vq^2) <= MAX_MODULE = 32767*92% #endif #ifdef MAX_MODULATION_93_PER_CENT #define MAX_MODULE 30473 // root(Vd^2+Vq^2) <= MAX_MODULE = 32767*93% #endif #ifdef MAX_MODULATION_94_PER_CENT #define MAX_MODULE 30800 //root(Vd^2+Vq^2) <= MAX_MODULE = 32767*94% #endif #ifdef MAX_MODULATION_95_PER_CENT #define MAX_MODULE 31128 // root(Vd^2+Vq^2) <= MAX_MODULE = 32767*95% #endif #ifdef MAX_MODULATION_96_PER_CENT #define MAX_MODULE 31456 // root(Vd^2+Vq^2) <= MAX_MODULE = 32767*96% #endif #ifdef MAX_MODULATION_97_PER_CENT #define MAX_MODULE 31783 // root(Vd^2+Vq^2) <= MAX_MODULE = 32767*97% #endif #ifdef MAX_MODULATION_98_PER_CENT #define MAX_MODULE 32111 // root(Vd^2+Vq^2) <= MAX_MODULE = 32767*98% #endif #ifdef MAX_MODULATION_99_PER_CENT #define MAX_MODULE 32439 // root(Vd^2+Vq^2) <= MAX_MODULE = 32767*99% #endif #ifdef MAX_MODULATION_100_PER_CENT #define MAX_MODULE 32767 // root(Vd^2+Vq^2) <= MAX_MODULE = 32767*100% #endif #ifdef MAX_MODULATION_77_PER_CENT #define START_INDEX 37 static const u16 circle_limit_table[91]= { 32468,32176,31893,31347,31084,30578,30334,29863,29636,29414,28984,28776,28373, 28178,27987,27616,27436,27086,26916,26585,26425,26267,25959,25809,25518,25375, 25098,24962,24829,24569,24442,24194,24072,23953,23719,23604,23381,23271,23056, 22951,22848,22644,22545,22349,22254,22066,21974,21883,21704,21616,21444,21359, 21275,21111,21030,20872,20793,20640,20564,20490,20343,20270,20128,20058,19920, 19852,19785,19653,19587,19459,19396,19271,19209,19148,19028,18969,18852,18795, 18738,18625,18570,18460,18406,18299,18246,18194,18091,18040,17940,17890,17792 }; #endif #ifdef MAX_MODULATION_79_PER_CENT #define START_INDEX 39 static const u16 circle_limit_table[89]= { 32489,32217,31952,31442,31195,30719,30489,30045,29830,29413,29211,28819,28629, 28442,28080,27904,27562,27396,27072,26914,26607,26457,26165,26022,25882,25608, 25475,25214,25086,24836,24715,24476,24359,24130,24019,23908,23692,23586,23378, 23276,23077,22979,22787,22692,22507,22416,22326,22150,22063,21893,21809,21645, 21564,21405,21327,21173,21097,21022,20875,20802,20659,20589,20450,20382,20247, 20181,20051,19986,19923,19797,19735,19613,19553,19434,19375,19260,19202,19090, 19034,18979,18871,18817,18711,18659,18555,18504,18403,18354,18255 }; #endif #ifdef MAX_MODULATION_81_PER_CENT #define START_INDEX 41 static const u16 circle_limit_table[87]= { 32508,32255,32008,31530,31299,30852,30636,30216,30012,29617,29426,29053,28872, 28520,28349,28015,27853,27536,27382,27081,26934,26647,26507,26234,26101,25840, 25712,25462,25340,25101,24984,24755,24643,24422,24315,24103,24000,23796,23696, 23500,23404,23216,23123,22941,22851,22763,22589,22504,22336,22253,22091,22011, 21854,21776,21624,21549,21401,21329,21186,21115,20976,20908,20773,20706,20575, 20511,20383,20320,20196,20135,20015,19955,19838,19780,19666,19609,19498,19443, 19334,19280,19175,19122,19019,18968,18867,18817,18719 }; #endif #ifdef MAX_MODULATION_83_PER_CENT #define START_INDEX 44 static const u16 circle_limit_table[84]= { 32291,32060,31613,31397,30977,30573,30377,29996,29811,29451,29276,28934,28768, 28444,28286,27978,27827,27533,27390,27110,26973,26705,26574,26318,26069,25948, 25709,25592,25363,25251,25031,24923,24711,24607,24404,24304,24107,24011,23821, 23728,23545,23456,23279,23192,23021,22854,22772,22610,22530,22374,22297,22145, 22070,21922,21850,21707,21636,21497,21429,21294,21227,21096,21032,20904,20778, 20717,20595,20534,20416,20357,20241,20184,20071,20015,19905,19851,19743,19690, 19585,19533,19431,19380,19280,19182 }; #endif #ifdef MAX_MODULATION_85_PER_CENT #define START_INDEX 46 static const u16 circle_limit_table[82]= { 32324,32109,31691,31489,31094,30715,30530,30170,29995,29654,29488,29163,29005, 28696,28397,28250,27965,27825,27552,27418,27157,26903,26779,26535,26416,26182, 26067,25842,25623,25515,25304,25201,24997,24897,24701,24605,24415,24230,24139, 23960,23872,23699,23614,23446,23282,23201,23042,22964,22810,22734,22584,22437, 22365,22223,22152,22014,21945,21811,21678,21613,21484,21421,21296,21234,21112, 21051,20932,20815,20757,20643,20587,20476,20421,20312,20205,20152,20048,19996 ,19894,19844,19744,19645 }; #endif #ifdef MAX_MODULATION_87_PER_CENT #define START_INDEX 48 static const u16 circle_limit_table[81]= { 32559,32154,31764,31575,31205,31025,30674,30335,30170,29847, 29689,29381,29083,28937,28652,28375,28239,27974,27844,27589, 27342,27220,26983,26866,26637,26414,26305,26090,25984,25777, 25575,25476,25280,25184,24996,24811,24720,24542,24367,24281, 24112,24028,23864,23703,23624,23468,23391,23240,23091,23018, 22874,22803,22662,22524,22456,22322,22191,22126,21997,21934, 21809,21686,21625,21505,21446,21329,21214,21157,21045,20990, 20880,20772,20719,20613,20561,20458,20356,20306,20207,20158, 20109 }; #endif #ifdef MAX_MODULATION_89_PER_CENT #define START_INDEX 50 static const u16 circle_limit_table[78]= { 32574,32197,32014,31656,31309,31141,30811,30491,30335,30030, 29734,29589,29306,29031,28896,28632,28375,28249,28002,27881, 27644,27412,27299,27076,26858,26751,26541,26336,26235,26037, 25844,25748,25561,25378,25288,25110,24936,24851,24682,24517, 24435,24275,24118,24041,23888,23738,23664,23518,23447,23305, 23166,23097,22962,22828,22763,22633,22505,22442,22318,22196, 22135,22016,21898,21840,21726,21613,21557,21447,21338,21284, 21178,21074,21022,20919,20819,20769,20670,20573 }; #endif #ifdef MAX_MODULATION_91_PER_CENT #define START_INDEX 52 static const u16 circle_limit_table[76]= { 32588,32411,32066,31732,31569,31250,30940,30789,30492,30205, 29925,29788,29519,29258,29130,28879,28634,28395,28278,28048, 27823,27713,27497,27285,27181,26977,26777,26581,26485,26296, 26110,26019,25840,25664,25492,25407,25239,25076,24995,24835, 24679,24602,24450,24301,24155,24082,23940,23800,23731,23594, 23460,23328,23263,23135,23008,22946,22822,22701,22641,22522, 22406,22291,22234,22122,22011,21956,21848,21741,21636,21584, 21482,21380,21330,21231,21133,21037 }; #endif #ifdef MAX_MODULATION_92_PER_CENT #define START_INDEX 54 const u16 circle_limit_table[74]= { 32424,32091,31929,31611,31302,31002,30855,30568,30289,30017, 29884,29622,29368,29243,28998,28759,28526,28412,28187,27968, 27753,27648,27441,27238,27040,26942,26750,26563,26470,26288, 26110,25935,25849,25679,25513,25350,25269,25111,24955,24803, 24727,24579,24433,24361,24219,24079,23942,23874,23740,23609, 23479,23415,23289,23165,23042,22982,22863,22745,22629,22572, 22459,22347,22292,22183,22075,21970,21917,21813,21711,21610, 21561,21462,21365,21268 }; #endif #ifdef MAX_MODULATION_93_PER_CENT #define START_INDEX 55 const u16 circle_limit_table[73]= { 32437,32275,31959,31651,31353,31207,30920,30642,30371,30107, 29977,29723,29476,29234,29116,28883,28655,28433,28324,28110, 27900,27695,27594,27395,27201,27011,26917,26733,26552,26375, 26202,26116,25948,25783,25621,25541,25383,25228,25076,25001, 24854,24708,24565,24495,24356,24219,24084,24018,23887,23758, 23631,23506,23444,23322,23202,23083,23025,22909,22795,22683, 22627,22517,22409,22302,22250,22145,22042,21941,21890,21791, 21693,21596,21500 }; #endif #ifdef MAX_MODULATION_94_PER_CENT #define START_INDEX 56 const u16 circle_limit_table[72]= { 32607,32293,31988,31691,31546,31261,30984,30714,30451,30322, 30069,29822,29581,29346,29231,29004,28782,28565,28353,28249, 28044,27843,27647,27455,27360,27174,26991,26812,26724,26550, 26380,26213,26049,25968,25808,25652,25498,25347,25272,25125, 24981,24839,24699,24630,24494,24360,24228,24098,24034,23908, 23783,23660,23600,23480,23361,23245,23131,23074,22962,22851, 22742,22635,22582,22477,22373,22271,22170,22120,22021,21924, 21827,21732 }; #endif #ifdef MAX_MODULATION_95_PER_CENT #define START_INDEX 57 const u16 circle_limit_table[71]= { 32613,32310,32016,31872,31589,31314,31046,30784,30529,30404, 30158,29919,29684,29456,29343,29122,28906,28695,28488,28285, 28186,27990,27798,27610,27425,27245,27155,26980,26808,26639, 26473,26392,26230,26072,25917,25764,25614,25540,25394,25250, 25109,24970,24901,24766,24633,24501,24372,24245,24182,24058, 23936,23816,23697,23580,23522,23408,23295,23184,23075,23021, 22913,22808,22703,22600,22499,22449,22349,22251,22154,22059, 21964 }; #endif #ifdef MAX_MODULATION_96_PER_CENT #define START_INDEX 58 const u16 circle_limit_table[70]= { 32619,32472,32184,31904,31631,31365,31106,30853,30728,30484, 30246,30013,29785,29563,29345,29238,29028,28822,28620,28423, 28229,28134,27946,27762,27582,27405,27231,27061,26977,26811, 26649,26489,26332,26178,26027,25952,25804,25659,25517,25376, 25238,25103,25035,24903,24772,24644,24518,24393,24270,24210, 24090,23972,23855,23741,23627,23516,23461,23352,23244,23138, 23033,22930,22828,22777,22677,22579,22481,22385,22290,22196 }; #endif #ifdef MAX_MODULATION_97_PER_CENT #define START_INDEX 60 const u16 circle_limit_table[68]= { 32483,32206,31936,31672,31415,31289,31041,30799,30563,30331, 30105,29884,29668,29456,29352,29147,28947,28750,28557,28369, 28183,28002,27824,27736,27563,27393,27226,27062,26901,26743, 26588,26435,26360,26211,26065,25921,25780,25641,25504,25369, 25236,25171,25041,24913,24788,24664,24542,24422,24303,24186, 24129,24015,23902,23791,23681,23573,23467,23362,23258,23206, 23105,23004,22905,22808,22711,22616,22521,22429 }; #endif #ifdef MAX_MODULATION_98_PER_CENT #define START_INDEX 61 const u16 circle_limit_table[67]= { 32494,32360,32096,31839,31587,31342,31102,30868,30639,30415, 30196,29981,29771,29565,29464,29265,29069,28878,28690,28506, 28325,28148,27974,27803,27635,27470,27309,27229,27071,26916, 26764,26614,26467,26322,26180,26039,25901,25766,25632,25500, 25435,25307,25180,25055,24932,24811,24692,24574,24458,24343, 24230,24119,24009,23901,23848,23741,23637,23533,23431,23331, 23231,23133,23036,22941,22846,22753,22661 }; #endif #ifdef MAX_MODULATION_99_PER_CENT #define START_INDEX 62 const u16 circle_limit_table[66]= { 32635,32375,32121,31873,31631,31394,31162,30935,30714,30497, 30284,30076,29872,29672,29574,29380,29190,29003,28820,28641, 28464,28291,28122,27955,27791,27630,27471,27316,27163,27012, 26864,26718,26575,26434,26295,26159,26024,25892,25761,25633, 25569,25444,25320,25198,25078,24959,24842,24727,24613,24501, 24391,24281,24174,24067,23963,23859,23757,23656,23556,23458, 23361,23265,23170,23077,22984,22893 }; #endif #ifdef MAX_MODULATION_100_PER_CENT #define START_INDEX 63 const u16 circle_limit_table[65]= { 32767,32390,32146,31907,31673,31444,31220,31001,30787,30577,30371, 30169,29971,29777,29587,29400,29217,29037,28861,28687,28517, 28350,28185,28024,27865,27709,27555,27404,27256,27110,26966, 26824,26685,26548,26413,26280,26149,26019,25892,25767,25643, 25521,25401,25283,25166,25051,24937,24825,24715,24606,24498, 24392,24287,24183,24081,23980,23880,23782,23684,23588,23493, 23400,23307,23215,23125 }; #endif Volt_Components Stat_Volt_q_d; /********************************************************************************************************** 把经过PID调整过的d、q值的合成矢量模值限制在最大值,如果超过了,那么等比例缩小d、q值 **********************************************************************************************************/ void RevPark_Circle_Limitation(void) { s32 temp; //计算Vd^2+Vq^2 temp = Stat_Volt_q_d.qV_Component1 * Stat_Volt_q_d.qV_Component1 + Stat_Volt_q_d.qV_Component2 * Stat_Volt_q_d.qV_Component2; if ( temp > (u32)(( MAX_MODULE * MAX_MODULE) ) ) //如果(Vd^2+Vq^2)大于MAX_MODULE^2,就要进行比例缩小 { u16 index; //假设Vq=x*32767, Vd=y*32767 temp /= (u32)(512*32768); //(Vq^2+Vd^2)/(512*32768) = (x^2+y^2)*32767^2/(512*32768)=64(x^2+y^2) temp -= START_INDEX ; //程序中,载波频率=15K,因此调制系数选择95%,MAX_MODULE=32767*95%=31128,START_INDEX=57 index = circle_limit_table[(u8)temp]; //当Vq、Vd接近于最大值32767,即x、y接近于1,temp=64(x^2+y^2)-START_INDEX=128-57有最大值71 //当Vd^2+Vq^2的值只比MAX_MODULE^2大一点,temp=(Vq^2+Vd^2)/(512*32768)-START_INDEX=MAX_MODULE^2/(512*32768)-57有最小值0 //因此调制系数为95%的circle_limit_table表中只有72个数,并且根据Vd^2+Vq^2的大小来选择缩小的系数 temp = (s16)Stat_Volt_q_d.qV_Component1 * (u16)(index); //使用缩小系数来缩小Vq Stat_Volt_q_d.qV_Component1 = (s16)(temp/32768); temp = (s16)Stat_Volt_q_d.qV_Component2 * (u16)(index); //使用缩小系数来缩小Vd Stat_Volt_q_d.qV_Component2 = (s16)(temp/32768); } }
#define SQRT_3 1.732051 //根号3 #define T (PWM_PERIOD * 4) //TIM1 ARR值的4倍 #define T_SQRT3 (u16)(T * SQRT_3) #define SECTOR_1 (u32)1 #define SECTOR_2 (u32)2 #define SECTOR_3 (u32)3 #define SECTOR_4 (u32)4 #define SECTOR_5 (u32)5 #define SECTOR_6 (u32)6 void CALC_SVPWM(Volt_Components Stat_Volt_Input) { u8 bSector; s32 wX, wY, wZ, wUAlpha, wUBeta; u16 hTimePhA=0, hTimePhB=0, hTimePhC=0; wUAlpha = Stat_Volt_Input.qV_Component1 * T_SQRT3; wUBeta = -(Stat_Volt_Input.qV_Component2 * T); wX = wUBeta; wY = (wUBeta + wUAlpha)/2; wZ = (wUBeta - wUAlpha)/2; //下面是查找定子电流的扇区号 if (wY<0) { if (wZ<0) { bSector = SECTOR_5; } else // wZ >= 0 if (wX<=0) { bSector = SECTOR_4; } else // wX > 0 { bSector = SECTOR_3; } } else // wY > 0 { if (wZ>=0) { bSector = SECTOR_2; } else // wZ < 0 if (wX<=0) { bSector = SECTOR_6; } else // wX > 0 { bSector = SECTOR_1; } } switch(bSector) //根据所在扇区号,计算三相占空比 { case SECTOR_1: case SECTOR_4: hTimePhA = (T/8) + ((((T + wX) - wZ)/2)/131072); hTimePhB = hTimePhA + wZ/131072; hTimePhC = hTimePhB - wX/131072; break; case SECTOR_2: case SECTOR_5: hTimePhA = (T/8) + ((((T + wY) - wZ)/2)/131072); hTimePhB = hTimePhA + wZ/131072; hTimePhC = hTimePhA - wY/131072; break; case SECTOR_3: case SECTOR_6: hTimePhA = (T/8) + ((((T - wX) + wY)/2)/131072); hTimePhC = hTimePhA - wY/131072; hTimePhB = hTimePhC + wX/131072; break; default: break; } TIM1->CCR1 = hTimePhA; TIM1->CCR2 = hTimePhB; TIM1->CCR3 = hTimePhC; }
hTimePhA = (T/8) + ((((T + wX) - wZ)/2)/131072); hTimePhB = hTimePhA + wZ/131072; hTimePhC = hTimePhB - wX/131072;
Curr_Components Stat_Curr_a_b; Curr_Components Stat_Curr_alfa_beta; Curr_Components Stat_Curr_q_d; Curr_Components Stat_Curr_q_d_ref_ref; //电流环的给定值,用于电流环Id,Iq和前馈电流控制的给定值 Volt_Components Stat_Volt_q_d; Volt_Components Stat_Volt_alfa_beta; void FOC_Model(void) //电流环处理函数 { Stat_Curr_a_b = GET_PHASE_CURRENTS(); //读取2相的电流值 Stat_Curr_alfa_beta = Clarke(Stat_Curr_a_b); //Ia,Ib通过Clark变换得到Ialpha和Ibeta Stat_Curr_q_d = Park( Stat_Curr_alfa_beta,ENC_Get_Electrical_Angle() ); //输入电角度、Ialpha和Ibeta,经过Park变换得到Iq、Id //q轴的pid运算,得到Vq Stat_Volt_q_d.qV_Component1 = PID_Regulator(Stat_Curr_q_d_ref_ref.qI_Component1,Stat_Curr_q_d.qI_Component1, &PID_Torque_InitStructure); //d轴的pid运算,得到Vd Stat_Volt_q_d.qV_Component2 = PID_Regulator(Stat_Curr_q_d_ref_ref.qI_Component2,Stat_Curr_q_d.qI_Component2, &PID_Flux_InitStructure); RevPark_Circle_Limitation(); //归一化 Stat_Volt_alfa_beta = Rev_Park(Stat_Volt_q_d); //反Park变换 CALC_SVPWM(Stat_Volt_alfa_beta); //svpwm实现函数,实际的电流输出控制 }