一.ADC的配置问题
1.GPIO初始化配置
开始ADC对应的GPIO口,本驱动程序使用到五个GPIO,分别对应U V W三相电流及母线电压和温度采样,统一配置为模拟输入。
GPIO的配置代码如下:
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA |RCC_AHB1Periph_GPIOC | RCC_AHB1Periph_GPIOB| RCC_AHB1Periph_GPIOD|RCC_AHB1Periph_GPIOE, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC2, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
GPIO_StructInit(&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = RHEOSTAT_ADC1_GPIO_PIN1 | RHEOSTAT_ADC1_GPIO_PIN2| RHEOSTAT_ADC1_GPIO_PIN3;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_Init(RHEOSTAT_ADC1_UVWGPIO_PORT, &GPIO_InitStructure);
GPIO_StructInit(&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = RHEOSTAT_ADC1_GPIO_PIN4 |RHEOSTAT_ADC1_GPIO_PIN5;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_Init(RHEOSTAT_ADC_TEMPVOLTGPIO_PORT, &GPIO_InitStructure);
2.ADC初始化配置
-
ADC1和ADC2配置:配置为同步注入模式,设置分频值,关闭DMA。
-
为了在电机开始运行前采集到的当前的零飘电流,需要先进行可以采集零飘电流的ADC配置,配置如下: ADC1和ADC2采用相同的配置。 关闭扫描模式 关闭边沿触发 关闭连续转换 数据左对齐 数据设置为12位
-
在进行完配置之后如果立即开始采集零漂电流,会出现采样值为0的情况,解决方法时设置微小延时,等待内部校准。
-
开始零漂电流的采集:使用ADC1来采集三相电流,先关闭注入通道转换结束中断,防止在采集到零漂电流后进入ADC中断,开始FOC计算。关闭中断后关闭ADC的边沿触发,防止在采集过程中收到别的触发信号。设置ADC1的注入通道的采样对象和周期,开始采集。
零漂电流:零点漂移(零漂)是直接耦合放大电路中存在的一个特殊问题。所谓零点漂移的是指放大电路在没有输入信号时,用灵敏的直流表测量输出端,也会有变化缓慢的输出电压产生,称为零点漂移现象。零点漂移的信号会在各级放大的电路间传递,经过多级放大后,在输出端成为较大的信号,如果有用信号较弱,存在零点漂移现象的直接耦合放大电路中,漂移电压和有效信号电压会混杂在一起被逐级放大,当漂移电压大小可以和有效信号电压相比时,是很难在输出端分辨出有效信号的电压;在漂移现象严重的情况下,往往会使有效信号“淹没”,使放大电路不能正常工作。
-
电机运行状态的电流采集:将ADC1和2配置为运行状态所需要的模式,即ADC1和ADC2的注入通道1分别采集A相电流和B相电流,并在运行中动态调整;通道2分别采集母线电压和温度。同时将触发条件设置为定时器的更新触发,等待电机启动。电机启动后,将触发条件设置为定时器的输出捕获触发,使用定时器1(产生pwm波的定时器)的闲置通道配置为pwm模式,同步定时器产生的pwm波,在合适的点触发ADC。
ADC的配置代码如下:
ADC_DeInit();
ADC_CommonInitStructure.ADC_Mode = ADC_DualMode_InjecSimult;
ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div6 ;
ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled ;
ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
ADC_CommonInit(&ADC_CommonInitStructure);
ADC_StructInit(&ADC_InitStructure);
ADC_InitStructure.ADC_ScanConvMode = ENABLE;
ADC_InitStructure.ADC_ExternalTrigConvEdge= ADC_ExternalTrigConvEdge_None;
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T8_CC1;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Left;
ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
ADC_InitStructure.ADC_NbrOfConversion = 1 ;
ADC_Init(RHEOSTAT_ADC1, &ADC_InitStructure);
ADC_InitStructure.ADC_ScanConvMode = ENABLE;
ADC_InitStructure.ADC_ExternalTrigConvEdge= ADC_ExternalTrigConvEdge_None;
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T8_CC1;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Left;
ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
ADC_InitStructure.ADC_NbrOfConversion = 1 ;
ADC_Init(RHEOSTAT_ADC2, &ADC_InitStructure);
ADC_Cmd(RHEOSTAT_ADC1, ENABLE);
ADC_Cmd(RHEOSTAT_ADC2, ENABLE);
while(WaitForAD != 0 )
{
WaitForAD--;
}
SVPWM_3ShuntCurrentReadingCalibration();
ADC_InjectedSequencerLengthConfig(RHEOSTAT_ADC2,2);
ADC_InjectedChannelConfig(RHEOSTAT_ADC2, PHASE_A_ADC_CHANNEL, 1, SAMPLING_TIME_CK);
ADC_InjectedChannelConfig(RHEOSTAT_ADC2, TEMP_FDBK_CHANNEL, 2, SAMPLING_TIME_CK);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitStructure.NVIC_IRQChannel = Rheostat_ADC_IRQ;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = ADC_PRE_EMPTION_PRIORITY;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = ADC_SUB_PRIORITY;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = Rheostat_TIM_IRQ ;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = TIM1_UP_PRE_EMPTION_PRIORITY;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = TIM1_UP_SUB_PRIORITY;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
void SVPWM_3ShuntCurrentReadingCalibration(void)
{
static u16 bIndex;
hPhaseAOffset=0;
hPhaseBOffset=0;
hPhaseCOffset=0;
static u8 FourAvg = 0;
ATemp = 0;
BTemp = 0;
CTemp = 0;
while(WaitForAD != 0 )
{
WaitForAD--;
}
ADC_ITConfig(RHEOSTAT_ADC1, ADC_IT_JEOC, DISABLE);
ADC_ExternalTrigInjectedConvEdgeConfig(ADC1, ADC_ExternalTrigInjecConvEdge_None);
ADC_InjectedSequencerLengthConfig(RHEOSTAT_ADC1,3);
ADC_InjectedChannelConfig(ADC1, PHASE_A_ADC_CHANNEL,1,SAMPLING_TIME_CK);
ADC_InjectedChannelConfig(ADC1, PHASE_B_ADC_CHANNEL,2,SAMPLING_TIME_CK);
ADC_InjectedChannelConfig(ADC1, PHASE_C_ADC_CHANNEL,3,SAMPLING_TIME_CK);
ADC_ClearFlag(RHEOSTAT_ADC1, ADC_FLAG_JEOC);
ADC_SoftwareStartInjectedConv(RHEOSTAT_ADC1);
for(FourAvg = 0;FourAvg < AvgCurNum;FourAvg ++)
{
for(bIndex=0; bIndex <NB_CONVERSIONS; bIndex++)
{
while(!ADC_GetFlagStatus(ADC1,ADC_FLAG_JEOC)) {}
ATemp += (ADC_GetInjectedConversionValue(RHEOSTAT_ADC1,ADC_InjectedChannel_1)>>3);
BTemp += (ADC_GetInjectedConversionValue(RHEOSTAT_ADC1,ADC_InjectedChannel_2)>>3);
CTemp += (ADC_GetInjectedConversionValue(RHEOSTAT_ADC1,ADC_InjectedChannel_3)>>3);
ADC_ClearFlag(RHEOSTAT_ADC1, ADC_FLAG_JEOC);
ADC_SoftwareStartInjectedConv(RHEOSTAT_ADC1);
}
}
hPhaseAOffset = (u16)(ATemp/AvgCurNum);
hPhaseBOffset = (u16)(BTemp/AvgCurNum);
hPhaseCOffset = (u16)(CTemp/AvgCurNum);
SVPWM_InjectedConvConfig();
}
void SVPWM_InjectedConvConfig(void)
{
ADC_InjectedSequencerLengthConfig(RHEOSTAT_ADC1,2);
ADC_InjectedSequencerLengthConfig(RHEOSTAT_ADC2,2);
ADC_InjectedChannelConfig(RHEOSTAT_ADC1, PHASE_B_ADC_CHANNEL, 1, SAMPLING_TIME_CK);
ADC_InjectedChannelConfig(RHEOSTAT_ADC1, BUS_VOLT_FDBK_CHANNEL, 2, SAMPLING_TIME_CK);
ADC_ExternalTrigInjectedConvConfig(RHEOSTAT_ADC1,ADC_ExternalTrigInjecConv_T1_TRGO);
ADC_ExternalTrigInjectedConvEdgeConfig(RHEOSTAT_ADC1,ADC_ExternalTrigInjecConvEdge_Falling);
ADC_ITConfig(RHEOSTAT_ADC1, ADC_IT_JEOC | ADC_IT_AWD, ENABLE);
}
3.运行状态下的ADC
在运行状态下,ADC1和ADC2注入通道1的采集对象在不同的扇区会有不同的配置。这是由于三相采样电阻在驱动电路的下桥臂导通时才有电流,为保证能采集的电流,只找导通时间最长的两相,剩余的一相根据基尔霍夫电流定律计算。根据PWM波图像,在第四和第五扇区,采集A相和B相电流;在第一和第六扇区,采集C相和B相电流;在第二和第三扇区,采集A相和C相电流。
电流获取代码如下:
Curr_Components SVPWM_3ShuntGetPhaseCurrentValues(void)
{
Curr_Components Local_Stator_Currents;
Curr_Components new_value;
Curr_Components result;
s32 wAux;
u8 count;
s32 sum1 = 0;
s32 sum2 = 0;
int i,j,temp;
switch (bSector)
{
case 4:
case 5:
wAux = (s32)(hPhaseAOffset)- ((ADC1->JDR1)<<1);
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 = (s32)(hPhaseBOffset)-((ADC2->JDR1)<<1);
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;
}
break;
case 6:
case 1:
wAux = (s32)(hPhaseBOffset)-((ADC1->JDR1)<<1);
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;
}
wAux = ((ADC2->JDR1)<<1)-hPhaseCOffset-Local_Stator_Currents.qI_Component2;
if (wAux> S16_MAX)
{
Local_Stator_Currents.qI_Component1 = S16_MAX;
}
else if (wAux <S16_MIN)
{
Local_Stator_Currents.qI_Component1 = S16_MIN;
}
else
{
Local_Stator_Currents.qI_Component1 = wAux;
}
break;
case 2:
case 3:
wAux = (s32)(hPhaseAOffset)-((ADC1->JDR1)<<1);
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) - hPhaseCOffset - Local_Stator_Currents.qI_Component1;
if (wAux> S16_MAX)
{
Local_Stator_Currents.qI_Component2=S16_MAX;
}
else if (wAux <S16_MIN)
{
Local_Stator_Currents.qI_Component2 = S16_MIN;
}
else
{
Local_Stator_Currents.qI_Component2 = wAux;
}
break;
default:
break;
}
return(Local_Stator_Currents);
}
二.定时器的配置问题
配置能够产生6路pwm波的定时器,改变定时器的占空比即可控制电机转速或转矩。
1.GPIO初始化配置
需要一个能够产生6路PWM波的高级定时器,定时器1或定时器8,对应6个GPIO口,同时需要一个刹车GPIO,共计需要7个GPIO。配置为复用推挽模式。
代码如下:
GPIO_StructInit(&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = RHEOSTAT_TIM1_GPIO_PIN1 | RHEOSTAT_TIM1_GPIO_PIN2 | RHEOSTAT_TIM1_GPIO_PIN3 ;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(RHEOSTAT_TIM1_GPIO_PORT, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = RHEOSTAT_TIM1N_GPIO_PIN1 | RHEOSTAT_TIM1N_GPIO_PIN2 | RHEOSTAT_TIM1N_GPIO_PIN3;
GPIO_Init(RHEOSTAT_TIM1N_GPIO_PORT, &GPIO_InitStructure);
2.定时器的初始化配置
定时器的初始化代码如下:
TIM_DeInit(TIM1);
TIM_TimeBaseStructInit(&TIM1_TimeBaseStructure);
TIM1_TimeBaseStructure.TIM_Prescaler = PWM_PRSC;
TIM1_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_CenterAligned1;
TIM1_TimeBaseStructure.TIM_Period = PWM_PERIOD;
TIM1_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV2;
TIM1_TimeBaseStructure.TIM_RepetitionCounter = REP_RATE;
TIM_TimeBaseInit(TIM1, &TIM1_TimeBaseStructure);
3.输出捕获模式的配置
定时器的四个通道都配置为中央对齐模式
代码如下:
TIM_OCStructInit(&TIM1_OCInitStructure);
TIM1_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM1_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM1_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;
TIM1_OCInitStructure.TIM_Pulse = 0x505;
TIM1_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;
TIM1_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_Low;
TIM1_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Reset;
TIM1_OCInitStructure.TIM_OCNIdleState = LOW_SIDE_POLARITY;
TIM_OC1Init(TIM1, &TIM1_OCInitStructure);
TIM_OC2Init(TIM1, &TIM1_OCInitStructure);
TIM_OC3Init(TIM1, &TIM1_OCInitStructure);
GPIO_StructInit(&GPIO_InitStructure);
TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Enable);
TIM_OC2PreloadConfig(TIM1, TIM_OCPreload_Enable);
TIM_OC3PreloadConfig(TIM1, TIM_OCPreload_Enable);
TIM_OCStructInit(&TIM1_OCInitStructure);
TIM1_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;
TIM1_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM1_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Disable;
TIM1_OCInitStructure.TIM_Pulse = PWM_PERIOD-1;
TIM1_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM1_OCInitStructure.TIM_OCNPolarity =TIM_OCNPolarity_Low;
TIM1_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Reset;
TIM1_OCInitStructure.TIM_OCNIdleState = LOW_SIDE_POLARITY;
TIM_OC4Init(TIM1, &TIM1_OCInitStructure);
TIM_OC4PreloadConfig(TIM1, TIM_OCPreload_Enable);
4.刹车和死区配置
刹车可以通俗的理解为停止产生PWM波,当改变刹车位的电平时,会启动或停止PWM的产生。
死区是为了保证mos开关电路不在同一时刻导通,烧毁电路。
代码如下:
TIM1_BDTRInitStructure.TIM_OSSRState = TIM_OSSRState_Enable;
TIM1_BDTRInitStructure.TIM_OSSIState = TIM_OSSIState_Enable;
TIM1_BDTRInitStructure.TIM_LOCKLevel = TIM_LOCKLevel_1;
TIM1_BDTRInitStructure.TIM_DeadTime = DEADTIME;
TIM1_BDTRInitStructure.TIM_Break = TIM_Break_Disable;
TIM1_BDTRInitStructure.TIM_BreakPolarity = TIM_BreakPolarity_Low;
TIM1_BDTRInitStructure.TIM_AutomaticOutput = TIM_AutomaticOutput_Disable;
TIM_BDTRConfig(TIM1, &TIM1_BDTRInitStructure);
TIM_SelectOutputTrigger(TIM1, TIM_TRGOSource_Update);
TIM_ClearITPendingBit(TIM1, TIM_IT_Break);
TIM_ITConfig(TIM1, TIM_IT_Break,ENABLE);
TIM_Cmd(TIM1, ENABLE);
TIM_GenerateEvent(TIM1, TIM_EventSource_Update);
TIM_ClearFlag(TIM1, TIM_FLAG_Update);
TIM_ITConfig(TIM1, TIM_IT_Update, DISABLE);
TIM_ITConfig(TIM1, TIM_IT_CC4,DISABLE);
获取源码:公众号【程序员DeRozan】回复1207
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)