Forum: Mikrocontroller und Digitale Elektronik Interrupts (6 Eingänge)


von Tobias K. (Gast)


Lesenswert?

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

von (prx) A. K. (prx)


Lesenswert?

Pins in Schleife abfragen kann Pin-Interrupts ersetzen.
Mega8 durch Mega88 ersetzen bringt Pin-Change Interrupt.

von condor (Gast)


Lesenswert?

du soltest deine software für die Ausgänge mal überdenken !

oder nimm einen timmer (mit int.) zum eingänge einlesen ...

von Karl H. (kbuchegg)


Lesenswert?

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.

von spontan (Gast)


Lesenswert?

>die 6 Ausgänge (sind an PC0, PC1,
>PC2, PC3, PC4, PC5) von einem Mega8 auslest

Was nun Eingänge oder Ausgänge?

von Tobias K. (Gast)


Lesenswert?

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)

von Tobias K. (Gast)


Lesenswert?

@ Spontan
Eingänge ... Sorry

von Karl H. (kbuchegg)


Lesenswert?

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)

von Tom M. (Gast)


Lesenswert?

Wie ist der Zusammenhang von den 6 Eingängen zu den beiden Ausgängen?
Welche Reaktionszeit ist nötig?

von STK500-Besitzer (Gast)


Lesenswert?

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.

von Tobias K. (Gast)


Angehängte Dateien:

Lesenswert?

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

von Karl H. (kbuchegg)


Lesenswert?

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.

von Tobias K. (Gast)


Lesenswert?

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 
...

von Simon K. (simon) Benutzerseite


Lesenswert?

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?

von Tobias K. (Gast)


Lesenswert?

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

von Karl H. (kbuchegg)


Lesenswert?

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.

von Simon K. (simon) Benutzerseite


Lesenswert?

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.

von Tobias K. (Gast)


Lesenswert?

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

von Tobias K. (Gast)


Lesenswert?

Nachtrag @Simon K.
Es handelt sich um 6 Eingänge wie man jetzt auch aus meiner 
dokumentation entnehmen kann

von Werner (Gast)


Lesenswert?

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.

von Simon K. (simon) Benutzerseite


Lesenswert?

> 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?

von Simon K. (simon) Benutzerseite


Lesenswert?

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.

von Tobias K. (Gast)


Lesenswert?

@Simon K.
Ja genau so meine ich dass .... Und zwar in meinem ganzen Beitrag :)

Und wie verwendet man solche Software timer?

von Markus W. (Firma: guloshop.de) (m-w)


Lesenswert?

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.

von Tobias K. (Gast)


Lesenswert?

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?

von Peter D. (peda)


Lesenswert?


von spontan (Gast)


Lesenswert?

>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.

von Karl H. (kbuchegg)


Lesenswert?

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?`

von Karl H. (kbuchegg)


Lesenswert?

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.

von Karl H. (kbuchegg)


Lesenswert?

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)

von Tobias K. (Gast)


Lesenswert?

@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

von Simon K. (simon) Benutzerseite


Lesenswert?

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
Noch kein Account? Hier anmelden.