Hallo zusammen,
Ich möchte Encoder gesteuert einige Funktionen ausführen. Die Fallende
Flanke löst ein Interrupt aus welches ein Flag setzt und in der WHile1
wir das Flanke zurück gesetzt und eine Funktion ausfgerufen. Im
Interrupt prüfe ich ob das Flag zurücksetzt wurde. Wenn nein wird der
Fehlercode 4 an meinen LEDs angezeigt.
Ich habe das Problem das bei einer Interrupt Frequenz von 500Hz in
unregemäßigen Abständen der ATmega 128 mit einem 14,...MHz Quarz nicht
schafft das Interrupt zu verarbeiten und er immer in den Fehlerzustand
geht.
Hier ist mein Code
1
#include"allHeader.h"
2
volatileintselftest_need=0;
3
volatileintencoderA_flag=0;
4
5
6
7
8
intmain()
9
{
10
11
12
13
initInputs();
14
initOutputs();
15
initStatusLEDs();
16
17
18
// einstellen fallende Flanke + Aktivieren
19
EICRB&=~(1<<ISC40);
20
EICRB|=(1<<ISC41);
21
EIMSK|=(1<<INT4);
22
23
24
sei();
25
26
27
28
29
while(1)
30
{LEDPORT=selftest_need;
31
32
if(encoderA_flag)
33
{
34
encoderA_flag=0;//ggf. ans Ende
35
36
}
37
38
}
39
}
40
41
42
43
44
// Encoderinterrupt
45
ISR(INT4_vect)
46
{
47
if(encoderA_flag==1)
48
{
49
selftest_need=4;
50
}
51
else
52
{
53
selftest_need=0;
54
}
55
56
/*if(encoderDirection()!=LEFT)
57
selftest_need = 5;*/
58
59
encoderA_flag=1;
60
61
}
Habt ihr eine Idee voran es liegen kann? Ich habe schon versucht mit
einem Rechteckgenerator den Encoder zu ersetzten das Problem bleibt
leider das Gleiche.
> volatile int selftest_need = 0;
warum 16bit um 0 oder 1 zu speichern?
kosten sinnlos Rechenzeit und ist nicht mehr atomar. Ändere es mal auf
uint8_t ab.
Peter II schrieb:> neuling schrieb:>> Ich habe ein minmale zappeln auf dem Rechtecksignal kann das die Ursache>> sein?>> ja
ok und wie löse ich das jetzt am besten? Ein C gegen Masse? reicht das
schon?
A. K. schrieb:> Tritt das Problem auch beim gezeigten Schrumpfprogramm auf, oder> nur> beim Original?
auch bei dem minimal Beispiel bei unter 1Hz Interruptfrequenz!!!
neuling schrieb:> ok und wie löse ich das jetzt am besten? Ein C gegen Masse? reicht das> schon?
wenn man alles richtig Dimensioniert ja, aber daran denken, das ein
Kondensator im ersten Moment ein Kurzschluss ist
oder per Software
http://www.mikrocontroller.net/articles/Drehgeber
neuling schrieb:> Ich möchte Encoder gesteuert einige Funktionen ausführen. Die Fallende> Flanke löst ein Interrupt aus
Soll das jetzt ein Trollbeitrag sein ?
Natürlich ist es nicht zuverlässig, einen Encoder per Flankeninterrupt
auszuwerten. Da muss man nicht auf die Desinformationskampagne von
TorstenC und m.n. reinfallen.
Beitrag "Drehimpulsgeber"
Peter II schrieb:> neuling schrieb:>> Ich habe ein minmale zappeln auf dem Rechtecksignal kann das die Ursache>> sein?>> ja
Nicht bei dem Testcode.
Prellen spielt sich im Millisekundenbereich ab. Wenn ein mit 14Mhz
getakteter M128 da nicht mitkommt, ist irgendwas anderes faul
Doch bei dem Testcode.
Wenn nämlich "funktioniert" bedeutet: "keine Fehler-LED leuchtet" und
wegen Prellen nach dem RETI nur einen "Hauptschleifenbefehl" ausgeführt
wird, was nicht reicht um encoderA_flag zu löschen und der nächste Int
dann schreit "Fehler".
Wenn man den μC verprellt, da spielt er manchmal nicht mehr mit ;-)
du greifst sowohl im interrupt als auch in deiner hauptschleife auf die
gleiche variable zu. sind die zugriffe nicht atomic, geht das beinahe
schon mit ansage schief.
kann natürlich auch hardwarebedingt sein, aber wenn du sagst du hast es
schon mit nem generator getestet..
mach mal in der hauptschleife um die prüfung herum die interrupts aus.
Karl H. schrieb:> Was machen>>>> initInputs();>> initOutputs();>> initStatusLEDs();>> Die Pullups am Eingang hast du aktiviert?
void initOutputs()
{
JETDDR |= (1<<JET1);
JETDDR |= (1<<JET2);
}
void initInputs()
{
ENCODERDDR &= ~(1<<ENCODERA);
ENCODERDDR &= ~(1<<ENCODERB);
}
void initStatusLEDs()
{
LEDDDR |= 255; // set LEDpins
}
dunno.. schrieb:> mach mal in der hauptschleife um die prüfung herum die interrupts aus.
Dann funktioniert es. Muss ja auch so sein, denn das erneute aufrufen
des Interrups löst ja den Fehler aus.
Wenn ich die Interrups aber aus mache, kann ich mir die Abfrage auch
sparen. Ich möchte ja jeden fallenden Flankenwechsel erkennen. Es darf
keiner verpasst werden. Sollten 2 Flankenwechsel ohne Verarbeitung
dazwischen kommen benötitge ich den Fehler. Wenn das Interrupt während
der Verarbeitung kommt wäre das ok solange Es bis zum nächsten Interrupt
wieder in der Verarbeitung ist.
Wie löse ich das am saubersten.
neuling schrieb:> Wenn ich die Interrups aber aus mache, kann ich mir die Abfrage auch> sparen. Ich möchte ja jeden fallenden Flankenwechsel erkennen.
Wenn der interrupt während der Abfrage aus ist, wird nur nicht in die
ISR gesprungen. Die Flanke wird aber trotzdem erkannt, und die ISR
sofort ausgeführt, sobald der interrupt wieder aktiviert wird.
was du verpassen würdest, wäre, wenn du zur zeit der abfrage zwei
interrupts bekommst. rechne mal aus wie schnell das sein musste, und mit
wieviel u/min dein encoder gedreht werden müsste..
Peter II schrieb:> oder er prellt
Richtig, das ist natürlich auch noch sehr gut möglich.
Trotzdem, der Code so wie er ist ist doch gerade das paradebeispiel aus
ner vorlesung über race-conditions.
neuling schrieb:> Wenn ich die Interrups aber aus mache
Jeder Interrupt, der nicht unbedingt benötigt und deshalb nicht
verwendet wird, reduziert die möglichen Probleme um den Faktor 2..10.
Und einen Drehgeber, an dem mit der Hand gedreht wird, liest man am
Besten mit dem sowieso nötigen 1ms-TimerTic ein. Sieh dir dazu mal den
Beitrag "Drehimpulsgeber" an. Dort wird die Thematik
ausführlich und kontrovers diskutiert. Solange, bis zum Schluss die
Interrupt-Verarbeiter übrig bleiben...
> Ich möchte ja jeden fallenden Flankenwechsel erkennen. Es darf keiner> verpasst werden.
Wie schnell können diese Flanken denn überhaupt wechseln?
Mit Interrupt aus und wieder ein geht es. Jetzt habe ich ein anderes
interesantes Problem.
Ich möchte jetzt noch 2 Lichtschranken über Interrupt einbinden und je
nach Auslösung einen Trigger senden. Die Lichtschranken Liefern 5V und
bei Unterbrechung fallen sie auf 0V.
Ich habe den Code wie folgt erweitert:
#include "allHeader.h"
volatile uint8_t selftest_need = 0;
volatile uint8_t encoderA_flag = 0;
volatile uint8_t ls1_flag = 0;
volatile uint8_t ls2_flag = 0;
int main()
{
initInputs();
initOutputs();
initStatusLEDs();
JETPORT &= ~(1<<JET1);
JETPORT &= ~(1<<JET2);
// einstellen fallende Flanke + Aktivieren
EICRB &= ~(1<<ISC40);
EICRB |= (1<<ISC41);
EIMSK |= (1<<INT4);
EICRB &= ~(1<<ISC50);
EICRB |= (1<<ISC51);
EIMSK |= (1<<INT5);
EICRB &= ~(1<<ISC60);
EICRB |= (1<<ISC61);
EIMSK |= (1<<INT6);
sei();
while(1)
{ LEDPORT = selftest_need;
CAMPORT &= ~(1<<CAM1);
CAMPORT &= ~(1<<CAM2);
cli();
if(encoderA_flag)
{
encoderA_flag = 0; //ggf. ans Ende
JETPORT |= (1<<JET1);// im Regelfall nicht da
JETPORT |= (1<<JET2);// im Regelfall nicht da
}
sei();
cli();
if(ls1_flag)
{
ls1_flag = 0; //ggf. ans Ende
JETPORT |= (1<<JET1);
}
sei();
cli();
if(ls2_flag)
{
ls2_flag = 0; //ggf. ans Ende
JETPORT |= (1<<JET2);
}
sei();
}
}
// Encoderinterrupt
ISR(INT4_vect)
{
if(encoderA_flag == 1)
{
selftest_need = 4;
}
else
{
selftest_need = 0;
}
encoderA_flag = 1;
}
// LS1interrupt
ISR(INT5_vect)
{
if(ls1_flag)
{
selftest_need = 1;
}
else
{
selftest_need = 0;
}
ls1_flag = 1;
}
// LS2interrupt
ISR(INT6_vect)
{
if(ls2_flag)
selftest_need = 2;
ls2_flag = 1;
}
Zum Problem:
Wenn ich am Encoderpin (hier PE4) den Encoder anlege lösen meine Trigger
im Encodertakt aus. Wie gewollt.
Kommentiere ich das Trigger setzen im der Encoderverarbeitung aus, hätte
ich erwartet wenn ich eine Lichtschranke unterbreche der gewünschte
Trigger kommt. Lichtschranke 1 PE5 und Lichtschranke 2 PE6.
Ist meine Erwartung bis hier richtig?
Es passiert leider garnix.
Nächste Erwartung:
Wenn ich folgene Änderung mache:
Keine änderung in der Verdrahtung
// Encoderinterrupt
ISR(INT4_vect) -> ISR(INT5_vect)
// LS1interrupt
ISR(INT5_vect) -> ISR(INT4_vect)
// LS2interrupt
ISR(INT6_vect) -> ISR(INT6_vect)
Ich hätte erwartet das jetzt mit dem Encodertakt der Trigger JET1
ausgelöst wird. Erwartung falsch?
Was passiert: Die Lichtranke 1 löst bei Unterbrechung den Trigger JET1
aus. Warum?
Nächste Erwartung:
Wenn ich folgene Änderung mache:
Keine änderung in der Verdrahtung
// Encoderinterrupt
ISR(INT4_vect) -> ISR(INT5_vect)
// LS1interrupt
ISR(INT5_vect) -> ISR(INT6_vect)
// LS2interrupt
ISR(INT6_vect) -> ISR(INT4_vect)
Ich hätte erwartet das jetzt mit dem Encodertakt der Trigger JET2
ausgelöst wird. Oder aber nach dem eben erlebten. Die Lichtranke 2 löst
bei Unterbrechung den Trigger JET2 aus. Erwartung falsch?
Was passiert: Die Lichtranke 1 löst bei Unterbrechung den Trigger JET2
aus. Warum?
Ich kann es mir nicht erklären hat jemand eine Idee warum. Bitte etwas
ausführlcih erklären ich möchte es verstehen und die Problem in Zukunft
nicht mehr haben.
neuling schrieb:> Karl H. schrieb:>> Was machen>>>>>> initInputs();>>> initOutputs();>>> initStatusLEDs();>>>> Die Pullups am Eingang hast du aktiviert?>> void initOutputs()> {>> JETDDR |= (1<<JET1);> JETDDR |= (1<<JET2);>
Und wo sind die Pullups?
Bastler schrieb:> Doch bei dem Testcode.> Wenn nämlich "funktioniert" bedeutet: "keine Fehler-LED leuchtet" und> wegen Prellen nach dem RETI nur einen "Hauptschleifenbefehl" ausgeführt> wird, was nicht reicht um encoderA_flag zu löschen und der nächste Int> dann schreit "Fehler".
Wie lange dauert bei 14Mhz die Ausfuehrung eines Hauptschleifenbefehls
und in welchen Zeitrauemen spielt sich Tastenprellen ab?
Alles was ihr angefuehrt habt ist soweit richtig. Nur spielt es in
seinem Testcode keine Rolle. Sein Eingang ist ohne Pullup und faengt
sich Stoerungen ein. Ganz einfach
Das muss euch doch selber auffallen, dass da eine enorme Zeitdiskrepanz
vorliegt. Der AVR hat eine Zykluszeit vun unter 0.1 mikrosekunden. Und
den willst du mit Kontaktprellen ueberfahren?
Seine Hauptschleife laeuft in geschaetzten 1 Mikrosekunde einmal rum.
Selbst wenn ich fuer die Isr noch was zugebe, ist das Flag spaetestens
nach 3 Mikrosekunden wieder geloescht. Und da hab ich schon alles Worst
Case angenommen und alle Huehneraugen mit zugedrueckt.
Lothar M. schrieb:> Wie schnell können diese Flanken denn überhaupt wechseln?
Der Encoder häng an einem kleine Föderband welchen über einen Motor
angetrieben wird. Die Flanken können sich therotisch zwischen 275µs..2ms
wiederholen. Mich würde ja schon freunen wenn es im oberen Bereich geht.
> Seine Hauptschleife laeuft in geschaetzten 1 Mikrosekunde einmal rum.
Selbst wenn ich fuer die Isr noch was zugebe, ist das Flag spaetestens
nach 3 Mikrosekunden wieder geloescht.
Da ist alles valide, nur: wenn er die Hauptschleife per CLI/SEI gegen
parallele Interrupts verriegelt, dann geht's. Denn dann kommt kein neuer
Int bevor das Flag gelöscht ist. Solange der "Drehgeber" keinen Namen
hat, sind die ms nur geschätzt. Und die Indizien sprechen für mehrfache
INT's in kurzer Zeit. Wie sonst sollte das gepostete Programm sich sonst
so verhalten. Aber ist nur so meine Idee, darf jeder beliebig anders
sehen.
neuling schrieb:> Bastler schrieb:>> olange der "Drehgeber" keinen Namen>> hat, sind die ms nur geschätzt.>> das ist der verwendete Encoder:> http://www.conrad.de/ce/de/product/198518/Kuebler-Inkremental-Drehgeber-Typ-2400-Vollwelle-Wellen-6-mm-Aufloesung-1024-ImpU-Drehzahl-max-12000-Umin?ref=list>> Bastler schrieb:>> Und die Indizien sprechen für mehrfache>> INT's in kurzer Zeit.> Und wie löse ich das am besten?
IM Grunde indem du überhaupt keinen externen Interrupt benutzt. Wozu
auch?
Bei den Zeiten, die du hast reicht es einen Timer aufzusetzen, der alle
paar zig µS den Eingangsport abfragt und dann die Werte mit den jeweils
vorhergehenden verglicht.
Zb Timer0 (8 Bit Timer), Vorteiler 1 oder 8, in der Overflow ISR das PIN
Register auslesen und mitzählen wie oft du den gleichen Wert gekriegt
hast. Hast du 3 oder 4 mal hintereinander den gleichen Wert, dann ist
der Wert auch real. Ansonsten hast du irgendwelche Spikes am Eingang -
wo auch immer die herkommen.
Externer Interrupt wird überbewertet. Das hört sich zwar alles nett an,
sobald man da aber Spikes ausfiltern muss, ist es gleich gar nicht mehr
so einfach.
Einen Timer hingegen braucht man sowieso in den meisten Programmen. Da
kann der das dann auch noch gleich mit erledigen.
Bastler schrieb:>> Seine Hauptschleife laeuft in geschaetzten 1 Mikrosekunde einmal rum.> Selbst wenn ich fuer die Isr noch was zugebe, ist das Flag spaetestens> nach 3 Mikrosekunden wieder geloescht.>> Da ist alles valide, nur: wenn er die Hauptschleife per CLI/SEI gegen> parallele Interrupts verriegelt, dann geht's.
Hab ich das überlesen oder wo hast du diesen CLI/SEI her?
> hat, sind die ms nur geschätzt. Und die Indizien sprechen für mehrfache> INT's in kurzer Zeit.
Das streitet auch keiner ab.
Nur tendiere ich zur einfachsten Erklärung. Im Falle fehlender Pullups
habe ich die erst mal im Auge, als eine Mechanik, die es schafft mir in
weniger als 3µs zwei fallende Flanken auf einen Eingang zu legen.
Cli/sei sind aus der Version, die dann funktioniert haben soll.
Ok, für mich war "mehrfache INT's ohne daß Main das Flag zurücksetzten
kann" die Krankheit. BTW, der Sensor hat 1μs Flanken, typischer
(hochohmiger) Bastleraufbau und die mehreren INT's im μs-Bereich sind
da.
Peter D. schrieb:> Ich würds mit nem Pin-Change-Interrupt auf beide Pins auslesen.
Da wäre jetzt auch meine Idee gewesen.
Wenn ich das richtig verstanden habe lege ich Phase A des Encoders an
den ICP3-PIN (PE7).
Setze dann im TCCR3 Register mit Cs00..CS02 Steigende oder fallende
Flanke.
Im TCCR3B kann ich dir Rauschunterdrückeung über ICNC3 aktivieren.
In ISR(ICF3) Frage ich jetzt bei Pins ab und habe die Drehrichtung. Kann
mein Flag setzen und in der main den Rest machen und das Flag zurück
setzen.
Ist das so richtig? Oder habe ich das Falsch verstanden?
neuling schrieb:> Jetzt löst der jeder Takt einen Reset aus. Ich verstehe nur nicht warum.
ok das lag an der Fehlenden Zeile
EIMSK |= (1<<INT7);
Jetzt habe ich alt bekanntes Problem das. Das Interrupt nicht bearbeiter
wird und die FehlerLED wieder 4 anzeigt. Sollte die Funktion nicht gnau
das verhindern?
neuling schrieb:> Wenn ich das richtig verstanden habe lege ich Phase A des Encoders an> den ICP3-PIN (PE7).
Will man die höchste Auflösung, muß jeder Zustandswechel gezählt werden.
Also beide Anschlüsse als Pin-Change und dann die Zählroutine, wie im
Timerinterrupt für manuelle Encoder.
Timerinterrupt wäre bei der Pulszahl doch recht hohe Interruptlast.
Peter D. schrieb:> Will man die höchste Auflösung, muß jeder Zustandswechel gezählt werden.
Mir reicht die Auflösung von einem
Peter D. schrieb:> Will man die höchste Auflösung, muß jeder Zustandswechel gezählt werden.> Also beide Anschlüsse als Pin-Change und dann die Zählroutine, wie im> Timerinterrupt für manuelle Encoder.> Timerinterrupt wäre bei der Pulszahl doch recht hohe Interruptlast.
Wo lege ich dann Phase B an?
Die Frage die ich mir stelle warum verarbeite er das Interrupt nicht
sauber? Es muss doch möglich sein über eine einfache ISR nur die
fallenden Flaken zu erkennen und dann was zu machen.
Ich würde mich sehr freuen wenn mir jemand an meinem Code helfen könnte
das zum laufen zu bekommen.
Wie sieht denn der Aufbau aus, und wie sieht das Signal direkt am Pin
aus. Sind das schöne Rechtecke oder wegen "hochohmig abgeschlossener"
langer Kabel an den Flanken ausklingende n MHz Schwingungen. Irgendwie
scheint es ja manchmal zu INT's im Abstand kleiner als 1-stellige μs zu
kommen und das macht der AVR ja nicht ohne Grund.
Ich schalte gern zum Testen am Anfang einer ISR ein Pin und am Ende
wieder zurück. 10€ LA dran und man sieht sofort, ob man wirklich mehrere
INT's hat. Der bisherige "Versuchsaufbau" läst das nur vermuten. Messen
ist besser!
Dieses LA Vorgehen zeigt aus schon graphisch die CPU-Last, wenn in der
main-Schleife wenn's nix mehr zu tun gibt kurz bis zum nächsten Int
schläft, und um dieses sleep herum ein Pin toggled. Bleibt "Sleep" lange
genug an, dann ist alles im grünen Bereich. Einfacher als Takte
addieren.
OldMan schrieb:> Der Hersteller, Fa. Kübler, gibt an, dass die Ausgänge der Drehgeber mit> einer Mindestlast von 1 kOhm betrieben werden sollen. Hast Du daran> gedacht?
Ja habe ich berücksichtigt.
Mit folgendem Code im Interrupt :
1
// Encoderinterrupt
2
3
ISR(INT7_vect)
4
{
5
JETPORT|=(1<<JET1);
6
delay_us(500);
7
JETPORT&=~(1<<JET1);
8
if(ls1_flag)
9
{
10
selftest_need=1;
11
}
12
else
13
{
14
selftest_need=0;
15
}
16
ls1_flag=1;
17
18
19
if(encoderA_flag==1)
20
{
21
selftest_need=4;
22
}
23
24
encoderA_flag=1;
25
26
}
Sehe ich bei const Low am InterruptPin am Jet1Pin Alle 50Hz die 50us als
High. Ziehe ich das Netzteil aus der Steckdose sind die 50Hz weg. Kann
das mein Problem sein?
Spätestens jetzt wäre dann der Zeitpunkt, an dem ein Schaltplan, eine
Erklärung des Aufbaus, und ggfs. ein Foto des selben nötig sind. Dabei
bitte die Hinweise zu Bildformaten und Größen beachten..
dunno.. schrieb:> Spätestens jetzt wäre dann der Zeitpunkt,
Ich glaube, Du erwartest zu viel, denn:
neuling schrieb:> Ich möchte Encoder gesteuert einige Funktionen ausführen.neuling schrieb:> Der Encoder häng an einem kleine Föderband welchen über einen Motor> angetrieben wird.
Was denn nun?
neuling schrieb:> Ich würde mich sehr freuen wenn mir jemand an meinem Code helfen könnte> das zum laufen zu bekommen.
Ich habe mir Deinen Code nur oberflächlig angesehen. Warum, weil er
keinen Sinn ergibt. Ich denke, das geht nicht nur mir so.
Erwarte nicht, daß ein undurchsichtiger Ansatz eines unbekannten
Problems hier zu glänzender Funktion geführt wird.
Erkläre doch zunächst, wie Dein Drehgeber verwendet werden soll, und
lese auch die Links, die Dir genannt wurden.
m.n. schrieb:> und lese auch die Links, die Dir genannt wurden.
Und versuche, sie zu verstehen.
Und wenn dann was nicht klar ist: nachdenken, überlegen und evtl.
fragen.
neuling schrieb:> Ziehe ich das Netzteil aus der Steckdose sind die 50Hz weg.> Kann das mein Problem sein?
Welches Netzteil?
Das ist ja wieder mal grausame Salamitaktik hier...
Aus https://de.wikipedia.org/wiki/Salamitaktik:
1
Eine weitere Verwendung für Salamitaktik beschreibt die Vorgehensweise,
2
die Wahrheit nur scheibchenweise zu "servieren". Eine in Bedrängnis geratene
3
Person, verrät nur so viel von ihrem (vermeintlichen) rechtlichen oder
4
moralischen Fehlverhalten, wie ihr bereits nachgewiesen werden kann oder
5
wie sie es für als taktisch sinnvoll erachtet.[6]
6
7
Im Zusammenhang mit Software- oder Hardwareprojekten wird unter Salamitaktik
8
das unerwünschte Verhalten des Kunden bezeichnet, immer wieder neue
9
Anforderungen an ein Projekt zu stellen. Die Situation ist in diesem Fall
10
gekennzeichnet durch mangelhafte Planung und unkoordinierte sowie
neuling schrieb:> Ja habe ich berücksichtigt.>> Mit folgendem Code im Interrupt :
Was hat Dein Code mit meinem Hinweis bzgl. der Last für den Drehgeber zu
tun?
Langsam bin ich der Meinung, dass Du überhaupt nicht verstehst was Du
tust.
>Sehe ich bei const Low am InterruptPin am Jet1Pin Alle 50Hz die 50us als>High. Ziehe ich das Netzteil aus der Steckdose sind die 50Hz weg. Kann>das mein Problem sein?
Dein Problem liegt ganz wo anders.
Was willst du?
Was machst du?
Warum machst du es so?
Wieso im Interrupt ein delay?
Zeig uns den Aufbau!
Zeig uns den Code!
Sag was nicht geht!