Forum: Mikrocontroller und Digitale Elektronik ATtiny84 Pin Change Interrupt


von Simon N. (simon_n703)


Lesenswert?

Hallo,

ich möchte bei meinen ATtiny 84 einen Pin Change Interrupt durchführen. 
Er soll die ganze Zeit schlafen bis er an dem Pin 8 ein Wechsel von Low 
-> High bekommt. Danach soll er einen Ausgang/Ventil schalten und sich 
dann wieder schlafen legen bis zum nächsten Interrupt.
Ich probiere jetzt schon seit Woche daran rum leider habe ich immer noch 
keine Lösung gefunden, wäre super wenn irgend jemand mir weiterhelfen 
könnte.
Und ja... ich habe sämtliche Beträge zu Pin Change Interrupt schon 
durchgelesen und komme trd nicht weiter.
Bin noch ein blutiger Anfänger im Arduino programmieren...

Danke schon mal im Voraus

Simon

von c-hater (Gast)


Lesenswert?

Simon N. schrieb:

> Und ja... ich habe sämtliche Beträge zu Pin Change Interrupt schon
> durchgelesen und komme trd nicht weiter.

Mein Beileid. Einzige logische Konsequenz: Such' dir ein anderes Hobby. 
Das hier, ist einfach nicht innerhalb deiner intellektuellen 
Möglichkeiten...

von Stefan F. (Gast)


Lesenswert?

Zeige uns deinen Lösungsansatz und erkläre ihn soweit du kannst.

von Martin (Gast)


Lesenswert?

@ TO

Poste einfach dein Programm. Es gibt hier auch normaler Menschen, die 
dir gern helfen, nicht nur Pöbler & Asoziale.

von re (Gast)


Lesenswert?

Simon N. schrieb:
> ich habe sämtliche Beträge zu Pin Change Interrupt schon
> durchgelesen

(1) War auch 
http://ww1.microchip.com/downloads/en/devicedoc/Atmel-7701_Automotive-Microcontrollers-ATtiny24-44-84_Datasheet.pdf 
(Seite 31ff und Seite 47ff) dabei?

(2) Was genau funktioniert denn nicht? Das Schlafenlegen, das 
Aufwachen, oder der Interrupt selbst?

(re)

von Georg M. (g_m)


Lesenswert?


von Simon N. (simon_n703)


Lesenswert?

1
#include <avr/sleep.h>
2
#include <avr/interrupt.h>
3
4
#define Trig 9           //digitaler Triggerport für Start Abstandsmessung
5
#define Echo 8           //digitaler Ergebnisport der Abstandsmessung
6
#define Poti 0           //analoger Port für Abstandseinstellung
7
#define Rel 1            // digitaler Port Ansteuerung Relais
8
#define TRIGGERTIMEOUT 100000
9
10
11
12
const float VENTILSPERRE_ms = 800;    // Zeitspanne in ms, in der das Relais nicht wieder aktiviert werden kann zzgl. Relaislaufzeit
13
14
int iOeffnungsdauer = 90;  // Dauer der Relaisaktivierung in ms, eingestellt via Poti
15
16
17
void setup() {
18
19
  // put your setup code here, to run once:
20
21
  pinMode(Trig, OUTPUT);
22
  pinMode(Echo, INPUT);
23
  pinMode(Rel, OUTPUT);
24
25
  digitalWrite(Rel, LOW);
26
27
}
28
29
float Abstand_cm()
30
{
31
  float time_us = 0, time_oneway = 0, distance = 0;
32
  const float SCHALLSPEED = 332.35772;
33
  
34
  delay(10);
35
  
36
  //Aktivierungssequenz Ultraschallsensor starten
37
  digitalWrite(Trig, LOW);
38
  delayMicroseconds(5000);
39
  digitalWrite(Trig, HIGH);
40
  delayMicroseconds(10);
41
  digitalWrite(Trig, LOW);
42
  delayMicroseconds(5);
43
  
44
  //Rückgabe Zeitwert Weg vom Hindernis und zurück
45
  time_us = pulseIn(Echo, HIGH);
46
  
47
  //Berechnung einfache Laufzeit und Umwandlung in s
48
  time_oneway = time_us/2000000;
49
50
  //Berechnung Entfernung
51
  distance = time_oneway*SCHALLSPEED*100;
52
53
 
54
  return distance;
55
56
}
57
58
void sleep() {
59
60
  GIMSK |= _BV(PCIE0);
61
  GIMSK |= _BV(PCIE1);
62
  PCMSK0 |= _BV(PCINT10);                  // Use PB2 as interrupt pin
63
  ADCSRA &= ~_BV(ADEN);                   // ADC off
64
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);    // replaces above statement
65
  
66
  sleep_enable();                         // Sets the Sleep Enable bit in 
67
                                             the MCUCR Register (SE BIT)
68
  sei();                                  // Enable interrupts
69
  sleep_cpu();                            // sleep
70
71
  cli();                                  // Disable interrupts
72
73
  PCMSK0 &= ~_BV(PCINT10);                 // Turn off PB2 as interrupt pin
74
  sleep_disable();                        // Clear SE bit
75
  ADCSRA |= _BV(ADEN);                    // ADC on
76
  
77
  sei();                                  // Enable interrupts
78
}
79
80
81
82
ISR(PCINT0_vect) {
83
84
      
85
}
86
87
88
89
ISR(PCINT1_vect) {
90
91
}
92
93
94
95
void loop() {
96
97
  sleep();
98
99
// put your main code here, to run repeatedly:
100
101
  float fAbstand;
102
  float fAbstandswert = 12;  //Default Abstandsschwellwert in cm zum 
103
                               aktivieren Relais
104
105
 
106
  fAbstand = Abstand_cm();
107
108
109
//Öffnen Relais, wenn Abstand ausreichend
110
if(fAbstand > 4){
111
  if(fAbstandswert >= fAbstand )
112
  {
113
    digitalWrite(Rel, HIGH);
114
    
115
    delay(iOeffnungsdauer); //Aktivitätsdauer Relais;
116
    
117
    digitalWrite(Rel, LOW);
118
119
    delay(VENTILSPERRE_ms);
120
  }
121
  
122
    //Sperrzeit Relais
123
    
124
  
125
}
126
127
  fAbstandswert = 10;
128
129
130
}


Das ist soweit mein Programm. So wie ich das PCI verstanden haben.
Das Programm tut garnichts wenn ich es in den uC lade.

Es ist ein Programm das vorher schon ging ohne PCI und ich das eben 
jetzt auf mit PCI erweitern wollte.

: Bearbeitet durch Moderator
von S. Landolt (Gast)


Lesenswert?

> PCMSK0 |= _BV(PCINT10);
> PCMSK0 &= ~_BV(PCINT10);

?
PCINT10 befindet sich in PCMSK1.

von Stefan F. (Gast)


Lesenswert?

Reduziere das Programm mal auf weniger, wo eine LED anzeigt, ob die CPU 
läuft oder schläft. Teste das erstmal ohne Interrupt-Konfiguration (also 
für immer schlafen) und dann nochmal mit Interrupt.

von Stefan F. (Gast)


Lesenswert?

S. Landolt schrieb:
> PCINT10 befindet sich in PCMSK1.

Sehr gut. Das wird es wohl sein.

von Simon N. (simon_n703)


Lesenswert?

S. Landolt schrieb:
>> PCMSK0 |= _BV(PCINT10);
>> PCMSK0 &= ~_BV(PCINT10);
>
> ?
> PCINT10 befindet sich in PCMSK1.

Stimmt das habe ich auch grad gelesen im Datenblatt 
http://ww1.microchip.com/downloads/en/devicedoc/Atmel-7701_Automotive-Microcontrollers-ATtiny24-44-84_Datasheet.pdf 
was 're (Gast) hochgeladen hat.
Hab's grad ausprobiert daran liegt es nicht.

Soweit ich das am Strom messen kann schläft er dauerhaft.

Stefan ⛄ F. schrieb:
> Reduziere das Programm mal auf weniger, wo eine LED anzeigt, ob
> die CPU
> läuft oder schläft. Teste das erstmal ohne Interrupt-Konfiguration (also
> für immer schlafen) und dann nochmal mit Interrupt.

alles klar mach ich

Beitrag #6512265 wurde von einem Moderator gelöscht.
von Simon N. (simon_n703)


Lesenswert?

Stefan ⛄ F. schrieb:
> Reduziere das Programm mal auf weniger, wo eine LED anzeigt, ob
> die CPU
> läuft oder schläft. Teste das erstmal ohne Interrupt-Konfiguration (also
> für immer schlafen) und dann nochmal mit Interrupt.
1
#include <avr/sleep.h>
2
#include <avr/interrupt.h>
3
4
void setup() {
5
6
  pinMode(4, OUTPUT); //LED
7
  pinMode(8, INPUT);  //Taster
8
9
}
10
11
12
void sleep() {
13
14
  GIMSK |= _BV(PCIE0);
15
  GIMSK |= _BV(PCIE1);
16
  PCMSK1 |= _BV(PCINT10);                  // Use PB2 as interrupt pin
17
  ADCSRA &= ~_BV(ADEN);                   // ADC off
18
  
19
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);    // replaces above statement
20
  sleep_enable();  // Sets the Sleep Enable bit inthe MCUCR Register 
