Forum: Compiler & IDEs ISR Timer Interrupt 1 funktioniert nicht richtig


von xASP (Gast)


Lesenswert?

Hallo Leute

Habe mir mal eine leichten Code zusammengebastelt, beí dem über die ISR 
Overflow Routine vier Taster abgefragt werden.

Diese sollen anschließend eine LED toggeln.

Ohne Interrupt funzt es und auch mit Interrupt, aber nur, wenn ich 
diesen zusammen mit einer lcd_init IN die while(1) schleife tue. Leider 
erhalte ich dabei starke Displayfehler, da das Display dadurch ja immer 
neu initialisiert wird.

Packe ich das ganze außerhalb der while(1) Schleife kann ich die LED 
nicht mehr toggeln.

habe mir auch die lcd_init mal näher betrachtet und bei dieser werden zu 
Beginn die Interrupts ausgeschalten cli() und am Ende wieder 
eingeschalten sei()! kann es damit zusammenhängen?

also hier mal mein Code!




// Deklarationen 
==============================================================

// Festlegung der Quarzfrequenz

#ifndef F_CPU          // optional definieren
#define F_CPU 18432000UL    // MiniMEXLE mit 18,432 MHz Quarz
#endif


// Include von Header-Dateien

#include <avr/io.h>        // I/O-Konfiguration (intern weitere Dateien)
#include <stdbool.h>       // Bibliothek fuer Bit-Variable
#include <avr/interrupt.h>    // Definition von Interrupts
#include <util/delay.h>      // Definition von Delays (Wartezeiten)
#include "lcd_lib_de.h"      // Header-Datei fuer LCD-Anzeige


// Makros

#define  SET_BIT(PORT, BIT)  ((PORT) |=  (1 << (BIT))) // Port-Bit 
Setzen
#define CLR_BIT(PORT, BIT)  ((PORT) &= ~(1 << (BIT))) // Port-Bit 
Loeschen
#define TGL_BIT(PORT, BIT)   ((PORT) ^=  (1 << (BIT))) // Port-Bit 
Toggeln


// Konstanten

#define ON_TIME    50      // "Ein-Zeit" in Inkrementen zu 100 ms
#define OFF_TIME  10      // "Aus-Zeit" in Inkrementen zu 100 ms

#define ENABLE    7

// Variable


bool sw1a = 1;        // Bitspeicher fuer Taste 1 alt
bool sw2a = 1;        // Bitspeicher fuer Taste 2 alt
bool sw3a = 1;        // Bitspeicher fuer Taste 3 alt
bool sw4a = 1;        // Bitspeicher fuer Taste 4 alt

bool sw1n = 1;        // Bitspeicher fuer Taste 1 neu
bool sw2n = 1;        // Bitspeicher fuer Taste 2 neu
bool sw3n = 1;        // Bitspeicher fuer Taste 3 neu
bool sw4n = 1;        // Bitspeicher fuer Taste 4 neu

bool Taste_x = 0;
bool Taste_4 = 0;

unsigned int Lux_Ausgabe(void);

unsigned int Interruptzeit = 900;

int i;
int x;

void initDisplay_Timer1(void);    // Initialisierung Display und Timer1
void sound(void);       // Unterprogramm für Piepton und Countdown 
Ausgabe
void initTimer0(void);    // Timerfunktion für Soundausgabe
void countDown(void);    // 30sec-CountDown mit Displayausgabe
void Tastenabfrage(void);


//====================================================================== 
==

// 
Hauptprogramm==========================================================


int main(void)

{

  initDisplay_Timer1();

  sei();

  while(1)

  {


    if(Taste_x==1)

    {
      Taste_x=0;
      SET_BIT(DDRB, DDB2);
      TGL_BIT(PORTB, PB2);
    }
  }
  //countDown();
}



//====================================================================== 
===

// 
Interruptroutine========================================================

// Interrupt Timer 2 18432000/256=72000hz / pre8 = 9000hz => 
0,11111ms/OVF


ISR (TIMER2_OVF_vect)

{
  --Interruptzeit;      // Interruptzeit 900*0,111ms=0,1s bis 
Tastenabfrage

  if(Interruptzeit==0)

  {
    Interruptzeit=900;
    Tastenabfrage();
  }
}



//====================================================================

// 
Tastenabfrage===========================================================


void Tastenabfrage()

{
  CLR_BIT(PORTD, ENABLE);      // Enable-Signal auf 0
  DDRC = DDRC & 0xF0;        // Port C auf Eingabe schalten
  PORTC = 0x0F;          // Pullup-Rs eingeschaltet

  _delay_us(10);          // Wartezeit Umstellung Hardware-Signal

  sw1n = (PINC & (1 << PC0));
  sw2n = (PINC & (1 << PC1));
  sw3n = (PINC & (1 << PC2));
  sw4n = (PINC & (1 << PC3));

  if ((sw1n==0)&(sw1a==1))  // wenn Taste 1 soeben gedrueckt wurde:
    Taste_x = 1;        //     Flankenbit Taste 1 setzen

  if ((sw2n==0)&(sw2a==1))  // wenn Taste 2 eben gedrueckt wurde:
    Taste_x = 1;        //     Flankenbit Taste 2 setzen

  if ((sw3n==0)&(sw3a==1))  // wenn Taste 3 eben gedrueckt wurde:
    Taste_x = 1;        //     Flankenbit Taste 3 setzen

  if ((sw4n==0)&(sw4a==1))  // wenn Taste 4 eben gedrueckt wurde:
    Taste_4 = 1;        //     Flankenbit Taste 4 setzen

  sw1a = sw1n;        // aktuelle Tastenwerte speichern
  sw2a = sw2n;        // in Variable f?r alte Werte
  sw3a = sw3n;
  sw4a = sw4n;

  DDRC = DDRC | 0x0F;        // Port C auf Ausgabe schalten

}





