Forum: Mikrocontroller und Digitale Elektronik Mehrkanal Impulszähler PIC


von Miki (Gast)


Lesenswert?

Hallo,

ich stehe vor folgendem Problem.

Ich möchte gerne Impulse zählen. Die Anforderungen sind hier wie folgt:
Es gibt 6 Kanäle auf denen Impulse mit 5µs länge ankommen.
Die Frequenz variiert von 0Hz – 65kHz

Momentan nutze ich den Interrupt on Change (IOC) des PIC16F18346 und 
frage hier bei jedem Interrupt mit dem IOCCFX Flag ab welcher Pin den 
Interrupt ausgelöst hat.

Leider scheint mir das sehr ungenau zu sein, wahrscheinlich gibt es hier 
Probleme wenn zwei Pins zur gleichen Zeit einen Impuls erfassen.

Hat jemand eventuell einen Tip wie man das genauer / besser hinbekommen 
kann.


Danke im vorraus.

von Ingo Less (Gast)


Lesenswert?

Miki schrieb:
> Leider scheint mir das sehr ungenau zu sein, wahrscheinlich gibt es hier
> Probleme wenn zwei Pins zur gleichen Zeit einen Impuls erfassen.
Musst du alle Kanäle gleichzeitig erfassen? Grundsätzlich solltest du 
dich etwas mit Zeitmessung beschäftigen. Hier gibt es zwei 
unterschiedliche Ansätze: Tormethode und Periodenmethode. 
Periodenmethode vermisst bei lagsamen Frequenzen die Periodendauer. Die 
Tormethode zählt ankommende Pulse in einem definierten Zeitfenster, 
sinnvoll bei hoher Frequenz. Bei deinem Frequenzbereich 0(!)-65kHz musst 
du beide Varianten anwenden und diese auch dynamisch umschalten können. 
Das ist nicht so einfach wie es klingt. Wenn du alle Kanäle nacheinander 
vermessen könntest wäre das schon sehr sinnvoll. Dir ist klar, dass egal 
welches Verfahren du benutzt, mindestens 20s vergehen bei 0,1Hz bevor du 
ein Ergebnis hast? Irgendwo musst du auch Abstriche machen, denn der von 
dir geforderte Dynamikumfang liegt bei unendlich...

von m.n. (Gast)


Lesenswert?

Ingo Less schrieb:
> Grundsätzlich solltest du
> dich etwas mit Zeitmessung beschäftigen. Hier gibt es zwei
> unterschiedliche Ansätze: Tormethode und Periodenmethode.

Er braucht nicht die Frequenz sondern nur die Anzahl.

Miki schrieb:
> Momentan nutze ich den Interrupt on Change (IOC) des PIC16F18346 und
> frage hier bei jedem Interrupt mit dem IOCCFX Flag ab welcher Pin den
> Interrupt ausgelöst hat.

Du mußt den alten Wert zwischenspeichern und mit dem neuen Wert 
vergleichen. Daran kann man die Änderung der Pins und ihre Flanke 
feststellen. Der PIC sollte das doch locker schaffen.
temp = (alter_wert ^ neuer_wert) & neuer_wert;
In temp stehen die Änderungen mit positiver Flanke.

von Larry (Gast)


Lesenswert?

Zu Z80-Zeiten haette man 2 CTCs an die CPU gehaengt und waere fertig.

von Larry (Gast)


Lesenswert?

> Der PIC sollte das doch locker schaffen.

Bei knapp 16 us wird das mit dem locker wohl nichts.

von Frank K. (fchk)


Lesenswert?

Miki schrieb:

> Ich möchte gerne Impulse zählen. Die Anforderungen sind hier wie folgt:
> Es gibt 6 Kanäle auf denen Impulse mit 5µs länge ankommen.
> Die Frequenz variiert von 0Hz – 65kHz

Nimm ein kleines FPGA (z.B. Lattice MachXO, gibts ab 2.50€, handlötbares 
Gehäuse) und implementiere dort Deine 6 Zähler mit einer Dir genehmen 
Bitbreite und einem Mechanismus zum Auslesen. Das wird bis in dem 
MHz-Bereich zuverlässig funktionieren.

fchk

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Miki schrieb:
> Leider scheint mir das sehr ungenau zu sein
Wie stellst du das fest?

> Probleme wenn zwei Pins zur gleichen Zeit einen Impuls erfassen.
Hast du da evtl. ein Problem beim Zurücksetzen der Flags?
Setzt du im Interrupt vielleicht einfach alle Bits auf einmal zurück?

Zeig doch mal den entsprechenden Code.

von Ingo Less (Gast)


Lesenswert?

m.n. schrieb:
> Er braucht nicht die Frequenz sondern nur die Anzahl.
Oh ja sorry, hatte mich durch die Frequenz ablenken lassen...

Larry schrieb:
> Bei knapp 16 us wird das mit dem locker wohl nichts.
Nein, dass ist eigentlich nicht vernünftig um zu setzen denke ich.

Frank K. schrieb:
> Nimm ein kleines FPGA (z.B. Lattice MachXO, gibts ab 2.50€, handlötbares
> Gehäuse) und implementiere dort Deine 6 Zähler mit einer Dir genehmen
> Bitbreite und einem Mechanismus zum Auslesen. Das wird bis in dem
> MHz-Bereich zuverlässig funktionieren.
Halte ich auch für die beste Lösung. Oder diskret mit nem Zählergrab und 
Latches (sofern dern Zähler die nicht intern hat) die Zählerstände 
nacheinander auslesen...

von Blumpf (Gast)


Lesenswert?

Hat dein PIC Timer?

Im Normalfall kann der Flanken zählen, und damit sollte man deinen Fall 
abdecken können.
Der kann dir auch einen Interrupt geben, wenn du eine gewisse Zahl 
überschreitest, oder du liest ihn zyklisch.

Das externe Signal kommt an den Takteingang des Timers.

Ich habe das schon für einen Geigerzähler verwendet, beispielsweise. Der 
Vorteil liegt darin, dass die CPU nicht belastet wird.

von Ingo Less (Gast)


Lesenswert?

Blumpf schrieb:
> Das externe Signal kommt an den Takteingang des Timers.
Er hat 6 Signale zu zählen, nichtmal ein STM32F4 hat 6 Eingänge für 
externe Zählsignale, ich halte es für unwahrscheinlich, das ein 8-Bitter 
sowas an Board hat...

von m.n. (Gast)


Lesenswert?

Ingo Less schrieb:
> nichtmal ein STM32F4 hat 6 Eingänge für
> externe Zählsignale,

Oh doch. Timer 1, 2, 3, 4, 5, 8, 9 und 12 sind zusammen 8.

Beim PIC könnte man auch eine Kombination von Hardwarezählern und 
flankengetriggerten Interrupts verwenden.
W.S. programmiert das sicher auch in Assembler ;-)

von Blumpf (Gast)


Lesenswert?

Ingo Less schrieb:
> Blumpf schrieb:
>> Das externe Signal kommt an den Takteingang des Timers.
> Er hat 6 Signale zu zählen, nichtmal ein STM32F4 hat 6 Eingänge für
> externe Zählsignale, ich halte es für unwahrscheinlich, das ein 8-Bitter
> sowas an Board hat...

Hmm, guter Einwand.

Ganz furchtbar schlecht siehts aber nicht aus. Immerhin hat der PIC 4 
Takteingänge für Timer, und damit sind schon 4 von 6 automatisch 
gezählt.

Bleiben 2 übrig. Je nach Zählrate wäre das über Interrupts umsetzbar, 
oder man muss Logik dazubauen. Beispiel:
http://www.ti.com/lit/ds/symlink/sn74lv8154.pdf
Den würde man parallel auslesen.

Eventuell ließe sich sicher was mit seriellem Interface auftreiben. 
Leider ist die Auswahl bei diskreter Logik nicht so toll, und ich konnte 
in 5 Minuten nichts finden.

Im Notfall könnte man einfach einen zweiten PIC als Counter verwenden 
und die über UART verbinden.

Ich würde zählen immer einem Peripheriebaustein oder Logik überlassen, 
weil bei externen Ereignissen dann die Zählinterrupts das Verhalten der 
Software unverhershbar werden lassen. Wird schwierig, das zu testen.

von Miki (Gast)


Lesenswert?

Ingo Less schrieb:
> Bei deinem Frequenzbereich 0(!)-65kHz

Ich korrigiere auf 1-65kHz

Lothar M. schrieb:
> Hast du da evtl. ein Problem beim Zurücksetzen der Flags?
> Setzt du im Interrupt vielleicht einfach alle Bits auf einmal zurück?
>
> Zeig doch mal den entsprechenden Code.

OK das werde ich mal probieren, mein code sieht bisher so aus:
1
void IOC_ISR (void)
2
{
3
    if(IOCCF0) counter0++;
4
    if(IOCCF1) counter1++;
5
    if(IOCCF2) counter2++;
6
    if(IOCCF3) counter3++;
7
    if(IOCCF4) counter4++;
8
    if(IOCCF5) counter5++;
9
}

Blumpf schrieb:
> Hat dein PIC Timer?
>
> Im Normalfall kann der Flanken zählen, und damit sollte man deinen Fall
> abdecken können.
> Der kann dir auch einen Interrupt geben, wenn du eine gewisse Zahl
> überschreitest, oder du liest ihn zyklisch.

Ja aber leider keine 6 Zähleingänge

von Apollo M. (Firma: @home) (majortom)


Lesenswert?

der fpga vorschlag ist gut, aber ich denke beim to reicht es weder zu 
dieser noch zur nutzung der hw resourcen des pic's.

immer wieder die selben typen, ... zu keinen eigenen lsg. fähig, 
bestenfalls halbe fragen und viel hoffen, dass andere was können.


mt

: Bearbeitet durch User
von m.n. (Gast)


Lesenswert?

Apollo M. schrieb:
> der fpga vorschlag ist gut

Wenn man den oben erwähnten STM32F4 nimmt, hat man auch genug 
Zählereingänge per Hardware.
Was aber überhaupt nicht klar ist, wo die Daten verwendet werden sollen. 
Es müßte ja noch irgendeine (Vor-)verarbeitung oder Ausgabe stattfinden. 
Da dürfte es unter Umständen eng werden.

Miki schrieb:
>> Bei deinem Frequenzbereich 0(!)-65kHz
>
> Ich korrigiere auf 1-65kHz

Du mußt garnicht korrigieren; 0 Hz ist für jeden Zähler die optimale 
Eingangsfrequenz ;-)

von Miki (Gast)


Lesenswert?

Apollo M. schrieb:
> der fpga vorschlag ist gut, aber ich denke beim to reicht es weder zu
> dieser noch zur nutzung der hw resourcen des pic's.
>
> immer wieder die selben typen, ... zu keinen eigenen lsg. fähig,
> bestenfalls halbe fragen und viel hoffen, dass andere was können.
>
> mt

Bezüglich der FPGA Lösung gebe ich dir volkommen recht, wäre bestimmt 
super aber mangels Kentnisse werde ich das nicht umgesetzt kriegen.

Bezüglich der Nutzung der PIC Pherepherie kann ich dir leider kein Recht 
geben, das klappt bestimmt. Aber da selbst ein solcher Spezialist (wie 
du es anscheinend bist) spontan keine Lösung parat hatte denke ich das 
auch nicht ganz so trivial ist. Sonst höttest du diese bestimmt direkt 
gepostet statt irgendwelcher umproduktiver Kommentare.....

Zurück zum Thema,momentan denke ich das die Lösung mit externen Zählern 
(SN74LV8154) mangels FPGA,CPLD Kentnisse die beste sein wird.

von Volker S. (vloki)


Lesenswert?

Miki schrieb:
> momentan denke ich das die Lösung mit externen Zählern
> (SN74LV8154) mangels FPGA,CPLD Kentnisse die beste sein wird.

Wenn schon eine Lösung mit mehreren Bauteilen, warum dann nicht wie 
schon vorgeschlagen einfach 2 PICs? Die 18346 haben doch 3 Counter 
(Timer1/3/5)?
Die Kommunikation ist bestimmt auch nicht schwieriger.

: Bearbeitet durch User
von temp (Gast)


Lesenswert?

Wenn der kürzeste Impuls 5µs lang ist, dann sollte es reichen 8Bit eines 
Ports alle 4µs zu Sampeln. Wenn man die entsprechende Interruptroutine 
mit der höchsten Priorität in den RAM legt bleiben bei einem Stm32F103 
und 72MHz noch 288 Takte übrig. Ungetestet könnte das in C so aussehen:
1
uint8_t utmp=0;
2
volatile uint32_t carr[8]; 
3
4
void cntloop()
5
{
6
  uint8_t u=GPIOA->IDR & 0xff;
7
  uint8_t ug=(u^utmp)&u;
8
  utmp=u; 
9
  for (int n=0; n<8; n++)
10
    {
11
    if (ug&(0x01<<n))
12
      carr[n]++;
13
    }
14
}

Das wird übersetzt zu:
1
    4B0B        ldr r3, =0x10000048 <utmp>
2
    480C        ldr r0, =0x10000024 <carr>
3
    781C        ldrb r4, [r3]
4
    F04F4590    mov.w r5, #0x48000000
5
    692B        ldr r3, [r5, #16]
6
    4621        mov r1, r4
7
    B2DC        uxtb r4, r3
8
    EA240101    bic.w r1, r4, r1
9
    2300        movs r3, #0
10
    FA41F203    asr.w r2, r1, r3
11
    07D2        lsls r2, r2, #31
12
    D504        bpl 0x0800046C
13
    F8502023    ldr.w r2, [r0, r3, lsl #2]
14
    3201        adds r2, #1
15
    F8402023    str.w r2, [r0, r3, lsl #2]
16
    3301        adds r3, #1
17
    2B08        cmp r3, #8
18
    D1F3        bne 0x0800045A
19
    E7EC        b 0x0800044E

cntloop() ist natürlich die Interruptroutine des schnellen Timers.
Bevor ich hier nach anderen Lösungen suchen würde wäre das einen Versuch 
Wert. Selbst wenn nur noch 10% Zeit für was anderes übrig bleiben, 
reicht das sicher für die Weiterverarbeitung der Zählerstände. Darüber 
wissen wir aber noch nichts.

von Volker S. (vloki)


Lesenswert?

temp schrieb:
> Bevor ich hier nach anderen Lösungen suchen würde wäre das einen Versuch
> Wert.
Ob Stm32 statt PIC16 nicht schon unter (ganz) andere Lösungen fällt?

: Bearbeitet durch User
von m.n. (Gast)


Lesenswert?

Miki schrieb:
> Zurück zum Thema,momentan denke ich das die Lösung mit externen Zählern
> (SN74LV8154) mangels FPGA,CPLD Kentnisse die beste sein wird.

Dann zeichne Dir einen Schaltplan, bei dem Dein 20-pol. µC 3 x Zähler 
ICs mit 8 Bit Datenbus ausliest. Das wird sicherlich spontan zu einer 
Änderung Deines Planes führen. Zudem neigen 16 Bit Zähler bei 65 kHz 
Eingangsfrequenz zu Überläufen im Sekundenabstand. Wohin mit diesen 
Ausgängen, die bei Überlauf auch nur einen kurzen Impuls liefern?

Wenn schon ext. Bausteine verwendet werden sollen, dann eher Zähler >= 
32 Bit im 8-pol. Gehäuse per IIC-Bus auszulesen. Mag sein, daß es so 
etwas fertig gibt, andernfalls könnte ein passender µC dies erledigen.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Angehängte Dateien:

Lesenswert?

Miki schrieb:
> Hat jemand eventuell einen Tip wie man das genauer / besser hinbekommen
> kann.
Ich würde das als kleine Fingerübung zur Frühstückspause etwa so machen 
wie im Anhang. Für 6 Stück 32 Bit Zähler und das entsprechende 
Schattenregister brauche ich 384 Flipflops, dazu kommen noch knapp 20 
für den Rest, sodass ein MachXO2 mit 640 Flipflops im 48-Pin QFN 7x7mm 
Gehäuse locker ausreicht:
https://www.latticesemi.com/en/Products/FPGAandCPLD/MachXO2
Und wenn ich ein wenig Gehinschmalz und 5..10 extra Codezeilen 
reinstecke pass das auch in ein FPGA mit nur 256 Flipflops. Damit kostet 
der Spaß dann knapp 3€ bei Einzelstückzahlen.

Miki schrieb:
> Bezüglich der FPGA Lösung gebe ich dir volkommen recht, wäre bestimmt
> super aber mangels Kentnisse werde ich das nicht umgesetzt kriegen.
Ist ein nettes Thema und die Einarbeit lohnt sich...  ;-)

Ich setze solche Zähler bewusst niemals(!) zurück, denn solches 
Zurücksetzen bringt garantiert irgendwann Pulsverluste. Überläufe können 
bei einem 32-Bit-Zähler einfach in der Software abgefangen werden. Die 
treten bei 65kHz am Eingang sowieso nur alle 18 Stunden auf.
Man könnte die Zählerbreite auch auf "nur" 24 Bits festlegen, dann hat 
man schlimmstenfalls alle 4 Minuten einen Überlauf. Mindestens so oft 
müssten dann die Zähler ausgelesen werden, dass man keinen Überlauf 
"verschlampt". Aber vermutlich passiert das Auslesen eh' viel öfter, 
sodass auch 16-Bit-Zähler reichen und das Design von vorn herein ins 
kleinste FPGA passt.

: Bearbeitet durch Moderator
von Blumpf (Gast)


Lesenswert?

Lothar M. schrieb:
> Ich setze solche Zähler bewusst niemals(!) zurück, denn solches
> Zurücksetzen bringt garantiert irgendwann Pulsverluste. Überläufe können
> bei einem 32-Bit-Zähler einfach in der Software abgefangen werden.

Geht immer, wenn garantiert ist, dass nur ein Überlauf stattgefunden 
hat. Dann kann man das im Code herausrechnen.
Wenn das Ergebnis neu-alt <0 ist, hat ein Überlauf stattgefunden.

Ich wüsste adhoc gar nicht, wie man anders garantieren soll, dass keine 
Impulse verloren gehen.

von Larry (Gast)


Lesenswert?

Auf einem 16LF1509 braucht eine "for fun" geschriebene Interruptroutine
< 10 us um 6 16 bit Zaehler zu bedienen.

Dazu kaeme dann noch die Interruptlatenz.

Sollte also gehen.

von Larry (Gast)


Lesenswert?

P.S.

Und ca. 5 us mehr fuer pflegeleichtere 32 bit Zaehler.
Das ganze bei 20 MHz Takt.

von Blumpf (Gast)


Lesenswert?

Larry schrieb:
> Auf einem 16LF1509 braucht eine "for fun" geschriebene Interruptroutine
> < 10 us um 6 16 bit Zaehler zu bedienen.
>
> Dazu kaeme dann noch die Interruptlatenz.
>
> Sollte also gehen.

Wenn du 6 aysnchrone 65kHz-Signale zählen wilst, kannst du entweder 6 
individuelle Interrupts einrichten, dann reden wir von 384% maximaler 
CPU-Auslastung (wenn du mal 65kHzx10µsx6Kanäle nimmst).
Oder du tastest alle Signale in einer ISR (timergesteuert) ab, dann 
musst du aber mindestens mit der doppelten Frequenz abtasten, um alles 
zu erwischen. Macht 130kHz. Geht also auch nicht.

Wenn die Signale synchron zum Timertakt sind, dann gehts. Wie man das 
hibekommen will, weiß ich nicht. Eventuell mit Flipflops.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Blumpf schrieb:
> Oder du tastest alle Signale in einer ISR (timergesteuert) ab, dann
> musst du aber mindestens mit der doppelten Frequenz abtasten, um alles
> zu erwischen. Macht 130kHz. Geht also auch nicht.
Wenn man "nur" den aktuellen Pinzustand auswertet, dann muss man spürbar 
schneller als mit 5µs abtasten, denn so lange dauert ein Impuls, wie 
schon
Miki schrieb:
>>> auf denen Impulse mit 5µs länge ankommen.

Oder man macht es mit dem vorgeschlagenen X µs-Interrupt und den 
Flipflops der IOCCFX Flags, die ja diese Flanke speichern, bis sie 
wieder zurückgesetzt werden. In diesem Fall darf X dann fast 15ns 
(1/65kHz) werden und bei 125ns kürzester Befehlszykluszeit kann der 
PIC16F18346 ja immerhin grob überschlagen 120 Maschinenbefehle 
ausführen. Damit sollte das doch hinzubekommen sein.

: Bearbeitet durch Moderator
von Larry (Gast)


Lesenswert?

Es geht noch anders. Ich werte nur die aus, und setze nur die
zurueck, wenn der Interrupt "feuert". Falls also waehrend
der Bearbeitung noch welche dazu kommen: Kein Problem.
Die landen dann einfach im naechsten Durchlauf.
Halt 10 us spaeter.

von ??? (Gast)


Lesenswert?

Lothar M. schrieb:
> In diesem Fall darf X dann fast 15ns
> (1/65kHz) werden

15 ns ???

von Larry (Gast)


Lesenswert?

> 15 ns ???

Ja, der FPGA laesst gruessen. :-)

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

??? schrieb:
> 15 ns ???
Oh, kleiner Typo, bin offenbar zu oft in diesen Zeitbereichen unterwegs. 
Ja, FPGA sind schon toll...  ;-)

> 15 ns ???
1/65kHz sind latürnich 15µs.

: Bearbeitet durch Moderator
von temp (Gast)


Lesenswert?

Ich habe folgendes mal auf einem Bluepill-Board probiert.
1
#include <stdio.h>
2
#include <stdlib.h>
3
#include <stm32f10x.h>
4
5
uint8_t utmp=0;
6
volatile uint32_t carr[8]; 
7
8
__attribute__ ((long_call, optimize("O3"), section (".fast")))
9
void TIM2_IRQHandler(void)  
10
{
11
  GPIOC->BSRR=GPIO_BSRR_BS13;
12
  TIM2->SR=0; //|=TIM_SR_UIF;
13
14
  uint8_t u=GPIOA->IDR & 0xff;
15
  uint8_t ug=(u^utmp)&u;
16
  utmp=u;
17
18
  for (int n=0; n<8; n++)
19
    {
20
    if ((ug&(0x01<<n))!=0)
21
      carr[n]++;
22
    }
23
  GPIOC->BRR=GPIO_BRR_BR13;
24
} 
25
26
void main(void) 
27
{
28
  RCC->APB1ENR|=RCC_APB1ENR_TIM2EN;
29
  RCC->APB2ENR|=RCC_APB2ENR_IOPCEN;
30
  RCC->APB2ENR|=RCC_APB2ENR_IOPAEN;
31
  GPIOC->CRH |= GPIO_CRH_MODE13_0 | GPIO_CRH_MODE13_1;
32
  GPIOC->CRH &= ~(GPIO_CRH_CNF13_0 | GPIO_CRH_CNF13_1);
33
  GPIOC->BRR=GPIO_BRR_BR13;
34
35
  TIM2->ARR=72*2;
36
37
  TIM2->DIER=TIM_DIER_UIE;
38
  TIM2->CR1=TIM_CR1_CEN;
39
40
  NVIC_EnableIRQ(TIM2_IRQn);
41
  
42
  while (1)
43
    ; 
44
}

Damit wird mit 500kHz gesampelt und der Interrupt braucht ca. 1µs.  Im 
schlimmsten Fall (alle 8 Counter muessen incrementiert werden) sind es 
ca. 1,3µs. Also bleibt noch genügend Zeit für was anderes übrig. Wenn es 
ein Einzelstück werden soll, ist es extrem preiswert.

von Mark W. (kram) Benutzerseite


Lesenswert?

Andere Herangehensweise: Wenn die Pulse recht genau sind, dann koennte 
man damit auch einen Kondensator laden und in Abstaenden dessen Spannung 
mit einem ADC messen, hat der besagte PIC doch bestimt.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Mark W. schrieb:
> Wenn die Pulse recht genau sind, dann koennte man damit auch einen
> Kondensator laden und in Abstaenden dessen Spannung mit einem ADC
> messen, hat der besagte PIC doch bestimt.
Da fallen mir aber auf Anhieb einige Pferdefüße und Haken an der Sache 
ein...

temp schrieb:
> Ich habe folgendes mal auf einem Bluepill-Board probiert.
Nett. Hat schon Vorteile, so ein 32-Bit µC.

> Im schlimmsten Fall (alle 8 Counter muessen incrementiert werden) sind
> es ca. 1,3µs.
Kannst du mal ausprobieren, ob es was bringt, wenn du selber die 
Schleife ausrollst?
1
    if (ug&0x01)  carr[0]++;
2
    if (ug&0x02)  carr[1]++;
3
    if (ug&0x04)  carr[2]++;
4
    if (ug&0x08)  carr[3]++;
5
    if (ug&0x10)  carr[4]++;
6
    if (ug&0x20)  carr[5]++;
7
    if (ug&0x40)  carr[6]++;
8
    if (ug&0x80)  carr[7]++;
Oder hat das der Compiler eh' schon gemacht?

von temp (Gast)


Angehängte Dateien:

Lesenswert?

Lothar M. schrieb:
> Kannst du mal ausprobieren, ob es was bringt, wenn du selber die
> Schleife ausrollst?

Das habe ich gemacht, allerdings ohne sichtbare Änderungen. Den 
erzeugten Code habe ich aber nicht verglichen. Hier noch 2 Screenshots 
vom Oszi. Der eine wenn keine Zähler incrementiert werden müssen und 
alternativ alle 8 müssen eins weiterrücken.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

temp schrieb:
> Das habe ich gemacht, allerdings ohne sichtbare Änderungen.
Im Vergleich zu was?
Sowohl deine verschliffene Variante wie auch die ausgerollte jeweils 1µs 
bei keinem und 1,4µs bei allen Zählern?

von temp (Gast)


Lesenswert?

Lothar M. schrieb:
> Sowohl deine verschliffene Variante wie auch die ausgerollte jeweils 1µs
> bei keinem und 1,4µs bei allen Zählern?

Ja genau.

Hier mal ein Stück aus dem Dissassembler beim Debuggen meiner Version 
mit der for-Schleife, die am Ende keine mehr ist:
Hier mit "if ((ug&(0x01<<n))==0)" um das Weiterzählen zu erzwingen.

1
for (int n=0; n<8; n++)
2
{
3
if ((ug&(0x01<<n))==0)
4
    D403        bmi 0x2000002E
5
--- main.c -- 75 -------------------------------------------
6
carr[n]++;
7
    491D        ldr r1, =0x200000A4 <carr>
8
    680A        ldr r2, [r1]
9
    3201        adds r2, #1
10
    600A        str r2, [r1]
11
--- main.c -- 74 -------------------------------------------
12
if ((ug&(0x01<<n))==0)
13
    0799        lsls r1, r3, #30
14
    D403        bmi 0x2000003A
15
--- main.c -- 75 -------------------------------------------
16
carr[n]++;
17
    491A        ldr r1, =0x200000A4 <carr>
18
    684A        ldr r2, [r1, #4]
19
    3201        adds r2, #1
20
    604A        str r2, [r1, #4]
21
--- main.c -- 74 -------------------------------------------
22
if ((ug&(0x01<<n))==0)
23
    075A        lsls r2, r3, #29
24
    D403        bmi 0x20000046
25
--- main.c -- 75 -------------------------------------------
26
carr[n]++;
27
    4917        ldr r1, =0x200000A4 <carr>
28
    688A        ldr r2, [r1, #8]
29
    3201        adds r2, #1
30
    608A        str r2, [r1, #8]
31
--- main.c -- 74 -------------------------------------------
32
if ((ug&(0x01<<n))==0)
33
    071C        lsls r4, r3, #28
34
    D403        bmi 0x20000052
35
--- main.c -- 75 -------------------------------------------
36
carr[n]++;
37
    4914        ldr r1, =0x200000A4 <carr>
38
    68CA        ldr r2, [r1, #12]
39
    3201        adds r2, #1
40
    60CA        str r2, [r1, #12]
41
--- main.c -- 74 -------------------------------------------
42
if ((ug&(0x01<<n))==0)
43
    06D8        lsls r0, r3, #27
44
    D403        bmi 0x2000005E
45
--- main.c -- 75 -------------------------------------------
46
carr[n]++;
47
    4911        ldr r1, =0x200000A4 <carr>
48
    690A        ldr r2, [r1, #16]
49
    3201        adds r2, #1
50
    610A        str r2, [r1, #16]
51
--- main.c -- 74 -------------------------------------------
52
if ((ug&(0x01<<n))==0)
53
    0699        lsls r1, r3, #26
54
    D403        bmi 0x2000006A
55
--- main.c -- 75 -------------------------------------------
56
carr[n]++;
57
    490E        ldr r1, =0x200000A4 <carr>
58
    694A        ldr r2, [r1, #20]
59
    3201        adds r2, #1
60
    614A        str r2, [r1, #20]
61
--- main.c -- 74 -------------------------------------------
62
if ((ug&(0x01<<n))==0)
63
    065A        lsls r2, r3, #25
64
    D403        bmi 0x20000076
65
--- main.c -- 75 -------------------------------------------
66
carr[n]++;
67
    490B        ldr r1, =0x200000A4 <carr>
68
    698A        ldr r2, [r1, #24]
69
    3201        adds r2, #1
70
    618A        str r2, [r1, #24]
71
--- main.c -- 74 -------------------------------------------
72
if ((ug&(0x01<<n))==0)
73
    09DB        lsrs r3, r3, #7
74
    D103        bne 0x20000082
75
--- main.c -- 75 -------------------------------------------
76
carr[n]++;
77
    4A08        ldr r2, =0x200000A4 <carr>
78
    69D3        ldr r3, [r2, #28]
79
    3301        adds r3, #1
80
    61D3        str r3, [r2, #28]
81
--- main.c -- 76 -------------------------------------------
82
}
83
GPIOC->BRR=GPIO_BRR_BR13;
84
    F44F5200    mov.w r2, #0x2000
85
    4B02        ldr r3, =0x40011000
86
--- main.c -- 79 -------------------------------------------
87
}
88
    BC10        pop {r4}
89
--- main.c -- 78 -------------------------------------------
90
GPIOC->BRR=GPIO_BRR_BR13;
91
    615A        str r2, [r3, #20]
92
--- main.c -- 79 -------------------------------------------
93
}

von Chris B. (dekatz)


Lesenswert?

Wenn wir jetzt schon bei 32-Bitter angelangt sind und der TE ohnehin mit 
PIC arbeitet, kann er das Problem auch gleich mit einem PIC32MZxxxxx 
erschlagen.
Der hat genügend Timer, jeder mit externen Takt befeuerbar, jeder einen 
eigenen Interrupt.
Die Interruptroutinen brauchen da nur mehr je einen Zähler 
inkrementieren, Int-Flag rücksetzen und am Ende der Messung stehen ein 
paar Multiplikationen und Additionen an......

von temp (Gast)


Lesenswert?

Chris B. schrieb:
> Wenn wir jetzt schon bei 32-Bitter angelangt sind und der TE ohnehin mit
> PIC arbeitet, kann er das Problem auch gleich mit einem PIC32MZxxxxx
> erschlagen.

Mein Beispiel ist in reinem C und sollte auch auf einem PIC32 laufen. 
Ich kann aber nur für die Controller sprechen die ich kenne. PIC32 
gehört nicht dazu und wird es auch nicht mehr.
Trotzdem ist es hin und wieder besser man hat eine Lösung die eventuell 
etwas mehr Zeit braucht, dafür aber in engen Grenzen komplett 
vorhersehbar abläuft unabhängig von den Pegeln an den Eingängen.
Nach dem selben Muster wäre es möglich kurze digitale Filter mit zu 
berechnen. Sicher nicht in diesem Beispiel wegen der min. Zeit von 5µs.
Trotzdem, das mit einem einzelnen Timer und einem einzigen Interrupt 
abzuhandeln ist ohne Aufwand auf die verschiedensten Controller 
portierbar. Besser jedenfalls als wenn man extrem an den Hardwareblöcken 
hängt.
Ich würde mir dafür jedenfalls nicht 6 Interrupt-Routinen ans Bein 
heften.

von Volker S. (vloki)


Lesenswert?

temp schrieb:
> Besser jedenfalls als wenn man extrem an den Hardwareblöcken
> hängt.
> Ich würde mir dafür jedenfalls nicht 6 Interrupt-Routinen ans Bein
> heften.

Hardwareblöcke sind doch gerade dazu da, bestimmte Dinge nicht in 
Software machen zu müssen. Bräuchte man sonst uC?
Wieso 6 IR-Routinen? (Eine reicht doch, um regelmäßig alle 
Hardware-Counter auszulesen, bzw. deren evtl. automatisch 
zwischengespeicherten Werte)

von temp (Gast)


Lesenswert?

Volker S. schrieb:
> Hardwareblöcke sind doch gerade dazu da, bestimmte Dinge nicht in
> Software machen zu müssen. Bräuchte man sonst uC?
Verwendet meine Lösung denn keine Hardwarblöcke?

Chris B. schrieb:
> Der hat genügend Timer, jeder mit externen Takt befeuerbar, jeder einen
> eigenen Interrupt.

> Wieso 6 IR-Routinen? (Eine reicht doch, um regelmäßig alle
> Hardware-Counter auszulesen, bzw. deren evtl. automatisch
> zwischengespeicherten Werte)


Ich habe auf den Post von Chris B. geantwortet und nicht auf deine 
Vorstellungen.
Das schöne daran ist, dass es jeder machen kann wie er will und es 
sicher viele Lösungsansätze gibt. Ich habe ein Beispiel probiert und 
gepostet und ob es dir gefällt oder nicht ist mir Wumpe. Jeder der will, 
kann seine Lösung hier rein stellen, aber bitte kein Geschwafel sondern 
am konkreten Beispiel.
Ich werde jedenfalls nicht danach suchen, bei welche PICs es möglich ist 
6 separate Timer mit jeweils externem Eingang zu verwenden.

von Volker S. (vloki)


Lesenswert?

temp schrieb:
> Volker S. schrieb:
>> Hardwareblöcke sind doch gerade dazu da, bestimmte Dinge nicht in
>> Software machen zu müssen. Bräuchte man sonst uC?
> Verwendet meine Lösung denn keine Hardwarblöcke?

Wenn ich einen Zähler brauche, dann schau ich gewöhnlich zuerst mal ob 
da schon einer da ist, den ich nur konfigurieren muss und der dann die 
Aufgabe unabhängig vom Programm übernehmen kann.


temp schrieb:
> Ich habe auf den Post von Chris B. geantwortet
> ...
> Ich werde jedenfalls nicht danach suchen, bei welche PICs es möglich ist
> 6 separate Timer mit jeweils externem Eingang zu verwenden.

Ich auch nicht, aber ich hatte den Eindruck Chris B. hätte einen 
konkreten vorgeschlagen.


Der TE hat vermutlich eh schon das Weite gesucht, damit ihm nicht der 
Kopf platzt ob der zu vielen guten Lösungsmöglichkeiten ;-)
Ich hätte eben erst noch auf Rückmeldung gewartet bevor ich so ganz 
konkrete Beispiele gebe um eine bestimmte Lösung aufzudrängen. Bringt ja 
nix.

von Larry (Gast)


Lesenswert?

Wenn ich bei meiner ISR auch spaeter eintrudelnde IOC beruecksichtige,
komme ich bei 6 16 bit Zaehlern in der ISR auf max. 12.2 us
(plus Latenz zum Aufruf).
Und die duerfen asynchron kommen wie sie wollen, weil sie ja
im IOCAF-Register gelatcht und nur bei Zaehlung zurueckgesetzt werden.
Das globale IOCIF wird auch nur geloescht, wenn in der ISR
keine neuen IOCs dazu gekommen sind.

Wo ist also das Problem?

von m.n. (Gast)


Lesenswert?

temp schrieb:
> Ich würde mir dafür jedenfalls nicht 6 Interrupt-Routinen ans Bein
> heften.

Um bei Deinem F103 zu bleiben, reichen zwei ISRs, die jeweils eine 
Gruppe von Capture-Interrupts bedienen.
An PA0-PA3 liegen die vier Capture-Eingänge von TIM2 und an PA6+PA7 zwei 
von TIM3. Jeder dieser Eingänge kann einen Interrupt auslösen, wobei die 
Eingangsflanke und eine leichte Filterung separat eingestellt werden 
können.

Daß der µC für diese Aufgabe schnell genug ist, hattest Du ja schon 
gezeigt. Der Vorteil gegenüber einem Polling mit 500 kHz ist jedoch, daß 
bei niedrigen Impulsfrequenzen die Interruptlast nur sehr gering ist. 
Wer neugierig ist, kann nebenbei auch noch die Frequenz messen ;-)

Wenn man einen F103 in einem größeren Gehäuse verwendet, kann man wie 
oben beim F4xx angedeutet alles per Hardware zählen. Dazu wird von den 
betreffenden Timer TIMx_CH1 verwendet und im "External Clock Mode 1" 
betrieben.

von temp (Gast)


Lesenswert?

m.n. schrieb:
> Um bei Deinem F103 zu bleiben, reichen zwei ISRs, die jeweils eine
> Gruppe von Capture-Interrupts bedienen.
> An PA0-PA3 liegen die vier Capture-Eingänge von TIM2 und an PA6+PA7 zwei
> von TIM3. Jeder dieser Eingänge kann einen Interrupt auslösen, wobei die
> Eingangsflanke und eine leichte Filterung separat eingestellt werden
> können.

Und das soll besser sein? Hast du auch mal den Fall bedacht, dass an 
einer oder mehrerer der Leitungen anstelle des Nutzsignals ein besseres 
Rauschen anliegt? Das kann die Interruptlast dann so weit treiben das 
überhaupt nichts mehr geht. Das trifft aber auf alle Varianten zu die 
mit Flankeninterrupts arbeiten und aus meiner Sicht aus diesem Grund 
ungeeignet sind.

m.n. schrieb:
> Der Vorteil gegenüber einem Polling mit 500 kHz ist jedoch, daß
> bei niedrigen Impulsfrequenzen die Interruptlast nur sehr gering ist.

Ja, mir tut es auch immer weh wenn ich zusehen muss wie sich so ein µC 
mit Interrupts quält die noch dazu vorhersehbar sind in Zeit und Länge. 
Das ist schon eine schwere Microcontrollerrechtsverletzung und muss 
unbedingt unterbunden werden. Koste es was es wolle und wenn ich dafür 
einen 144pin Controller brauche anstelle eines mit 32 oder 48 Beinen 
spielt das überhaupt keine Rolle.

m.n. schrieb:
> Wenn man einen F103 in einem größeren Gehäuse verwendet, kann man wie
> oben beim F4xx angedeutet alles per Hardware zählen. Dazu wird von den
> betreffenden Timer TIMx_CH1 verwendet und im "External Clock Mode 1"
> betrieben.

Und das ist nur deshalb besser nur weil du dich besser fühlst? Nenn mal 
einen Typ bei dem 6 Timer mit externem Zählereingang vorhanden sind.

von Volker S. (vloki)


Angehängte Dateien:

Lesenswert?

temp schrieb:
> Nenn mal
> einen Typ bei dem 6 Timer mit externem Zählereingang vorhanden sind

Hat Cris B. doch schon längst getan. Da wären sogar 8 drin:

von temp (Gast)


Lesenswert?

Volker S. schrieb:
> Hat Cris B. doch schon längst getan. Da wären sogar 8 drin:


Chris B. schrieb:
> Wenn wir jetzt schon bei 32-Bitter angelangt sind und der TE ohnehin mit
> PIC arbeitet, kann er das Problem auch gleich mit einem PIC32MZxxxxx
> erschlagen.

PIC32MZxxxxx ist eine ganze Serie und kein einzelner Typ. Noch dazu in 
einer komplett anderen Leistungs- und Preisklasse. Den preiswertesten 
davon gibt es  bei Mouser für ca. 8.50€ incl. MwSt. Für den Preis gibt 
es 5 komplette Bluepill Boards.

von m.n. (Gast)


Lesenswert?

@temp
Sag mal, hast Du schlecht geschlafen?
Da Du den F103 ins Spiel gebracht hattest, dachte ich, Du würdest Dich 
damit auskennen. Das war wohl ein Irrtum.

Die TIMx_CHx-Eingänge kann man derart filtern lassen, daß selbst der 
oben genannte 5 µs Impuls als Störung unterdrückt wird. Dein 
konstruiertes "Rauschen" läßt daher garkeine ISR anspringen.

von temp (Gast)


Lesenswert?

m.n. schrieb:
> Sag mal, hast Du schlecht geschlafen?
> Da Du den F103 ins Spiel gebracht hattest, dachte ich, Du würdest Dich
> damit auskennen. Das war wohl ein Irrtum.

Am Ende der Argumentationskette bleiben wie immer nur noch Beleidigungen 
übrig...
Damit bin ich raus.

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.