- Labornetzteil AliExpress         
Ergebnis 1 bis 8 von 8

Thema: Problem bei SingleShunt Strommessung für BLDC

Hybrid-Darstellung

Vorheriger Beitrag Vorheriger Beitrag   Nächster Beitrag Nächster Beitrag
  1. #1
    Neuer Benutzer Öfters hier
    Registriert seit
    11.04.2011
    Beiträge
    6

    Problem bei SingleShunt Strommessung für BLDC

    Hallo zusammen,

    der Beitrag ist recht lang geworden, es würde mich trotzdem freuen, wenn sich jemand die Zeit nimmt ihn zu lesen.
    Ich versuche gerade einen BLDC-Regler mit feldorientierter Regelung und
    singleshunt Strommessung aufzubauen. Allerdings stellen mich die
    Messergebnisse nicht ganz zufrieden. Vielleicht hat ja jemand Erfahrung
    damit und kann mir dabei etwas helfen. Für die Strommessung verwende ich
    einen ACS709 Hall-Effekt-Stromsensor. Im Anhang mal ein Screenshot, wie
    die Ströme aktuell aussehen.
    Klicke auf die Grafik für eine größere Ansicht

Name:	18.01.jpg
Hits:	23
Größe:	40,0 KB
ID:	29648

    Die Ströme werden zweimal pro PWM-Periode gemessen und über das
    Kirchhoffsches Gesetz der jeweils fehlende dritte Strom berechnet.
    Des Prinzip wird auch hier nochmals erklärt: http://ww1.microchip.com/downloads/e...tes/01299A.pdf
    Ich weiß nun nicht, ob der Fehler bereits in der Hardware liegt oder in meiner Software.

    Als Mikrocontroller verwende ich einen STM32F103C8.
    Timer 1 verwende ich zu PWM Erzeugung. Dieser zählt von 0 bis 2048 und
    dann wieder runter auf 0. Timer 3 läuft synchron zählt aber von 0 bis
    4095. Damit triggere ich den ADC. Dabei wird in der ISR von Timer 3 der
    neue Vergleichswert für die Zweite triggerung des ADCs geladen. In der
    ADC-ISR wird dann wieder der Wert für die erste Triggerung geladen.

    Init des Timer 3:
    Code:
    void ADC_Timer_ini()
    {
      RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
      TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
    
      TIM_TimeBaseStructure.TIM_Prescaler =  0;
    
      TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
      TIM_TimeBaseStructure.TIM_Period = 4095;
      TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
      TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
    
      TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
      TIM_UpdateRequestConfig(TIM3, TIM_UpdateSource_Global);
      TIM_UpdateDisableConfig(TIM3,DISABLE);
      TIM_Cmd(TIM3, ENABLE);
    }
    
    void ADC_Timer_Compare_ini()
    {
      TIM_OCInitTypeDef TIM_OCInitStructure;
    
      TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;
      TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
      TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;
      TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
      TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;
      TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;
      TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCIdleState_Set;
      TIM_OCInitStructure.TIM_Pulse = 2048;
      TIM_OC4Init(TIM3, &TIM_OCInitStructure);
    
      TIM_OCInitStructure.TIM_Pulse = 1024;
    
      TIM_OC1Init(TIM3, &TIM_OCInitStructure);
      TIM_OCInitStructure.TIM_Pulse = 3072;
      TIM_OC3Init(TIM3, &TIM_OCInitStructure);
      TIM_DMACmd(TIM3, TIM_DMA_CC1, ENABLE);
      TIM_DMACmd(TIM3, TIM_DMA_CC3, ENABLE);
    }
    
    void ADC_Timer_Interrupt_ini()
    {
      NVIC_InitTypeDef NVIC_InitStructure;
    
      NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn  ;
      NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
      NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
      NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
      NVIC_Init(&NVIC_InitStructure);
    
      TIM_ITConfig(TIM3, TIM_IT_CC4, ENABLE);
    }
    Ini des Timer 1:
    Code:
    void PWMTimer_ini()
    {
      RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
      TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
    
       TIM_TimeBaseStructure.TIM_Prescaler =  0;
    
      TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_CenterAligned1;
      TIM_TimeBaseStructure.TIM_Period = 2048;
      TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
      TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
    
      TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);
      TIM1->CR1 |= TIM_CR1_URS;  // Nur Over- bzw. Underflow erzeugt Update event
      TIM_UpdateRequestConfig(TIM1, TIM_UpdateSource_Regular);
      TIM_UpdateDisableConfig(TIM1,DISABLE);
      TIM_Cmd(TIM1, ENABLE);
    
      TIM_DMAConfig(TIM1, TIM_DMABase_CCR1, TIM_DMABurstLength_3Transfers);
    }
    
    void PWMChannel_ini()
    {
      TIM_OCInitTypeDef TIM_OCInitStructure;
      TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;
      TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
      TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;
      TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;
      TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_Low;
      TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;
        TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCIdleState_Set;
    
        TIM_OCInitStructure.TIM_Pulse = 0;
    
        TIM_OC1Init(TIM1, &TIM_OCInitStructure);
        TIM_OC2Init(TIM1, &TIM_OCInitStructure);
        TIM_OC3Init(TIM1, &TIM_OCInitStructure);
    
        TIM_CtrlPWMOutputs(TIM1, ENABLE);
    
        TIM1->CCMR1 |= TIM_CCMR1_OC1PE | TIM_CCMR1_OC2PE;  // Compare-Werte erst beim Update-Event übernehmen
        TIM1->CCMR2 |= TIM_CCMR2_OC3PE;            // Compare-Werte erst beim Update-Event übernehmen
    }
    ADC Ini:
    Code:
    void ADC_2_ini(void)
    {
      RCC_ADCCLKConfig(RCC_PCLK2_Div6);  // ADC Takt max 14MHz.  72MHz/6 = 12MHz
      RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC2, ENABLE);
    
      ADC_InitTypeDef ADC_InitStructure;
      ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
      ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
      ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
      ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
      ADC_InitStructure.ADC_NbrOfChannel = 1;
      ADC_InitStructure.ADC_ScanConvMode = ENABLE;
      ADC_Init(ADC2, &ADC_InitStructure);
    
      ADC_InjectedSequencerLengthConfig(ADC2, 2);
      ADC_InjectedChannelConfig(ADC2, ADC_Channel_1, 1, ADC_SampleTime_7Cycles5);
      ADC_InjectedChannelConfig(ADC2, ADC_Channel_1, 2, ADC_SampleTime_7Cycles5);
    
      ADC_InjectedDiscModeCmd(ADC2, ENABLE);
      ADC_ExternalTrigInjectedConvCmd(ADC2, ENABLE);
      ADC_ExternalTrigInjectedConvConfig(ADC2, ADC_ExternalTrigInjecConv_T3_CC4);
    
      ADC_Cmd(ADC2, ENABLE);
    
      // Starte Kalibierung
      ADC_ResetCalibration(ADC2);
      while(ADC_GetResetCalibrationStatus(ADC2));
      ADC_StartCalibration(ADC2);
      while(ADC_GetCalibrationStatus(ADC2));
    }
    
    void ADC_2_Interrupt_ini()
    {
      NVIC_InitTypeDef  NVIC_InitStructure;
      NVIC_InitStructure.NVIC_IRQChannel = ADC1_2_IRQn;
      NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
      NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
      NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
      NVIC_Init(&NVIC_InitStructure);
      ADC_ITConfig(ADC2, ADC_IT_JEOC, ENABLE);
    }
    ISR Timer 3:
    Code:
    void TIM3_IRQHandler(void)
    {
      if(TIM_GetITStatus(TIM3, TIM_IT_CC4))
      {
        GPIOB->ODR ^= GPIO_Pin_6;
        TIM_ClearITPendingBit(TIM3, TIM_IT_CC4);
        TIM3->CCR4 =  pwm_aktuell.adc_comp.adc_triggerung_2;
      }
    }
    ISR ADC:
    Code:
    void ADC1_2_IRQHandler(void)
    {
      ADC_ClearITPendingBit(ADC2, ADC_IT_JEOC);
    
    
      ADC_Strom_1 = ADC_GetInjectedConversionValue(ADC2, ADC_InjectedChannel_1);
      ADC_Strom_2 = ADC_GetInjectedConversionValue(ADC2, ADC_InjectedChannel_2);
    
      TIM3->CCR4 =  pwm_aktuell.adc_comp.adc_triggerung_1;
      flags |= adc_messung_fertig;
    
      strom_auswerten();
    }
    Funktion zum Auswerten der Strommesswerte:
    Code:
    void strom_auswerten(void)
    {
      ACS_ref = gleitender_mittelwert(ACS_ref, ADCBuffer[0], 3);
    
      ADC_Strom_1 -= ACS_ref + ACS_0_Strom_offset;
        ADC_Strom_2 -= ACS_ref + ACS_0_Strom_offset;
    
        ADC_Strom_1 = ADC_Strom_1 << 3;
        ADC_Strom_2 = ADC_Strom_2 << 3;
    
      if(flags & erste_adc_messung )
              {
                flags &= ~erste_adc_messung;
                flags &= ~adc_messung_fertig;
              }
              else
              {
                flags &= ~adc_messung_fertig;
    
                if(counter==2)
                {
                if(array_counter==2000)
                {
                  asm("nop");
                }
                else
                {
                    counter = 0;
                  I_U_array[array_counter] = I_U_flt;//I_U_flt;
                  I_V_array[array_counter] = I_V_flt;//I_V_flt;
                  I_W_array[array_counter] = I_W_flt;
    
                  //I_U_array[array_counter] = ADC_Strom_1;//I_U_flt;
                  //I_V_array[array_counter] = - ADC_Strom_2;//I_V_flt;
                  //I_W_array[array_counter] = -ADC_Strom_1 + ADC_Strom_2;
    
                  teta_array[array_counter++] = teta;
                }
                }
                else
                {
                  counter += 1;
                }
    
                 switch (sektor)
                    {
                    case 1:  // 0- 60°
                    {
                      I_W_raw = - ADC_Strom_2;
                      I_V_raw = ADC_Strom_1;
                      I_U_raw = - I_V_raw - I_W_raw;
                      break;
                    }
                    case 2:  // 60-120°
                    {
                      I_U_raw = -ADC_Strom_2;
                      I_W_raw = ADC_Strom_1;
                      I_V_raw = (- I_W_raw - I_U_raw);
                      break;
                    }
                    case 3:  // 120-180°
                    {
                        I_U_raw = - ADC_Strom_2;
                        I_W_raw = ADC_Strom_1;
                      I_V_raw = - I_U_raw - I_W_raw;
                      break;
                    }
                    case 4:  //180-240°
                    {
                      I_U_raw = ADC_Strom_1;
                      I_W_raw = - ADC_Strom_2;
                      I_V_raw = - I_W_raw - I_U_raw;
                      break;
                    }
                    case 5:  //240-300°
                    {
                      I_U_raw = ADC_Strom_1; 
                      I_W_raw = - ADC_Strom_2;
                      I_V_raw = - I_W_raw - I_U_raw;
                      break;
                    }
                    case 6:  //300-360°
                    {
                      I_V_raw = ADC_Strom_1;
                      I_W_raw = - ADC_Strom_2;
                      I_U_raw = - I_V_raw - I_W_raw;
                      break;
                    }
                    default: break;
                  }
              }
    
         I_U_flt = gleitender_mittelwert(I_U_flt, I_U_raw, filter_gewichtung_strom);
      I_V_flt = gleitender_mittelwert(I_V_flt, I_V_raw, filter_gewichtung_strom);
      I_W_flt = gleitender_mittelwert(I_W_flt, I_W_raw, filter_gewichtung_strom);
      return;
    }
    Ich habe nun echt schon viel versucht und gemessen. Wenn ich zum Beispiel nur einen Wechselstrom durch den Hall-Sensor schicken, wird dieser auch korrekt gemessen:
    Klicke auf die Grafik für eine größere Ansicht

