Forum: Mikrocontroller und Digitale Elektronik Universelle C-Funktion zur Flankenerkennung - Fehlerbehebung


von Helene M. (hmeyer)


Lesenswert?

Hallo,
ich möchte eine Fkt zur Flankenerkennung schreiben, bei der ich per 
Übergabeparameter bestimmen kann, auf welchen Taster geachtet werden 
soll.
Mir ist bewusst, dass diese Funktionen so nicht funktionieren, da er in 
der lokalen "alt" Variable ja immer nur den Zustand für den zuletzt 
getätigten Tasteraufruf gespeichert hat und aktuell der Aufruf z.B. mit 
einem ganz anderen Taster erfolgen kann.
Nur wie kann ich die Funktionen abändern, damit diese universell 
funktionieren?
1
unsigned char neu = 0;
2
unsigned char pos_edge(unsigned char Taster_Nummer)
3
{
4
static unsigned char alt = 0;
5
neu = TASTEN_P3 & Taster_Nummer;
6
if(neu != alt && TASTEN_P3 & Taster_Nummer)
7
 {
8
 alt = neu;
9
 return (1);
10
 }
11
 else
12
 {
13
 alt = neu;
14
 return (0);
15
 }
16
}
17
18
unsigned char neg_edge(unsigned char Taster_Nummer)
19
{
20
static unsigned char alt = 0;
21
neu = TASTEN_P3 & Taster_Nummer;
22
if(neu != alt && (!(TASTEN_P3 & Taster_Nummer)))
23
 {
24
 alt = neu;
25
 return (1);
26
 }
27
 else
28
 {
29
 alt = neu;
30
 return (0);
31
 }
32
}

von Cyblord -. (cyblord)


Lesenswert?

Für Flankenerkennung muss FÜR JEDEN Eingang ein EIGENES Flag mit dem 
vorherigen Zustand mitgeführt werden.
D.h. du musst diese Flags irgendwo speichern. Wenn du also max. 10 
Eingänge erkennen willst könntest du ein Array mit 10 Flags anlegen.

Wenn schon universal, dann packe das alles in ein eigenes Modul (in C 
ist das eine .c und .h Datei).

Mit klarer Schnittstelle.
Die Flags werden als interne zustände in static Variablen im Modul 
gehalten oder sogar in einer eigenen Context-Structur, die dann halt 
immer mit übergeben werden muss.

Mir ist auch nicht klar warum du zwei Funktion hast, mit Pos und Neg. 
Flanke?

Als Schnittstelle reicht EINE Funktion an welche der aktuelle Zustand 
des Eingang übergeben wird. Die Flanke soll ja gerade erst durch dein 
Modul erkannt werden. Die kennst du ja vorher nicht.

: Bearbeitet durch User
von Peter D. (peda)


Lesenswert?

Am effektivsten macht man das nicht umständlich für jede Taste extra, 
sondern über die komplette Portbreite und ruft das zyklisch im 
Timerinterrupt auf, damit keine Flanke verloren geht. Außerdem kann man 
dabei bequem die Tasten mit entprellen.
Im Main maskiert man nur noch das gewünschte Bit des Flagregisters zur 
Auswertung und löscht es.
In eine uint64_t Variable passen so bis zu 64 Tasten.

von Cyblord -. (cyblord)


Lesenswert?

Peter D. schrieb:
> Am effektivsten macht man das nicht umständlich für jede Taste extra,
> sondern über die komplette Portbreite und ruft das zyklisch im
> Timerinterrupt auf, damit keine Flanke verloren geht. Außerdem kann man
> dabei bequem die Tasten mit entprellen.
> Im Main maskiert man nur noch das gewünschte Bit des Flagregisters zur
> Auswertung und löscht es.
> In eine uint64_t Variable passen so bis zu 64 Tasten.

Damit hast du halt eine starke Bindung an die Hardware und eben keine 
davon entkoppelte Logik oder gar ein gut abstrahiertes Interface.
Es gibt auch keinen Grund hier das Letzte Bit einzusparen.

Beitrag #7606544 wurde vom Autor gelöscht.
von Peter D. (peda)


Lesenswert?

Cyblord -. schrieb:
> Damit hast du halt eine starke Bindung an die Hardware und eben keine
> davon entkoppelte Logik oder gar ein gut abstrahiertes Interface.

Das Hauptproblem sehe ich eher darin, diese Funktionen irgendwo in den 
Wirren des Codes einzeln aufzurufen und dadurch Flanken zu verpassen.
Daher finde ich die zentrale Ausführung im Timerinterrupt und auf 
Portbreite bedeutend zuverlässiger. Auch wenn ich nur wenige Pins davon 
als Taste benutze.
Was ich auch gerne mache, im Interrupt die Ereignisse zu sammeln und sie 
dann später im Main in aller Ruhe auszuwerten.

: Bearbeitet durch User
von Cyblord -. (cyblord)


Lesenswert?

Peter D. schrieb:
> Das Hauptproblem sehe ich eher darin, diese Funktionen irgendwo in den
> Wirren des Codes einzeln aufzurufen und dadurch Flanken zu verpassen.

Dann wäre System aber sehr deutlich unterdimensioniert.

von Arduino F. (Firma: Gast) (arduinof)


Lesenswert?

Helene M. schrieb:
> ich möchte eine Fkt zur Flankenerkennung schreiben, bei der ich per
> Übergabeparameter bestimmen kann, auf welchen Taster geachtet werden
> soll.

Dann stopfe deine Tastenparameter alle in eine Struktur, und wenn es 
mehr Tasten werden sollen, die Strukturen in ein Array.

Das static muss da auf jeden Fall weg, denn es tötet dir die ungehemmte 
Wiederverwendung.

von Flunder (flunder)


Lesenswert?

So was :
1
static uint8_t alt = 0U;
2
static uint8_t pos = 0U;
3
static uint8_t neg = 0U;
4
5
void watch_edges(void)
6
{
7
uint8_t neu = TASTEN_P3;
8
    pos |= neu & ~alt;
9
    neg |= alt & ~neu;
10
    alt = neu;
11
}
12
13
uint8_t pos_edge(uint8_t Taster_Nummer)
14
{
15
uint8_t result = pos & Taster_Nummer;
16
    pos &= ~Taster_Nummer;
17
    /* Anfang optional */
18
    if (0U != result)
19
    {
20
        result = 1U;
21
    }
22
    /* Ende optional */
23
    return result;
24
}
25
26
uint8_t neg_edge(uint8_t Taster_Nummer)
27
{
28
uint8_t result = neg & Taster_Nummer;
29
    neg &= ~Taster_Nummer;
30
    /* Anfang optional */
31
    if (0U != result)
32
    {
33
        result = 1U;
34
    }
35
    /* Ende optional */
36
    return result;
37
}

von Jasson J. (jasson)


Lesenswert?

@TE
Ein paar weniger Posts weiter oben steht ein Hinweis "Structs" zu 
verwenden.

In diesem Beispiel würde eine Struct "button" die von pins eingelesenen 
Zustände und "old" states enthalten, um auf deren Basis die 
Flankenerkennung zu machen.

Man könnte dann ein Array vom Typ dieser Strucs anlegen mit so vielen 
Elementen, wie du Tasten hast.

Die Funktionen würde man so schreiben, dass sie mittels eines Indexes 
eine Instanz in dem Array addressiert und die Logik auf den Werten der 
Instanz operieren lässt.

Hatte versucht, ein Beispiel im I-Net zu finden, fand keines, also hab 
ich ein
>Experiment mit ChatGPT gemacht.

Das direkte Beispiel zu meinem beschriebenen Vorschlag oben (nicht auf 
Funktion geprüft)
1
#include <stdbool.h>
2
#include <stdint.h>
3
#include <stdio.h>
4
5
// Define the struct for digital inputs
6
typedef struct {
7
    bool state;
8
    bool lastState;
9
} Digital_Input;
10
11
// Function to check if a pin has a rising edge
12
bool PinHasRisingEdge(Digital_Input* pinArr, uint8_t pinSel) {
13
    // Check if the current state is HIGH and the last state was LOW
14
    if (pinArr[pinSel].state && !pinArr[pinSel].lastState) {
15
        return true;  // Rising edge detected
16
    } else {
17
        return false; // No rising edge
18
    }
19
}
20
21
// Function to check if a pin has a falling edge
22
bool PinHasFallingEdge(Digital_Input* pinArr, uint8_t pinSel) {
23
    // Check if the current state is LOW and the last state was HIGH
24
    if (!pinArr[pinSel].state && pinArr[pinSel].lastState) {
25
        return true;  // Falling edge detected
26
    } else {
27
        return false; // No falling edge
28
    }
29
}
30
31
int main() {
32
    Digital_Input inputArray[8]; // Assuming 8 digital inputs
33
34
    // Result bytes for rising and falling edges
35
    uint8_t risingEdgeResults = 0;
36
    uint8_t fallingEdgeResults = 0;
37
38
    while (1) {
39
        // Read from the specific 8-bit port (replace PORTA with your actual port)
40
        uint8_t inputData = PINA;
41
42
        // Dispatch each bit to one element in Digital_Input
43
        for (int i = 0; i < 8; ++i) {
44
            inputArray[i].lastState = inputArray[i].state;
45
            inputArray[i].state = (inputData >> i) & 0x01;
46
        }
47
48
        // Run PinHasRisingEdge and PinHasFallingEdge for each pin
49
        for (int i = 0; i < 8; ++i) {
50
            // Update result bytes with the results in a bit-stuffed fashion
51
            risingEdgeResults |= (PinHasRisingEdge(inputArray, i) ? 1 : 0) << i;
52
            fallingEdgeResults |= (PinHasFallingEdge(inputArray, i) ? 1 : 0) << i;
53
        }
54
55
        // Example: Print the results
56
        printf("Rising Edge Results: 0x%X\n", risingEdgeResults);
57
        printf("Falling Edge Results: 0x%X\n", fallingEdgeResults);
58
    }
59
60
    return 0;
61
}

: Bearbeitet durch User
von Jasson J. (jasson)


Lesenswert?

>> Hier noch meine gesamte "Konversation" mit ChatGPT
Wenn man z.B. von einem AtMega spricht, ist PORTA natürlich Käse, muss 
PINA sein
1
>ME:
2
can you provide a code example in programming language C, which showcases following scenario:
3
4
The state of eight digital Input pins of a microcontroller are read in and afterwards in functions it is detected, if a pin had a rising or falling edge. Each pin is represented by a struct name "Digital_Input". Instances of that struct are hold in an array of type "Digital_Input". 
5
6
There  is a function with the signature "bool PinHasRisingEdge(Digital_Input* pinArr, uint8_t pinSel )"
7
As input argutment it gets the reference to the arry of digital inputs and a numeric value selecting the one to operate the functions logic on. 
8
The locig detects if there is a rising edge. If there is a rising edge the return value is true, else it is false. 
9
10
There  is a function with the signature "bool PinHasFallingEdge(Digital_Input* pinArr, uint8_t pinSel )"
11
As input argutment it gets the reference to the arry of digital inputs and a numeric value selecting the one to operate the functions logic on. 
12
The locig detects if there is a falling edge. If there is a rising edge the return value is true, else it is false. 
13
14
>>ChatGPT:
15
Certainly! Here's an example in C that demonstrates the scenario you described:
16
17
#include <stdbool.h>
18
#include <stdint.h>
19
20
// Define the struct for digital inputs
21
typedef struct {
22
    bool state;
23
    bool lastState;
24
} Digital_Input;
25
26
// Function to check if a pin has a rising edge
27
bool PinHasRisingEdge(Digital_Input* pinArr, uint8_t pinSel) {
28
    // Check if the current state is HIGH and the last state was LOW
29
    if (pinArr[pinSel].state && !pinArr[pinSel].lastState) {
30
        return true;  // Rising edge detected
31
    } else {
32
        return false; // No rising edge
33
    }
34
}
35
36
// Function to check if a pin has a falling edge
37
bool PinHasFallingEdge(Digital_Input* pinArr, uint8_t pinSel) {
38
    // Check if the current state is LOW and the last state was HIGH
39
    if (!pinArr[pinSel].state && pinArr[pinSel].lastState) {
40
        return true;  // Falling edge detected
41
    } else {
42
        return false; // No falling edge
43
    }
44
}
45
46
int main() {
47
    // Example usage
48
    Digital_Input inputArray[8]; // Assuming 8 digital inputs
49
50
    // Simulating a change in state for a specific pin
51
    uint8_t pinToTest = 3;
52
    inputArray[pinToTest].state = true;
53
    inputArray[pinToTest].lastState = false;
54
55
    // Check for rising edge
56
    if (PinHasRisingEdge(inputArray, pinToTest)) {
57
        // Rising edge detected
58
        // Do something here
59
    }
60
61
    // Check for falling edge
62
    if (PinHasFallingEdge(inputArray, pinToTest)) {
63
        // Falling edge detected
64
        // Do something here
65
    }
66
67
    return 0;
68
}
69
This example assumes that you have an array of Digital_Input structures representing the state of each digital input. The PinHasRisingEdge and PinHasFallingEdge functions take the array and the selected pin as parameters and return true if the specified condition is met, otherwise false.
70
71
>>Me:
72
Great, can you modify the main() function to have it an infinite loop, which reads in a generic 8 bit port, dispatch each bit of the read byte to one element in "Digital_Input", then runs the functions PinHasRisingEdge and PinHasFallingEdge. For each of the functions exists a byte which holds in a bitstuffed fashion the results of the itterative function calls
73
74
75
>>ChatGPT:
76
Certainly! I've modified the main() function to read in a generic 8-bit port in an infinite loop, dispatch each bit to one element in the Digital_Input array, and then run the PinHasRisingEdge and PinHasFallingEdge functions. I've also added two result bytes to hold the results of the function calls in a bit-stuffed fashion:
77
78
79
#include <stdbool.h>
80
#include <stdint.h>
81
#include <stdio.h>
82
83
// Define the struct for digital inputs
84
typedef struct {
85
    bool state;
86
    bool lastState;
87
} Digital_Input;
88
89
// Function to check if a pin has a rising edge
90
bool PinHasRisingEdge(Digital_Input* pinArr, uint8_t pinSel) {
91
    // Check if the current state is HIGH and the last state was LOW
92
    if (pinArr[pinSel].state && !pinArr[pinSel].lastState) {
93
        return true;  // Rising edge detected
94
    } else {
95
        return false; // No rising edge
96
    }
97
}
98
99
// Function to check if a pin has a falling edge
100
bool PinHasFallingEdge(Digital_Input* pinArr, uint8_t pinSel) {
101
    // Check if the current state is LOW and the last state was HIGH
102
    if (!pinArr[pinSel].state && pinArr[pinSel].lastState) {
103
        return true;  // Falling edge detected
104
    } else {
105
        return false; // No falling edge
106
    }
107
}
108
109
int main() {
110
    Digital_Input inputArray[8]; // Assuming 8 digital inputs
111
112
    // Result bytes for rising and falling edges
113
    uint8_t risingEdgeResults = 0;
114
    uint8_t fallingEdgeResults = 0;
115
116
    while (1) {
117
        // Simulate reading from a generic 8-bit port
118
        uint8_t inputData = 0b11001100;
119
120
        // Dispatch each bit to one element in Digital_Input
121
        for (int i = 0; i < 8; ++i) {
122
            inputArray[i].lastState = inputArray[i].state;
123
            inputArray[i].state = (inputData >> i) & 0x01;
124
        }
125
126
        // Run PinHasRisingEdge and PinHasFallingEdge for each pin
127
        for (int i = 0; i < 8; ++i) {
128
            // Update result bytes with the results in a bit-stuffed fashion
129
            risingEdgeResults |= (PinHasRisingEdge(inputArray, i) ? 1 : 0) << i;
130
            fallingEdgeResults |= (PinHasFallingEdge(inputArray, i) ? 1 : 0) << i;
131
        }
132
133
        // Example: Print the results
134
        printf("Rising Edge Results: 0x%X\n", risingEdgeResults);
135
        printf("Falling Edge Results: 0x%X\n", fallingEdgeResults);
136
    }
137
138
    return 0;
139
}
140
This example continuously simulates reading from a generic 8-bit port, updates the state of the Digital_Input array, and runs the edge detection functions for each pin, updating the result bytes accordingly. The results are then printed in a bit-stuffed fashion.
141
142
>>Me:
143
Can you replace the line "uint8_t inputData = 0b11001100;" with "uint8_t inputData = PORTA;" ?
144
145
>>ChatGPT:
146
Certainly! If you want to read from a specific 8-bit port, you can replace the line "uint8_t inputData = 0b11001100;" with "uint8_t inputData = PORTA;". Note that "PORTA" should be replaced with the actual port you are using. Here's the modified code:
147
148
#include <stdbool.h>
149
#include <stdint.h>
150
#include <stdio.h>
151
152
// Define the struct for digital inputs
153
typedef struct {
154
    bool state;
155
    bool lastState;
156
} Digital_Input;
157
158
// Function to check if a pin has a rising edge
159
bool PinHasRisingEdge(Digital_Input* pinArr, uint8_t pinSel) {
160
    // Check if the current state is HIGH and the last state was LOW
161
    if (pinArr[pinSel].state && !pinArr[pinSel].lastState) {
162
        return true;  // Rising edge detected
163
    } else {
164
        return false; // No rising edge
165
    }
166
}
167
168
// Function to check if a pin has a falling edge
169
bool PinHasFallingEdge(Digital_Input* pinArr, uint8_t pinSel) {
170
    // Check if the current state is LOW and the last state was HIGH
171
    if (!pinArr[pinSel].state && pinArr[pinSel].lastState) {
172
        return true;  // Falling edge detected
173
    } else {
174
        return false; // No falling edge
175
    }
176
}
177
178
int main() {
179
    Digital_Input inputArray[8]; // Assuming 8 digital inputs
180
181
    // Result bytes for rising and falling edges
182
    uint8_t risingEdgeResults = 0;
183
    uint8_t fallingEdgeResults = 0;
184
185
    while (1) {
186
        // Read from the specific 8-bit port (replace PORTA with your actual port)
187
        uint8_t inputData = PORTA;
188
189
        // Dispatch each bit to one element in Digital_Input
190
        for (int i = 0; i < 8; ++i) {
191
            inputArray[i].lastState = inputArray[i].state;
192
            inputArray[i].state = (inputData >> i) & 0x01;
193
        }
194
195
        // Run PinHasRisingEdge and PinHasFallingEdge for each pin
196
        for (int i = 0; i < 8; ++i) {
197
            // Update result bytes with the results in a bit-stuffed fashion
198
            risingEdgeResults |= (PinHasRisingEdge(inputArray, i) ? 1 : 0) << i;
199
            fallingEdgeResults |= (PinHasFallingEdge(inputArray, i) ? 1 : 0) << i;
200
        }
201
202
        // Example: Print the results
203
        printf("Rising Edge Results: 0x%X\n", risingEdgeResults);
204
        printf("Falling Edge Results: 0x%X\n", fallingEdgeResults);
205
    }
206
207
    return 0;
208
}
209
Make sure to replace "PORTA" with the actual port you are using in your microcontroller environment.

von Jasson J. (jasson)


Lesenswert?

PPS:
@Flunder

Ich kenne natürlich deinen Hintergrund nicht - am besten gleich 
angewöhnen, Code auf Englisch zu schreiben.

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.