21
  sei();                                  // Enable interrupts
22
  sleep_cpu();                            // sleep
23
24
  cli();                                  // Disable interrupts
25
26
  PCMSK1 &= ~_BV(PCINT10);        // Turn off PB2 as interrupt pin
27
  sleep_disable();                        // Clear SE bit
28
  ADCSRA |= _BV(ADEN);                    // ADC on
29
30
  sei();                                  // Enable interrupts
31
}
32
33
void loop() {
34
  
35
sleep();
36
  
37
38
    digitalWrite(4, HIGH);
39
    
40
    delay(1000); 
41
    
42
    digitalWrite(4, LOW);
43
    
44
    delay (500);
45
  
46
47
 }

Das wäre jetzt das geänderte Programm wo nur eine LED leuchten soll 
sobald der Taster (8) betätigt wird.
Der uC schläft durchgehend und wird nicht aufgeweckt.

: Bearbeitet durch Moderator
von EGS_TI (Gast)


Lesenswert?

Funktioniert das heutzutage ohne "main"-Funktion?

von EGS_TI (Gast)


Lesenswert?

EGS_TI schrieb:
> Funktioniert das heutzutage ohne "main"-Funktion?

Achso, das ist dieser Arduino Kram.

von Charly B. (charly)


Lesenswert?

EGS_TI schrieb:
> EGS_TI schrieb:
>> Funktioniert das heutzutage ohne "main"-Funktion?
>
> Achso, das ist dieser Arduino Kram.
/offTopic

genau, noch ekliger als C ...... *

/offTopic off


Tip: versuchs mal in ASM

von Asdf (Gast)


Lesenswert?

Kenne die arduino IDE nicht besonders, aber sollte da nicht noch 
irgendwo eine ISR (zumindest in C) sein, die den Pin Change INterrupt 
behandelt?

von Hr. Rühe (Gast)


Lesenswert?

Asdf schrieb:
> Kenne die arduino IDE nicht besonders, aber sollte da nicht noch
> irgendwo eine ISR (zumindest in C) sein, die den Pin Change INterrupt
> behandelt?

Bitte nicht stören. Es ist die Spitzenkraft Stefan ⛄ F. am Werk.

von Stefan F. (Gast)


Lesenswert?

Simon N. schrieb:
> Teste das erstmal ohne Interrupt-Konfiguration

Simon N. schrieb:
> Das wäre jetzt das geänderte Programm:

> GIMSK |= _BV(PCIE0);
> GIMSK |= _BV(PCIE1);
> PCMSK1 |= _BV(PCINT10);
> cli();
> sei();

Sehe ich anders. Du hast Interrupts konfiguriert, aber keine ISR. Das 
muss abstürzen.

von HildeK (Gast)


Lesenswert?

Stefan ⛄ F. schrieb:
> Sehe ich anders. Du hast Interrupts konfiguriert, aber keine ISR. Das
> muss abstürzen.
Das ist zumindest in dem Minimalprogramm der Hauptfehler. Ich habe nicht 
geprüft, ob die PCINT-Geschichte richtig konfiguriert ist.

Simon N. schrieb:
> Der uC schläft durchgehend und wird nicht aufgeweckt.

Weil keine ISR vorhanden ist, schläft er tatsächlich nicht dauernd, 
sondern macht einen Soft-Reset. Da das sleep() ganz am Anfang von loop() 
steht, wird er nach dem Restart als erstes auf sleep() treffen und 
einschlafen. Mit dem Tastendruck weckst du ihn auf, aber er macht eben 
einen Reset und kommt nie weiter als bis zu diesem sleep().
Da das sehr schnell geht, kannst du das nicht z.B. am Stromverbrauch 
messen. Und da er schon vor den Befehlen zum ein- und ausschalten der 
LEDs wieder Reset macht, werden die auch nicht bedient.
Mach mal in deinem Testprogramm den Sleep-Aufruf ganz an den Schluss von 
loop(), dann wirst du was sehen. Falsch ist es wg. fehlender PCINT-ISR 
trotzdem. So gesehen deckt der jetzige Code wenigstens das Problem auf 
...

von Asdf (Gast)


Lesenswert?

Schreib einach eine minimale ISR und dann is gut

von Simon N. (simon_n703)


Lesenswert?

Wie wäre den eine minimale ISR? Oder was überhaupt ein ISR ist? Kann mir 
da drunter leider nichts vorstellen...

: Bearbeitet durch User
von Stefan F. (Gast)


Lesenswert?

Das waren minimale ISR:
1
ISR(PCINT0_vect) {
2
3
}
4
5
6
7
ISR(PCINT1_vect) {
8
9
}

Aber eigentlich wollte ich dich dazu animieren, erstmal ohne ISR zu 
testen um zu sehen, ob das Programm ansonsten in Ordnung ist. Die ISR 
(un Interrupt-Konfiguration) wieder einzufügen wäre der nächste Schritt 
danach.

von Simon N. (simon_n703)


Lesenswert?

Ahh oke danke. Aber wieso brauch ich das wenn ich in die ISR garnichts 
reinschreibe. Die ISR sagt doch quasi was während des Interrupts getan 
werden sollen oder?

von S. Landolt (Gast)


Angehängte Dateien:

Lesenswert?

Auf den Interrupt PCINT10 hin erfolgt ein Sprung zum dazugehörenden 
Interruptvektor. Folglich muss dort etwas Vernünftiges stehen, auch wenn 
es nur ein reti ist.

von HildeK (Gast)


Lesenswert?

Simon N. schrieb:
> Aber wieso brauch ich das wenn ich in die ISR garnichts
> reinschreibe.

Wenn du einen Interrupt scharf schaltest (GIMSK |= _BV(PCIE0);) und mit 
sei() Interrupts global aktivierst, dann muss auch eine Interrupt 
Service Routine vorhanden sein. Denn wenn der Interrupt auftritt, wird 
der Prozessor in einer Tabelle nach der Adresse dieser Routine schauen 
und die anspringen.
Ist sie nicht definiert, läuft er ins Leere bzw. nach Adresse 0, was 
sich so ähnlich auswirkt wie ein Reset.

Wenn die ISR nichts tun muss, kann man sie auch so definieren:
EMPTY_INTERRUPT(PCINT0_vect);

von asdf (Gast)


Lesenswert?

In die ISR muss dann die Abfrage des Tasters. Da die PCINT-Logik der 
ATMegas auf alle Pegelwechsel reagiert musst Du in der ISR prüfen welche 
Taste den Zustand geändert hat und ob die Änderung von high->low oder 
low->high war. Das bedeutet, dass ein Tastendruck einen Interrupt 
auslöst und ein Tastenloslassen ebenfalls.
1
ISR(PCINT1_vect) // hier Deinen passenden Vektor rein
2
{
3
    if (digitalRead(8) == HIGH)
4
    {
5
         // hier kommt Deine Logik rein
6
         // Zum Testen einfach eine LED toggeln
7
    }
8
}

von Stefan F. (Gast)


Lesenswert?

Simon N. schrieb:
> Aber wieso brauch ich das wenn ich in die ISR garnichts
> reinschreibe. Die ISR sagt doch quasi was während des Interrupts getan
> werden sollen oder?

Wenn du Interrupts per Konfiguration aktiviert, dann wird die ISR 
Funktion beim Interrupt ausgeführt. Wenn keine solche Funktion 
existiert, wird irgendwas ausgeführt, nur nichts sinnvolles. Beim 
avr-gcc führt das konkret zu einem Neustart des Programms ähnlich einem 
Reset nur dass dabei die Hardware nicht zurückgesetzt wird.

Das ist so als ob die jemand sagt:

Wenn ich Klatsche, springe aus Fenster A, darunter fängt dich jemand auf 
und sagt dir wie es weiter geht.

Wenn ich Huste, springe aus Fenster B, darunter fängt dich jemand auf 
und sagt dir wie es weiter geht.

Dann springst du und niemand fängt dich auf. Weil er vergessen hat, die 
ISR zu schreiben.

Eine Leere ISR würde einem idealten Trampolin entsprechen. Du springst 
raus, und es katapultiert dich dahin zurück, wo du her gekommen bist. 
Ohne Trampolin fällst du auf den harten Boden.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Simon N. schrieb:
> Das ist soweit mein Programm.

Ich habe den Code mal in
1
[c]
2
   ...
3
[/c]
eingebettet, damit man dies auch mit Proportionalschrift lesen kann.

Bitte beim nächsten Mal beachten.

von Simon N. (simon_n703)


Lesenswert?

Also jetzt nochmal als Wiederholung...:
1
.
2
.
3
.
4
   ISR(PCINT1_vect) {
5
}
6
void loop() {
7
  
8
sleep();
9
  
10
   digitalWrite(4, HIGH);
11
    
12
    delay(1000); 
13
    
14
    digitalWrite(4, LOW);
15
    
16
    delay (500);
17
 }
