Forum: Mikrocontroller und Digitale Elektronik Probleme Leistungssteuerung mit UART und AVR


von Yll K. (yllias)


Angehängte Dateien:

Lesenswert?

Guten Tag,

ich arbeite im Rahmen eines Projekts an einer Leistungssteuerung mit dem 
ATMega 644p, die Signale für das Schalten von Solid State Relais 
generieren soll. Die Leistung soll von 0-100% in 1% Schritten 
eingestellt werden. Zwei Kanäle sind dabei einphasig, der dritte Kanal 
ist für Drehstrom.

Mein Programm ist so aufgebaut, dass der Nulldurchgang der Netzspannung 
den Interrupt 0 auslöst, in dessen ISR ein Counter hochgezählt wird. In 
der Main wird der Counter dazu benutzt, ein Signal für die 
Paketsteuerung zu generieren. Je nach Konfiguration wird in der Main 
zwischen verschiedenen Modi gewechselt werden (Phasenanschnitt, 
Paketsteuerung etc.).

Im Anhang findet ihr meinen Code, bei Fragen bitte einfach schreiben.

Für den Phasenanschnitt habe ich den Timer0 initialisiert, der jede 50us 
einen Overflow Interrupt auslöst, in dessen ISR wiederum ein Counter 
hochgezählt wird. Beim Nulldurchgang wird der Counter zurückgesetzt. Mit 
diesem Counter und einigen Arrays, wo Werte für die jeweiligen 
Zündwinkel stehen, wird der Phasenanschnitt generiert.

Alle zwei Sekunden (also wenn der Interruptcounter bei 200 ist), wird 
über UART eine Nachricht an den PC gesendet, der dann einen Steuerstring 
zurücksendet, der den gewünschten Modus und die Prozentwerte der 
einzelnen Kanäle enthält (sieht dann z.B. so aus: "3-50-90-10#"). Der 
String löst den UART_Receive Interrupt aus, wo die einzelnen Zeichen 
ausgelesen werden und in der Main dann zusammengefügt und gleich 
zerteilt und den Steuervariablen für Modus etc. zugeordnet werden.

Nun habe ich folgende Fragen bzw. Probleme:
1. Gibt es eine bessere Lösung für den Phasenanschnitt außer den Timer 
mit festgelegter Zeit? Die gewünschten Zeiten sind leichter nicht sehr 
konstant, da der Counter zur Zeit des Vergleichs in der main manchmal 
einen Schritt zu weit oben oder zu weit unten ist.

2. Da alle 2 Sekunden eine Zeichenkette mit UART eingelesen wird, gibt 
es Probleme mit dem Phasenanschnitt, wo manche Netzperioden einfach 
verloren gehen. Generell sind die Signale zu dieser Zeit nicht ganz 
richtig (siehe Screenshot 1: Die Periode wo neue Werte gelesen werden, 
ist nicht richtig. Screenshot 2: Beim Anfang einer 2 Sekunden Periode 
ist das Signal bei der Paketsteuerung kurz high, dann low, dann wieder 
high, obwohl es die ganze Zeit high sein sollte).

Eine Minimierung des Schadens könnte ich dadurch erreichen, dass ich nur 
einen String vom PC zurückschicke, wenn ich dort die Werte verändere. 
Das Problem dabei ist, dass die Variablen dann für eine Periode geändert 
werden, in der nächsten Periode aber auf die alten Werte zurückkehren. 
Aus unerklärlichen Gründen MUSS ich deshalb alle 2 Sekunden wieder neue 
Werte anfordern, da sie sonst wieder auf die alten Werte springen. Alle 
Variablen sind volatile.

Ich weiß, dass das ein ziemlich umfangreiches Problem ist, aber ich 
würde mich sehr freuen, falls jemand einen Vorschlag hat.

LG

EDIT: Relais zur Solid state relais geändert

: Bearbeitet durch User
von c-hater (Gast)


Lesenswert?

Yll K. schrieb:

> ich arbeite im Rahmen eines Projekts an einer Leistungssteuerung mit dem
> ATMega 644p, die Signale für das Schalten von Relais generieren soll.
> Die Leistung soll von 0-100% in 1% Schritten eingestellt werden. Zwei
> Kanäle sind dabei einphasig, der dritte Kanal ist für Drehstrom.

Leistungsteuerung mit Relais? Was soll das denn für ein Bullshit sein?

> Mein Programm ist so aufgebaut
[...]

Wenn's zeitkritisch wird, musst du Sprachen verwenden, bei denen du 
exaktes Timing explizit erzwingen kannst. C gehört nicht dazu, denn das 
kann nur "so schnell wie möglich" und das ist gerade bei Verteilung der 
Aufgaben auf mehrere ISRs und main() leider obendrein noch sehr viel 
langsamer als es tatsächlich möglich wäre...

Asm rules.

von my2ct (Gast)


Lesenswert?

c-hater schrieb:
> Leistungsteuerung mit Relais?

Yll K. schrieb:
> ... Solid State Relais

von Yll K. (yllias)


Lesenswert?

c-hater schrieb:
> Leistungsteuerung mit Relais? Was soll das denn für ein Bullshit sein?

Meinte natürlich Solid State Relais, habs jetzt geändert. Bin zwar nur 
für das Generieren der Signale zum Schalten der SSRs zuständig, aber 
wieso sollte das nicht gehen?

Nehmen wir mal an, mir ist es egal, dass eine Periode falsch ist und ich 
lese neue Werte nur ein, wenn sie sich ändern. Wieso springen die 
Variablen auf ihre alten Werte zurück, wenn ich den String nicht alle 2 
Sekunden sondern nur einmal zum Mikrocontroller schicke?

von c-hater (Gast)


Lesenswert?

Yll K. schrieb:

> Meinte natürlich Solid State Relais, habs jetzt geändert.

Welche? Viele von den Dingern führen ein Eigenleben, insbesondere 
schalten sie oft von sich aus nur im Nulldurchgang (des Stroms!) um, 
u.U. sogar nur in jedem zweiten.

Das ist zwar für viele Anwendungen eine sehr nützliche Eigenschaft, in 
deiner wäre es aber ein absoluter Show-Stopper...

von Yll K. (yllias)


Lesenswert?

Insgesamt 5 Stück, sind soweit ich weiß vom Typ "random turn on", also 
sollte das kein Problem sein.

Aber um die Hardware kümmert sich jemand anderes. Ich bin nur für die 
Steuersignale verantwortlich.

Wie gesagt, ist mein Hauptproblem, dass die Variablen nach dem Interrupt 
ihren Wert nicht behalten (bzw. nur bis zur nächsten Steuerperiode 
behalten), obwohl sie volatile sind und sie nur bei einem Interrupt 
geändert werden sollen.

: Bearbeitet durch User
von Kevin M. (arduinolover)


Lesenswert?

c-hater schrieb:
> Wenn's zeitkritisch wird, musst du Sprachen verwenden, bei denen du
> exaktes Timing explizit erzwingen kannst. C gehört nicht dazu,

Zeitkritisch ist hier garnichts, die 50Hz sind so langsam da lacht sich 
jeder µC ins fäustchen....

Du solltest deine Signalgenerierung entweder komplett in Hardware (PWM 
über Timer) oder wenigstens in einem Interrupt generieren, in der Main 
ist das eher nicht so gut. Bei den Interrupts muss ggf. auf die 
Prioritäten geachtet werden.

von Yll K. (yllias)


Lesenswert?

Kevin M. schrieb:
> Du solltest deine Signalgenerierung entweder komplett in Hardware (PWM
> über Timer) oder wenigstens in einem Interrupt generieren, in der Main
> ist das eher nicht so gut.

Die Paketsteuerung haut von der Genauigkeit ganz gut hin, ich denke das 
kann ich in der main lassen.

Bezüglich Phasenanschnitt: Sollten ISRs nicht so schlank wie möglich 
gehalten werden? Wenn ich das ganze Zeug für den Phasenanschnitt in der 
ISR mache, ist sie nicht mehr so kompakt.

von c-hater (Gast)


Lesenswert?

Kevin M. schrieb:

> Zeitkritisch ist hier garnichts, die 50Hz sind so langsam da lacht sich
> jeder µC ins fäustchen....

Das ist die Frequenz der PWM. Bei einer Phasenanschnittsteuerung 
moduliert man aber den Duty. Und muss die Frequenz obendrein noch 
synchronisieren, um in der Phase zu bleiben.

Und wenn man das alles saudoof macht, sprich: in C und in Software, dann 
IST das definitiv schon ziemlich zeitkritisch. Inbesondere dann, wenn 
der µC gleichzeitig auch noch andere Sachen erledigt.

> Du solltest deine Signalgenerierung entweder komplett in Hardware (PWM
> über Timer) oder wenigstens in einem Interrupt generieren, in der Main
> ist das eher nicht so gut. Bei den Interrupts muss ggf. auf die
> Prioritäten geachtet werden.

Aha. Es wird nur leider nicht möglich sein, die Sache komplett in 
Hardware abzuhandeln, wegen des Problems der Synchronisation. Bleiben 
also nur noch Interrupts als Lösungsmöglichkeit. Und genau da ist C 
ziemlich Scheisse. Mit mehreren Codebäumen kann es einfach nicht gut 
umgehen. Die Standardimplementierung mit blockierenden ISRs tut ein 
Übriges und sehr schnell ist man beim "geht nicht". Selbst bei 
lächerlichen Frequenzen wie 50Hz...

Natürlich kann man auch C-Code Beine machen. Aber das ist dann nicht 
mehr portabel. D.h.: der einzige Vorteil von C fällt weg, man kann es 
auch einfach gleich in Assembler machen. Dann wird sowas viel einfacher 
beherrschbar...

von Kevin M. (arduinolover)


Lesenswert?

c-hater schrieb:
> Aha. Es wird nur leider nicht möglich sein, die Sache komplett in
> Hardware abzuhandeln, wegen des Problems der Synchronisation.

Also ich hab hier einen 3D-Drucker stehen mit einem 230V Heizbett das 
von einem Modul von mir und einem SSR angesteuert wird und da geht das 
alles in Hardware. ;)

Es geht mit dem Atmega vielleicht nicht mit der richtigen Hardware aber 
schon. Das einzige was die CPU macht ist ab und an mal einen neuen 
compare Wert ins Timer register zu schreiben.

c-hater schrieb:
> Das ist die Frequenz der PWM. Bei einer Phasenanschnittsteuerung
> moduliert man aber den Duty. Und muss die Frequenz obendrein noch
> synchronisieren, um in der Phase zu bleiben.

Ja die PWM Frequenz bleibt aber bei 50Hz und das ist lächerlich......

Yll K. schrieb:
> sollten ISRs nicht so schlank wie möglich
> gehalten werden?

So schlank wie möglich und so lang wie nötig. Da wird dir auch jeder 
seine eigene Meinung dazu sagen. Ich habe hier Projekte da passiert in 
der Main genau nichts. Solange ein ISR nicht länger dauert als die Zeit 
zwischen zwei aufrufen ist das grundsätzlich kein Problem. Wie gesagt 
muss man mit prioritäten aufpassen und schauen das man sich andere dinge 
nicht Blockiert. Da kann durchaus auch eine Menge schief gehen, man 
sollte halt wissen was man tut.

von c-hater (Gast)


Lesenswert?

Kevin M. schrieb:

> man
> sollte halt wissen was man tut.

Das ist immer so. Ganz egal, welche Sprache oder welche Zielhardware...

von Yll K. (yllias)


Lesenswert?

Vielen Dank für eure Antworten und Hinweise. Ich schau mir das mit dem 
Timing mal genauer an, aber derzeit kann ich die kleinen Abweichungen 
schon verkraften.

Jetzt nochmal die Frage zu UART: Alle 2 Sekunden sende ich den char 'r' 
an den PC, der dann einen Parameter in Form eines Steuerstrings an den 
uC zurücksendet wo der String verarbeitet wird. Wie schon besprochen, 
verursacht dieses Einlesen alle 2 Sekunden eine Verzögerung, weshalb das 
Programm den Steuerstring nur zurückschickt, wenn ich dort Parameter 
verändert habe.

Das funktioniert seitens des uC aber irgendwie nicht...

Es ist so:
- Zu Beginn haben die Variablen z.B. die Werte a=1, b=0, c=0 und d=0
- uC sendet ein 'r' an den PC
- am PC liegen veränderte Parameter vor, also schickt er einen String 
zurück
- UART Receive Interrupt wird ausgelöst, der String wird am uC 
verarbeitet, das Programm generiert ein korrektes Signal, die Variablen 
haben z.B. die Werte a=6, b=50, c=50 und d=50
- nach diesen 2 Sekunden wird erneut ein 'r' gesendet, falls es neue 
Parameter gibt
- am PC liegen keine veränderten Parameter vor, er sendet also nichts 
zurück, d.h. es wird kein Interrupt am uC ausgelöst
- die Variablen springen wieder zurück auf 1, 0, 0 und 0, obwohl sie auf 
6, 50, 50, 50 bleiben sollten

Wie kann das sein? Die Variablen sind alle volatile.

: Bearbeitet durch User
von c-hater (Gast)


Lesenswert?

Yll K. schrieb:

> Wie kann das sein? Die Variablen sind alle volatile.

Das Problem ist das Timing, nicht die Volatilität der Variablen.

von Rainer V. (a_zip)


Lesenswert?

Mangels ausreichender Kenntnis der höheren Sprachen kann ich dir hier 
auch nichts zu deinem Programm sagen. Aber der Hinweis, es in ASM zu 
versuchen ist nicht so übel. Zeitkritische Sachen sind immer verzwickt 
und warum sollte man sich das Leben nicht so einfach wie möglich 
machen... Zu deinem Problem der Werte, die nicht gehalten werden, könnte 
man doch vermuten, dass du irgendwo (ungewollt) immer wieder die 
Initialisierung durchführst...so viele Möglichkeiten, die Anfangswerte 
in die Variablen reinzuschreiben, wird es ja nicht geben.
Viel Spass und Gruß, Rainer

von Yll K. (yllias)


Lesenswert?

Inwiefern ist das Timing daran schuld, dass die Variablen ihren Wert 
nicht halten können? Für mich ergibt das leider keinen Sinn, weil sie 
eine gewisse Zeit ja schon die richtigen Werte haben`.

von c-hater (Gast)


Lesenswert?

Yll K. schrieb:

> Inwiefern ist das Timing daran schuld, dass die Variablen ihren Wert
> nicht halten können? Für mich ergibt das leider keinen Sinn, weil sie
> eine gewisse Zeit ja schon die richtigen Werte haben`.
  ^^^^^^^^^^^^^^^^^

Du hast dir deine Frage praktisch schon selbst beantwortet!

von Yll K. (yllias)


Lesenswert?

Hab das Problem lösen können. Der UART Transmit Interrupt war aktiviert 
und hat Probleme gemacht.

Statt:
1
UCSR0B = (1<<RXEN0)|(1<<TXEN0)|(1<<RXCIE0)|(1<<TXCIE0);

Gehört das hier in die UART_Init Funktion:
1
UCSR0B = (1<<RXEN0)|(1<<TXEN0)|(1<<RXCIE0);

Brauche den Transmit Interrupt sowieso nicht, hab beim Kopieren wohl 
vergessen den zu löschen. Programm funktioniert nun wie es sollte.

Danke und LG,

Yll

von Stefan F. (Gast)


Lesenswert?

C-Hater, kannst du mal bitte damit aufhören, wieder und wieder zu 
behaupten, dass C hier nicht geeignet sei? Du weißt ganz genau, dass das 
nicht stimmt, also höre auf, den Yll zu verarschen!

von Kevin M. (arduinolover)


Lesenswert?

@Stefan er ist aber doch ein c-hater er kann doch nicht anders... :D

Ich bin mir fast sicher das ein anständiger C Compiler besseren Code 
erzeugt als alles was irgendjemand der es nicht seit Jahrzehnten macht 
in ASM Produzieren würde.

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.