//=====================================================================

// Initialisierung Display und Timer1===============================


void initDisplay_Timer1()      // Start der Displayinitialisierung
{
  lcd_init();            // Initialisierungsroutine aus der lcd_lib
  lcd_clearDisplay();

  TCCR2A = 0;            // Timer 1 auf "Normal Mode" schalten
  TCCR2B |= (1<<CS21);      // mit Prescaler /8 betreiben
  TIMSK2 |= (1<<TOIE2);      // Overflow-Interrupt aktivieren

}



Vielen Dank schonmal für eure Ratschläge!

von xASP (Gast)


Lesenswert?

oh hier noch der Auszug aus der lcd_init!

void lcd_init (void)
{
  cli();    //globale Interrupts deaktivieren

  DDRC = 0x0f;  // Port C, Bit 0..3 (LCD-Daten) auf Output
  DDRD |= ((1<<E) | (1<<RS));

  PORTC = 0x0f;  // Port C, Bit0..3 (LCD-Daten) SET

  // Steuersignale auf LOW
  P_STEUER &=~((1<<E) | (1<<RS));  // E und RS auf 0 setzen
  _delay_ms (20);

  // Display in 4-bit Modus initialisieren
  P_DATA &=0xf0;
  P_DATA |=0x03;
  lcd_enable();
  _delay_ms (10);
  lcd_enable ();
  _delay_ms (10);
  lcd_enable ();

  P_DATA &=1;
  _delay_ms (2);
  lcd_enable();
  _delay_us (50);

  // 2 Zeilen, 5 x 7 Pixel
  lcd_write (0x28);
  _delay_us (40);

  // Display einschalten
  lcd_write (0x0C);
  _delay_us (50);

  // Curser increment mode
  lcd_write (0x02);
  _delay_us (50);

  //Display loeschen (funktioniert nur, wenn es 2x aufgerufen wird)
  lcd_write (0x01);
  _delay_ms (3);
  lcd_write (0x01);
  _delay_ms (3);

  sei();  // globale Interrrupts aktivieren
}

von Hc Z. (mizch)


Lesenswert?

Du machst zu Beginn von Tastenabfrage()
1
  DDRC = DDRC & 0xF0;        // Port C auf Eingabe schalten
2
  PORTC = 0x0F;          // Pullup-Rs eingeschaltet
Eine gedrückte Taste legt offensichtlich eines der unteren 4 Bits auf 0. 
Am Ende von Tastenabfrage() machst Du dann
1
  DDRC = DDRC | 0x0F;        // Port C auf Ausgabe schalten
Damit werden die Tastenpins auf Output geschaltet; sie geben jetzt 
'high' aus (denn nach PORTC hast Du 0xf geschrieben).  Jetzt hast Du bei 
gedrückter Taste einen sauberen Kurzschluss des Ausgangs.

Wozu die ganze In/Out-Umschalterei?

Weiter habe ich nicht geschaut.

von xASP (Gast)


Lesenswert?

Die Sache ist die, das die Steuersignale des Displays auch auf Port C 
liegen. Deswegen werden sie zu Beginn auf Eingang geschalten für die 
Abfrage der Taster und anschließend auf Ausgang, damit wieder Daten zum 
Display gespeist werden können.

von Hc Z. (mizch)


Lesenswert?

Was den Kurzschluss auch nicht besser macht.  Und je mehr Leitungen da 
dran hängen, umso knapper wird die _delay_us(10).  Die scheint mir eh so 
schon knapp (und ist im Interrupt auch recht unpraktisch, aber geht wohl 
nicht anders).


Vieles blieb mir auch sonst völlig unklar, z.B.

> Ohne Interrupt funzt es und auch mit Interrupt, aber nur, wenn ich
> diesen zusammen mit einer lcd_init IN die while(1) schleife tue.

Wie tut man einen Interrupt in die Hauptschleife?

Dann das Übliche, wenn eine Interruptroutinen-Übergabe nicht 
funktioniert: Taste_x ist nicht volatile.

EDIT: Sperrst Du auch bei sämtlichen Display-Ausgaben die Interrupts, 
bis der Transfer komplett ist?

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Schau mal nach dem Zauberwort "volatile"

Die Taster hängen an den gleichen Ports wie das LCD?

von xASP (Gast)


Lesenswert?

@ Zimmerer:

Sorry das war etwas missverständlich ausgedrückt.
Ich meinte das so, die Interrupteinstellungen muss man ja eigentlich nur 
einmal definieren oder?
Deswegen habe ich sie zusammen mit der lcd_init in das Unterprogramm 
initDisplay_Timer1 gepackt. Wenn man nun dieses Unterprogramm außerhalb 
der while-Schleife aufruft, klappt das mit der LED nicht, ruft man sie 
dagegen in der while-Schleife auf, klappt das mit dem Umschalten der 
LED, dafür hat aber das Display starke Fehler, da es ja in jedem 
Schleifendurchgang neu geladen wird.


@ Johann:

Ich habe jetzt die bool'schen Variablen so gesetzt:

volatile bool Taste_x = 0;
volatile bool Taste_4 = 0;

Und siehe da, es funktioniert... Ich hoffe ich hab des jetzt so richtig 
gemacht und es war net nur Zufall, dass es jetzt klappt :P

Zu den Ein-und Ausgängen... wir benutzen in unserer FH das MINIMexle mit 
einem ATmega88 und dort hängt an PortC sowohl die Taster als auch die 
Steuerleitungen fürs LCD.


Gruß und danke an alle :)

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.