bedeutet wenn ein Interrupt am Pin anliegt, egal welcher, würde die LED 
ansteuern.
1
.
2
.
3
.
4
   if (digitalRead(8) == HIGH)
5
    {
6
    digitalWrite(4, HIGH);
7
    
8
    delay(50); 
9
    
10
    digitalWrite(4, LOW);
11
    
12
    }
13
void loop() {
14
  
15
sleep();
16
17
//Motor läuft  
18
19
}

wenn jetzt ein Interrupt am Pin 8 ist der von LOW -> HIGH wechselt dann 
leuchtet die LED und danach läuft der Motor ODER ein Interrupt am Pin 8 
mit bspw. HIGH -> LOW läuft nur der Motor. (LED leuchtet nicht auf)

Hab ich das ez richtig verstanden?

von asdf (Gast)


Lesenswert?

Simon N. schrieb:
> Hab ich das ez richtig verstanden?

Nein.

Du musst das, was passieren soll in die ISR schreiben. Der Code:
1
ISR(PCINT1_vect) // hier Deinen passenden Vektor rein
2
{
3
    if (digitalRead(8) == HIGH)
4
    {
5
         // hier kommt Deine Logik rein
6
         // Zum Testen einfach eine LED toggeln
7
         digitalWrite(4, !digitalRead(4));
8
    }
9
}

sorgt dafür, dass jedesmal, wenn die Taste gedrückt wird (aber nie, wenn 
sie losgelassen wird), sich der Zustand am Pin 4 des Arduino ändert.

von Einer K. (Gast)


Lesenswert?

asdf schrieb:
> Du musst das, was passieren soll in die ISR schreiben.
Das ist nicht wahr!

Es reicht auch, wenn "das, was passieren soll" nach sleep() ausgeführt 
wird.

Merke:
Der Interrupt soll hier nur zum wecken dienen.

von asdf (Gast)


Lesenswert?

Arduino Fanboy D. schrieb:
>> Du musst das, was passieren soll in die ISR schreiben.
> Das ist nicht wahr!
>
> Es reicht auch, wenn "das, was passieren soll" nach sleep() ausgeführt
> wird.
>
> Merke:
> Der Interrupt soll hier nur zum wecken dienen.

Ja, stimmt für diesen Fall.

von Simon N. (simon_n703)


Lesenswert?

Also funktioniert alles und ich hab jetzt auch verstanden worauf es bei 
einem PCI ankommt danke schon mal an alle Helfer!!!

Dadurch hat sich aber ein neues Problem aufgetan und zwar in meinem 
Ursprünglichen Programm sollte ja der PCI durch einen Ultraschallsensor 
erfolgen. Dieser liefert ja kontinuierlich Werte... . Geht das dann 
überhaupt das ich den µC durch diesen Sensor aufwachen lassen kann? Bzw. 
kann meine Interrupt Anweisung auch so etwas wie einen Sollwert besitzen 
und dann erst den µC aufwachen lassen?

von Einer K. (Gast)


Lesenswert?

Manch ein AVR (vielleicht auch deiner) bietet einen Analog Komparator.
Auch dieser kann als Interruptquelle dienen.

von HildeK (Gast)


Lesenswert?

Simon N. schrieb:
> sollte ja der PCI durch einen Ultraschallsensor
> erfolgen. Dieser liefert ja kontinuierlich Werte... .
Kontinuierliche Werte? Den musst du aktiv triggern und dann liefert er 
dir nach der Schalllaufzeit ein Signal am Echo-Pin. Dazwischen muss ein 
Timer die Zeit feststellen.
Vielleicht solltest du dein Vorhaben etwas näher erläutern. Bisher ging 
es ja nur um den Teil des Aufwachens via PCINT.

> Geht das dann
> überhaupt das ich den µC durch diesen Sensor aufwachen lassen kann? Bzw.
> kann meine Interrupt Anweisung auch so etwas wie einen Sollwert besitzen
> und dann erst den µC aufwachen lassen?
Nein, der Interrupt weckt den µC immer. Du kannst dann aber nachschauen, 
ob du was tun musst und wenn nicht, ihn sofort wieder einschlafen 
lassen.
Wenn du z.B. bei jedem 10. Aufwachen nur eine Aktion ausführen willst, 
dann musst du in der ISR auf 10 Zählen, ein Flag setzen wenn die 10 
erreicht ist und dieses in der Mainloop abfragen. Ist es gesetzt, dann 
lass den µC was tun. Wenn nicht, schicke in wieder in den Schlaf.

von Simon N. (simon_n703)


Lesenswert?

HildeK schrieb:
> Vielleicht solltest du dein Vorhaben etwas näher erläutern.

Ich habe bei uns im Flur einen Desinfektionsspender selber gebaut und 
eben so eine kleine Platine zusammengebastelt mit einem Arduino drauf. 
Wenn der Ultraschall Sensor eine Hand (Abstand ca. 10cm) erkennt, soll 
er ein Ventil kurz öffnen um einen Tropfen des Desinfektionsmittel 
herausfallen lassen. Da der µC zu 95% nichts tut soll er in dieser Zeit 
schlafen (um Energie zu sparen) und genau dieses Problem wollte ich mit 
den PCI beheben.

HildeK schrieb:
> Wenn du z.B. bei jedem 10. Aufwachen nur eine Aktion ausführen willst,
> dann musst du in der ISR auf 10 Zählen, ein Flag setzen wenn die 10
> erreicht ist und dieses in der Mainloop abfragen. Ist es gesetzt, dann
> lass den µC was tun. Wenn nicht, schicke in wieder in den Schlaf.

Ja das wäre grundsätzlich eine Idee aber eben auf den Fall das er 95% 
schlafen soll, doch iwie nur ein Tropfen auf den heißen Stein.


Auser ich schreib in meine ICR Anweisung eben genau diese Bedingung mit 
dem Abstand, setz dann dort eine Flag (wenn der Abstand erfüllt ist), 
bearbeite es  im Programm dann erst in der loop weiter. Dann würde ja 
quasi der µC erst aufwachen wenn die Flag HIGH ist oder?

: Bearbeitet durch User
von Stefan F. (Gast)


Lesenswert?

Simon N. schrieb:
> Geht das dann
> überhaupt das ich den µC durch diesen Sensor aufwachen lassen kann? Bzw.
> kann meine Interrupt Anweisung auch so etwas wie einen Sollwert besitzen
> und dann erst den µC aufwachen lassen?

Nee, das geht nicht. Es sei denn du verwendest einen Sensor den du auf 
einen bestimmten Sollwert programmieren kannst und der den µC nur bei 
Überschrieten der Grenze aufweckt.

Simon N. schrieb:
> Da der µC zu 95% nichts tut soll er in dieser Zeit
> schlafen (um Energie zu sparen) und genau dieses Problem wollte ich mit
> den PCI beheben.

Reden wir von so einem Sensor, der einen Impuls ausgibt, dessen Länge 
mit der Distanz zur Person korrespondiert?

Erstens nimmt der Sensor währen der Messung einige mA auf und zweitens 
musst die Zeitspanne messen, was nicht geht, wenn der µC während dessen 
im Tiefschlaf liegt.

Ich würde hier eher den Clock Prescaler nutzen, um die Taktfrequenz 
herab zu setzen.

Ein passiver IR Sensor wäre hier besser, der bräuchte weniger 
Standby-Strom.

von HildeK (Gast)


Lesenswert?

Simon N. schrieb:
> Wenn der Ultraschall Sensor

Mit 'näher beschreiben' war mir eigentlich wichtiger, welchen Sensor du 
da hast, welches Signal der abgibt. Was angesteuert wird, ist jetzt 
klar.

Ich kenne die HC-SR04, auf die bezog ich mich. Die musst du laufend mit 
einem Trigger versorgen und dann messen, wie lange die Zeit des 
Echopulses ist.
Auch da kann man den Schlafmodus sinnvoll nutzen. Es reicht doch, z.B. 
alle  500ms eine Messung zu starten, auszuwerten und wieder in sleep 
gehen. Der WD-Timer kann dann zum Aufwachen dienen.
Wenn niemand in der Nähe ist (Wand in 2m Abstand z.B.), dann ist der 
Messvorgang in rund 10-20ms abgeschlossen. Ist irgendwas näher, dann 
entsprechend kürzer.
Leider ist ohne erkanntes Echo die Echopulsdauer sehr lang (200ms), aber 
man kann ja, wenn die Zeit größer als 0.5-1ms wird, abzubrechen und 
wieder schlafen zu gehen und es nach einem Timer-Aufwachen in 500ms 
erneut zu probieren.

Ich habe ähnliches vor einiger Zeit gemacht in meiner Garage, so dass 
ich auf den Zentimeter genau mein Auto mit bestem Abstand zum Garagentor 
und der Wand abstellen kann.

Simon N. schrieb:
> Auser ich schreib in meine ICR Anweisung eben genau diese Bedingung mit
> dem Abstand, setz dann dort eine Flag (wenn der Abstand erfüllt ist),
> bearbeite es  im Programm dann erst in der loop weiter. Dann würde ja
> quasi der µC erst aufwachen wenn die Flag HIGH ist oder?

