attiny und interrupt

hallo zusammen,

ich würde gerne die attiny interrupt funktion nutzen, aber ich blicke da leider nicht ganz durch........
schon auf einigen seiten gegucket und im datenblatt.....

ich würde gerne ein funksender für ein bewegungsmelder und oder rauchmelder bauen....
der soll alle paar std den batteriestand übersenden, das geht schon mal.....
ansonsten soll er schlafen........

kommt jetzt ein high-signal vom zb bewegungsmelder, soll er aufwachen und senden.....
ist er grade mit dem senden das batteriestandes beschäftigt soll er abbrechen und ebenfalls den alarm senden......

das meisten hab ich schon, aber ich komme mit der interupt sache nicht weiter........

ist das ok so ? denke mal nicht (; :

(ist nur der sketch um den umgang mit dem interrupt zu lernen)

#include <avr/sleep.h>
#include <avr/power.h>    // Power management


void setup()  
{   

  pinMode(0, OUTPUT);
  
  PCMSK0 |= (1<<PCINT1); //pin12  is PCINT1
  GIMSK  |= (1<<PCIE0);
  sei();
  sleep();
  
   
}

void loop()
{
  
}


ISR(PCINT0_vect)
{
LED();
}

void LED()
{
digitalWrite(0, HIGH);
delay (1000);
digitalWrite(0, LOW);
delay (1000);
}


void sleep() 
{
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
power_all_disable (); 
sleep_enable();
sleep_mode();
sleep_cpu();             // µC schläft 
sleep_disable();
power_all_enable ();    
              
}

die led geht an, wenn ich an den phys. pin 12 5v anlege.......
aber die blinkt nicht auf......bzw geht nicht wieder aus.......
und damit das funktioniert muss ich an pin 12 ein pullup widerstand anbringen

Ich würde das Blinken in loop() machen, nicht im Interrupt Handler. Insbesondere wegen delay(), das funktioniert im Interrupt Handler ziemlich sicher nicht.

ok, danke ! das ist ja schonmal was !

also delays gehen im interrup nicht ?

(das oben ist nur ein beispiel für mich, um das zu lernen).

der eigentliche sketch ist ja ein funksender.....

geht virtual wire denn im interrupt-handler ?

und verstehe ich das richtig ? (bezogen auf obriges beispiel)
wenn ein high-signal auf dem pin anliegt, startet der interrup handler und danach fängt der loop von vorne an ?

und der interrupt, den ich verwendet habe, ist auch in der lage ein laufendes program zu unterbrechen ? (weil schalte den ja nicht ab?)

also wäre für das, was ich vorhabe folgendes sinnvoll ?:

ich habe mein teil vom sketch, der fürs auslesen der batterispannung und fürs senden usw zuständig ist mit einer variablen für "alarm".....

der tiny schläft und wird zb einmal pro std durch den watchdog geweckt..... im watchdog interrups handler ist dann "alarm = 0", weil geht ja nur darum die batterispannung zu übermitteln.

und in den interrup handler für den pin, auf dem der alarmausgelößt wird kommt dann "alarm = 1"....

wenn de rtiny jetzt schläft, und es kommt ein "alarm" wird er durch den interrupt geweckt, "alarm auf 1" gesetzt und dann gehts mit loop weiter ? loop sendet dann den string für den alarm und der tiny geht wieder schlafen.......

In die ISR gehört sowenig wie möglich. Virtual Wire dürfte nicht schnell sein. Setze in der ISR nur ein Flag, den Rest machst du in der loop.

magictrips:
also delays gehen im interrup nicht ?

Beim Eintritt in eine ISR wird das globale Interrupt Enable Flag deaktiviert damit sich Interrupts nicht gegenseitig unterbrechen können. Damit wird der Timer0 Interrupt nicht mehr ausgelöst. delay() fragt aber in einer Schleife ständig micros() ab.

Die Lösung ist wie gesagt in der ISR nur eine boolsche Variable zu setzten (volatile nicht vergessen!) auf die man in loop() abfragt. Dann weiß man dort das was zu tun ist.

also delays gehen im interrup nicht ?

Delays gehen gar nicht!
Delays sind böse.
Ok... manchmal macht die Verwendung von Microdelays Sinn. Wenn es auf 100%iges Timig ankommt.

geht virtual wire denn im interrupt-handler ?

Da VirtualWire vermutlich auch mit Interrupts arbeitet, ein klares Nein!
Es sei denn du triffst spezielle Vorkehrungen, z.B. machst deine Dinge und die fremden Libs Reentrant.

ich verstehe das leider immer noch nicht so ganz

mit dem sketch geht die led bei einem interrupt an phys. pin 1,2,3 an (mehr hab ich nicht getestet)

#include <avr/sleep.h>
#include <avr/power.h>    // Power management

int Alarm = 0;

void setup() 
{   

  pinMode(0, OUTPUT);
  PCMSK0 |= (1<<PCINT1); //pin12  is PCINT1
  GIMSK  |= (1<<PCIE0);
  sei();
  sleep(); 
   
}


void loop()
{
  
 if (Alarm == 1)
 {
 LED();
 Alarm = 0;
 }
 
}


ISR(PCINT0_vect)
{
Alarm = 1;
}

void LED()
{
digitalWrite(0, HIGH);
delay (1000);
digitalWrite(0, LOW);
delay (1000);
digitalWrite(0, HIGH);
delay (1000);
digitalWrite(0, LOW);
delay (1000);
digitalWrite(0, HIGH);
delay (1000);
digitalWrite(0, LOW);
delay (1000);
}


void sleep()
{
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
power_all_disable ();
sleep_enable();
sleep_mode();
sleep_cpu();             // µC schläft
sleep_disable();
power_all_enable ();   
             
}

wie kann ich denn NUR auf pin 2 (und 3 und 4) einen interrupt einstellen.....
also drei interrupts = 3 seperate alarme.

1.) Alle Variablen die innerhalb und außerhalb von ISRs verwendet werden müssen als volatile deklariert werden
2.) Verwende besser einen unsigned char und nicht einen int. 2-Byte Variablen mit ISRs können auch Probleme bereiten da der Zugriff nicht atomar ist

