Forum: Mikrocontroller und Digitale Elektronik Eingangsabfrage und Kontaktentprellung funktioniert nicht richtig in AVR Studio 4


von Christian W. (christian_w)


Lesenswert?

Hallo zusammen,

den ganzen Tag experimentiere ich nun schon mit AVR Studio um einen 
vernünftigen C-Code hinzubekommen, der mir ein Eingangssignal auswertet 
und den Eingangspin entprellt.

Ich möchte:

- bei vorhandenem Eingangssignal eine Schleife laufen lassen, die eine 
bestimmte Zeit verstreichen lässt, aber das nur solange, wie auch das 
Eingangssignal vorhanden ist

- ist das Eingangssignal zu kurz, soll auch die Schleife wieder 
abgebrochen werden und der Controller soll nichts unternehmen

Ich war schon soweit, dass es funktioniert hat aber der Ausstieg aus der 
Schleife erfolgte willkürlich, das heißt, mal wurde die Schleife 1x 
durchlaufen, aber manchmal auch 2x bevor der Controller ausstieg! Ich 
habe keine Ahnung warum...

Konkret geht es darum, das ich ein Signal haben möchte, wenn ein 
Eingangstaster länger als, sagen wir 1 Sekunde, gedrückt bleibt.

die "billige" Version mit _delay_ms hatte ich auch schon getestet, aber 
wenn ich den taster kurz antippe, und 1 sekunde später nochmal kurz, 
dann hab ich trotzdem ein "falsch" erkanntes eingangssingal von 1 
sekunde dauer. das ist natürlich nicht beabsichtigt.

ich suche einen c-quellcode der nur auf 1 sekunde "dauerhaften" 
tastendruck reagiert und dann demenstprechend return 1 oder return 0 
zurückgibt.

jemand ne idee?

ich habe schon alle optimierungsstufen von o0 bis 0s durch, eingestellte 
parameter stimmen auch alle...

hier wäre mein codebeispiel für die funktion, aber es geht nicht.
compilerfehlermeldungen = 0, aber eingangssignal wird nicht erkannt. 
eine led die leuchten sollte, tut es nicht ;) ausser nur, wenn man sie 
manuell ansteuert mit PORTD |= (1<<PD4).

das allerkomischste ist es, dass es mal exakt 1 sekunde dauert, bis auf 
tastendruck reagiert wird, und dann mal exakt 2 sekunden! nur warum? :(

christian

1
// Funktion: Taster entprellen und abfragen
2
int status_standardtaster(void)
3
{
4
5
  warten = 0;
6
7
  do
8
  {
9
    
10
    if ( (PIND & (1<<PIND5)) ) // Eingangssignal vorhanden?
11
    {
12
      warten = warten + 1;
13
14
      if (warten > 10000) { return 1; } // Eingangssignaldauer lange genug
15
    }
16
  
17
    if ( !(PIND & (1<<PIND5)) )  { return 0;  } // Eingangssignal nicht da
18
19
  }while( (PIND & (1<<PIND5)) ); // Solange Eingangssignal vorhanden
20
21
  return 0;
22
}

von Peter D. (peda)


Lesenswert?

Beitrag "Universelle Tastenabfrage"

Und dann einfach get_key_long() aufrufen.


Peter

von Christian W. (christian_w)


Lesenswert?

danke für die antwort. habs mir grad angesehen. aber ich möchte gerne 
meinen quellcode auch verstehen, den ich da reinschreibe... ist momentan 
leider nicht der fall grins...

noch jemand ne idee?

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Leider zeigst du kein komplettes Beispiel.

Ein mögliches Problem könnte durch Wegoptimieren der nutzlosen Variable 
warten entstehen. warten tut man mit einem Timer oder mit einer 
Wartefunktion.

Wartefunktionen gibt es in der avr-libc unter den Namen _delay_ms() und 
_delay_us() (plus eine Funktion mit Angabe von Schleifen). Wenn dein 
Code damit nicht funktioniert, bringt es IMHO nichts, die 
Libraryfunktionen durch ein Eigenkonstrukt zu ersetzen. Das Problem ist 
dann verlagert.

Ein weiteres Problem könnte durch die Hardwareschaltung entstehen. Dein 
Code verlangt einen sog. active high Taster. In dem Codefetzen ohne 
Schaltplan ist nicht erkennbar, wie LOW und HIGH Zustand garantiert 
werden, also wo sich die Pullup- oder Pulldown-Widerstande befinden.

1
#include <util/delay.h>
2
int status_standardtaster(void)
3
{
4
  uint16_t warten = 40; // 40*25 = 1000ms = 1s
5
6
  DDRD &= ~((1<<PIND5)); // Eingang
7
  // Pulldown an PIND5 benötigt!
8
 
9
  while( (PIND & (1<<PIND5)) && (warten != 0) )
10
  {
11
    _delay_ms(25);
12
    warten--;
13
  }
14
15
  return (warten == 0) ? 1 ; 0;
16
}

Durch die Abfrage nur alle 25ms sollte ein i.d.R. kürzes Tastenprellen 
unberücksichtigt bleiben.

von Christian W. (christian_w)


Lesenswert?

hallo, danke.

an PIND5 ist ein 10 k Pulldown Widerstand.

hab noch einen compilerfehler bei dieser zeile:

return (warten == 0) ? 1 ; 0;
../entprelltester2.c:26: error: expected ':' before ';' token

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Das erste ; soll ein : sein, wie der Compiler richtig anmerkt. 
Tippfehler von mir, sorry.

Du kannst das auch ausschreiben, wenn dir der Bedingungsoperator, 
ternärer Operator, ? : für die bedingte Wertzuweisung nicht gefällt.

Genaugenommen muss man für exakte 1000ms gedrückten Taster auch noch den 
Pin abfragen. Im Code oben könnte man den Taster 25ms vor Schluss 
loslassen, das while verlassen weil warten == 0 wird und trotzdem ein 1 
zurückgeben!

1
  // Taster immer noch gedrückt UND 1000ms abgelaufen?
2
  if ( (PIND & (1<<PIND5)) && (warten == 0) )
3
    return 1;
4
  else
5
    return 0;

von Christian W. (christian_w)


Lesenswert?

hallo, danke!

klappt jetzt ohne probleme, tastersignal wird nach exakt 1 sekunde 
weitergegeben... nur wo lag bei mir das problem? vielleicht weil ich 
vorwärts, statt rückwärts gezählt habe und die delay-funktion vergessen 
habe...? :-)

kann man die prozessorzeit eigentlich vernachlässigen, die durch das 
runterzählen der variable "warten" versemmelt wird? sollte meine 
rechnung richtig sein, vergehen da 2 takte pro durchlauf, also 80 takte, 
wären dann bei 1 mhz so etwa 80 mikrosekunden?

danke

christian

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Deine Routine entprellt nicht ausreichend. Bei jedem 
Schleifendurchlauf besteht die Chance, dass ein Prellen des Tasters zu 
einem Return 0 führt.

Wenn du in meinem Code nicht 40 x 25ms sondern 1000 x 1ms Delays 
verwendest (oder gar in den µs Bereich wechselst), funktioniert die auch 
nicht gut. Die 25ms Pause zwischen den Abfragen überspringt das typische 
Prellen. Steht aber auch so erklärt in dem Artikel Entprellung bei 
dem Warteschleifenverfahren. 25ms aus Erfahrung im Artikel und weil das 
40 Schleifen als ganzzahligen Teiler von 1000ms ergibt.

Klar hat man eine Ungenauigkeit durch den Overhead der Schleifen 
(herunterzählen, Vergleichen, Springen). Wenn eine exakte Routine 
benötigt wird, müsste man das berücksichtigen. Die exakte Zeit kann man 
z.B. mit der Stoppuhr im AVR Studio Simulator herausfinden. Bei soviel 
Aufwand dann auch eine genauere Taktquelle verwenden.

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.