Name:	16.01.jpg
Hits:	6
Größe:	29,0 KB
ID:	29649
    Nur die Messung in Kombination mit dem SVPWM Modul funktioniert überhaupt nicht Mir fällt nichts mehr ein was ich noch versuchen kann. Deshalb wäre ich über eure Hilfe sehr dankbar.

    Viele Grüße und vielen Dank im Voraus Michael

  2. #2
    Erfahrener Benutzer Roboter-Spezialist
    Registriert seit
    06.08.2008
    Ort
    Graz
    Beiträge
    521
    2 Ideen:
    1) Sind die Timer immer synchron, oder driften sie auseinander?
    2) Der Hallsensor wird durch den Motor und dessen Magnetfeld gestört.

    LG!
    alles über meinen Rasenmäherroboter (wer Tippfehler findet darf sie gedanklich ausbessern, nur für besonders kreative Fehler behalte ich mir ein Copyright vor.)

  3. #3
    Neuer Benutzer Öfters hier
    Registriert seit
    11.04.2011
    Beiträge
    6
    Hallo,

    zuerst danke für die Antwort.
    Zu 1. ich habe das getestet in dem ich mit beiden Timern ein PWM erzeugt habe und die Ausgänge mit dem Oszi gemessen habe. Diese sind synchron und driften auch nicht.
    Zu 2. Der Sensor ist recht weit Entfernt vom Motor, deshalb kann ich mir das nicht so recht vorstellen.

    Viele Grüße Michael

  4. #4
    shedepe
    Gast
    Hey mit welcher Frequenz läuft deine PWM ?
    http://www.allegromicro.com/~/media/...Datasheet.ashx

    Nachdem Datenblatt ist die maximale ungedämpfte Frequenz die damit gemessen werden kann 120 kHz. Je nach Kondensator zwischen dem Filter Pin und GND kann das auch erheblich weniger sein.

    Ich würde vorschlagen du misst testweise mal mit einem herkömmlichen Messshunt. Damit kannst du deinen Quellcode überprüfen und Fehler die durch den Stromsensor entstehen ausschließen.

  5. #5
    Neuer Benutzer Öfters hier
    Registriert seit
    11.04.2011
    Beiträge
    6
    Hallo,

    mein PWM läuft mit 17,6kHz. Ich habe auch schon mit einem Shunt getestet. Dies kann ich aber mit dem aktuellen Code nochmals versuchen.

    Viele Grüße Michael

    EDIT: Ich habe nun nochmal mit dem ACS709 und einem Shunt gemessen. Sieht leider beides gleich schlecht aus :/
    Klicke auf die Grafik für eine größere Ansicht

Name:	ACS_709.jpg
Hits:	12
Größe:	36,1 KB
ID:	29655Klicke auf die Grafik für eine größere Ansicht

Name:	Shunt.jpg
Hits:	10
Größe:	34,0 KB
ID:	29656

    Viele Grüße Michael
    Geändert von EOS400DMAN (24.01.2015 um 15:23 Uhr)

  6. #6
    shedepe
    Gast
    Könntest du zu dem Diagramm bitte die Beschriftung noch mal extra dazu schreiben. Die ist leider so klein geworden, dass man sie kaum lesen kann.
    Zu den Messwerten. Wenn ich grade keinen Denkfehler drin habe würde ich die Messwerte so als realistisch einschätzen. Es wird nacheinander ein Stromfluss durch die einzelnen Motorspulen festgestellt der auch umgetastet worden ist.

Ähnliche Themen

  1. Tiefpass bei Strommessung
    Von .:markus:. im Forum Elektronik
    Antworten: 5
    Letzter Beitrag: 15.12.2010, 17:34
  2. Antworten: 13
    Letzter Beitrag: 27.08.2010, 21:59
  3. Problem bei Strommessung/Temperaturdrift
    Von ssalbach im Forum Sensoren / Sensorik
    Antworten: 12
    Letzter Beitrag: 11.06.2009, 14:20
  4. Antworten: 26
    Letzter Beitrag: 30.07.2008, 17:45
  5. Antworten: 13
    Letzter Beitrag: 27.05.2008, 11:41

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •  

fchao-Sinus-Wechselrichter AliExpress