3.) Das sind Pin-Change Interrupts. Das hat zwei Folgen:
3.1.) Der Interrupt wird mit beiden Flanken ausgelöst. Das wird bei dir mit dem riesigen Delay aber keine Rolle spielen
3.2.) Wenn man die Pins trennen will muss man in der ISR abfragen welcher Pin den Interrupt ausgelöst hat, da sich mehrere Pins (bis zu acht) einen Interrupt Vektor, d.h. eine ISR teilen.

ok. vielen dank !

ich habs jetzt mal so probiert:

#include <avr/sleep.h>
#include <avr/power.h>    // Power management

char *Alarm = "0";

void setup() 
{   

  pinMode(0, OUTPUT);
  pinMode(2, INPUT);
  pinMode(3, INPUT);
  pinMode(4, INPUT);
  PCMSK0 |= (1<<PCINT1); //pin12  is PCINT1
  GIMSK  |= (1<<PCIE0);
  sei();
  sleep(); 
   
}


void loop()
{
 
 if (strcmp(Alarm, "1") == 0)
 {
 LED();
 Alarm = 0;
 }
 
 if (strcmp(Alarm, "2") == 0)
 {

 Alarm = 0;
 }
 
 if (strcmp(Alarm, "3") == 0)
 {
 
 Alarm = 0;
 }
 
}


ISR(PCINT0_vect)
{
if (digitalRead(2) == HIGH)
{
Alarm = "1";
}
else if (digitalRead(3) == HIGH)
{
Alarm = "2";
}
else if (digitalRead(4) == HIGH)
{
Alarm = "3";
}
else
{
Alarm = 0;
sleep(); 
}

}

void LED()
{
digitalWrite(0, HIGH);
delay (1000);
digitalWrite(0, LOW);
delay (1000);
digitalWrite(0, HIGH);
delay (1000);
digitalWrite(0, LOW);
delay (1000);
digitalWrite(0, HIGH);
delay (1000);
digitalWrite(0, LOW);
delay (1000);
}


void sleep()
{
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
power_all_disable ();
sleep_enable();
sleep_mode();
sleep_cpu();             // µC schläft
sleep_disable();
power_all_enable ();   
             
}

aber geht auch nicht wirklich.......deswegen gehe ich mal davon aus, das ich das immer noch nicht ganz verstanden hab......

hab versucht, das zu berücksichtigen, was du geschrieben hast......

zb abfrage ob "HIGH"-flanke und unterschiedung, von welchem pin.
ein char statt ein int.

was ich auch noch nicht ganz verstehe....
mehrere pins teilen sich ja ein vektor......
wenn jetzt aber einer dieser pins ein interrupt ist und der andere ein output, was hat das dann für auswirkungen auf das programm bzw die interrupts ?

Was soll denn jetzt der Quatsch mit Strings? unsigned char = byte. Einfach eine Zahl von 0-255.

Und volatile hast du dir immer noch nicht angesehen:
http://www.arduino.cc/en/Reference/Volatile

So:

volatile byte alarm = 0;

zb abfrage ob "HIGH"-flanke und unterschiedung, von welchem pin.

Du fragst auf den Zustand ab, nicht die Flanke. Das reicht in diesem Fall aber wahrscheinlich.

