Forum: Mikrocontroller und Digitale Elektronik Hilfe beim MPPT.


von Robert M. (andro86)


Angehängte Dateien:

Lesenswert?

Hallo zusammen, ich benötige eure Hilfe bei meinem MPPT. Ich soll einen 
MPPT mittels SEPIC-Wandler Topologie (Topologie ist vorgegeben) für 
einen Thermogenerator bauen mit dem eine Batterie geladen werden soll. 
Im Anhang ist der dazu entworfene Schaltplan. Dabei habe ich L1 und L2 
auf einen gemeinsamen Eisenpulver Ringkern gewickelt.
Für den MPPT Algorithmus benutze ich die Methode der steigenden 
Konduktanz (Incremental Conductance). Der entsprechende µC Code folgt.
1
/***********************************************************************************************
2
 * MPPTAlgorithmus.c
3
 * 
4
 * Used µC       : ATmega32U4 
5
 * Compiler      : AVR Studio 6.1 
6
 * Configuration : External oscillator with 16 MHz.
7
 **********************************************************************************************/
8
  
9
   
10
/***********************************************************************************************
11
************************************* Adjusted Fuse-Bits ***************************************
12
***********************************************************************************************/  
13
 
14
/*
15
  Notice: [x] means programmed (enabled or 0), while [] means unprogrammed (diasabled or 1)!
16
17
  BODLEVEL  [4V3]
18
  HWBE    [x]
19
  OCDEN    []
20
  JTAGEN    []  ...  need to be disabled because of the ADC pins
21
  SPIEN    [x]  ... never disable this fuse otherwise the µC becomes not programmable!!!
22
  WDTON    []
23
  EESAVE    []
24
  BOOTSZ    [2048W_3800]
25
  BOOTRST    []
26
  CKDIV8    []  ... [x] => clock prescaler = 8:  [] => clock prescaler = 1.
27
  CKOUT    []
28
  SUT_CKSEL  [EXTXOSC_8MHz_XX_258CK_65MS]
29
30
*/
31
  
32
33
/***********************************************************************************************
34
**************************************** Header-files ******************************************
35
***********************************************************************************************/
36
37
// <avr/io.h> integrates all the necessary PORT and register names.
38
#include <avr/io.h>
39
//<util/delay.h> Header file with summary of waiting functions.
40
#include <util/delay.h>
41
//<stdint.h> Integer types with predefined width such as uint8_t or int16_t.
42
#include <stdint.h>
43
44
45
/***********************************************************************************************
46
************************************ Variable Definition ***************************************
47
************************************       Global        ***************************************
48
***********************************************************************************************/
49
50
51
volatile int8_t duty_cycle = 127;
52
53
/***********************************************************************************************
54
********************************  Declaration of functions  ************************************  
55
********************************       "Function head"      ************************************
56
***********************************************************************************************/
57
58
  void ADC_Initialization(void);
59
  
60
  void Set_DutyCycle(uint8_t duty_cycle);
61
  
62
  uint32_t ADC_Read_Value(uint8_t pin_channel);
63
  
64
  uint32_t ADC_Read_AvarageValue(uint8_t pin_channel, uint8_t samples);
65
  
66
67
/***********************************************************************************************
68
**************************************** Main Routine ******************************************
69
***********************************************************************************************/
70
  
71
int main(void)
72
{
73
74
  
75
  int32_t u_in = 0;
76
  int32_t i_in = 0;
77
  
78
  int32_t u_in_previous = 0;
79
  int32_t i_in_previous = 0;
80
  
81
  int32_t delta_u_in = 0;
82
  int32_t delta_i_in = 0;
83
  
84
    // set Pin F4-7 as Input (ADC Input Channels).
85
  DDRF &= ~((1<<DDF4)|(1<<DDF5)|(1<<DDF6)|(1<<DDF7));
86
    // deactivate Pull-Up Resistor on Pin F4-7.
87
  PORTF &= ~((1<<PF4)|(1<<PF5)|(1<<PF6)|(1<<PF7));
88
89
/***********************************************************************************************
90
*************************************** Timer/Counter ******************************************
91
*************************************** PWM-generator ******************************************
92
***********************************************************************************************/  
93
                                                         
94
    TCCR0A|=(1<<WGM01)|(1<<WGM00); // Setting fast-PWM mode.                        
95
     TCCR0A|=(1<<COM0A1);       /* OC0A become low at a match and high at top.*/
96
97
                                                                                           
98
       // PWM-frequency = timer clock/(Prescaler * 256)= 16 MHz/(1*256) = 62.5 kHz 
99
  TCCR0B|=(1<<CS00);        // Prescaler = 1. Datasheet Page 105.
100
     TCCR0B &=~(1<<WGM02);      // TCNT0 run continuous after match until TOP reaches.                                     
101
                                                                                                                                                           
102
     Set_DutyCycle(duty_cycle);    // Clock ratio/ trigger the PWM.                                                      
103
                                                                                      
104
    DDRB|=(1<<PB7);    // Set Pin P7 for OC0A as output.        
105
106
/***********************************************************************************************
107
*************************************** Initialize ADC *****************************************
108
***********************************************************************************************/  
109
  
110
  ADC_Initialization();
111
  
112
/***********************************************************************************************
113
***************************************** While Loop *******************************************
114
************************************************************************************************/
115
116
    while(1)
117
    {
118
    _delay_ms(2);
119
    
120
      //Sampling the current and voltage values
121
    u_in = ADC_Read_AvarageValue(4,10);
122
    i_in = ADC_Read_AvarageValue(5,10);
123
   
124
/***********************************************************************************************
125
********************************** Incremental Conductance  ************************************  
126
**********************************        Algorithm         ************************************
127
***********************************************************************************************/       
128
        
129
      delta_u_in = u_in-u_in_previous;
130
      delta_i_in = i_in-i_in_previous;
131
     
132
      if(delta_u_in == 0 )
133
      {//Yes branch delta_u_in == 0
134
        
135
        if(delta_i_in == 0)
136
        { 
137
          // Yes branch do nothing. MPP is found.
138
                            
139
        }
140
        else // No branch delta_i_in == 0
141
        { 
142
          if(delta_i_in > 0)
143
          {
144
            -- duty_cycle;
145
          }
146
          else
147
          {
148
            if(delta_i_in < 0)
149
            {          
150
              ++ duty_cycle;
151
            }            
152
          }                           
153
        }            
154
      }
155
      else // No branch delta_u_in == 0
156
      {
157
        if((1000*delta_i_in)/delta_u_in == - (1000*i_in)/u_in)
158
        {
159
          // Yes branch do nothing. MPP is found.
160
        }
161
        else // No branch delta_i_in/delta_u_in == - i_in/u_in.
162
        {
163
          if((1000*delta_i_in)/delta_u_in > - (1000*i_in)/u_in)
164
          {
165
            -- duty_cycle;
166
          }
167
          else
168
          {
169
            if((1000*delta_i_in)/delta_u_in < - (1000*i_in)/u_in)
170
            {
171
              ++ duty_cycle;
172
            }            
173
          }                
174
        }          
175
      }
176
     
177
      u_in_previous = u_in;
178
      i_in_previous = i_in;
179
      
180
      
181
      Set_DutyCycle(duty_cycle);
182
  }
183
}
184
/***********************************************************************************************
185
******************************* Definition of the functions  ***********************************  
186
*******************************       "Functionbody"         ***********************************
187
************************************************************************************************/      
188
189
  void ADC_Initialization(void)
190
  {
191
    ADMUX|=(1<<REFS0);              // Set reference voltage to AVcc.
192
193
    ADCSRA|=(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0);  // Set prescaler to 128.
194
    ADCSRA|=(1<<ADEN);              // Activate converter.
195
      //AD conversion is started
196
    ADCSRA|=(1<<ADSC);    
197
    while (ADCSRA & (1<<ADSC) )        // Wait for completion of the conversion.
198
    {  
199
     }
200
     /* ADCW must be read once, otherwise the result of the next conversion is not 
201
        taken. */
202
    (void) ADCW;    
203
  
204
  }    
205
  
206
  uint32_t ADC_Read_AvarageValue(uint8_t pin_channel, uint8_t samples)
207
  {
208
    uint32_t sum = 0;
209
      
210
    for (uint8_t i = 0; i < samples; ++i ) 
211
    {
212
      sum += ADC_Read_Value( pin_channel );
213
    }  
214
    
215
    return ( sum / samples );
216
  }  
217
  
218
  uint32_t ADC_Read_Value(uint8_t pin_channel)
219
  {
220
    ADMUX = (ADMUX & ~(0x1F)) | (pin_channel & 0x1F);
221
    ADCSRA |= (1<<ADSC);          // one Conversion "single conversion"
222
    while (ADCSRA & (1<<ADSC) ) 
223
    {                    // Wait for completion of the conversion
224
    }
225
    return ADCW;
226
  }
227
  
228
  void Set_DutyCycle(uint8_t duty_cycle)
229
  {
230
      OCR0A =  duty_cycle;  
231
  }

Meinen MPPT sollte ich ursprünglich am Thermogenerator selber testen, 
doch es gab einige Komplikationen und somit bin ich auf 2 Netzteile 
umgestiegen. Eingangsseitig habe ich den TEG durch ein Leistungsnetzteil 
ersetzt, das mir eine Spannung im Bereich von 1-10 V und einen Srom von 
0.1 - 1 A liefert. Ausgangsseitig habe ich als Batterieersatzt ein 
weiteres Netzteil an die U_Out Klemmen geschaltet, das schon einige Watt 
Leistung aufnehmen kann und mir immer konstante 12 V liefert. Dieser 
ganze Messaufbau dient einzig und allein dazu um zu testen, ob mein 
gebauter MPPT vom Prinzip her funktioniert. Den Wandler betreibe ich mit 
einer Schaltfrequenz von 62.5 kHz.
Was oben im Schaltplan nicht zu sehen ist, ist ein zusätzlicher 
Widerstand in Reihe geschaltet zwischen eingangsseitigem 
Leistungsnetzteil und Eingang SEPIC Wandler. Er soll den internen 
Widerstaden des TEG darstellen und hat einen Wert von 1.5 Ohm. Ich hab 
diesen hier gewählt, weil das der niedrigste Wert war, den ich hier 
finden konnte, der zudem auch noch einpaar Watt Leistung verträgt.

Zur Theorie: Wenn mein Tracker den MPP gefunden hat, so müsste sich am 
Eingang meines Wandlers doch die halbe Leerlaufspannung meines 
Leistungsnetzteiles einstellen oder nicht? Genau dann hab ich doch meine 
Widerstandsanpassung und kann die größte Leistung entnehmen?

Zur Praxis: Mein Tracker verhält sich total chaotisch und macht nicht 
wirklich das was er machen soll. Mal schwingt sich die Eingangsspannung 
des Wandlers auf keinen Wert ein und wenn doch, dann liegt er um etwa 
0.5 bis 0.7 V unter der errechneten MPP Spannung. Und selbst dann bleibt 
er nicht immer auf diesen Wert, sondern fängt nach einer Zeit wieder an 
zu schwingen.
Ich bin auch mal mit der Schaltfrequenz runter auf 7 kHz gegangen und da 
schien es besser zu funktionieren. Der MPP wurde für kleinere Spannungen 
getroffen, doch je höher ich mit der Netzteilspannung ging, desto weiter 
lief der Arbeitspunkt dem MPP davon.

Ich weis gerade nicht wie ich das zum laufen bringen könnte, von daher 
wäre ich über jede Anregung und Hilfestellung dankbar.

von MaWin (Gast)


Lesenswert?

> Wenn mein Tracker den MPP gefunden hat, so müsste sich am
> Eingang meines Wandlers doch die halbe Leerlaufspannung meines
> Leistungsnetzteiles einstellen oder nicht

Nö, Leerlaufspannung und Belastungsspannung eines Netzteils sind nahezu 
identisch.

>  Genau dann hab ich doch meine Widerstandsanpassung

Dazu musst du erst zwischen Netzteilausgang udn Wandlereingang einen 
Leistungsiwderstand schalten, um den Innenwiderstand des Netzteils 
künstlich zu erhöhen.

von MaWin (Gast)


Lesenswert?

> Was oben im Schaltplan nicht zu sehen ist, ist ein zusätzlicher
> Widerstand in Reihe geschaltet zwischen eingangsseitigem
> Leistungsnetzteil und Eingang SEPIC Wandler

Aha, und Elkos davor und dahinter (nach Masse) ?

von Robert M. (andro86)


Lesenswert?

MaWin schrieb:
>> Wenn mein Tracker den MPP gefunden hat, so müsste sich am
>> Eingang meines Wandlers doch die halbe Leerlaufspannung meines
>> Leistungsnetzteiles einstellen oder nicht
>
> Nö, Leerlaufspannung und Belastungsspannung eines Netzteils sind nahezu
> identisch.
>
>>  Genau dann hab ich doch meine Widerstandsanpassung
>
> Dazu musst du erst zwischen Netzteilausgang udn Wandlereingang einen
> Leistungsiwderstand schalten, um den Innenwiderstand des Netzteils
> künstlich zu erhöhen.

Genau dazu habe ich ja meinen 1.5 Ohm Widerstand dorthin geschaltet. Es 
sieht wie folgt aus:

Leistungsnetzteil----Leistungswiderstand----Wandler.

: Bearbeitet durch User
von MaWin (Gast)


Lesenswert?

Bei 10V/1A Netzteil liegt der MPP am 1.5 Ohm Widerstand doch bei vollem 
Strom, also 1A, also wird der MPP mit der Strombegrenzung des Netzteils 
kollidieren. Mindestens 5 Ohm wären wohl nötig.

von Robert M. (andro86)


Lesenswert?

MaWin schrieb:
> Bei 10V/1A Netzteil liegt der MPP am 1.5 Ohm Widerstand doch bei vollem
> Strom, also 1A, also wird der MPP mit der Strombegrenzung des Netzteils
> kollidieren. Mindestens 5 Ohm wären wohl nötig.

Der würde auch schon bei 3 V in die Begrenzung gehen, wenn sich mein 
Wandlerwiderstand den 1.5 Ohm anpassen würde. Fakt ist jedoch, ich kann 
mit der Spannung schon bis 8 V hoch gehen und ich komme damit nicht 
wirklich oft in die Begrenzung des Netzteiles. Und jetzt weis ich nicht, 
ob es an meiner Leistungselektronik, an meinem Code oder an Beidem 
liegt.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.