Forum: Mikrocontroller und Digitale Elektronik Arduino: Interrupt (INT0) Rekursion möglich?


von Christian J. (Gast)


Lesenswert?

Hallo,

mangels Kenntnissen wie man den Atmega "richtig" programmiert bzw. auch 
kene Toolchain dafür vorhanden vergewaltige ich einen Arduino Pro Mini 
etwas, bzw. nutze die IDE nur zum Uploaden. Er soll IR Daten einlesen 
was er auch tut, inzwischen zumindest.

Die TSOP Low Flanken werden auf INT0 erkannt und dort vermessen.

Erkenntnis 1: micros() funktioniert in einer ISR nur, wenn man 
Interrupts wieder zulässt. Sonst kommt da Murks bei raus. Im Netz wird 
oft was anderes behauptet aber es ist so.

Erkenntnis 2: Oh weh! Damit erlaube ich ja auch Störsignalen auf dem 
TSOP sich rekursiv einzhuhaken, denn die ISR Sperre für den Durchlauf 
der INT0 ISR wird ja durch das globale INT Flag ausgelöst.

Das GICR Register ist über die Arduino IDE nicht erreichbar, da wollte 
ich zunächst nut INT0 blockieren aber die INTs für micros() zulassen.

Und jetzt wird es tricky:
1
void int0vect()
2
{
3
  (Varibalendeklarationen)
4
5
if (f_ISR_Blocker) return;
6
interrupts();        // Erlaube micros()
7
f_ISR_Blocker = true; // Routine gegen Fehlsignale blocken
8
period = micros()-10; // Aktuellen Timerwert speichern und Offset abziehen
9
while (!digitalRead(TSOP));     // Warte bis Pin wieder HIGH geht
10
period = micros()-period;       // Dauer in us berechnen
11
noInterrupts();
12
f_ISR_Blocker = false;
13
--> Auswertung
14
15
}

durch f_ISR_Blocker versuche ich das "aufzuhalten", dass unmittelbar 
nach Einspruung Störsignale einen Stacküberlauf erzeugen.

Gibt es da noch einen eleganteren Weg? Wenn GICR verfügbar wäre würde 
ich da direkt abschalten aber leider meckert er dass er das register 
nicht kennt.
MCUCR aber ist vorhanden.

Gruss
Christian

von Linksammler (Gast)


Lesenswert?

Deine Arduino-IDE installiert einen normalen AVR-GCC mit.
Also "Toolchain vorhanden", wenn auch etwas versteckt.

Dann: vergiss das ausmessen mit "micros()".
Der AVR hat extra Hardware zum vermessen von solchen Signalen: Timer mit 
Capture.

von g457 (Gast)


Lesenswert?

> Gibt es da noch einen eleganteren Weg?

Ja. Warten in einer ISR ist per se pöse [0].

> Wenn GICR verfügbar wäre würde ich da direkt abschalten aber leider
> meckert er dass er das register nicht kennt.

Zurecht. Heisst ja auch EIMSK. Kuckst Du Datenplatt.

HTH

[0] extrem gute Gründe ausgenommen, die liegen hier aber nicht vor

von Christian J. (Gast)


Lesenswert?

Linksammler schrieb:

> Dann: vergiss das ausmessen mit "micros()".
> Der AVR hat extra Hardware zum vermessen von solchen Signalen: Timer mit
> Capture.

Aber über die Jehova IDE sind die nicht erreichbar. Dafür muss man auf 
die registerebene runter. Und es fehlen eben Registerdeklarationen.

von Linksammler (Gast)


Lesenswert?

Christian J. schrieb:
> Und es fehlen eben Registerdeklarationen.
1
#include <avr/io.h>

von Christian J. (Gast)


Lesenswert?

Habe was:

https://gist.github.com/billroy/4032657

Maximal aber 4,6ms möglich und das ist knapp.

von Christian J. (Gast)


Lesenswert?

g457 schrieb:
> Zurecht. Heisst ja auch EIMSK. Kuckst Du Datenplatt.

Jo.... mal das Brett vom Kopp wegnehmen :-)

