Hallo, ich habe eine Schaltung entwickelt, die 6 Ausgänge (sind an PC0, PC1, PC2, PC3, PC4, PC5) von einem Mega8 auslest und dann zwei Ausgänge, die an PD0 und PD1 hängen schaltet. Die Ausgänge werden manchmal länger (30 sec) und manchmal ziemlich kurz (ca. 2 sec) angesteuert (gg GND geschaltet) Jetzt habe ich folgendes Problem --> ein ausgang wird über 30 Sekunden auf GND gezogen und in dieser zeit wird ein anderer für ein paar Sekunden ausgelöst --> Schaltet nicht Für dies bräuchte ich nun einen Interrupt. (denke ich) Dazu habe ich mir einige Beiträge usw. durchgelesen und habe festgestellt, dass dies nur über PD2 und PD3 möglich ist und es eben nur 2 Interrupts gibt (INT0 und INT1) ... Ich bräuchte aber 6 stück Ich habe schon einige Interrupt versuche in bascom gemacht die auch klappten... Aber in diesem Fall funktioniert das ganze nichtmehr Die Platine mit dieser Steuerung ist leider ziemlich unzugänglich verbaut... nur programmieren wäre möglich Hoffe ihr könnt mir da weiterhelfen :) Gruss Tobias
Pins in Schleife abfragen kann Pin-Interrupts ersetzen. Mega8 durch Mega88 ersetzen bringt Pin-Change Interrupt.
du soltest deine software für die Ausgänge mal überdenken ! oder nimm einen timmer (mit int.) zum eingänge einlesen ...
Tobias K. schrieb: > Jetzt habe ich folgendes Problem --> ein ausgang wird über 30 Sekunden > auf GND gezogen und in dieser zeit wird ein anderer für ein paar > Sekunden ausgelöst --> Schaltet nicht Was ich so aus deinen Beschreibungen rausgelesen habe: (Poste bitte in Zukunft das Programm, dann müssen wir nicht raten) Du hast dasselbe Problem, wie so viele vor dir. Und das Problem, bzw. die Art wie es dazu gekommen ist, lautet: Wartezeiten werden nicht mit Delay (bzw in BASCOM eben wait) gemacht, sondern mit einem Timeransatz. Da liegt der Schlüssel darin, dass ein Programm mehr oder weniger mehrere Dinge quasi gleichzeitig machen kann. Beitrag "Re: Arduino Keypad und Multitasking" (und folgende Beiträge in diesem Post) In dem Moment, in dem du bei der Aufgabenstellung "ein Pin soll für x Sekunden geschaltet werden" an Pin einschalten x Sekunden warten Pin ausschalten denkst, hast du schon verloren. Das ist zwar ein naheliegender, aber leider auch falscher Weg, wenn es darum geht, dass das Programm auch noch andere Aufgaben erfüllen muss.
>die 6 Ausgänge (sind an PC0, PC1, >PC2, PC3, PC4, PC5) von einem Mega8 auslest Was nun Eingänge oder Ausgänge?
Ich würde die Lösung jetzt folgendermasen ansetzen While (PINC.1 = 0 AND PINC.2 = 0 AND .... (alle anderen)) Then If PINC.0 = 1 Then XXXXXXX waitms 10000 YYYYYYY End If Wenn jetzt PINC.0 für 30 sekunden angeht wird z.B. ein Ausgang geschaltet gewartet und wieder ausgeschaltet. Sobald aber ein anderer PIN eingeschaltet wird trifft die Forderung der while-schleife nichtmehr zu und bricht dann ab. Aber geht er dann auch in die Schleife für z.B. PINC.1? In dieser würde ja auch wieder stehen, dass PINC.0 low sein muss (ist aber noch auf high)
Tobias K. schrieb: > Ich würde die Lösung jetzt folgendermasen ansetzen > > While (PINC.1 = 0 AND PINC.2 = 0 AND .... (alle anderen)) Then > If PINC.0 = 1 Then > XXXXXXX > waitms 10000 > YYYYYYY > End If siehst du ... schon falsch. Damit läufst du zwangsweise in Probleme rein. Das ist der naive Ansatz mit all seinen Nachteilen. Du musst weg von Warteschleifen! (Auch waitms ist nichts anderes) Dein Ansatz muss sein: Ich habe eine Uhr, die in (zb) 1 Sekunden Abständen tickt (in Form eines Aufrufs einer Timer Interrupt Funktion). Was gibt es jetzt, nachdem 1 Sekunde vergangen ist, was gibt es jetzt konkret zu tun? Das kann zb sein, dass man von der noch ausstehenden Wartezeit 1 Sekunde abzieht und wenn sich dadurch die Wartezeit auf 0 reduziert hat, dann schaltet man einen Ausgang ab der eingeschaltet wurde nachdem man die Wartezeit auf 10 Sekunden gestellt hat. Das ist der Ansatz, mit dem man Multitasking Aufgaben in den Griff kriegt. siehe auch Multitasking bzw. haufenweise Forenanfragen anderer, die mit dem gleichen Problem kämpfen (und die alle genau den gleichen taktischen Fehler - zeitliche Warteschleifen - gemacht haben)
Wie ist der Zusammenhang von den 6 Eingängen zu den beiden Ausgängen? Welche Reaktionszeit ist nötig?
Tobias K. schrieb: > While (PINC.1 = 0 AND PINC.2 = 0 AND .... (alle anderen)) Then > If PINC.0 = 1 Then > XXXXXXX > waitms 10000 > YYYYYYY > End If Wie Karl Heinz schon schrieb: So wird das nichts. 1. Soll der Ausgang bei einer Flanke von 0=>1 für die Zeit geschaltet werden, oder so lange, wie die 1 anliegt und ab der Flanke 1->0 noch eine gewisse Zeit eingeschaltet sein? Deine Methode führt dazu, dass der Ausgang genau das zweite Verhalten zeigt. Denn solange der Pin den Pegel 1 besitzt, wird immer die Warteschleife angelaufen.
Also wenn ich das ganze jetzt richtig versehe, soll es bei einer Flanke 1->0 noch eine gewisse Zeit eingeschaltet sein (außer ein anderer der noch überbleibenden 5 Pins wird high) Im Anhang mal der Code
Yep. Das Allererste was du brauchst, ist erst mal ein Timer. Den konfigurierst du so, dass er alle x Zeiteinheiten eine Funktion aufruft. Da liegt der Schlüssel zur Lösung deines Problems. Wie gross x tatsächlich ist, spielt nicht so sehr die große Rolle. Wenn irgend möglich soll es eine Zeit sein, so dass deine gewünschten benötigten Zeiten ganzzahlige VIelfache davon sind. Wenn die tatsächlichen Zeiten nicht allzu kritisch sind, peilt man zb eine Zeit von ein paar Millisekunden an. Ob im µC 1 Sekunde tatsächlich 1 tausendstel Sekunde kürzer oder länger ist, spielt meist nicht die große Rolle. Aber um Timer kommst du nicht herum, wenn du einigermassen ernsthaft programmieren willst. Also musst du dich damit beschäftigen. BASCOM macht dir das ohnehin einfach.
Okay, das mit dem Timer ist mir klar ... Hier mal meine Überlegung:
1 | $regfile = "m8def.dat" |
2 | $crystal = 1000000 |
3 | |
4 | XXX |
5 | |
6 | Config Timer1 = Timer , Prescale = 256 |
7 | |
8 | On Timer1 Isr_Prüfen |
9 | |
10 | Enable Interrupts |
11 | |
12 | Do |
13 | ...Hauptprogramm |
14 | If PINC.0 = 1 Then |
15 | PORTD.1 = 1 |
16 | Enable Timer1 'anstelle von waitms |
17 | End if |
18 | Loop |
19 | End |
20 | |
21 | Isr_Prüfen: |
22 | PORTD.1 = 0 'das was eigentlich nach dem waitms kommt |
Der Prescale müsste dann nurnoch so berechnet werden, dass es mit dem waitms übereinstimmt Einziges Problem: ich kann ja nur Timer 1 hernehmen, da sonst der Prescale zu hoch wird (oder?) und ich bräuchte ja dann insgesamt 6 Timer ...
Naja, noch nicht ganz richtig. Mach doch erstmal einen Plan fertig. Was passiert wann? Welche Ausgänge hängen von welchen Eingängen und welcher Zeit ab?
Ein Plan und die Zeiten ist schon durch meinen alten Programmcode festgelegt ... Es geht eben nur um den Abbruch. Könntest du mir "nicht ganz richtig" etwas genauer definieren ... wenn ich einmal ein Beispiel habe das auch stimmt sollte das ganze klappen
Tobias K. schrieb: > Der Prescale müsste dann nurnoch so berechnet werden, dass es mit dem > waitms übereinstimmt Ist schon nicht schlecht. > Einziges Problem: ich kann ja nur Timer 1 hernehmen, da sonst der > Prescale zu hoch wird (oder?) und ich bräuchte ja dann insgesamt 6 Timer > ... Nö. Warum? Du hast ja auch noch Variablen und mit denen kann man zählen. WEnn deine ISR aufgerufen wird, und das in 1 Sekunden Abständen, dann kann man bei jedem Aufruf eine Variable zb um 1 erhöhen oder verringern und mit dem Zahlenwert dieser Variablen weitermachen. Wenn man 10 mal 1 Sekunde wartet, hat man in Summe auch 10 Sekunden gewartet. (Und den Timer kann man durchaus auch einfach durchlaufen lassen. Den muss man nicht dauernd starten und stoppen. Das lässt sich auch alles mit speziellen Werten bzw. Vereinbarungen in diesen Variablen regeln)
1 | $regfile = "m8def.dat" |
2 | $crystal = 1000000 |
3 | |
4 | XXX |
5 | |
6 | Config Timer1 = Timer , Prescale = 256 |
7 | |
8 | On Timer1 Isr_Prüfen |
9 | |
10 | Dim Wartezeit1 As Integer |
11 | Wartezeit1 = -1 |
12 | |
13 | Enable Interrupts |
14 | |
15 | Do |
16 | ...Hauptprogramm |
17 | If PINC.0 = 1 Then |
18 | PORTD.1 = 1 |
19 | Wartezeit1 = 200 |
20 | End if |
21 | Loop |
22 | End |
23 | |
24 | Isr_Prüfen: |
25 | If Wartezeit1 > 0 then |
26 | Wartezeit1 = Wartezeit1 - 1 |
27 | If Wartezeit1 = 0 then |
28 | PORTD.1 = 0 |
29 | Wartezeit1 = -1 |
30 | endif |
31 | endif |
Hier gibt es eben eine Variable 'Wartezeit1' (du wirst natürlich einen besserern Namen benutzen, der besser an das was du vor hast angepasst ist). Diese Variable hat Werte mit bestimmten Bedeutungen: -1 .... die Wartezeit läuft nicht 0 .... die Wartezeit ist abgelaufen >0 .... die noch verbleibende Wartezeit Nichts und niemand hindert dich jetzt daran, für jede zu schaltende Komponente denselben Mechanismus zu benutzen: Eine jeweils eigene Variable, die in der ISR in bekannten Zeitabständen überprüft und gegebenenfalls verringert wird. Und zwar alle in ein und derselben ISR, von der du weißt in welchen zeitlichen Abständen sie aufgerufen wird. Die 200, die ich hier benutzt habe ergeben sich aus der Timereinstellung UND der gewünschten tatsächlichen Wartezeit. Wird die ISR 100 mal in der Sekunde aufgerufen, dann wären das eben 2 Sekunden. Du setzt im Hauptprogramm den Pin auf 1, 'startest' mit der Zuweisung den Mechanismus in der ISR und 2 Sekunden später (eben nach dem 200ten Aufruf) setzt die ISR den Pin wieder auf 0 und deaktiviert den Mechanismus.
Tobias K. schrieb: > Ein Plan und die Zeiten ist schon durch meinen alten Programmcode > festgelegt Programmcode != Doku > ... Es geht eben nur um den Abbruch. Siehste, Abbruch wovon? > Könntest du mir "nicht ganz richtig" etwas genauer definieren ... wenn > ich einmal ein Beispiel habe das auch stimmt sollte das ganze klappen Könnte ich, dafür müsste ich aber erst mal die Anforderungen wissen. Sind es jetzt 6 Eingänge oder 6 Ausgänge? Wo kommt die Verzögerung ins Spiel? Und weiteres.
Ich beschreibe jetzt einmal den Ablauf 1: Wenn PINC.0 An ist, dann soll Variable_1 angehen Wenn PINC.1 An ist soll Variable_1 nach 7 Sekunden wieder ausgehen 2: (es passiert entweder 2.1 oder 2.2) 2.1 Wenn PINC.5 Aus ist und PINC.4 An ist dann soll Variable_2 angehen Wenn PINC.2 An ist soll Variable_2 nach 14 Sekunden wieder ausgehen 2.2 Wenn PINC.5 An ist und PINC.4 und PINC.3 dann soll Variable_2 und PORTD.1 angehen (und nach 7,5 Sekunden wieder aus) Wenn PINC.2 An ist soll Variable_2 nach 14 Sekunden ausgehen 1 & 2: Wenn Variable_1 oder Variable_2 an, dann ist PortD.0 An Wenn Variable_1 und Variable_2 aus, dann ist PortD.0 Aus Hoffe dass ist verständlich
Nachtrag @Simon K. Es handelt sich um 6 Eingänge wie man jetzt auch aus meiner dokumentation entnehmen kann
Falls die Erzeugung der Verzögerungszeiten über delay_ms() bzw. waitms das Problem sein sollte und man nicht mit Interrupts arbeiten möchte, gibt es natürlich die Möglichkeit, alles in einer Schleife ablaufen zu lassen, d.h. Eingänge Abfragen und Ausgänge entsprechend setzen. Bei der Schleif könnte man mit einem festen Delay (z.B. 1 s) die ungefähre Dauer eines Durchlaufs festlegen. Jedem Ausgang wird ein Zähler zugeordnet, der bei jedem Durchlauf heruntergezählt wird und bei 0 den Ausgang wieder abschaltet. Das wird dann nicht richtig genau, könnte aber die Lösung für dein Problem sein. Mit einem Timer an Stelle des Delays könnte man genauere Zeiten erreichen. Wesentlich ist, dass man nicht für die Kontolle jedes Vorgangs einen eigenen Timer braucht, sondern (Software-)Zähler verwendet, von denen man viele anlegen kann.
> Wenn PINC.1 An ist soll Variable_1 nach 7 Sekunden wieder ausgehen
Wie soll das denn funktionieren?
Du meinst bestimmt, wenn PINC.1 von 0 auf 1 wechselt, soll Variable_1
nach 7 Sekunden auf 0 gesetzt werden?
Werner schrieb: > Wesentlich ist, dass man nicht für > die Kontolle jedes Vorgangs einen eigenen Timer braucht, sondern > (Software-)Zähler verwendet, von denen man viele anlegen kann. Mit so einem Gefrickel würde ich gar nicht anfangen. Das ist einfach nicht praxistauglich bei größeren Programmen. Und wenn man es richtig macht, braucht man auch nicht für jeden Vorgang einen eigenen (Hardware) Timer, sondern kann ebenfalls "Software-Zähler" verwenden.
@Simon K. Ja genau so meine ich dass .... Und zwar in meinem ganzen Beitrag :) Und wie verwendet man solche Software timer?
A. K. schrieb: > Mega8 durch Mega88 ersetzen bringt Pin-Change Interrupt. Versteh auch nicht, warum so viele Leute unbedingt den alten ATmega8 verwenden wollen, der keinen PCI hat. Der Pin-Change-Interrupt ist bei solchen Sachen doch unheimlich praktisch! Aus dem Datenblatt der Mikrocontroller-Typen ATmega88A bis ATmega328: "The External Interrupts are triggered by the INT0 and INT1 pins or any of the PCINT23...0 pins. Observe that, if enabled, the interrupts will trigger even if the INT0 and INT1 or PCINT23...0 pins are configured as outputs. This feature provides a way of generating a software interrupt. The pin change interrupt PCI2 will trigger if any enabled PCINT[23:16] pin toggles. The pin change interrupt PCI1 will trigger if any enabled PCINT[14:8] pin toggles. The pin change interrupt PCI0 will trigger if any enabled PCINT[7:0] pin toggles. The PCMSK2, PCMSK1 and PCMSK0 Registers control which pins contribute to the pin change interrupts. Pin change interrupts on PCINT23...0 are detected asynchronously. This implies that these interrupts can be used for waking the part also from sleep modes other than Idle mode." Das heißt, man kann Interrupts mit bis zu 24 Ein- oder Ausgängen verknüpfen.
So wie ich das sehe könnte ich mir einfach einen Atmega 88 kaufen, flashen, und einfach gegen den anderen tauschen? Man kann die Interrupts zwar mit den Ein/Ausgängen verknüpfen, aber es gibt wieder nur 2 stück oder?
>Man kann die Interrupts zwar mit den Ein/Ausgängen verknüpfen, aber es >gibt wieder nur 2 stück oder? Beratungsresistent? Tastenbehandlung im Interrupt ist das blödeste, was einem einfallen kann, Entprellung mit Delay gleich danach. Zeitabläufe von Sekunden durch Warteschleifen sind der Gipfel des Unverständnisses. Vorschläge gabs genug, "Taten statt Worte" wäre mal langsam gefragt.
Tobias K. schrieb: > @Simon K. > Ja genau so meine ich dass .... Und zwar in meinem ganzen Beitrag :) > > Und wie verwendet man solche Software timer? Welchen Teil von hier Beitrag "Re: Interrupts (6 Eingänge)" hast du denn nicht verstanden?`
Tobias K. schrieb: > So wie ich das sehe könnte ich mir einfach einen Atmega 88 kaufen, So wie ich das sehe, tipp ich mir die Finger wund und du liest es nicht einmal.
Markus W. schrieb: > A. K. schrieb: >> Mega8 durch Mega88 ersetzen bringt Pin-Change Interrupt. > > Versteh auch nicht, warum so viele Leute unbedingt den alten ATmega8 > verwenden wollen, der keinen PCI hat. Der Pin-Change-Interrupt ist bei > solchen Sachen doch unheimlich praktisch! Wofür? In dieser Aufgabenstellung braucht kein Mensch einen Pin-Change Interrupt. Statt dessen braucht man nur ein bischen Nachdenken, wie man die Zeitsteuerung mit einem Timer macht - Problem gelöst. (Ich hab nix gegen den Mega88. Ganz im Gegenteil. Aber red ihm bitte nicht ein, dass sein Problem nur durch Austausch des Prozessors gelöst wäre. Das ist es nämlich nicht. Ausserdem schadet es auch einem BASCOM Programmierer nicht, wenn er ein paar grundlegende Basisprogrammiertechniken lernt)
@Karl Heinz Buchegger Tut mir leid, aber wie ich für Simon K. eine Dokumentation geschrieben hab, hast du deinen doch ziemlich Hilfreichen beitrag gepostet, und in dieser Zeit wurden noch 2 andere gepostet, so habe ich den überblick verloren und deinen einfach nicht gesehen :( Vielen Dank ... ich werde gleich versuchen das ganze umzusetzen
Ich hab heute nicht die Zeit mich auf die Dokumentation einzulassen. Das darf ruhig jemand anders machen. Damit kann man jedenfalls schon mal annähernd was anfangen. Pin-Change Interrupts sind hier aber äußerst falsch angebracht bei Signalen die sich alle paar Sekunden mal ändern.
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.