Forum: Mikrocontroller und Digitale Elektronik Abstand zwischen zwei Flanken wird nicht korrekt ermittelt


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Klaus (Gast)


Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ich verzweifle gerade an einer vermeintlich einfachen Aufgabe: Die Zeit 
zwischen zwei Flanken zu messen! ATmega8a im AS7.

Ich möchte ein digitales Datenprotokoll auswerten, alle ca. 7,5ms kommt 
ein Paket und den Anfang des Pakets möchte ich ermitteln. Das 
Datensignal ist an PD2 (INT0) angeschlossen, der entsprechende INT ist 
auch aktiviert. Zum Test gebe ich den erkannten Beginn des Datenpakets 
über einen Flankenwechsel auf PB3 aus. Soweit zumindest die Theorie. 
Wenn ich in der ISR nur auf die Flankenwechsel schaue und diese nach PB3 
"spiegele", funktioniert es wie gewünscht. Wenn ich aber das Intervall 
zwischen zwei Flanken bestimmen und als Schwellwert für die Erkennung 
eines neuen Datenpakets verwenden möchte, dann klappt das eigentlich 
auch. ABER: In der Berechnung/Abfrage des Intervalls muss irgendetwas 
schief gehen, so dass die Bedingung viel zu häufig erfüllt wird. Das 
Bild vom Oszi ist anbei (Gelb = Datensignal / Rot = Pegel PB3), man 
sieht es wohl recht deutlich, dass PB3 deutlich häufiger umgeschaltet 
wird, als neue Datenpakete anfangen.

Hoffentlich könnt ihr mir helfen! Danke!
Klaus

P.S. Ich hatte zur Probe mal die Intervalldauer per UART ausgeben lassen 
- da hat es wie gewünscht funktioniert! Ich vermute, dass mir eine der 
Compiler-Optimierungen einen Strich durch die Rechnung macht (-Os).

1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
4
uint8_t count2us_highByte;
5
uint16_t count_previous;
6
7
uint8_t state;
8
9
void init() {
10
11
  // Init IO-ports
12
    DDRB = (1 << PB3);
13
    PORTB = 0;
14
15
    DDRD  = (0 << PD2);      // INT0
16
    PORTD = (0 << PD2);
17
18
    MCUCR = (0 << ISC01)
19
        | (1 << ISC00);    // Any logical edge on INT0 generates an interrupt request
20
    GICR = (1 << INT0);      // Enable interrupt on INT0
21
22
  // Init timer
23
  TCCR0 = (0 << CS02)
24
        | (1 << CS01)
25
        | (0 << CS00);       // Prescaler 8 --> 2us pro Tick
26
  TIMSK = (1 << TOIE0);      // Int for OVF
27
28
  sei();
29
}
30
31
32
int main(void) {
33
  init();
34
  while(1) { ; }
35
}
36
37
ISR(TIMER0_OVF_vect) { count2us_highByte++; }  // Eigenbau-16Bit-Timer --> HighByte inkrementieren
38
  
39
ISR(INT0_vect) {
40
  uint16_t count;
41
  uint16_t interval;
42
  uint8_t tmp_sreg;
43
  
44
  tmp_sreg = SREG;
45
  cli();
46
47
  count = TCNT0 + (count2us_highByte << 8);    // Genauen Zeitstempel bestimmen
48
49
  interval = count - count_previous;           // Zeitdifferenz zur letzten Flanke bestimmen
50
51
  if (interval > 3000) {                       // Wenn mehr als 3000 * 2us, dann Pegel an PB3 umschalten
52
    if (state) { PORTB &= ~(1 << PB3); }
53
    else { PORTB |= (1 << PB3); }
54
    state = 1 - state;
55
    }
56
57
  count_previous = count;                      // Zaehlerstand fuer die naechste Runde speichern
58
59
  SREG = tmp_sreg;
60
}

von Stephan (Gast)


Bewertung
0 lesenswert
nicht lesenswert
uint8_t count2us_highByte;
uint16_t count_previous;

Sage dem Compiler mal, dass diese beiden Variablen volatile sind.

