Forum: Mikrocontroller und Digitale Elektronik Brushless-Regler: Umschaltung Analog Komparator <-> ADC


von Gelöscht (kami89)


Angehängte Dateien:

Lesenswert?

Hallo zusammen,

Ich bin dabei, einen Regler zu bauen um Brushless-Motoren aus dem 
Modellbaubereich anzusteuern. Die Hardware habe ich, nun bin ich noch an 
der Software dran.

Verwendet wird ein ATMega168 mit 16MHz Quarz. Schema im Anhang. Kleiner 
Hinweis: IN_A, IN_B und IN_C kann ich auf Eingang schalten, damit das 
PWM-Signal auf die Treiber geleitet wird.

Für die Kommutierung verwende ich das altbekannte Prinzip, bei dem die 
offene Phase mit der Sternpunktspannung mit dem internen Komparator 
verglichen, und bei jedem Interrupt die nächste Kommutierung ausgelöst 
wird (BEMF). Das funktioniert eigentlich genau so wie es soll (s. 
Anhang).

Nun aber zum Problem:
Nebenbei soll auch noch der Strom gemessen werden, bzw. die Spannung 
über dem Shunt. Da aber der ADC blockiert ist, während dem der Analog 
Komparator auf die ADC-Eingänge konfiguriert ist, muss das ganze voll 
kontrolliert ablaufen. Ich dachte mir, dass man direkt nach jeder 
Kommutierung den Komparator abschaltet, und per ADC den Strom misst. 
Danach kann dann wieder auf den Komparator geschaltet werden. Bei 
Vollgas liegen zwischen zwei Kommutierungen ca. 160 Mikrosekunden. Das 
sind etwa 2600 Takte, das müsste doch locker genügen für eine 
A/D-Wandlung, oder?

Dann sollte man den Strom aber auch noch zu einem definierten Zeitpunkt 
messen, am besten genau in der Mitte eines Positiven Pulses vom PWM. Nur 
so erreicht man verwertbare Ergebnisse. Dieser Zeitpunkt entspricht 
übrigens dem Overflow-Ereignis vom Timer 1.

Meine Idee war dann halt, nach jeder Kommutierung den ADC auf 
Interruptbetrieb zu schalten, und als "Trigger Source" den Overflow von 
Timer 1 zu definieren (ADTS0..2 in ADCSRB). Im Interrupt vom ADC erfolgt 
dann das Auslesen vom Analogwert, und schliesslich das Wiederaktivieren 
vom Komparator.

Leider funktioniert das nicht so wie es soll. Es erfolgen immer zwei 
Kommutierungen direkt nacheinander, was wohl darauf hindeutet, dass der 
Komparator-Interrupt einmal zu viel aufgerufen wird (s. Anhang).

Ich habe schon alles mögliche versucht, auch mal vor jedem Umschalten AC 
<-> ADC ein cli() und nach dem Umschalten ein sei() auszuführen, brachte 
aber auch keine Änderung.

Mache ich irgendwo einen grundlegenden Fehler? Vom Timing her sollte das 
schon hinkommen, oder?

Ich wäre wirklich extrem froh wenn mir jemand helfen kann, habe schon 
etliche Stunden mit der Fehlersuche verbracht, aber gebracht hats 
nichts.

Wenn ihr mehr Infos braucht, einfach nachfragen. Den Code habe ich extra 
nochmals komplett durchkommentiert, damit das einigermassen 
nachvollziehbar wird ;-)

Die grüne Kurve auf den Oszibildern ist der Ausgang von LED1.

Gruss Urban

von Gelöscht (kami89)


Angehängte Dateien:

Lesenswert?

...Sourcecode vergessen anzuhängen ;-)

von Anon Y. (avion23)


Lesenswert?

Hi Urban,
könntest du es fixen indem du den pending interrupt in der ISR löschst?

von Gelöscht (kami89)


Lesenswert?

Hallo Anon,
Das bringt leider auch nichts, das habe ich bereits probiert...

Übrigens, weiss vielleicht gerade jemand ob man Logic Level FETs auch am 
IR2104 mit 14V betreiben darf? Bis jetzt funktioniert das wunderbar, 
aber ich bin mir nicht so ganz sicher ob die FETs das auch dauerhaft 
aushalten?!

mfg

von Java 6 Programmier­handbuch (Gast)


Lesenswert?

Bei der Frage sollte ein Blick ins Datenblatt des MOSFETS klärend 
wirken. Da muss unter absolute Maximum ratings (oder so) eine Zeile U_GS 
oder V_GS (max) sein, wo die obere Grenze drinsteht.

LG, Björn

von Java 6 Programmier­handbuch (Gast)


Lesenswert?

Hier: 
http://www.digchip.com/datasheets/parts/datasheet/232/IRF1205-pdf.php
steht, deine MOSFETs halten bis zu 20V Gatespannung aus.

LG, Björn

von Gelöscht (kami89)


Lesenswert?

OK Danke Björn, ich wusste eben nicht ob man die Mosfets auch wirklich 
mit der unter "Maximum Ratings" deklarierten Spannung dauerhaft 
betreiben darf.
Übrigens habe ich jetzt dank dir gerade noch gemerkt, dass ich im Schema 
die falschen Mosfets drin habe, verbaut sind nämlich IRLR7843 :-)

mfg

von Stefan (Gast)


Lesenswert?

Hallo,

hast du das Problem mittlerweile gelöst (ist ja schon ein Jahr her)?
Ich stehe nämlich genau vor dem gleichen Problem.

Vieleicht hat jemand noch einen Tipp für mich....


Und zwar wenn ich in der ISR des Analog-Komparators die ADC-Wandlung 
starte und den Interrupt für den ADC freigebe wird die Wandlung auch 
durchgeführt und die ISR des ADC wird aufgerufen, jedoch läuft dann das 
Programm stockend. Es macht den Anschein als würde es hängen oder irgend 
etwas verschlucken durch die nach einander ausgeführten ISR´s....hier 
mal der Quelltext dazu...
1
ISR (ANA_COMP_vect) 
2
{
3
  next_commutate_state (0);
4
    
5
  ACSR &= ~(1<<ACIE);                        //Analogkomparator aus
6
7
  ADCSRA |= (1<<ADEN) | (1<<ADSC);           //ADC ein und starten
8
}
9
10
11
ISR(ADC_vect)
12
{
13
  motorstrom = ADCL;
14
    
15
  ADCSRA &= ~(1<<ADEN);
16
17
  ACSR |= (1<<ACIE); 
18
}

Wenn ich allerdings in der ISR des Analogkomparators warte bis die 
ADC-Wandlung abgeschlossen ist, d.h. den ADC ohne Interrupt laufen 
lassen funktioniert alles wunderbar....
1
ISR (ANA_COMP_vect) 
2
{  
3
  next_commutate_state (0);
4
5
  ADCSRA |= (1<<ADEN) | (1<<ADSC);
6
  while (ADCSRA & (1<<ADSC) );
7
  ADCSRA &= ~(1<<ADEN); 
8
}


Ist nicht möglich den ADC und AC Interruptgesteuert laufen zu lassen? 
oder gibt es nur einen Trick wie man das Problem lösen könnte?

Grüße und danke für eure Hilfe

von Gelöscht (kami89)


Lesenswert?

Hallo!

Stefan schrieb:
> hast du das Problem mittlerweile gelöst (ist ja schon ein Jahr her)?

Ja, das ursprüngliche Problem konnte ich noch lösen. Wenn ich mich 
richtig erinnere lag es (peinlicherweise) an einem logischen UND (&&), 
das eigentlich ein binäres UND (&) hätte sein müssen ;-)

Stefan schrieb:
> Ist nicht möglich den ADC und AC Interruptgesteuert laufen zu lassen?
> oder gibt es nur einen Trick wie man das Problem lösen könnte?

Also ich hatte damals das Gefühl dass die Reihenfolge der Befehle eine 
Rolle spielt, auch wenn man es nicht erwarten würde. Ich bin 
schlussendlich hauptsächlich durch sehr sehr viel Ausprobieren zum Ziel 
gekommen.

Ich kann dir ja mal Stücke aus meinem Code geben. Dass alles so 
funktioniert kann ich allerdings nicht garantieren, da ich den Code 
angefangen habe auf timergesteuerte Kommutierung (einstellbarer 
Kommutierungswinkel) umzubauen, dann das Projekt aber liegen gelassen 
habe.

Also direkt nach einer Kommutierung wird zuerst der AC deaktiviert...
1
ACSR &= ~(1 << ACIE); // Analog Comparator Interrupt deaktivieren

...und dann der ADC mit dieser Funktion aktiviert:
1
void set_adc(uint8_t adc_channel, bool_t pwm_triggered)
2
{
3
  ADMUX = (ADMUX & (0xE0)) | // MUX0 bis MUX3 löschen
4
      (adc_channel & 0x0F) | // ADC-Kanal für Vergleich wählen
5
      (1 << ADLAR); // Linksbündig, um 8-Bit auszulesen
6
7
  if (pwm_triggered)
8
  {
9
    // Wird immer in der Mitte des PWM-On-Signals gemessen
10
    ADCSRB = (1 << ADTS1) | (1 << ADTS2); // Timer1 Overflow (PWM Top) als Trigger
11
    ADCSRB |= (1 << ACME); // Analog Comparator Multiplexer Enable
12
  }
13
  else
14
  {
15
    // Free Running Mode
16
    ADCSRB = 0x00; // Free Running Mode, Multiplexer disabled
17
  }
18
19
  ADCSRA = (1 << ADEN) | // ACD Enable
20
      (1 << ADSC) | // ADC Start Conversation
21
      (1 << ADATE) | // ADC Auto Trigger Enable
22
      (1 << ADIF) | // ADC Interrupt Flag löschen
23
      (1 << ADIE) | // ADC Interrupt Enable
24
      (1 << ADPS2); // ADC Prescaler 16
25
}

Nach der ADC Wandlung (in der ISR) wird der Komparator wieder aktiviert:
1
void set_analog_comparator(uint8_t compare_adc_channel)
2
{
3
  ADCSRA = (1 << ADIF); // ADC Interrupt Flag löschen und ADC deaktivieren, AC ist nun aktiv
4
5
  ADMUX = (ADMUX & (0xE0)) | // MUX0 bis MUX3 löschen
6
      (compare_adc_channel & 0x0F); // ADC-Kanal für Vergleich wählen
7
8
  ACSR |= (1 << ACIE); // Analog Comparator Interrupt Enable
9
  ACSR |= (1 << ACI); // Analog Comparator Interrupt Flag löschen
10
}

Vielleicht kannst du damit ja was anfangen ;-)

mfg

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.