Nein, wenn du in der ISR bist, dann ist er ja aufgewacht. Das Flag sagt 
nur dem restlichen Programm: jetzt ist was passiert, prüfe ob du was tun 
musst und tue es oder gehe wieder schlafen.

Ich hab jetzt viel geschrieben, wenn du einen anderen Sensor hast also 
ich vermute, dann war das evtl. alles Makulatur.
Nenne den Sensor!

von Simon N. (simon_n703)


Lesenswert?

HildeK schrieb:
> Mit 'näher beschreiben' war mir eigentlich wichtiger, welchen Sensor du
> da hast, welches Signal der abgibt. Was angesteuert wird, ist jetzt
> klar.

Achso sorry. Ich habe den HC-SR04 Ultraschall Sensor.
Dann ist der PCI eigentlich nicht der richtige Weg...

HildeK schrieb:
> Ich habe ähnliches vor einiger Zeit gemacht in meiner Garage, so dass
> ich auf den Zentimeter genau mein Auto mit bestem Abstand zum Garagentor
> und der Wand abstellen kann.

Ja genau. Eigentlich genau wie das dein µC wird ja auch die meiste Zeit 
schlafen bzw. eben mit dem WDT nur ab und zu messen.

von HildeK (Gast)


Lesenswert?

Simon N. schrieb:
> Achso sorry. Ich habe den HC-SR04 Ultraschall Sensor.
> Dann ist der PCI eigentlich nicht der richtige Weg...

So ist es! Der PCINT hilft hier nicht.
Du brauchst einen Timer mit Interrupt, ich denke der CTC-Mode ist 
geeignet, um die Echozeit zu vermessen. Und du brauchst den 
WD-Interrupt, um den Schläfer regelmäßig aufzuwecken.

So mal ein grober Vorschlag zur Vorgehensweise:
- im Ruhezustand selten messen, z.B. alle zwei Sekunden, dazwischen 
schlafen. Ruhezustand kann auch heißen: die gemessene Distanz verändert 
sich nicht mehr: gegenüberliegende Wand z.B..
- kommt jemand näher, das Messintervall auf 250ms oder 500ms verkürzen, 
um schneller reagieren zu können.
- wenn die richtige Distanz mit z.B. <10cm (oder was auch immer passt) 
erkannt wird, dann ggf. zwei, dreimal die Distanz verifizieren und dein 
Ventil für kurze Zeit öffnen. Ich habe ein Medianfilter mit 5 Elementen 
eingebaut.
- dann würde ich noch eine Schutzzeit von einigen Sekunden einfügen, um 
wiederholtes Öffnen des Ventils zu vermeiden.
- dann wieder von vorne.

Anbieten würde sich zur Stromversorgung ein USB-Netzteil, da ist es 
nicht ganz so wichtig, dass der Prozessor möglichst viel im 
Power-Down-Schlaf sich befindet.
Lass das Schlafen erst mal weg und programmiere die Auswertung des 
Sensors. Das ist die Pflicht, den Power-Save würde ich als Kür 
bezeichnen ...

von HildeK (Gast)


Lesenswert?

Stefan ⛄ F. schrieb:
> Ich würde hier eher den Clock Prescaler nutzen, um die Taktfrequenz
> herab zu setzen.

Nein, eher nicht. Du willst ja über die Schalllaufzeit messen, wie weit 
der 'Gegenstand' entfernt ist. Der Sensor kann 3mm auflösen, d.h. man 
muss Differenzen von 17µs erkennen können, wenn man ihn ausreizen will.
Ich hatte meinen Tiny mit 8MHz laufen lassen und mit einer Auflösung von 
50µs, entspricht knapp 1cm gearbeitet.
Das dürfte mit einer herunter gesetzten Taktfrequenz dann schwierig 
werden.

von Georg M. (g_m)


Lesenswert?

Der LIDL-Seifenspender funktioniert mit 4xAAA. Es muss also irgendein 
stromsparender Sensor drin sitzen.

von Stefan F. (Gast)


Lesenswert?

HildeK schrieb:
> Der Sensor kann 3mm auflösen, d.h. man
> muss Differenzen von 17µs erkennen können

Das ist mir klar, ich hatte allerdings das Gefühl, dass er diese 
Auflösung gar nicht braucht. Wenn wir zum Beispiel auf 3cm Auflösung 
gehen, sind es 170µs, was mit einer viel geringeren Taktfrequenz geht. 
Außerdem kann man solche Zeiten mit einem Timer messen.

von Simon N. (simon_n703)


Lesenswert?

HildeK schrieb:
> So mal ein grober Vorschlag zur Vorgehensweise:

Alles klar so mach ich das.
Könntest du mir vlt noch einen groben Programmausschnitt von dem WDT 
zeigen oder ein Beispiel. Ich weis einfach nicht wie ich mir das richtig 
zusammenreimen kann. Oder einen Tipp wo ich mir das alles erklären 
lassen kann was der WDT benötigt bzw. was in der Syntax enthalten muss.

Stefan ⛄ F. schrieb:
> Ich würde hier eher den Clock Prescaler nutzen, um die Taktfrequenz
> herab zu setzen.

Ich habe den Einstellung von dem Typ des Arduinos die Taktfrequenz auf 
1MHz heruntergesenkt. Meinst du das? Oder irgendeinen Code im Programm?

: Bearbeitet durch User
von HildeK (Gast)


Lesenswert?

Simon N. schrieb:
> Könntest du mir vlt noch einen groben Programmausschnitt von dem WDT
> zeigen oder ein Beispiel.

Ich werde morgen mal schauen. Ich habe bestimmt ein Beispiel - 
allerdings in reinem C (nicht Arduino) und für den Tiny85 (oder 45/25).
Verwendbar ist das aber schon ...

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Simon N. schrieb:
> Könntest du mir vlt noch einen groben Programmausschnitt von dem WDT
> zeigen oder ein Beispiel.

Lies mal hier:

https://www.mikrocontroller.net/articles/AVR-GCC-Tutorial/Der_Watchdog

Ist zwar nicht für Deinen ATtiny, aber sollte schon das Prinzip 
verdeutlichen. Alles anderes solltest Du im Datenblatt vom ATtiny 
finden.

: Bearbeitet durch Moderator
von Peter D. (peda)


Lesenswert?

HildeK schrieb:
> Lass das Schlafen erst mal weg und programmiere die Auswertung des
> Sensors. Das ist die Pflicht, den Power-Save würde ich als Kür
> bezeichnen ...

Genau so macht man es. Man teilt die Aufgabe in einzelne Module auf und 
die unwichtigen kommen zum Schluß dran. Aber auch nur, wenn es was 
bringt. Stromsparen des MC bei Netzbetrieb ist vergeudete Arbeitszeit.

Ob man modular programmiert, erkennt man daran, daß sich problemlos 
weitere Module hinzufügen lassen. Ist alles nur ein großes 
undurchdringliches Codeknäuel, geht das nämlich nicht.
Auch lassen sich Module nacheinander entwickeln und testen.

von Simon N. (simon_n703)


Lesenswert?

Peter D. schrieb:
> Stromsparen des MC bei Netzbetrieb ist vergeudete Arbeitszeit.

Naja ich betriebe meine Schaltung mit ein paar Batterien und umso länger 
die halten desto besser. Die Schaltung läuft ja gerade schon nur halt 
ohne iwelche stromsparende Mittel und genau deshalb möchte ich überall 
Stromsparen wo es geht. (Mit niedriger Taktfrequenz und WDT)

: Bearbeitet durch User
von HildeK (Gast)


Angehängte Dateien:

Lesenswert?

HildeK schrieb:
> Ich werde morgen mal schauen. Ich habe bestimmt ein Beispiel -

Ich hab ein vorhandenes aufs Notwendigste reduziert. Siehe Anhang.

von HildeK (Gast)


Lesenswert?

Nachtrag:
Ich verwende häufigst den Tinyx5, dafür ist das Beispiel. Kann sein, 
dass einzelne Register im WD-Bereich leicht anders benannt sind beim 
Tinyx4.
Das habe ich jetzt nicht geprüft. Das sollte aber leicht matchbar sein.

Übrigens: deine Aufgabe müsst sich auch mit einem Tiny25 lösen lassen.
Zumindest in meinem Garagenprojekt habe ich den untergebracht: 2 Pins 
für den Sensor, 1 Pin für 2 LEDs aus einem WS2812-Stripe. Es sind noch 
zwei übrig ... 😀

Zum Batteriebetrieb: Das geht natürlich damit, aber weit mehr wird als 
der Prozessor wird das Ventil benötigen, auch der Sensor wird hungriger 
sein. Soweit ich mich erinnere, kann man dem Sensor auch nicht die 
Stromversorgung nehmen, denn dann braucht er einige Sekunden 'Bootzeit' 
bis er wieder bereit ist.

von Stefan F. (Gast)


Lesenswert?

HildeK schrieb:
> denn dann braucht er einige Sekunden 'Bootzeit'
> bis er wieder bereit ist.

Vor allen Dingen darf dabei keine Person davor stehen, sonst kalibriert 
er sich falsch.

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.