Guten Abend,
ich bin auf der Suche nach einer einfachen und übersichtlichen Erkennung
von Flanken in C.
Ich möchte Flanken erkennen die nicht schneller als meine Main Loop.
Mir geht es dabei einfach um eine übersichtliche Art auf ein Ereignis
nur beim Flankenwechsel zu reagieren.
Ein Beispiel wäre das ein Fehlerbit erkannt wird und einmal eine
Debugausgabe gesendet wird.
Habt ihr hier zu eine Funktion die man sich für solche Zwecke
referenzieren kann?
Danke für die Hilfe
Eine Funktion, um eine simple Zustands-Variable zu beschreiben?
Also wenn das einfach sein soll, dann würde ich mal sehr gerne sehen,
wie du das bisher programmiert hast.
1
uint8_terrorAlreadyProcessed=0;
2
3
intmain()
4
{
5
...
6
for(;;)// main loop
7
{
8
...
9
if(error==1)
10
{
11
if(errorAlreadyProcessed==0)
12
{
13
errorAlreadyProcessed=1;
14
processError();
15
}
16
}
17
}
Wie soll man das mit einer zusätzlichen Funktion verschönern? Kann ich
mir nicht vorstellen.
gedenk schrieb:> Ich möchte Flanken erkennen die nicht schneller als meine Main Loop.
Einmal in der Main Loop den "Flankeneingang" abfragen und das Ergebnis
in ein Register links reinschieben. Mit "and" 3 Länge die Länge
begrenzen. Mit compare 01 oder 10 auf die gewünschte Flanke prüfen.
gedenk schrieb:> Ein Beispiel wäre das ein Fehlerbit erkannt wird und einmal eine> Debugausgabe gesendet wird.
Das klingt für mich nicht danach, dass du jede Flanke erkennen willst,
sondern nur die erste steigende. Darauf bezog sich mein obiges Beispiel.
gedenk schrieb:> Das Problem ist das man sich Händisch immer eine Variable merken anlegen> muss uns sich den Zustand merken muss.
Natürlich muss man den vorherigen Zustand kennen, wie sollte man sonst
eine Änderung erkennen können ?
gedenk schrieb:> Das Problem ist das man sich Händisch immer eine Variable merken anlegen> muss uns sich den Zustand merken muss.
Ohne Variablen läßt sich nunmal schlecht programmieren.
Du kannst Dir ein Macro schreiben, was für Dich die Variable anlegt.
gedenk schrieb:> ich bin auf der Suche nach einer einfachen und übersichtlichen Erkennung> von Flanken in C.
Per ISR, dessen Interrupt nur bei einer Flankenart getriggert wird.
Peter D. schrieb:> Anbei mal ein einfaches Macro zur Flankenerkennung.
Danke für das Makro:)
Ich kann es im Moment nnicht testen da ich keine Hardware da habe.
Verstehe ich es richtig das man so Zb das Makro verwenden könnte?
if (get_edge(PINB & (1<<0))==RISE)
{
uputs_("PINB0 RISE\n\r");
}
Danke für die Hilfe
gedenk schrieb:> Das Problem ist das man sich Händisch immer eine Variable merken> anlegen> muss uns sich den Zustand merken muss.
Das ist nicht das Problem sondern die Lösung!
Ist der neue Wert anders als der alte bedingt nunmal das der Rechner
beide vergleichen kann.
NichtWichtig schrieb:> Das ist nicht das Problem sondern die Lösung!>> Ist der neue Wert anders als der alte bedingt nunmal das der Rechner> beide vergleichen kann.
Ist mir schon bewusst;)
Ich war nur auf der Suche nach einem System wo ich nicht Händisch diese
Variable anlegen muss.
Peter D. schrieb:> Anbei mal ein einfaches Macro zur Flankenerkennung.
Dies gefällt mir vom Prinzip her gut muss es jetzt testen.
gedenk schrieb:> ch war nur auf der Suche nach einem System wo ich nicht Händisch diese> Variable anlegen muss.
Dich zwingt Niemand dazu. Du kannst auch eine Speicherstelle/ Bit direkt
ansprechen.
gedenk schrieb:> Ich war nur auf der Suche nach einem System wo ich nicht Händisch diese> Variable anlegen muss.
Irgendwas musst du aber tun!
Telepathie, können unsere µC noch nicht.
Ansonsten kann ich dir nur eine bequeme C++ Lösung anbieten.
Im Anhang, ein Beispiel.
Danke Euch.
Aber viele verstehen meine Frage falsch.
Ich weiß das man zur Flanken erkennung den vorherigen Zustand wissen
muss.
Mir hat legendlich die Idee gefehlt wie man eine Flankenerkennung als
eine Art "Funktion" bzw Makro macht um nicht für jede Flanke die man
auswerten will jedes mal händisch eine Variable anlegen muss.
Die Lösung von Peter D.
Erfüllt genau meine Anforderung.
Die Merker Variable wird für jede Verwendung deklariert.
Und nein ich will keine Entprellung. Ich möchte nur eine
Flankenerkennung.
Danke schönen Tag
Arduino Fanboy D. schrieb:> Ansonsten kann ich dir nur eine bequeme C++ Lösung anbieten.
Ich habs zwar nicht probiert, aber der AVR-GCC wird mir bestimmt 1000
Fehlermeldungen vor den Latz knallen.
Wie heißen denn die dafür nötigen Libs und wo kann man sie downloaden?
Es fällt mir doch sehr oft auf, das C++ Codebeispiele out of the box
erstmal nicht lauffähig sind und daher gerade für Anfänger keine Hilfe.
Hi
C ist nicht meine Sprache und trotzdem mal einen Tip zur
Flankenerkennung. Angenommen, du hast die Variablen "Alt" und "Neu"
sowie "Temp", "Fl_to_1" und "Fl_To_0".
Zuerest eine Exclusiv-Oder "Alt" mit "Neu" und das Ergebnis nach "Temp".
Nun mit "Temp" und "Alt" eine Und-Verknüpfng und du hast den Wechsel von
"1" nach "0". Dann eine Und-Verknüpfung von "Temp" und "Neu" und du hast
den Wechsel von "0" nach "1". Anschließend kopierst du "neu" nach "Alt".
Die Bits in den Variablen "Fl_to_1" sowie "Fl_to_0" kannst du jetzt
abfragen, die Bearbeitung ausführen und diese Bits löschen. Erst bei
einem erneuten Wechsel in der Variable "Neu" werden sie wieder in der
Flanke erkannt und neu gesetzt. In Assembler etwa 10 Anweisungen, wobei
hier immer von Bytes und nicht von Bits die Rede ist.
1
Flanken: ; In "Alt" und "Neu", Out "Fl_to_1" und "Fl_to_0"
2
LDS r16, alt
3
LDS r17, neu
4
EOR r16,r17
5
Mov temp, r16 ;temp = beliebiges Register
6
AND r16, r17 ;
7
STS Fl_to_1, r16 ; Ergebnis Flankenbits "0" nach "1"
8
LDS r16, alt
9
AND r16, temp
10
STS Fl_to_1, r16 ; Ergebnis Flankenbits "1" nach "0"
11
STS alt, r17
12
RET
Ich denk, in C ist das auch nicht viel schwieriger.
Gruß oldmax
Peter D. schrieb:> Wie heißen denn die dafür nötigen Libs und wo kann man sie downloaden?
Die kannst du bei mir bekommen!
Und dann wirft dein Kompiler auch keine Meldungen mehr.
C++11 sollte er dafür schon können, und einen der üblichen AVR Arduinos
solltest du verwenden.
Statt Makro-Magie könnte man sich auch einfach eine ganz normale
Funktion schreiben. Das mag altmodisch wirken, aber C ist ja auch eine
altmodische Programmiersprache - passt also.
1
#include<stdbool.h>
2
#include<stdint.h>
3
#include<stdio.h>
4
5
boolzustand_Schalter1=0;
6
7
/**
8
* Erkennt Flankenwechsel bei einem Signal.
9
* @param signal Eingangssignal
10
* @param zustandsVariable Zeiger auf eine Variable, die den vorherigen Zustand speichert.
11
* @return 1 bei stegender Flanke, -1 bei fallender Flanke, 0=keiner Änderung
12
*/
13
int8_tflanke(boolsignal,bool*zustandsVariable)
14
{
15
if(signal!=*zustandsVariable)
16
{
17
*zustandsVariable=signal;
18
if(signal)
19
return1;
20
else
21
return-1;
22
}
23
return0;
24
}
25
26
voidtest_fuer_schalter1(boolsignal)
27
{
28
int8_tf=flanke(signal,&zustand_Schalter1);
29
switch(f)
30
{
31
case+1:printf("steigende Flanke");break;
32
case-1:printf("fallende Flanke");break;
33
default:printf("keine Flanke");
34
}
35
}
36
37
intmain()
38
{
39
test_fuer_schalter1(0);
40
test_fuer_schalter1(1);
41
test_fuer_schalter1(1);
42
test_fuer_schalter1(0);
43
test_fuer_schalter1(0);
44
}
In Kombination mit einem I/O Pin könnte man das so verwenden:
1
#include<stdbool.h>
2
#include<stdint.h>
3
#include<stdio.h>
4
#include<util/delay.h>
5
#include<avr/io.h>
6
7
// Hier noch die Funktion "flanke" rein kopieren oder inkludieren.
Peter D. schrieb:> Anbei mal ein einfaches Macro zur Flankenerkennung.
static bool last_flag = false; /* new variable on every macro usage*/
das macro sollte hier mit "__LINE__" verbessert werden, damit
automatisch immer eine neue variable angelegt wird!
mt
gedenk schrieb:> Bei vielen Spsen gibt es RTrig Ftrig das sind Funktionen die intern den> Zustand speichern aber von extern kommt nur das zu Triggernde Signal> rein.
Man könnte auch einfach das Interrupt Flag eines zB AVR in der main
abfragen (und löschen). Das speichert entsprechend der Konfiguration das
Triggerereignis.
gedenk schrieb:> ich bin auf der Suche nach einer einfachen und übersichtlichen Erkennung> von Flanken in C.
du kannst keine Flanken erkennen, du kannst nur logische Zustände
vergleichen. Daraus kann man sich eine Pseudo- Flankenerkennung basteln
indem man eine Zustandsänderung sucht.
1
wenn(PortWert!=alterWert)Aenderungsflag=1;
2
alterWert=PortWert;
Damit findet man aber nur die erste Änderung
1
wenn(PortWert!=alterWert)Aenderungszaehler++;
2
alterWert=PortWert;
Bildet die Anzahl der Änderungen
Es kann sinnvoll sein einen Interrupt zu verwenden, der erkennt aber
Änderungen meist nur in eine Richtung.
Viele Controller haben Onchange Register die eine Änderung der Ports
seit der letzten Abfrage anzeigen. Das hat aber nichts mit C zu tun und
ist "nicht portabel".
Apollo M. schrieb:> das macro sollte hier mit "__LINE__" verbessert werden, damit> automatisch immer eine neue variable angelegt wird!
Wozu soll das gut sein?
Jede static Variable hat nur innerhalb des Blocks Gültigkeit und bleibt
bis zum nächsten Eintritt in den Block erhalten.
Der Linker ist daher verpflichtet, bei jeder Macroexpansion eine neue
Adresse zu vergeben und er macht das auch.
Apollo M. schrieb:> das macro sollte hier mit "__LINE__" verbessert werden, damit> automatisch immer eine neue variable angelegt wird!
Wie Peter dargelegt hat, ist das nicht notwendig. Du kannst ohne
Probleme beliebig viele gleichnamige (static-)Variablen innerhalb einer
Funktion anlegen und auch getrennt voneinander verwenden, solange sich
nicht der Scope überlappt.
Peter D. schrieb:> Private Libs würde ich immer so kenntlich machen:
Die Libs sind dafür vorgesehen in einen der Arduino Library Ordner
geworfen zu werden.
Sie sind dann also für alle Projekte zu sehen.
#include "abc.h"
Nutze ich für Dateien, welche nur in diesem Projekt sichtbar sind.
Im Projekt Ordner liegen.
#include <abc.h>
Um Libs aus den "öffentlichen" libraries zu verwenden. Wo man die Combie
Libs auch hinein werfen sollte.
Eine dritte Möglichkeit der Unterscheidung bietet sich nicht.
Peter D. schrieb:> Wozu soll das gut sein?> Jede static Variable hat nur innerhalb des Blocks Gültigkeit und bleibt> bis zum nächsten Eintritt in den Block erhalten.> Der Linker ist daher verpflichtet, bei jeder Macroexpansion eine neue> Adresse zu vergeben und er macht das auch.
korrekt, die blockklammerung habe ich übersehen. also in die tonne mit
meiner anmerkung!
mt
Stefanus F. schrieb:> Statt Makro-Magie könnte man sich auch einfach eine ganz normale> Funktion schreiben.
An dem Macro ist überhaupt nichts magisches. Der Code ist
straightforward und deutlich einfacher zu verstehen, als das C++
Beispiel.
Nicht jedem bekannt ist vielleicht, daß man Macros auch lesbar schreiben
darf, indem man sie mit dem '\' Zeichen auf mehrere Zeilen umbricht.
Der eigentliche Trick des Macros ist aber, daß es ein Block öffnet und
darin eine Variable anlegt. Somit wird bei jeder Verwendung automatisch
eine neue Variable erzeugt.
Als Magie würde ich das nicht bezeichnen.
Natürlich grassiert oft das Vorurteil, Macros sind ja ach so pöse. Dabei
wird aber verkannt, daß selbst die standard Includes schon sehr viele
Macros beinhalten.
Ich will das Makro nicht schlecht reden, sondern nur eine Alternative
aufzeigen.
Ich mag Makros nicht mehr so sehr, nachdem ich mich mit zu vielen
Verschachtelungen selbst verzettelt habe und andere Nutzer durch meine
Quelltexte nicht durchgeblickt haben. Mit Bedacht eingesetzt sind sie
sicher nicht grundsätzlich verkehrt.
Stefanus F. schrieb:> Ich will das Makro nicht schlecht reden, sondern nur eine Alternative> aufzeigen.
Deine Alternative ist aber nur eine Alternative, wenn es nur einen Pin
auszuwerten gilt. Peters Makro funktioniert aber auch für 2, 3, 4 Pins.
Hier wird der Code n-fach durch den Preprocessor einfach dupliziert -
nicht schön, aber wirksam.
Die allgemeinere Lösung über eine Funktion wäre daher wesentlich
interessanter. Der Spezialfall N=1 ist dabei eher uninteressant. Da kann
ich (fast) Peters Makro einfach in eine leere Funktion kopieren und
fertig.
Frank M. schrieb:> Die allgemeinere Lösung über eine Funktion wäre daher wesentlich> interessanter.
Ich betrachte den Flankenerkenner als endlichen Automaten.
Vielleicht die primitivste Form dessen, aber ein Automat.
Das bedingt, dass man irgendwo einen Zustand halten muss.
Hält man den Zustand in der Funktion (static), schränkt das die
Mehrfachverwendung ein. Wie bei den Makros führt das recht zwingend zu
Codeduplikaten, für jeden "Kanal" welcher überwacht werden möchte.
Die für "mich" sinnvollste Lösung wäre in C eine Variable außerhalb, für
den Zustand. z.B. Übergabe eines Zeigers auf den Zustand.
In C++ hält man den Zustand als Instanz Eigenschaft. Dürfe die übliche
Vorgehensweise sein.
----
Im Grunde sind das die drei Möglichkeiten, welche einem die µC Welt
bietet.
Mehr sehe ich nicht.
Geschickt gebaut, kann man so auch z.B. 8 Kanäle gleichzeitig in einem
Byte verwalten.
Natürlich kann man das auch in ASM oder einer anderen Sprache erledigen,
ändert aber nichts an den Notwendigkeiten.
Arduino Fanboy D. schrieb:> Geschickt gebaut, kann man so auch z.B. 8 Kanäle gleichzeitig in einem> Byte verwalten.
Jepp. Wenn man mit dem Speicher nicht geizen muss, gehts auch mit einem
Array namens last_states[].