-
interrupt so oder so
Hallo an alle,
Ich brauche mal eine kurze Hilfe in sachen Interrupt Programmierung.
Kurze Vorgeschichte:
Ich habe mehrere AVRmega32 aneinander gekettet. Davon ist einer der Master und die anderen Slave. Alle Slave haben eine eindeutige Adresse und werden von dem Master über einen eigens geschaffenen Bus nacheinander fortlaufend abgefragt. Das klappt mit einer WHILE {FOR-Schleife} auch prima.
Jetzt das Problem:
Um die Daten auszuwerten brauche ich eine möglichst genaue Zeitangabe.
Dies habe ich versucht durch einen externen CMOS4060 zu schaffen der mir einen 1ms Takt am Master als Eingang bringt. Diesen frage ich zwischendrin immer wieder ab und zähle die Takte mit bis der Master alle Slave abgefragt hat und werte dann die Daten aus (zähler wieder auf NULL). Jetzt habe ich mal mitgestopt und festgestellt das mir ca. 5-8% der Takte verloren gehen. Ich lese immer wieder über Interrupts habe damit aber keinerlei Erfahrung da ich eher ein ab und zu Programmierer bin. Man soll Takte auch intern genau verwalten können habe ich gehört (dann könnte ich den 4060 weglassen). Für diese Probleme (ob intern oder extern) und wie man sie löst bräuchte ich mal eine möglichst exakte Lösung in C wie und wo man Interrupts zählt (inkl. allem was ich einstellen muß (ich setze zurzeit in PonyProg keine Harken)). Der Takt sollte später möglichst schnell sein um die Genauigkeit zu erhöhen. Hauptsache das Ergebnis stimmt. Warum mir Takte fehlen kann ich mir schon vorstellen. Das liegt bestimmt an dem Senden und Empfangen des Masters (Wartezeiten) und der Darstellung auf dem Display.
Danke für eure Hilfe!!! Für euch ist das bestimmt kein Problem.
-
Womit programmierst du? AVR-Studio, CodeVision?
Welche Taktfrequenz hat dein Mega32.
Verwendest du schon einen Timer.
Wenn du einen ext. Takt nimmst, dann darfst du nicht pollen.
Mit Interrupts und Timer wirst du dich beschäftigen müssen.
Eine fertige Lösung wird dir kaum jemand bieten können, Hilfe ganz sicher.
-
also ich abreite mit 11Mhz am AVR einen Timer verwende ich nicht.
Allerdings habe ich mir pause_ms(xxx) über Beschäftigung des AVR geschaffen (FOR-Schleifen mal CPU-Takt).
Pollen???? Ausgang des 4060 auf Eingang des AVR PINA0
Es muß doch sowas geben wie:
zähle per Interrupt eine Variable zähler hoch wenn eine Flanke kommt
-
Das kannst du mit einem internen Timer machen.
-
ja das wäre mir am liebsten.
Aber dann brauche ich eine Variable die mir sagt wieviele Milli oder noch besser Mikrosekunden seit dem letzten Scanndurchlauf vergangen sind. Also sowas wie eine Zählschleife des Internen Taktes die unabhänig mit läuft. Ich habe bis jetzt nur solche Funktionen gefunden die den AVR schlafen lassen. Bin ich zu blöd google zu benutzen?
-
Pollen nennt man die Abfrage eines Pin in einer Schleife. Wenn die Abfrage langsamer ist als der Takt, geht natürlich etwas verloren.
Für dich wäre ein ext. Interrrupt not wendig, INT0 am PD2 z.B.
Besser wäre, wie schon erwähnt, ein Timer, der würde auch das pause_ms ersetzen.
-
genau das wäre auch mein Ansatz.
Gibt es eine kleine Headerdatei die mir die Anzahl der Mikrosekunden zurückliefert. Sowas wie.
.
.
.
takte = timerus();
timerus(0);
.
.
.
-
Das geht mit dem Timer0 ganz einfach.
Code:
#include <avr/interrupt.h>
volatile unsigned char zaehler;
// Im main einrichten
TCCR0=(1<<WGM1)|(1<<CS02); // CTC, prescaler /256
OCR0=42; // sollte mit dem Prescaler 1msec ergeben
TIMSK=(1<<OCIE0); // Output Comparematch Interrupt aktivieren
sei(); // Interrupt generell freigeben
//Interruptroutine
ISR(TIMER0_COMP_vect ){
zaehler++;
}
Die Variable zaehler wird jede 1msec um 1 erhöht
-
leider ohne Erfolg!!!
Ich habe also folgendes versuchsweise geschrieben:
#include <avr/io.h> //Zugriff auf IO's des Controllers
#include <avr/interrupt.h>
volatile unsigned char zaehler;
int main()
{
// Im main einrichten
TCCR0=(1<<WGM1)|(1<<CS02); // CTC, prescaler /256
OCR0=42; // sollte mit dem Prescaler 1msec ergeben
TIMSK=(1<<OCIE0); // Output Comparematch Interrupt aktivieren
sei(); // Interrupt generell freigeben
DDRB = 0xff; //PB0...PB7 als Ausgänge definieren
while(1)
{
PORTB = zaehler;
}
}
//Interruptroutine
ISR(TIMER0_COMP_vect )
{
zaehler++;
}
daraufhin mekert mein AVR Studio mit folgenden Meldungen:
../ZAEHLER/zaehlerinterrupt.c:10: error: `WGM1' undeclared (first use in this function)
../ZAEHLER/zaehlerinterrupt.c:10: error: (Each undeclared identifier is reported only once
../ZAEHLER/zaehlerinterrupt.c:10: error: for each function it appears in.)
../ZAEHLER/zaehlerinterrupt.c: At top level:
../ZAEHLER/zaehlerinterrupt.c:24: warning: return type defaults to `int'
make: *** [zaehlerinterrupt.o] Error 1
Build failed with 3 errors and 1 warnings...
hab ich da was falsch verstanden???
-
Der Fehler beim WGM1 kommt daher, das das wohl WGM01 heißen soll.
Die Warnung mit dem Return type ist etwas schwer zuzuordnen. Könnte davon kommen, das main als Int definiert wurde. Beim AVR (ohne Betreibssystem) ist eher void main() üblich.