von Linksammler (Gast)


Lesenswert?

Christian J. schrieb:
> Maximal aber 4,6ms möglich und das ist knapp.

dann ändere den Prescaler in "initTimer".

von Christian J. (Gast)


Lesenswert?

Linksammler schrieb:
> dann ändere den Prescaler in "initTimer".

Ist aufwendiger als das hier zudem der Stein nichts anderes zu tun hat 
als zu warten und zu decodieren.

EIMSK =  EIMSK & ~(1 << 0);  // INT0 abschalten
interrupts();      // Globale Ints für micros() zulassen
period = micros()-10;  // Aktuellen Timerwert speichern
while (!digitalRead(TSOP)); // Warte bis Pin wieder HIGH geht
period = micros()-period;   // Dauer in us berechnen
noInterrupts();    // Global wieder sperren
EIMSK =  EIMSK | (1 << 0);// INT0 reaktivieren

Kurze Frage bevor alles klar:Ist es richtig, dass die AVR bei Ausführung 
einer ISR das Global Int Flag sperren im SREG und es nach Ende wieder 
freigeben?

von Christian J. (Gast)


Lesenswert?

ps: ok, passt! Sieht schoa besser aus als dieser Arduino Kram. Läuft 
einwandfrei während im Zimmer hier die Daten durch die Luft sausen.

EIMSK =  EIMSK & ~(1 << 0);    // INT0 abschalten
SREG  = SREG | (1 << 7);    // Globale Ints für micros() zulassen
period = micros()-10;      // Aktuellen Timerwert speichern und Offset 
abziehen
while (!digitalRead(TSOP));     // Warte bis Pin wieder HIGH geht
period = micros()-period;       // Dauer in us berechnen
SREG  = SREG & ~(1<<7);      // Globale Ints wieder sperren
EIMSK =  EIMSK | (1 << 0);    // INT0 reaktivieren

von Linksammler (Gast)


Lesenswert?

Christian J. schrieb:
> Ist aufwendiger als das hier zudem der Stein nichts anderes zu tun hat
> als zu warten und zu decodieren.

Dumme Frage: Warum tust du dir dann überhaupt das INT0-Gehampel an?
Dann kannst du auch beide Flanken per Polling abfragen, Abwechselnd mit
> while (!digitalRead(TSOP));
und
> while (digitalRead(TSOP));

Schön ist das aber auch nicht.

von Christian J. (Gast)


Lesenswert?

Linksammler schrieb:
> Dumme Frage: Warum tust du dir dann überhaupt das INT0-Gehampel an?
> Dann kannst du auch beide Flanken per Polling abfragen, Abwechselnd mit
>> while (!digitalRead(TSOP));
> und
>> while (digitalRead(TSOP));

Kann man... aber INTs sind "eleganter" und hat mich mehr gereizt als das 
altbacken zu machen. Die Polling Lösung mit pulseIn habe ich vorher 
gemacht. Außerdem läuft der Empfang weiter während er schon den letzten 
Datensatz Richtung PC raushaut.

von Linksammler (Gast)


Lesenswert?

Christian J. schrieb:
> Kann man... aber INTs sind "eleganter"

Aber eine Warteschleife innerhalb eines INTs ist so ziemlich das 
"uneleganteste" was man darin veranstalten kann.

Wenn du schon die extra-Capture-Hardware nicht nutzen magst, aber 
zwingend den externen INT-Pin, warum nicht in der ISR nur timestamps 
ziehen, und jedes mal die Trigger-Flanke für den Interrupt 
umkonfigurieren?

die Profis (IRMP) machen das übrigens mit Polling aus dem 
Timer-Interrupt.

von Peter D. (peda)


Lesenswert?

Du scheinst da was grundsätzlich mißverstanden zu haben. Das Ziel beim 
Programmieren ist nicht, maximalen Schaden in der Programmstruktur 
anzurichten.
Sondern im Gegenteil, die Ressourcen mit Bedacht zu verwenden, damit 
auch noch viele andere Tasks implementiert werden können.