wenn jetzt aber einer dieser pins ein interrupt ist und der andere ein output, was hat das dann für auswirkungen auf das programm bzw die interrupts ?

Gar keine. Was soll sich da beißen?

Und hast du eigentlich irgendeinen Plan was du da machst? Pins 2, 3 und 4 sind PCINT8, PCINT9 und PCINT11. Die sind im PCMSK1 Register. Dazu musst du auch in GIMSK PCIE1 statt PCIE0 aktivieren. Und die ISR ist dann PCINT1_vect
Wir reden hier von einem ATtiny84 oder?

das mit den strings weiß ich auch nicht......
ich hatte das so verstanden:
"2.) Verwende besser einen unsigned char "

volatile hatte ich mir angesehen, ich wußte nur nicht, wie das da rein passt......

und um ehrlich zu sein.........ein wirklichen plan hab ich nicht, deswegen frag ich ja bzw versuche das irgendwie zu verstehen...... ich hab auch schon auf edlichen (meist englischen) seiten gesucht......aber naja.....

es ist ein attiny84, aber ich hab eine andere pinmap !!!!
phys. pin 13 ist bei mir input 0
und phys pin 2 ist bei mir input 10 !!!

damit müßte das was ich da fabriziert habe doch stimmen oder ?

Bitte nicht von unsigned char auf C String schließen. Das hat kaum was miteinander zu tun.

Das mit den Pins war mein Fehler. Ich habe da auf die physischen Pins geschaut. Die Arduino Pins heißen ja anders :frowning:

Du musst aber trotzdem die richtigen Interrupt Enable Pins und den richtigen Interrupt Vektor verwenden. Wenn wir mal das nehmen:

Dann sind Arduino Pins 2, 3 und 4 sogar identisch mit den PCINT Bezeichnungen. Also PCINT2, PCINT3 und PCINT4. Die drei Bits musst du alle aktivieren:

PCMSK0 = (1<<PCINT2) | (1<<PCINT3) | (1<<PCINT4);

PCINT0_vect passt dann

Siehe Datenblatt Seite 51ff:

vielen dank !!!

also wenn ich das jetzt richtig verstanden hab...
geht der interrupt an jedem pin (PCINTx) ?
die pins werden in gruppen/vectoren(y) eingeteilt.
jede gruppe hat ihr eigenes "ISR(PCINTy_vect)" = interrupt handler.

pin change interrups anschalten:
GIMSK |= (1<<PCIEy);

interrupts einschalten zb:
PCMSKy |= (1<<PCINTx);
sei();

interrups ausschalten:
PCMSKy &= ~ (1<<PCINTx);
cli();

also hiermit bekomme ich wieder ein interrupt auf phys. pin8-12
und wenn ich diese if abfragen um interrupt handler verwende, gehts nicht:

#include <avr/sleep.h>
#include <avr/power.h>    // Power management

volatile byte Alarm = 0;

void setup() 
{   

  pinMode(0, OUTPUT);
  digitalWrite(0, LOW);
  pinMode(2, INPUT);
  pinMode(3, INPUT);
  pinMode(4, INPUT);
  GIMSK  |= (1<<PCIE0);
  PCMSK0 = (1<<PCINT2) | (1<<PCINT3) | (1<<PCINT4);
  sei();
  sleep(); 
   
}


void loop()
{
 
if (Alarm == 1)
 {
 LED();
 Alarm = 0;
 }
 
 if (Alarm == 2)
 {

 Alarm = 0;
 }
 
 if (Alarm == 3)
 {
 
 Alarm = 0;
 }
 
 sleep();
 
}


ISR(PCINT0_vect)
{
//if (digitalRead(2) == HIGH)
//{
Alarm = 1;
/*}
else if (digitalRead(3) == HIGH)
{
Alarm = 2;
}
else if (digitalRead(4) == HIGH)
{
Alarm = 3;
}
else
{
Alarm = 0;
sleep(); 
}
*/
}

void LED()
{
digitalWrite(0, HIGH);
delay (1000);
digitalWrite(0, LOW);
delay (1000);
digitalWrite(0, HIGH);
delay (1000);
digitalWrite(0, LOW);
delay (1000);
digitalWrite(0, HIGH);
delay (1000);
digitalWrite(0, LOW);
delay (1000);
}


void sleep()
{
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
power_all_disable ();
sleep_enable();
sleep_mode();
sleep_cpu();             // µC schläft
sleep_disable();
power_all_enable ();   
             
}

und die interrupeingänge sind halt recht "empfindlich"......

Am besten ist es vielleicht du nimmst eine fertige Library. Die hier funktioniert auch auf dem ATtiny: