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
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.
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?
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...
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
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.
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.
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...
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.
Kevin M. schrieb: > man > sollte halt wissen was man tut. Das ist immer so. Ganz egal, welche Sprache oder welche Zielhardware...
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
Yll K. schrieb: > Wie kann das sein? Die Variablen sind alle volatile. Das Problem ist das Timing, nicht die Volatilität der Variablen.
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
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`.
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!
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
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!
@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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.