Es gibt meines Wissens auch (noch) keinen Award für die schlechteste 
CPU-Auslastung.

: Bearbeitet durch User
von Christian J. (Gast)


Lesenswert?

Linksammler schrieb:

> warum nicht in der ISR nur timestamps
> ziehen, und jedes mal die Trigger-Flanke für den Interrupt
> umkonfigurieren?

Jo, bei einem PIC auch schon so gemacht.... mal schauen, heute abend 
wenn ich Lust zu habe. Das ist echt eleganter. Aber es ist nicht alles 
aus der Arduino IDE erreichbar, was man mit klassischer programmierung 
macht.

von Peter D. (peda)


Lesenswert?

Christian J. schrieb:
> Aber es ist nicht alles
> aus der Arduino IDE erreichbar, was man mit klassischer programmierung
> macht.

Was soll denn da nicht gehen?

Arduino ist erstmal plain C, d.h. Du kannst alles machen, was in C auch 
geht.
Arduino hat nur noch eine zusätzliche Lib mit Funktionen, die natürlich 
Ressourcen belegen, wenn man sie benutzt. Aber niemand zwingt Dich, sie 
zu benutzen.
In der Doku müßten auch alle Einschränkungen und Seiteneffekte drin 
stehen.

von Joachim B. (jar)


Lesenswert?

Christian J. schrieb:
> Aber es ist nicht alles
> aus der Arduino IDE erreichbar, was man mit klassischer programmierung
> macht.

was denn?

ist mir nie aufgefallen, ich kann die Arduino nehmen oder klassisch wie 
vor meiner Arduinozeit, ich kann beide mixen und bin so von vor Arduino 
zum Ardunio pö a pö umgezogen.

Zuerst pur AVR im Studio, dann Arduino mit IDE, einige Codes von vor 
Arduino eingebaut und freunde mich so nach und nach mit der Arduino IDE 
an,

ob ich nun I2C per Register anspreche oder per wire.h ist doch egal, 
kommt fast immer auf selbe raus wenn man hinter die Arduinokulissen 
schaut.

von mraction (Gast)


Lesenswert?

Warum lässt du den Arduino Kram dann nicht weg? Du scheinst ja nicht 
unbedingt auf diese Abstraktionsschicht angewiesen zu sein...

von Christian K. (the_kirsch)


Lesenswert?

Peter Dannegger schrieb:
> Arduino ist erstmal plain C, d.h. Du kannst alles machen, was in C auch
> geht.
> Arduino hat nur noch eine zusätzliche Lib mit Funktionen, die natürlich
> Ressourcen belegen, wenn man sie benutzt. Aber niemand zwingt Dich, sie
> zu benutzen.
> In der Doku müßten auch alle Einschränkungen und Seiteneffekte drin
> stehen.

Wenn man die Arduino-HAL (Hardware Abstraction Layer; Ich nenn es jetzt 
mal HAL und nicht Lib) nicht verwenden möchte, sollte man auch nicht die 
Arduino-IDE verwenden.

Die main() wird bereits in der Arduino-HAL definiert, daher muss man die 
vorgesehenen Funktionen setup() und loop() verwenden.

Theoretisch aber nicht empfohlen, kannst du die setup() wie eine main 
benutzen und auf jeden weiteren Arduino-HAL Funktionsaufruf verzichten.

Jetzt kommt die krucks.
Man sollte loop() verwenden, da nach jedem Loop ein paar Arduino-HAL 
Tasks (zumindest für UART) gepollt werden.

Die Arduino-HAL führt eine Initialisierung der Hardware durch, und 
belegt einen Timer. Es werden für einige Hardwarekomponenten ISRs 
definiert, die du in deinem eigenen Code dann nicht selbst 
ausprogrammieren kannst.



Ich verwende Eclipse mit CDT und "AVR-Eclipse"-Plugin. Man kann aus 
Eclipse heraus mittels AVRDude die Arduinos per USB programmieren.

avr-gcc und avrdude werden zwar bei der Arduino-IDE mitgeliefert. Aber 
es fehlt eine make.exe.

Daher WinAVR installieren, da ist avr-gcc, avrdude und make enthalten.

von Christian J. (Gast)


Lesenswert?

Joachim B. schrieb:

> ob ich nun I2C per Register anspreche oder per wire.h ist doch egal,
> kommt fast immer auf selbe raus wenn man hinter die Arduinokulissen
> schaut.

Arduino belegt von Haus aus einige Ressourcen und das ist nicht 
dokumentiert. Fummelt man unter der HAL herum kann es sein dass einiges 
nicht mehr funktioniert. Stoppt man die Interrupts läuft auch I2C nicht 
mehr, die Uart nicht, millies, micros usw.

Ich nutze die Libs gerne und die Vereinfachungen, sowie die einfache 
Upload Möglichkeit mit 1-Click und Terminalfenster aber ansonsten will 
ich davon weg, hatte ich bei PICS auch nicht und kam damit gut klar. Nur 
solange ich AVR noch nicht so gut kenne nutze ich das.

von Joachim B. (jar)


Lesenswert?

Christian J. schrieb:
> Stoppt man die Interrupts läuft auch I2C nicht
> mehr, die Uart nicht, millies, micros usw.

millies, micros nutze ich nicht, zu abstrakt, bei meinen eigenen 
Timerroutinen weiss ich was läuft.
Bei der Uart schwanke ich noch zwischen geht so und ist grausam.

Christian J. schrieb:
> Ich nutze die Libs gerne und die Vereinfachungen, sowie die einfache
> Upload Möglichkeit mit 1-Click und Terminalfenster aber ansonsten will
> ich davon weg,

so gehts mir ja auch, die farb TFT mit Touch Ansteuerung selber fummeln, 
nee danke,
dito mit Nokia 5110 oder OLED.

Die RTC hatte ich mir mal selber geschrieben, nutze aber jetzt den 
Komfort der DS1307 Lib auch am DS3231 mit eigenen Erweiterungen, 
feststellen welcher drin ist, 1307 oder 3231 und dann entweder RAM oder 
Tempfühler nutzen.

Die WS2812b LIB musste ich patchen weil die buggy ist mit m1284p und die 
Autoren unwillig waren, alles kein Ding, machen es nicht andere muss ich 
halt selbst ran.

: Bearbeitet durch User
von Eric B. (beric)


Lesenswert?

Peter Dannegger schrieb:
> Es gibt meines Wissens auch (noch) keinen Award für die schlechteste
> CPU-Auslastung.

[troll]
Der würde dauerhaft an Windows gehen ;)
[/troll]

von Karl (Gast)


Lesenswert?

Eric B. schrieb:
> [troll]
> Der würde dauerhaft an Windows gehen ;)
> [/troll]

[fish for troll]
Deshalb gibt es bald Windows 10 für Arduino
[/fish for troll]

von Christian J. (Gast)


Lesenswert?

Christian K. schrieb:

> Die Arduino-HAL führt eine Initialisierung der Hardware durch, und
> belegt einen Timer. Es werden für einige Hardwarekomponenten ISRs
> definiert, die du in deinem eigenen Code dann nicht selbst
> ausprogrammieren kannst.

Das erklärt allerdings nicht solche Merkwürden wie dass eine lokale 
static Variable in einer Routine gar nicht static ist, sondern bei jedem 
Aufruf wieder auf 0 gesetzt wird. Ich habe mich neulich gewundert, dass 
ein einfaches

static int c = 0;

if(c++ > 3) {
c=0;
...

nie ausgeführt wird bis ich c mal ausgeben liess, was immer 1 wurde und 
dann wieder 0. Auch kein volatile half da. Woanders klappte das prima 
aber in der Routine die keine ISR war nicht. Leider kommt man an den Asm 
schwer ran, nur per Hand, was ich ärgerlich finde.

von Walter S. (avatar)


Lesenswert?

Christian J. schrieb:
> Das erklärt allerdings nicht solche Merkwürden wie dass eine lokale
> static Variable in einer Routine gar nicht static ist,

zeig doch Mal den ganzen Code, das klingt zu merkwürdig um wahr zu sein

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.