VG Stephan

von Klaus (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Hallo Stephan,

macht leider keinen Unterschied.

Grüße
Klaus
1
volatile uint8_t count2us_highByte;
2
volatile uint16_t count_previous;

von Stephan (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Hi Klaus,
Im Einführungstext sagst Du, dass ROT PB3 ist und GELB das Signal... ist 
das korrekt?
VG Stephan

von Klaus (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Hallo Stephan,

ist korrekt. Im gelben Signal kommt alle 7,5ms ein Datenpaket und für 
die weitere Auswertung brauche ich den Anfang davon. Zum debuggen habe 
ich diese "Datenpaketanfangserkennung" auf PB3 gelegt, s. rote Kurve.
Es SOLL so funktionieren:
- Speichern des Zeitstempels der letzten Flanke
- Bei einer neuen Flanke die Zeitdifferenz zur vorherigen Flanke merken
- Wenn das mehr als 6000us sind, dann PB3 umschalten

Erwartungshaltung: Ein recht sauberes Rechtecksignal auf PB3 (rot), 
welches den Pegel immer zu Beginn eines Datenpakets wechselt.

Istzustand: S. Screenshot + Frust :)

Viele Grüße
Klaus

von Stefan ⛄ F. (stefanus)


Bewertung
0 lesenswert
nicht lesenswert
Klaus schrieb:
> Ich vermute, dass mir eine der
> Compiler-Optimierungen einen Strich durch die Rechnung macht (-Os).

Das lässt sich ja leicht prüfen: stelle auf -O0 um.

von Stephan (Gast)


Bewertung
1 lesenswert
nicht lesenswert
count2us_highByte << 8

Kommt da nicht IMMER 0 raus?
count2us_highByte Ist doch uint8_t...
Hmm

VG Stephan

von Stefan ⛄ F. (stefanus)


Bewertung
0 lesenswert
nicht lesenswert
Die INT0 hat eine höhere Priorität als der TIMER0_OVF.
Wenn beide Interrupts zeitgleich anliegen, wird daher zuerst INT0 
aufgerufen, so dass deine oberen 8bit von den Pseudo-16bit veraltet und 
somit falsch sind.

von Markus F. (mfro)


Bewertung
0 lesenswert
nicht lesenswert
Stephan schrieb:
> count2us_highByte << 8
>
> Kommt da nicht IMMER 0 raus?
> count2us_highByte Ist doch uint8_t...
> Hmm
>
> VG Stephan

Huh?

C-Buch lesen!

von Klaus (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Stefan ⛄ F. schrieb:
> Klaus schrieb:
>> Ich vermute, dass mir eine der
>> Compiler-Optimierungen einen Strich durch die Rechnung macht (-Os).
>
> Das lässt sich ja leicht prüfen: stelle auf -O0 um.

Geprüft - macht leider keinen Unterschied.

Stephan schrieb:
> count2us_highByte << 8
>
> Kommt da nicht IMMER 0 raus?
> count2us_highByte Ist doch uint8_t...

Das kriegt der Compiler hin. Zumindest führen
1
  count = count2us_highByte;
2
  count = (count << 8);
3
  count += TCNT0 ;

und
1
  count = TCNT0 + (uint16_t)(count2us_highByte << 8);

zum gleichen Ergebnis wie der gepostete Code.

Viele Grüße
Klaus

von Klaus (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Stefan ⛄ F. schrieb:
> Wenn beide Interrupts zeitgleich anliegen, wird daher zuerst INT0
> aufgerufen, so dass deine oberen 8bit von den Pseudo-16bit veraltet und
> somit falsch sind.

Ich habe jetzt im Timer-INT ebenfalls die anderen Interrupts gesperrt:
1
ISR(TIMER0_OVF_vect) {
2
  uint8_t tmp_sreg;
3
  
4
  tmp_sreg = SREG;
5
  cli();
6
7
  count2us_highByte++;                    // Eigenbau-16Bit-Timer --> HighByte inkrementieren
8
9
  SREG = tmp_sreg;
10
11
}

Wirkung sehe ich noch keine. Oder hast du etwas anderes im Sinn? Dann 
bräuchte ich noch einen Tipp von dir.

Grüße
Klaus

von Stefan ⛄ F. (stefanus)


Bewertung
0 lesenswert
nicht lesenswert
Stephan schrieb:
> Kommt da nicht IMMER 0 raus?

Das dachte ich auch spontan, geht aber:
1
volatile uint8_t a;
2
volatile uint16_t b;
3
4
int main(void) 
5
{
6
    b=(a<<8);
7
}
1
00000090 <main>:
2
  90:  80 91 02 01   lds  r24, 0x0102  ; das ist Variable a
3
  94:  90 e0         ldi  r25, 0x00  
4
  96:  98 2f         mov  r25, r24     ; kopiere  Bit 0-7 nach Bit 8-15
5
  98:  88 27         eor  r24, r24     ; setze Bit 0-7 auf 0
6
  9a:  90 93 01 01   sts  0x0101, r25  ; speichern Bit 8-15
7
  9e:  80 93 00 01   sts  0x0100, r24  ; speichern Bit 0-7
8
  a2:  80 e0         ldi  r24, 0x00  
9
  a4:  90 e0         ldi  r25, 0x00  
10
  a6:  08 95         ret

Weiss jemand, wozu die drei nicht kommentierten ldi Befehle dienen? Mir 
kommen sie unnötig vor.

: Bearbeitet durch User
von Stefan ⛄ F. (stefanus)


Bewertung
0 lesenswert
nicht lesenswert
Klaus schrieb:
> Ich habe jetzt im Timer-INT ebenfalls die anderen Interrupts
> gesperrt.
> Wirkung sehe ich noch keine. Oder hast du etwas anderes im Sinn?

Kein Wunder, denn der hat sowieso schon höhere Priorität als der andere. 
Der Punkt ist, dass deine oberen 8 Bit (durch die Overflow ISR) zu spät 
hoch gezählt werden, wenn sich die beiden Interrupts überlappen. Die 
Overflow ISR wird immer erst nach INT0 ausgeführt. Sie muss aber immer 
vorher ausgeführt werden, denn innerhalb der INT0 ISR brauchst du ja den 
aktuellen Zählerstand.

: Bearbeitet durch User
von Andreas M. (amesser)


Bewertung
0 lesenswert
nicht lesenswert
cli() in der ISR(INT0_vect) brauchst Du nicht, die Interrupte sind 
innerhalb der ISR eh schon maskiert. Der TCNT0 läuft im Hintergrund 
weiter: Wenn der einen Überlauf hat während du in ISR(INT0_vect) bist, 
dann funktioniert deine Routine nicht. Statt auf den TCNT0 zu schauen, 
müsste doch dein "High-Byte" allein schon ausreichen (3000 / 256) ist 
etwa 12. Bei Längerer Signalpause kann Deine Bedingung übrigens auch mal 
nicht erfüllt sein, wenn man das Fenster trifft.

Ich würde mit einem Timeout arbeiten: Ein globaler Zähler; In 
ISR(INT0_vect) wenn Zähler 0 -> Anfang erkannt, Zähler immer auf 12 
setzen; In ISR(TCNT0_vect) wenn Zähler > 0 -> Zähler--;

von Klaus (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Hallo Stefan,

wirklich kritisch wäre das doch vor Allem im Überlauf des 
HighByte-Zählers, der alle 131ms auftritt?

Hast du eine Anregung, wie ich dies auflösen könnte?

Grüße
Klaus

von Stefan ⛄ F. (stefanus)


Bewertung
0 lesenswert
nicht lesenswert
Klaus schrieb:
> wirklich kritisch wäre das doch vor Allem im Überlauf des
> HighByte-Zählers, der alle 131ms auftritt?

Das wäre das nächste Problem in der Warteschlange.

> Beitrag "Abstand zwischen zwei Flanken wird nicht korrekt ermittelt"

Guck mal was der Andreas geschrieben hat.

Ich hätte für diese Aufgabe einen 16bit Timer verwendet und den 
Timer-Capture Interrupt.

von Andreas M. (amesser)


Bewertung
0 lesenswert
nicht lesenswert
Alternativ könnte man auch ganz ohne den TCNT0_ovf isr arbeiten: Anderen 
Vorteiler wählen so das die 6ms Timeout als Zählwert in den TCNT0 
reinpassen, Timer dauerhaft starten. In ISR(INT0_vect) prüfen ob TCNT0 
Overflow gesetzt ist, wenn ja -> Packet erkannt, TCNT0 mit (0 - 
Zählwert(6ms)) laden und danach Overflow Bit löschen. (Das Overflow Bit 
ist dann der Indikator dafür das 6ms seit der letzten Flanke vergangen 
sind)

von Markus F. (mfro)


Bewertung
0 lesenswert
nicht lesenswert
Stefan ⛄ F. schrieb:
> Stephan schrieb:
>> Kommt da nicht IMMER 0 raus?
>
> Das dachte ich auch spontan, geht aber:

Integer promotion.

von S. Landolt (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Das mit dem 'count2us_highByte' verstehe ich nicht - muss das nicht 
irgendwann auf 0 gesetzt werden?

von Stefan ⛄ F. (stefanus)


Bewertung
0 lesenswert
nicht lesenswert
S. Landolt schrieb:
> as mit dem 'count2us_highByte' verstehe ich nicht - muss das nicht
> irgendwann auf 0 gesetzt werden?

Der läuft von alleine über. Nach 255 kommt 0.

von Klaus (Gast)


Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Andreas M. schrieb:
> Statt auf den TCNT0 zu schauen,
> müsste doch dein "High-Byte" allein schon ausreichen (3000 / 256) ist
> etwa 12

Ah, super Idee! Damit kriege ich das hin! Für die Identifizierung des 
Paketbeginns ist das völlig ausreichend. Und das LowByte kann ich für 
die Erkennung der einzelnen Bits nutzen, das passt vom Wertebereich her!

TOP, vielen Dank für eure Hilfe!
Viele Grüße
Klaus

P.S. Ich würde normalerweise auch einen 16-Bit-Timer für die Geschichte 
verwenden. Und auch keinen Atmega8a. Das Projekt ist eine 
Custom-Firmware für ein Spielzeug, daher ist die Hardware vorgegeben. 
Den Timer1 brauche ich für die Generierung von zwei PWM-Signalen, daher 
ist der schon blockiert. Timer2 ist auch belegt. Und Timer0 muss daher 
den Systemtakt und diesen globalen Timer vorgeben.

von Stephan (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Markus F. schrieb:
> Integer promotion.

Ach ja, ich vergass.
Danke!

von Peter D. (peda)


Bewertung
0 lesenswert
nicht lesenswert
Wie schon gesagt wurde, zähle im Overflow einfach ein Timeout runter 
(Stop bei 0). Im externen Interrupt wird getestet, ob er 0 ist und 
wieder auf die minimle Pausenzeit gesetzt. 7,5ms sind ~14 Überläufe, 
d.h. ein Byte reicht.

Und laß diesen SREG Quatsch sein. Wo hast Du das bloß her?

von A. S. (achs)


Bewertung
0 lesenswert
nicht lesenswert
Wobei mich noch interessieren würde, warum dein erster Code den Fehler 
macht. Die zahlreichen hier gezeigten Probleme erklären den nämlich 
nicht.

Eine Möglichkeit: integral Promotion macht int und nicht uint (ich weiß 
es nicht auswendig).
Nur Highbyte ist natürlich besser, aber interessant wäre es, wenn Du das 
Mal ausprobierst.

von Peter D. (peda)


Bewertung
0 lesenswert
nicht lesenswert
A. S. schrieb:
> Wobei mich noch interessieren würde, warum dein erster Code den Fehler
> macht.

Es ist im Prinzip der hier beschriebene Effekt:
Beitrag "AVR Timer mit 32 Bit"

TCNT0 if auf 0 übergelaufen, aber der Overflow noch nicht behandelt, 
d.h. das High-Byte nicht hochgezählt.

von S. Landolt (Gast)


Bewertung
1 lesenswert
nicht lesenswert
> Wobei mich noch interessieren würde ...
> ... erklären den nämlich nicht

Vielleicht doch, zumindest teilweise, wenn man berücksichtigt, dass die 
INT0-ISR so um die 25 us benötigt. Ist ein Impuls in dem Datenburst 
kürzer als diese Zeit, wird nach dem Rücksprung aus der INT0-ISR direkt 
wieder hineingesprungen, der Timer-Interrupt hat ja niedrigere 
Priorität. Dann steht also, mit einer gewissen Wahrscheinlichkeit, in 
der INT0-ISR das 'count2us_highByte' noch auf dem alten Wert, TCNT0 ist 
aber kleiner als vorher, und folglich ist 'intervall' negativ bzw. zu 
groß, größer als 3000.

Dasselbe gilt, wenn der Timer-Überlauf zu Beginn der INT0-ISR auftritt, 
nur ist die Wahrscheinlichkeit dafür geringer.

von Kointro (Gast)


Bewertung
-2 lesenswert
nicht lesenswert
Mag sein, dass C einige Hürden bietet.

Aber schon die Vorgehensweise an allen technischen Möglichkeiten
des zig-fach überdimensionierten mega8 vorbei deutet auf schwere
Orientierungsprobleme in der realen Welt.

Wie wär's mit Vegan-Koch?

von A. S. (achs)


Bewertung
0 lesenswert
nicht lesenswert
S. Landolt schrieb:
> Dann steht also, mit einer gewissen Wahrscheinlichkeit, in
> der INT0-ISR das 'count2us_highByte' noch auf dem alten Wert, TCNT0 ist
> aber kleiner als vorher, und folglich ist 'intervall' negativ bzw. zu
> groß, größer als 3000.

Stimmt, daran hab ich garnicht gedacht. Und mein Ansatz oben war 
natpürlich quatsch, nehm ich zurück. Also: interval int16 (statt 
unsigned) machen.

(ich habe daran nicht gedacht, weil ich sowas wie interval immer signed 
mache.

von Stefan ⛄ F. (stefanus)


Bewertung
0 lesenswert
nicht lesenswert
A. S. schrieb:
> Also: interval int16 (statt unsigned) machen.

Du hast es nicht verstanden. Mit negativen Intervallen, wird nichts 
besser. Die Zahlen sind dann immer noch völlig falsch!

von A. S. (achs)


Bewertung
0 lesenswert
nicht lesenswert
Stefan ⛄ F. schrieb:
> Du hast es nicht verstanden. Mit negativen Intervallen, wird nichts
> besser. Die Zahlen sind dann immer noch völlig falsch!

Falsch ja. Aber hier geht es doch nur darum zu schauen, ob es dann 
funktioniert. Und das müsste es, denn der Fehler ist klein, also nicht 
relevant.

Wenn ich mindestens 7 ms will, ist es egal, ob ich auch Mal -1ms habe.

Eine Zeitmessung mit Überlauf-Zähler richtig zu machen ist zwar in 
wenigen Zeilen möglich, aber zum einen nicht einfach und zum anderen vom 
interrupthandling abhängig.

: Bearbeitet durch User
von W.S. (Gast)


Bewertung
-2 lesenswert
nicht lesenswert
Klaus schrieb:
> ABER: In der Berechnung/Abfrage des Intervalls muss irgendetwas
> schief gehen, so dass die Bedingung viel zu häufig erfüllt wird.

Du erwartest jetzt nicht, daß hier jeder deine gepostete Quelle 
akribisch untersucht, gelle?

Also mal ganz allgemein: du hast vermutlich einfach nur das falsche 
Konzept. Was genau willst du denn feststellen? Den zeitlichen Abstand 
zwischen den einzelnen Impulsen? Oder den zeitlichen Abstand zwischen 
den Bursts? Oder auch noch die Breite der Bursts?

Falls es sich nur um den zeitlichen Abstand zwischen den Anfängen der 
Bursts handelt, dann ist das ein ähnliches Problem wie beim 
Taste-Entprellen.

mein Vorschlag so aus dem Stegreif heraus wäre so:
1. konfiguriere deinen µC so, daß er nur auf die H-->L Flanke einen 
Interrupt auslöst.
2. habe eine Systemuhr in deiner Firmware, die einen Uhrtick von 1 ms 
bis höchstens 2 ms erzeugt.
3. habe in deiner Firmware eine Variable "ABSTAND", ein Flag "PING" und 
ein Byte "PONG"
4. suche dir einen Timer aus, der den Abstand zwischen deinen Bursts für 
deine Belange genau genug zählen kann.
5. in der ISR deines Interrupts machst du folgendes:
5a. setze PING
5b. wenn PONG nicht Null ist, dann beendest du die ISR
5c. wenn PONG Null ist, dann liest du den Timer aus und merkst ihn in 
ABSTAND, setzt den Timer auf 0 und startest ihn wieder. Damit hast du 
den zeitlichen Abstand zum vorherigen Burst in ABSTAND. Nun setzt du 
PONG auf so etwa 2..3 ms (je nach Uhrtick) und beendest die ISR.
6. in der ISR des Uhrticks machst du folgendes:
6a. wenn PING gesetzt ist, setzt du PONG auf 2..3 ms
6b. wenn PING nicht gesetzt ist, und PONG nicht Null ist, zählst du PONG 
um eins herunter.

So, das sollte es gewesen sein. PING zeigt an, daß deine ISR kürzlich 
aktiviert worden ist (quasi Prellen) und die ISR der Uhr sorgt dafür, 
daß PONG nur dann bis 0 dekrementiert wird, wenn wenigstens 2..3 ms am 
Stück kein PING mehr kommt. Dann ist der Burst vorbei und die ISR kann 
auf die nächste gültige Flanke warten.

W.S.

von A. S. (achs)


Bewertung
0 lesenswert
nicht lesenswert
Wenn Interrupts gesperrt:
Überlaufzähler auslesen
Timer auslesen
Wenn interruptflag: nochmal Timer auslesen und Überlaufzähler um 1 
erhöhen (lokal, im originalen Typ)

Wenn tof eine höhere prio hat:
Überlaufzähler auslesen
Timer auslesen
Wenn Überlaufzähler sich geändert hat, Timer nochmals Auslesen

Natürlich immer nur unter der Maßgabe, dass ein Timerüberlauf länger ist 
als der interruptcode.

Aber der TO braucht ja keinen zuverlässigen Code mehr.

von Stefan ⛄ F. (stefanus)


Bewertung
1 lesenswert
nicht lesenswert
W.S. schrieb:
> Du erwartest jetzt nicht, daß hier jeder deine gepostete Quelle
> akribisch untersucht, gelle?

Mecker nicht, das ist längst erledigt worden. Die Problemursache wurde 
bereits gestern erkannt und Lösungen empfohlen.

von A. S. (achs)


Bewertung
1 lesenswert
nicht lesenswert
W.S. schrieb:
> Du erwartest jetzt nicht, daß hier jeder deine gepostete Quelle
> akribisch untersucht, gelle?

Der TO hat schon eine Lösung. Und Landolt (und andere) das Problem wohl 
identifiziert.

von Bastler (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Man muss einfach den Hardware-Timer zweimal lesen, und dazwischen das 
Timer-Overflow-Flag einmal. Dann kann man Auswerten:
1
  disableTimerInterrupt();
2
3
  uintXX_t softcount = readSoftwareCounter();  
4
5
  uint8_t precount = readHardwareCounter()
6
  bool overflow1 = readOverflowFlag();
7
  uint8_t hardcount = readHardwareCounter()
8
9
  enableTimerInterrupt();
10
11
  bool overflow2 = hardcount < precount;
12
13
  if (overflow1 || overflow2)
14
    softcount++;

Und mit hardcount weiter rechnen.

von Peter D. (peda)


Bewertung
0 lesenswert
nicht lesenswert
A. S. schrieb:
> Wenn ich mindestens 7 ms will, ist es egal, ob ich auch Mal -1ms habe.

Dann gib mal -1 als unsigned int aus, was siehst Du?

von A. S. (achs)


Bewertung
0 lesenswert
nicht lesenswert
Peter D. schrieb:
> Dann gib mal -1 als unsigned int aus, was siehst Du?

Sag das Stefan

Stefan ⛄ F. schrieb:
> Du hast es nicht verstanden. Mit negativen Intervallen, wird nichts
> besser.

von A. S. (achs)


Bewertung
0 lesenswert
nicht lesenswert
Bastler schrieb:
> Dann kann man Auswerten:

Bzw ist man schon fertig:
1
  disableTimerInterrupt();
2
3
  uintXX_t softcnt = readSoftCnt();  
4
5
  uint8_t hardcnt = readHWCnt();
6
  If(readOverflowFlag())
7
  {
8
    hardcnt = readHWCnt();
9
    softcnt++;
10
  }
11
  
12
  enableTimerInterrupt();

Ohne di wird noch einfacher.

von c-lover (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Stefan ⛄ F. schrieb:
> Weiss jemand, wozu die drei nicht kommentierten ldi Befehle dienen? Mir
> kommen sie unnötig vor.

Der 1. erweitert die Variable a nach Integer.
Die beiden letzten liefern als Ergebnis der Funktion "int main()" den 
Wert 0.

von Stefan ⛄ F. (stefanus)


Bewertung
1 lesenswert
nicht lesenswert
c-lover schrieb:
> Der 1. erweitert die Variable a nach Integer.
> Die beiden letzten liefern als Ergebnis der Funktion "int main()" den
> Wert 0.

Aha, danke.

von max123 (Gast)


Bewertung
-1 lesenswert
nicht lesenswert
Hallo,
ich mache derartiges im TIMER-Interrupt.

[/c]

/* Zaehle neg Flanken an PIN 8
 *  mit einem Timerinterrupt.
 *  Also Drahtbrueke von PIN 8 auf GND.
 Drahtbruecke mehrmals herausziehen und wieder einstecken.
 Dadurch zaehlt das Programm die negativen Flanken.
Wird nun von "Seriellen Monitor" (dem Terminal in der Arduino IDE)
ein Zeichen geschickt, wird die Anzahl der neg. Flanken ausgegeben.

 Nicht vergessen: Seriele Baudrate auf 115200 einstellen.
 Das Einlesen eines Zeichens (zur Ausgabe) erfolgt ueber den
 Seriellen Interrupt.
 */
 #include <TimerOne.h>
uint16_t bra,wert;
uint16_t help;
uint16_t alt, differenz,n,anton;
int index;
char inChar;
char ein[20];

void tick()
{ n++;
  bra = digitalRead(8);
  if (bra == 0 && alt == 1 )
    wert ++;  //neg Flanken;

  alt = bra;
}
void setup()
{ pinMode(8, INPUT_PULLUP);
  Timer1.attachInterrupt(tick);
  Timer1.initialize(1000 );    //alle 1ms ein Interrupt
  Serial.begin(115200);        //Baud
  //Serial.println("mit der Seriellen Monitor ein Zeichen senden");
 }
void loop()
{
if(Serial.available() > 1)
   {
 //   Serial.print((long)wert);
 //   Serial.read();
   //  wert = 0;
    }
}

    void serialEvent()     //ISR, wird bei eingehenden Zeichen 
aufgerufen
{
  while (Serial.available() )
  {
    inChar =  (char)Serial.read();
    ein[index++] = (char) inChar;  //eingehende Zeichen werden an String 
gehängt
    index = constrain(index, 0, 19);
    if (inChar == '\n')      //im Terminalproramm unb edingt \n 
anhaengen
    {
      ein [index ] = '\0';     // ein \n schliesst ab
      Serial.println(wert);
      index = 0;
    }
}
}
[/c]

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.