Problem mit Code

OP #1180282
Lesenswert?

Guten Morgen,

ich hab ein Problem mit meinem Code, der will nicht richtig 
funktionieren. Ich möchte mit jeweils einen Taster, einen Port toggeln. 
Ich verwende einen Atmega16 mit externen 16 Mhz, dies hab ich im 
Makefile festgelegt.
1
#include <avr/io.h>
2
#include <util/delay.h>
3

4
#define Taster_1 (PIND&(1<<PD2))
5
#define Taster_2 (PIND&(1<<PD3))
6
#define Taster_3 (PIND&(1<<PD4))
7

8
volatile uint8_t var_1 = false;
9

10
uint8_t key_pressed(const volatile uint8_t input)
11
{
12
  static uint8_t last_state = 0;
13
  if ( last_state == input ) return 0; 
14
  _delay_ms(20);
15
  last_state = input;
16
  return input;
17
}
18

19

20
int main(void)
21
{
22
    
23
  DDRA = 0b11111111;
24
  DDRB = 0b11111111;
25
  DDRC = 0b11111111;
26
  DDRD = 0b11100011;
27

28
  while(1)
29
  {     
30

31
    if (key_pressed(Taster_1)) PORTC ^= 0xff;
32
    
33
    if (key_pressed(Taster_3)) PORTA ^= 0xff;
34
    
35
    }
36
    return 0;
37
}

Kann mir jemand helfen?
Gast #1180303
Lesenswert?

Ich bin jetzt noch nicht der Profi in C beim Atmel aber ich würde sagen 
das volatile braucht man bei diesem code nicht, es werden ja keien ISR 
genutzt.

Das sollte aber nicht die Lösung für das Problem sein.
Gast #1180307
Lesenswert?

>ich hab ein Problem mit meinem Code, der will nicht richtig
>funktionieren.

Wie genau äussert sich das?

Ansonsten:

Tasten müssen grundsätzlich entprellt werden. Das ist nicht so trivial, 
wie es zunächst aussieht. Eprobt und bewährt ist dafür die Methode von 
Peter Danneger, siehe Codesammlung.

Dann speichert dein key_pressed() last_State nicht für jede Taste 
einzeln, sondern nur den Wert des jeweils letzten Aufrufs. Wenn du die 
Funktion mehrfach hintereinander für verschiedene Tasten aufrufst, gibt 
es Durcheinander.

Auch hier: Nimm den Code aus der Codesammlung.

Oliver
#1180310
Lesenswert?

@Mathias:
Erstens solltest Du doch langsam wissen, dass man für eine Anfrage einen 
aussagekräftigen Betreff wählen soll, wie es in den Forenregeln steht. 
"Problem mit Code" ist kein aussagekräftiger Betreff!

Zweitens erwartet Deine Funktion einen "const volatile uint8_t", das, 
was Du da übergibst, ist aber alles andere als ein "const volatile 
uint8_t"...
Gast #1180313
Lesenswert?

> Dann speichert dein key_pressed() last_State nicht für jede Taste
> einzeln, sondern nur den Wert des jeweils letzten Aufrufs.
Das ist doch die Lösung das Problemes, Wenn Taste 1 gedrück und Taste 2 
nicht gedrückt dann ist der Laststate immer entgegengesetzt. Damit 
Blinken die Lampen ein 40ms Takt.
Gast #1180320
Lesenswert?

Du fragst abwechselnd Taster_1 und Taster_2 ab, aber speicherst den 
Zustand immer in der selben Variabel "last_state". Sobald Du eine Taste 
drückst ist (last_state == input) immer wieder false und die LED 
flakert...

Zum entprellen schlage ich volgende Änderung vor:
1
uint8_t key_pressed(const volatile uint8_t input)
2
{
3
  static uint8_t last_state = 0;
4
  uint8_t new_input;
5
  new_input = input;
6
  if ( last_state == new_input) return 0; 
7
  _delay_ms(20);
8
  // last_state = input; // input könnte geändert haben wegen prellung
9
  last_state = new_input;
10
  return new_input;
11
}
Gast #1180323
Lesenswert?

Du speicherst in last_state maximal die aktuell gedrückte Taste - alle 
anderen werden nicht gespeichert. Da du dann noch bei jedem Aufruf von 
key_pressed eine andere Maske übergibst toggeln die LEDs...

Deine key_pressed hat mit Entprellung nichts zu tun, aber das weißt du 
bestimmt!?
Gast #1180328
Lesenswert?

> Zum entprellen schlage ich volgende Änderung vor:
1
uint8_t key_pressed(const volatile uint8_t input)
2
{
3
  static uint8_t last_state = 0;
4
  uint8_t new_input;
5
  new_input = input;
6
  if ( last_state == new_input) return 0; 
7
  _delay_ms(20);
8
  // last_state = input; // input könnte geändert haben wegen prellung
9
  last_state = new_input;
10
  return new_input;
11
}

Korrigiere mich falls ich mich irre - aber entprellt wird auch auf diese 
Weise nichts. Bei beiden Versionen wird 20ms gewartet bis der aktuelle 
Wert in last_state geschrieben wird, mehr nicht. Ohne das _delay_ms(20); 
spart man sich 20ms und an der Funktion ändert sich nichts.
Gast #1180334
Lesenswert?

> Korrigiere mich falls ich mich irre - aber entprellt wird auch auf diese
> Weise nichts. Bei beiden Versionen wird 20ms gewartet bis der aktuelle
> Wert in last_state geschrieben wird, mehr nicht.
Doch schon, denn nach 20ms ist das prellen vorbei, damit wird also die 
Zeit in der die Kontakte nicht sauber geschlossen sind einfach 
übersprungen.
#1180335
Lesenswert?

Micha wrote:

> Korrigiere mich falls ich mich irre - aber entprellt wird auch auf diese
> Weise nichts.

Du irrst nicht.
Die Funktion ist immer noch haarscharf dieselbe wie vor der 
Modifikation. Nur eine Variable mehr ist unvolviert in die ein sowieso 
innerhalb der Funktion feststehender Wert einmal umkopiert wird.

> Ohne das _delay_ms(20); spart man sich 20ms

Das stimmt nicht ganz. Ohne das delay_ms ist die Funktion zu schnell, so 
dass der Aufrufer die Tasten schneller abfragt. Kurz gesagt: 
Funktionalität ist über das ganze Programm verstreut und wenn man an 
einer Ecke etwas ändert, hat das Auswirkungen auf die andere Ecke. 
Schlechter Programmierstil.
Gast #1180338
Lesenswert?

> Zum entprellen schlage ich volgende Änderung vor:
1
uint8_t key_pressed(const volatile uint8_t input)
2
{
3
  static uint8_t last_state = 0;
4
  uint8_t new_input;
5
  new_input = input;
6
  if ( last_state == new_input) return 0; 
7
  _delay_ms(20);
8
  // last_state = input; // input könnte geändert haben wegen prellung
9
  last_state = new_input;
10
  return new_input;
11
}

Abgesehen von alledem macht diese Funktion dasselbe wie die 
ursprüngliche, nur dass eine weitere Variable ver(sch)wendet wird...

@ Mathias Obetzhauser
Benutze Peter Danneggers Version. Die funktioniert und verschwendet 
keine Zeit mit warten. Und man muss auch das Rad nicht immer wieder neu 
erfinden...
#1180346
Lesenswert?

Mathias Obetzhauser wrote:
> Aber ich finde man sollte Interrupts nicht für sowas benutzen wie bei
> Peter.
> Das müsste doch eigentlich viel kürzer gehen. In anderen
> Programmiersprachen macht man einfach nur eine Einschaltverzögung von
> 20ms.

Wie schon angesprochen:
Hol dir aus der Codesammlung die PeDa Tastenentprellung. Die ist 100% 
fullproof und funktioniert klaglos.

Tastenentprellung ist nicht so simpel, wie es auf den ersten Blick 
aussieht.
Gast #1180365
Lesenswert?

> Aber ich finde man sollte Interrupts nicht für sowas benutzen wie bei
> Peter.
> Das müsste doch eigentlich viel kürzer gehen. In anderen
> Programmiersprachen macht man einfach nur eine Einschaltverzögung von
> 20ms.

Von der Laufzeit her ist Peters Version garantiert kürzer. Daher vermute 
ich du meinst mit "kürzer" weniger Code, richtig?

Falls ja kannst du wählen zwischen
- regelmäßig 20ms sinnlos mit warten verschwenden und etwas Code sparen 
oder
- etwas mehr Code schreiben und dafür mehr Rechenzeit übrig haben.

Auf die obige Weise geht es auf jeden Fall nicht! Und bis das 100% 
sicher läuft hast du (sehr) wahrscheinlich genausoviel Code wie bei 
Peters Version.

Und mit der verwendeten Programmiersprache hat das alles überhaupt 
nichts zu tun!
OP #1180371
Lesenswert?

Dann muss ich die woll nehmen von Peter. Ich möchte gerne die ganze 
Entprellroutine in eine Datei packen und dann wenn ich Tasten habe 
einfach includen. Und halt dann nur nen Aufruf.
1
#include <avr/io.h>
2
#include <util/debouce.h>
3

4
#define Taster_1 (PIND&(1<<PD2))
5

6
int main(void)
7
{
8
    
9
  DDRA = 0b11111111;
10
  DDRD = 0b11100011;
11

12
  while(1)
13
  {     
14
  if (debounce(Taster_1)) PORTA ^= 0xff;
15
  }
16
  return 0;
17
}

Kann mir jemand dann mal zeigen wie die debounce.h aussehen muss?

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren