mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik (narren-)fehler in code - hilfe?


Autor: narr (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
hallo zusammen, ich suche den fehler in diesem code, den ich (möglichst 
einfach) zum lernen mit Interrupts umzugehen geschrieben habe.
Es sollte passieren:
Blinken der led in ihrer 1. frequenz bis taster gedrückt wird, dann in 
der 2., bis er erneut gedrückt wird (wieder die erste) usw.

es wird immer der erste teil der schleife ausgeführt, dh die led blinkt 
immer in der selben frequenz.
wo ist der fehler?
/*=================================================================================== 

#include <stdbool.h>
#include <stdlib.h>
#include <stdint.h>

#include <avr/io.h>
#include <avr/interrupt.h>  

#define F_CPU 9.6E6        
#include <util/delay.h>    


bool onoff1;
bool onoff2;


ISR(PCINT0_vect)
{
  if (onoff1 == 1)
  {
    onoff2 = 1;
    onoff1 = 0;
  }
  else  
  {
    onoff2 = 0;
    onoff1 = 1;
  }

}


int main(void) 
{        

    DDRB  = 0b00000010;   
    PORTB = 0b00000000;

    GIMSK   |=  (1<<PCIE);         
   PCMSK   |=  (1<<PCINT0);     
   sei();        
  
  onoff1 = 1;
  onoff2 = 0;       
                          
   while (1)
  {
    if (onoff1)
    {
      for (int i=0; i<10; i++)
       {
        PORTB = 0b00000000;
        _delay_ms(50);
        PORTB = 0b00000010;
        _delay_ms(50);
      }
    }
    else if (onoff2)
    {  
      for (int i=0; i<10; i++)  
      {
        PORTB = 0b00000000;
        _delay_ms(200);
        PORTB = 0b00000010;
        _delay_ms(200);
      }
    }
    else 
    PORTB = 0b00000000;

  }
                                              
  return 0;                        
}                             

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
klassicher Fehler, doku nicht gelesen.

Suche mal im Tutorial nach volatil.

mfg
Peter

Autor: narr (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
danke, jetzt habe ich es gelesen - die deklaration der beiden 
boolvariablen als "volatile bool" ändert aber leider aucht nichts.. (?)

Autor: narr (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
irgendwie bekomme ich es nicht hin, eine globale bool variable über die 
isr funktion zu verändern (siehe code) - auch wenn sie jetzt volatile 
deklariert ist. was ich auch mache im code, die variable bleibt die 
selbe.
kann mir da irgendjemand einen ansatz geben?

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wie löst du den PCINT0 aus?

Wenn mit einem Taster, dann denke daran, dass Taster prellen, d.h. du 
bekommst nicht voraussagbar viele PCINT0s pro Tastendruck.

In diesem Fall würde ich mir zunächst einen prellfreien Digitaltaster 
aufbauen, um die PCINT Funktionalität zu erforschen.

In der Praxis macht man i.d.R. keine Tastenauswertung mit einem externen 
Interrupt, sondern nutzt ein Pollingverfahren per Software oder Timer 
(s. Artikel entprellung). Die Ausnahme: Wecken des µC aus einem 
Sleepmodus.

// Target: Attiny13 @ 9.6 MHz
// Debugstand: Simulation
#include <stdbool.h>
#include <stdlib.h>
#include <stdint.h>

#include <avr/io.h>
#include <avr/interrupt.h>  

#define F_CPU 9.6E6        
#include <util/delay.h>    

volatile bool onoff1 = 1; // <===
volatile bool onoff2 = 0; // <===

ISR(PCINT0_vect)
{
  if (onoff1)
  {
    onoff1 = 0;
    onoff2 = 1;
  }
  else  
  {
    onoff1 = 1;
    onoff2 = 0;
  }
}

void blinken(uint8_t num)
{ 
  uint8_t i, j;
  for (i=0; i<20; i++)
  {
    for (j=0; j<num; j+=50)
      _delay_ms(50);
    PORTB ^= (1<<PB1);
  }
}

int main(void) 
{        
  DDRB = (1<<PB1);   // PB1 Ausgabe

  GIMSK |=  (1<<PCIE);         
  PCMSK |=  (1<<PCINT0);     
  sei();        
  
  while (1)
  {
    if (onoff1)
      blinken(50);
    else if (onoff2)
      blinken(200);
    else // !onoff1 && !onoff2 sollte nie erreicht werden!
      PORTB &= ~(1<<PB1); // PB1 Ausgabe LOW
  }
}

Autor: narr (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
hallo stefan
ja, den PCINT0 löse ich per taster aus, den ich hardwareentprellt habe 
mit einem 33kohm widerstand und 0,33µF.
wie gut das funktioniert habe ich allerdings noch nicht mit dem oszi 
angeschaut.

Um genau den sleepmodus geht es mir - ich möchte den µC über den selben 
taster ein bzw ausschalten (dh in bzw aus dem sleepmode holen) - und 
wollte das über eine boolvariable machen, die ich bei jeder 
tasteraktivierung ändere - und damit in der main steuern, ob der 
controller sleepen soll oder seine funktion ausführen.

wie würde man das denn (sonst) umsetzen?

grüße

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mit dem PCINT habe ich das noch nicht gemacht.

Mit dem INT0 Interrupt ist ein Beispiel im Wiki
http://www.mikrocontroller.net/articles/Sleep_Mode...

und ich habe auf dem Pollin Board mit INT0 bei meinem Suppentimer 
experimentiert
http://www.mikrocontroller.net/articles/Pollin_Fun...

Das Prellen spielt dort keine Rolle, weil nur das einfache Wecken per 
Interrupt implementiert wird. Dann ist es egal, ob die Wecktaste prellt. 
Wach ist wach. Das Schlafenlegen kann dann mit einer regulären 
Tasteneingabe oder mit einem Timeout (Suppentimer) gemacht werden.

Allerdings ist das Wecken per Interrupt auch empfindlich gegen 
Spikes/Störungen auf der Leitung am Interruptpin. Man kann das 
berücksichtigen indem man nach dem Wecken zusätzlich den Tastenzustand 
pollt und wenn die Mindestgedrücktdauer nicht erfüllt ist direkt wieder 
pennen geht.

Autor: narr (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ich wurde eben darauf aufmerksam gemacht, dass ich ja beim drücken des 
tasters zwei pinchanges ausführe und damit meine boolvariablen danach 
wieder genauso aussehen wie vorher.. logisch.
wie kann ich das verhindern? ich erinnere mich dunkel daran, dass man 
irgendwo die flanke für den interrupt auswählen kann(?) oder anders?
ich bin auf dem gebiet noch seeeehr grün hinter den ohren...

Autor: MaWin (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Warum immer so viel Code ?
bool pressed=0,down=0,slow=0;
 
void main(void)
{
  DDRB = (1<<PB1);   // PB1 Ausgabe
  while(1)
  {
    pressed=(PINB&1)!=0; // angenommen Taster schaltet auf HI, sonst ==0
    if(pressed) slow^=!down;
    down=pressed;
    _delay_ms(slow?200:50);
    PORTB^=(1<<PB1);
  }
}

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Am einfachsten?

Du kannst den PCINT0 Pin abfragen, ob z.B. ein HIGH Pegel anliegt, d.h. 
ein Wechsel von LOW nach HIGH der Auslöser war. Und nur dann die Aktion 
machen.

ISR(PCINT0_vect)
{
  if ( (PINB & (1<<PB0)) ) // PVINT0 = PB0 beim Attiny13
  {
    onoff1 = ~onoff1;
    onoff2 = ~onoff2;
  }
}

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
MaWin schrieb:

> Warum immer so viel Code ?

Weil der TO mit PCINT0 experimentieren will?

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Du kannst den PCINT0 Pin abfragen, ob z.B. ein HIGH Pegel anliegt, d.h.
> ein Wechsel von LOW nach HIGH der Auslöser war. Und nur dann die Aktion
> machen.

Nachteil bzw. Beschränkung der Einfachmethode: Der Tastendruck muss 
länger dauern als die Aufrufzeit der ISR, damit der Pegel innerhalb der 
ISR noch ansteht und gemessen werden kann. Die Methode ist daher nix bei 
sehr schnellen Signalen z.B. von Sensoren für eine Drehzahlmessung

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
War grad im Datenblatt des Attiny13 unterwegs. Dort sieht es so aus, 
dass man beim PCINT nicht einstellen kann, auf welche Flanke reagiert 
wird.

Das ist aber beim INT0 Interrupt möglich.

Wenn der Sleepmodus dazu kommt gilt weiter, dass nur bestimmte externe 
Interrupts den µC aufwecken können und auch nur bestimmte Ereignisse wie 
z.B. LOW Pegel am externen Interruptpin. Näheres im Datenblatt.

Autor: narr (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
danke soweit, ich mache mich mal dran und schaue was passiert ;)

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.