PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Böse Interrupts



Florianinside
17.04.2006, 13:28
Hallo Forum,
zwischen Eiersuchen und Osterwünsche verteilen lese ich mich das erste mal in die Interrupt meines AVR 169 ein.

Ich habe einen IS471 an meinen Butterfly angeschlossen und möchte bei entsprechendem Signal eine Meldung über das LCD laufen lassen.

Das Problem, dass ich gerade habe ist, dass das Interrupt nicht ausgelöst wird und der entsprechende Programmtext nicht ausgeführt wird.

Ich denke, dass die Fehler in den EIFR (oder wie auch immer die sich schimpfen)-Registern zu finden sind und ich diese falsch anspreche.

Der Quelltext ist nicht groß, das ansprechen des LCD´s klappt prima.



// Auslesen eines IS471-Sensors

#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <avr/sleep.h>
#include <inttypes.h>
#include <avr/signal.h>
#include <inttypes.h>
#include "main.h"
#include "lcd_functions.h"
#include "lcd_driver.h"
#include <avr/delay.h>

#define pLCDREG_test (*(char *)(0xEC))

// extern unsigned int LCD_character_table[] PROGMEM;

volatile PGM_P statetext;

void PinChangeInterrupt(void)
{
cli(); // disable interrrupts

statetext = PSTR("wand");
LCD_puts_f(statetext, 1);
LCD_Colon(0);
_delay_loop_2(300000000); // Ja, Pausen in Interrupts sind böse

// Ist diese Zeile hier sinnvoll?
EIFR = (1<<PCIF1) | (1<<PCIF0); // Delete pin change interrupt flags

sei();
}

SIGNAL(SIG_PIN_CHANGE0)
{
PinChangeInterrupt();
}

SIGNAL(SIG_PIN_CHANGE1)
{
PinChangeInterrupt();
}

/************************************************** ***************************
*
* Function name : main
*
* Returns : None
*
* Parameters : None
*
* Purpose : Contains the main loop of the program
*
************************************************** ***************************/
int main(void)
{

DDRB = 0x00; // set Port B for input
//PORTB = 0xFF;
// Enable pin change interrupt on PORTB

// Auch in diesen Zeilen blicke ich nicht durch

PCMSK0 = (1<<PINB1)|(1<<PINB2)|(1<<PINB3)|(1<<PINB4);
PCMSK1 = (1<<PINB1)|(1<<PINB2)|(1<<PINB3)|(1<<PINB4);
EIFR = (1<<1)|(1<<2)|(1<<3)|(1<<4);
EIMSK = (1<<1)|(1<<2)|(1<<3)|(1<<4);

statetext = PSTR("1");

// Program initalization
Initialization();
sei(); // mt __enable_interrupt();

while (1) // Main loop
{

statetext = PSTR("1");
LCD_puts_f(statetext, 1);
LCD_Colon(0);

} //End Main loop

return 0;
}

/************************************************** **************************
*
* Function name : Initialization
*
* Returns : None
*
* Parameters : None
*
* Purpose : Initializate the different modules
*
************************************************** ***************************/
void Initialization(void)
{
/*
CLKPR = (1<<CLKPCE); // set Clock Prescaler Change Enable

// set prescaler = 8, Inter RC 8Mhz / 8 = 1Mhz
CLKPR = (1<<CLKPS1) | (1<<CLKPS0);

// Disable Analog Comparator (power save)
ACSR = (1<<ACD);

// Disable Digital input on PF0-2 (power save)
DIDR1 = (7<<ADC0D);

// mt PORTB = (15<<PORTB0); // Enable pullup on
PORTB = (15<<PB0); // Enable pullup on
// mt PORTE = (15<<PORTE4);
PORTE = (15<<PE4);

sbi(DDRB, 5); // set OC1A as output
sbi(PORTB, 5); // set OC1A high
*/

LCD_Init(); // initialize the LCD
}


Im Endeffekt wird das Signal vom IS471 von VCC auf GND invertiert und das soll der Butterfly erkennen.

Ach ja, ohne Interrupts sondern nur mit der Abfrage in einer Schleife klappt alles ganz prima.

Schon mal Danke fürs lesen,
ich wünsche noch weiterhin frohe OStern,
Florian.

izaseba
17.04.2006, 13:53
Hallo, ohne sich ein Dattenblatt zu Deinem µC runterzuladen, und sich die Register anzugucken, kann ich folgendes sagen...


#include <avr/delay.h>

Wo gibt es das ?

delay.h befindet sich meiner Meinung nach in util/ ....


_delay_loop_2(300000000);

300000000 ??


void _delay_loop_2 (uint16_t __count)

so steht es in delay.h drin und jetzt überleg mal wie groß maximal uint16_t
sein kann.

warum springst Du as der ISR in eine Funktion raus? das kann man ruhig in der ISR erledigen, ohne sie zu verlassen.

Warum machst Du cli(); in der ISR ? das ist sinnlos.

und ja
Ja, Pausen in Interrupts sind böse
dem kann ich nur zustimmen....

Gruß Sebastian

Florianinside
17.04.2006, 15:00
Hi izaseba,
schon einmal vielen Dank für die Antwort.

Also bei den Delays stimmt das soweit. Ich arbeite großen Teils mit Joe Pardues Butterfly-Buch, daher kommen auch die Delay-Angaben.

Die 300000000 kommt mir auch erstaunlich groß vor, bewirkt aber im Endeffekt keine großen Verzögerungen. Ich schätze, dass es sich bloß um eine halbe Sekunde delay handelt.

Wie dem auch sei, die Problematik, dass die Interrupts nicht beachtet werden, ist noch gegeben.

Ach ja, cli() rufe ich in der ISR auf, um in diesem Interrupt zu vermeiden, dass ein weiterer Interrupt erkannt wird.

Superhirn
17.04.2006, 16:03
Hi,
300000000 ist unmöglich da die variale nur max. 65536 zulässt.

und warum schreibst du:
PORTB = (15<<PB0); // Enable pullup on

Ich würddas schreiben:
PORTB |= (1<<PB0); // Enable pullup on

Grüße
Superhirn

PS: Mit deinem Problem kenn ich mich nicht so aus. aber dass ist das, was ich nicht verstehen kann.

izaseba
17.04.2006, 18:56
Ich arbeite großen Teils mit Joe Pardues Butterfly-Buch, daher kommen auch die Delay-Angaben.


Dann tue des Buch in die Tonne, wenn so ein Quatsch drin steht.

Gruß Sebastian

Florianinside
17.04.2006, 19:25
Na gut, die Delays scheinen tatsächlich ziemlich buggy zu sein, dann schmeiß ich die gerne raus (das Buch behalte ich noch ein paar Tage... ;).

Den Quelltext habe ich jetzt schon ein wenig reduzieren können, die aktuelle Version werde ich jetzt hier posten und weiterhin um Hilfe mit den Interrupts bitten - denn das klappt alles noch nicht....



#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <avr/sleep.h>
#include <inttypes.h>
#include <avr/signal.h>
#include <inttypes.h>
#include "main.h"
#include "lcd_functions.h"
#include "lcd_driver.h"
#include <avr/delay.h>

#define pLCDREG_test (*(char *)(0xEC))

volatile PGM_P statetext;

void PinChangeInterrupt(void)
{

statetext = PSTR("wand");
LCD_puts_f(statetext, 1);
LCD_Colon(0);

}

SIGNAL(SIG_PIN_CHANGE0)
{
PinChangeInterrupt();
}

SIGNAL(SIG_PIN_CHANGE1)
{
PinChangeInterrupt();
}

/************************************************** ***************************
*
* Function name : main
*
* Returns : None
*
* Parameters : None
*
* Purpose : Contains the main loop of the program
*
************************************************** ***************************/
int main(void)
{
LCD_Init();
DDRB = 0x00; // set Port B for input
PORTB = 0xFF;

// Enable pin change interrupt on PORTB

PCMSK1 = (1<<PCINT12)|(1<<PCINT11)|(1<<PCINT10)|(1<<PCINT9);
EIMSK = (1<<PCINT1);
statetext = PSTR("1");

// Program initalization

sei();

while (1) // Main loop
{

statetext = PSTR("1");
LCD_puts_f(statetext, 1);
LCD_Colon(0);

} //End Main loop

return 0;
}



Weiterhin vielen Dank für eure Hilfe,
cheers,
Flo.

ManniMammut
17.04.2006, 20:33
Die Delay-Include stimmt übrigens auch!
@Izaseba: Schau mal nach /opt/cross/avr/include/avr/ (oder wo auch immer dein avr-gcc liegt). Dadrin befindet sich auf jeden Fall ne delay.h, die auch funzt. Benutze sie schließlich selber. Achja, vll liegt's auch an der neuen Version...

mfG, Manni

izaseba
17.04.2006, 20:47
In der tat liegt delay.h in avr, aber mit einem sehr schönem Inhalt:


#warning "This file has been moved to <util/delay.h>."
#include <util/delay.h>


womit letzendlich auch die richtige .h included wird, ich halte mich halt nach der Library Reference wo die delay.h unter util/ aufgelistet ist.
Das ändert aber nichts an der Tatsache daß ein uint16_t keine 300 Mil. aufnehmen kann und wenn das so in einem Buch steht gehört das dingen für mich in den Müll.

Gruß Sebastian

Florianinside
17.04.2006, 20:54
Nein nein, die 3000000000000000000000 stand in keinem Buch ;)

Aus dem Buch stammt die Funktion an sich und auch, wo und in welcher Bibliothek sie zu finden ist.

Da mir die Verzögerung aber zu gering war, habe ich nach und nach den Wert erhöht. Mittlerweile habe ich auch rausgefunden, dass der Compiler den Wert automatisch auf 65000 runtersetzt.

Wie dem auch sei(), nach langem schmölern im AT169 Handbuch habe ich immer noch keine Ahnung, wie ich den Butterfly dazu bringen soll, die ersten 4 Pins (oder überhaupt einen dieser Pins) als Quelle für einen Interrupt anzusehen.

Any more Ideas??

Weiterhin einen schönen Abend,
Florian.

izaseba
17.04.2006, 21:12
also nochmal sorry, dann liegt das nicht am Buch :-)

Also ich hab mir das Dattenblatt runtergeladen und das erste was mir aufgefallen ist Register EIMSK hat kein Bit mit dem namen PCINT1
PCINT1 ist in der iom169.h mit 1 definiert und Bit 1 in EIMSK ist nicht vorhanden, naja vorhanden schon aber nicht benutzt.
Prüf das nochmal nach, vielleicht hilft es.
Es kann auch sein, daß ich einen an der wafel hab, es handelt sich doch um atmega169?

Gruß Sebastian

izaseba
17.04.2006, 21:20
Du meintest sicher EIMSK = (1<<PCIE1); oder EIMSK = (1<<PCIE0);

sehe Seite 53 Dattenblatt

Ich hoffe das war der Fehler...

Gruß Sebastian

Florianinside
17.04.2006, 21:36
JAAAAAAAA es tut sich was es tut sich was!!
Super, dein EIMSK = (1<<PCIE1) war die Tageslösung.

In der Main() wird permanent von 1 bis 9 gezählt bis ein Interrupt kommt.
Gehe ich mit der Hand vor den Sensor, bleibt die Zahl auf dem Display stehen, die als letzte auf das LCD gepinnt wurde.

Und danach bleibt der Butterfly stehen und es passiert nüscht, also es wird nicht das hübsche Wort "wand" angeschrieben, wie in der Interruptfunktion gefordert wird, sondern das Ding bleibt stehen und das wars.

Aber für die Angabe des Registers schonmal vielen Dank, Izaseba.

Florianinside
17.04.2006, 21:37
Naja, jetzt habe ich der PinChangeInterrupt() am Ende noch ein return; spendiert und manchmal klappt es, dass "wand" erscheint und er danach brav weiterzählt. Aber meistens bleibt er wieder nur hängen...

izaseba
17.04.2006, 21:49
wie ? einer void ...(void) Funktion hast Du noch ein return spendiert ?
Normal dürfte sich sowas nicht kompilieren lassen, oder zumindest eine Warnung ausgeben.
Tue Dir selber ein gefallen, und halte Deine ISR so klein wie möglich,
setze ein globale volatile variable z.B. volatile uint8_t blabla = 0;
un der ISR machst Du nur blabla =1; und in Deiner main schleife prüfst Du Sie mit if (blabla){
tue_was;
blabla = 0;
}
so ist es auf jedemfall sauberer....

Gruß Sebastian

skillii
17.04.2006, 22:42
Ja, es ist möglich eine "void"-Funktion mit return zu beenden.

Man schreibt es dann so:
return;

Florianinside
17.04.2006, 23:18
Im Endeffekt dürfte sich mein Butterfly gar nicht aufhängen.
Ein return kann übrigends ohne Wert in c immer gesetzt werden, weil es dann automatisch dem break glecihgesetzt wird.

Wieso sich der BTFLY aufhängt, muss ich aber noch klären.
In jedem Fall wurde mir in diesem Forum stark weitergeholfen.

Wieder vielen Dank,
Florian.

izaseba
17.04.2006, 23:27
Ja, es ist möglich eine "void"-Funktion mit return zu beenden.

Man schreibt es dann so:
return;

Aha, und was bringt das ?
Kann ich dann die Funktion vorzeitig beenden, ohne sie komplett abzuarbeiten also irgendwie aus einer if Abfrage z.B ?
Bis jetzt kannte ich ja return nur im Zusammenhang mit Rückgabewerten...
Man lernt ja nie aus, danke für den Hinweis.

Gruß Sebastian

skillii
17.04.2006, 23:35
Ja du kannst eine Funktion vorzeitig beenden.
z.B.:


if(lol==1)
{
return;
}

izaseba
17.04.2006, 23:37
Wieso sich der BTFLY aufhängt, muss ich aber noch klären.
Wie ich schon gesagt habe, befrei die ISR von der ganzen Last, Das ist ja eine ziemliche Rumspringerei, was Du da drin hast. SprinterSB hat mal einen Artikel in Wiki geschrieben, was der kompiler aus deinem Code macht, schau mal hier (https://www.roboternetz.de/wissen/index.php/Codevergleich_AVR-Compiler) und zwar unter Interrupt und Funktion aufrufen.
Du springst ja aus der ISR in eine Funktion, damit landet einiges auf dem Stack, in der Funktion werden wiederum Funktionen Aufgerufen, da landet wieder was auf dem Stack, vielleicht läuft der Dir über, keine Ahnung.

Gruß Sebastian

SprinterSB
17.04.2006, 23:46
Kann ich dann die Funktion vorzeitig beenden, ohne sie komplett abzuarbeiten also irgendwie aus einer if Abfrage z.B ?

Genau so ist es. Das geht natürlich auch für nicht-void-Funktionen, dann natürlich mit return-Wert. Das kann in einem if oder Schleife oder wo auch immer stehen. Overhead ist es nicht (zumindest bei avr-gcc). Zudem ist das ganz normales C/C++.

izaseba
17.04.2006, 23:51
Zudem ist das ganz normales C/C++.


8-[ ich Dümmerchen, bin für sowas mit goto am hantieren, o weh #-o
Das ist das was ich an diesem Forum so liebe, wenn man nicht selber helfen kann, wird zumindest einem geholfen.

Gruß Sebastian

skillii
17.04.2006, 23:56
Ich bin in meinen C/C++-Codes bisher immer ohne goto ausgekommen ;)

SprinterSB
18.04.2006, 00:05
Ach ja, das return-von-wo-auch-immer ist übrigens auch normales Java ;-)
Da würde dir nämlich ein goto fehlen.

Java kennt zwar das Schlüsselwort "goto", aber nur um zu sagen, daß es ganz ganz fürchterlich schlimm ist! ;-)

izaseba
18.04.2006, 00:08
Ja goto soll in manchen Programmiererkreisen keinen all zu großen Wert darstellen.

Irgendwann hab ich zu lernzwecken ein Beispielcode für twi durchgearbeitet
moment, hier (http://www.nongnu.org/avr-libc/user-manual/group__twi__demo.html)zu finden.
Es ist mit goto von oben bis unten gespickt, und ich denke daß der jenige welche, der das geschrieben hat zu der Elite gehört.

Aber es hängt wiedermal davon ab, was man macht.

Gruß Sebastian

SprinterSB
18.04.2006, 00:26
Ich kann diesen man-soll-auf-garkeinen-Fall-goto-verwenden-Dogmatismus nicht nachvollziehen.

Wenn man eine 3-fach geschachtelte Suchschleife nach Finden verlassen will, bricht man sich ohne goto einen ab, muss zusätzliche Variablen mitschleppen, verlangsamt die Suche und das Prog wird viel schwerer verständlich als durch einen schmerzlosen Hüpfer aus den Schleifen raus.

vajk
19.04.2006, 16:06
... Wenn man eine 3-fach geschachtelte Suchschleife nach dem Finden verlassen will, bricht man sich ohne goto einen ab, ...

Es ist aber unsauberer Stil.

Besser wäre es einfach die zwei äußeren Schleifenvariablen "hochzusetzen" und dann die innere Schleife mit break zu verlassen.

Allerdings ist ein jmp im asm-Code was normales ...

Und da in uC - Umgebung und je nach verwendetem Controller die Bytes rar sind, ist goto eine Variante, um code zu sparen.
Sollte aber möglichst linear eingesetzt und gut dokumentiert werden. Sonst blickt man seinen eigenen Code später nicht mehr ....

Viel Spaß noch,
Vajk