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
Hi Urban, könntest du es fixen indem du den pending interrupt in der ISR löschst?
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
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
Hier: http://www.digchip.com/datasheets/parts/datasheet/232/IRF1205-pdf.php steht, deine MOSFETs halten bis zu 20V Gatespannung aus. LG, Björn
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
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
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.