Forum: Mikrocontroller und Digitale Elektronik Tastenenprellung Deluxe P. Dannegger


von W. M. (muhh)


Lesenswert?

Hey Leute,

ich hatte schonmal einen ähnlichen Thread erstellt, in dem es um die 
genaue Funktionsweise der Tastenentprellung (Komfortroutine in C) von 
Peter Dannegger ging.

Jetzt habe ich aber ein Atmel ATXmega xplained A1 Board mit einem xmega 
128A1 der bei 32 MHz läuft.

Ich wollte fragen, wie die folgende Zeile genau funkioniert, um zu 
verstehen, wie ich meinen Counterstand nach der Taktfrequenz des MC 
berechnen muss, um eine von mir gewünschte "Abtastrate" zu bekommen.
1
TCNT0 = (uint8_t)(int16_t)-(F_CPU / 1024 * 10e-3 + 0.5);  // preload for 10ms

Ich dachte ich kann mir den Counterwert x mit der folgenden Formel 
berechnen:
(Preload = 1ms, Takt = 32MHz, Timer-Prescaler = 1024)

Kann das so überhaupt stimmten? Wäre super wenn ihr da ein paar 
Ratschläge für mich hättet ;)

Viele Grüße

von Uwe (de0508)


Lesenswert?

Hallo,

im Datenblatt steht doch immer eine schöne Formel.

Wenn man dann einen CTC Mode wählt folgt mit aufrunden.

Zaehler = (uint16_t)(1.0* F_CPU/ PRESCALER/ 1000 -1 + 0.5)

Wobei 1000Hz 1ms entspricht.

Also ganz einfach und natürlich.

: Bearbeitet durch User
von Timmo H. (masterfx)


Lesenswert?

Beim Xmega ganz einfach, da kannst du den Timer so einstellen dass er 
nur bis zu einem von dir eingestelltem Wert zählt und dann einen 
Overflow auslöst.
1
  TCE0.CTRLA = TC_CLKSEL_DIV256_gc;         // Prescaler
2
  TCE0.PER = (int16_t)F_CPU/256L*10e-3+0.5;  //10 ms 
3
  TCE0.INTCTRLA = TC_OVFINTLVL_LO_gc;  // Low Level Overflow Interrupt

von W. M. (muhh)


Lesenswert?

Danke für eure Hilfe.

@Uwe S.:

Hmmm... ich scheine nicht sorgfältig genug gelesen zuhaben, muss mir 
entgangen sein :)

@Timmo H.:

Danke für deine Mühe, den Code hatte ich schon ;)
Ich wollte in der ISR zunächst eine LED toggeln, an der ich dann die 
Frequenz messen kann, die ich mit dem Zählwert eingestellt habe. Wusste 
aber nicht wie man auf die Formel kommt, weiß ich jetzt immer noch 
nicht, aber ich weiß wenigstens, dass sie im Manual bzw. Datenblatt 
gegeben ist, also kommt man da vermutlich nicht so schnell alleine 
drauf?

von Timmo H. (masterfx)


Lesenswert?

War noch ein kleiner Fehler drin:
1
TCE0.PER = (int16_t)(F_CPU/256L*10e-3+0.5);
Warum. Ganz einfach. Der Timer Tickt mit dem Peripheral-Takt (meist 
F_CPU). Diesen kann mit mit einem Presclaler runterteilen (hier 256). 
Dann Tickt der Timer mit 32MHz/256 = 125 kHz. Damit dauert ein Takt 8ns. 
Damit du auf 10ms kommst musst du also 10ms/8ns Takte bzw. 10e-3s/8e-9s 
warten. Also 1250 Takte. Steht eigentlich alles im Timer-Kapitel im 
Datenblatt beschrieben.

von Karl H. (kbuchegg)


Lesenswert?

Willy M. schrieb:

> Frequenz messen kann, die ich mit dem Zählwert eingestellt habe. Wusste
> aber nicht wie man auf die Formel kommt, weiß ich jetzt immer noch
> nicht,

FAQ: Timer

ist ganz einfach und logisch

Wie ist die Taktfrequenz und wie ist der Prescaler eingestellt?
Aus den beiden Angaben folgt, wie weit der Timer in 1 Sekunde zählen 
könnte, wenn ich ihn lasse und er ohne Rücksicht auf Bitanzahl zählen 
könnte.

Und dann dreht man das einfach um: Bis zu welcher Zahl kann(muss) er 
zählen, wenn ich haben will, dass er das in x Zeiteinheiten schafft (x 
ist vorgegeben).
Kommt da dann eine Zahl raus, die zu gross für die Bitbreite des Zählers 
ist, dann muss man eben den Prescaler größer machen, damit der Timer 
langsamer zählt.


Letzten Endes ist das nur eine Variation von:
Ein Arbeiter kann in 1 Stunde 45 Werkstücke fertig machen. Wieviele 
Werkstücke muss er fertig machen, wenn er damit in 35 Minuten fertig 
sein soll? Wieviele Werkstücke muss er fertig machen, wenn er damit in x 
(x gegeben) Minuten fertig sein soll?

Gewöhn dich an den 3-Satz. Mehr als die Hälfte aller Berechnungen mit 
denen du es zu tun hast, sind im Kern nichts anderes als dieser berühmt 
berüchtigte 3-Satz.

: Bearbeitet durch User
von W. M. (muhh)


Lesenswert?

Oh man.... Ich hab einfach nur einen Denkfehler gehabt -.-

Ich habe gerechnet

1ms/( (1/32Mhz)/1024 ) und nicht

1ms/( 1/(32Mhz/1024) )

Ick raste aus !!!!!!!!!! :D
Soviel dazu -.-

Ich habe jetzt allerdings noch eine Frage. In dem damaligen Thread wo es 
um die Funktion der ganzen Routine ging hatte ich den Tipp bekommen, 
dass ich für einen Drehgeber lieber 1ms anstatt 10ms Abtastrate nehmen 
sollte. Das habe ich jetzt hiermit gemacht, die Frequenz beträgt 1,12 
kHz, was in etwa 900us Abtastrate entspricht.
Dennoch kommt es relativ häufig vor, dass wenn ich den Taster drücke die 
LED nicht weiter getoogelt wird.

Hier vielleicht nochmal der simple Code der while-Schleife:
1
while(1)
2
{
3
  if(get_key_press(PIN3_bm))
4
  {
5
    PORTE.OUTTGL = 0x77;
6
  }
7
}

Wie kann den dieses Fehlverhalten Zustandekommen?

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

Willy M. schrieb:

> um die Funktion der ganzen Routine ging hatte ich den Tipp bekommen,
> dass ich für einen Drehgeber lieber 1ms anstatt 10ms Abtastrate nehmen
> sollte.

Für die Auswertung des Drehgebers. Also den Knopf, den du links/rechts 
drehst.
Wenn das ein Drehgeber mit eingebautem Taster ist, bleibst du für die 
Auswertung des Tasters selber bei den ungefähr 10ms
(Tasterauswertung nur bei jedem 10-ten ISR Aufruf machen, wenn du die 
ISR auf ca 1ms eingestellt hast)

: Bearbeitet durch User
von Hannes L. (hannes)


Lesenswert?

Karl Heinz Buchegger schrieb:
> nur bei jedem 10-ten ISR Aufruf

Oder bei jedem 16-ten, dann braucht es weniger Ressourcen... ;-)

Duck&weg...

...

von W. M. (muhh)


Lesenswert?

Okay, danke für den Hinweis, mein Drehencoder hat auch einen 
integrierten Taster.

Aber vielleicht nochmal zum eigentlichen Problem. Die Abtastung scheint 
nicht so gut zu funktionieren.

Manchmal reagiert der Mikrocontroller nicht, wenn ich den Taster drücke 
dann bleibt die LED im ein- oder auch ausgeschalteten Zustand.
Ich kann mir nicht erklären wie das passiert....
Innerhalb von 900us den Taster zu drücken und wieder loszulassen ist ja 
Schwachsinn, dass schafft niemand so schnell, also müsste auch die 
Zustandsänderung bemerkt werden... Tut sie aber halt manchmal nicht

Habt ihr eine Idee wie diese Aussetzer zustande kommen und wie ich sie 
beheben kann?
Ich kann mich nicht daran erinnern, dass das auf dem MSP430G2553 kein 
Problem war, der hat das gemacht ohne zu mucken...

von Karl H. (kbuchegg)


Lesenswert?

Willy M. schrieb:

> Innerhalb von 900us den Taster zu drücken und wieder loszulassen ist ja
> Schwachsinn, dass schafft niemand so schnell, also müsste auch die
> Zustandsänderung bemerkt werden... Tut sie aber halt manchmal nicht

Oder sie wird doppelt registriert.

Der PeDa Code macht eine 4-fach Abtastung. 4*900 us macht ca. 3.6ms. 
Wenn der Taster langsamer als 3.6ms prellt, dann wertet der Code das 
dann daher als 2 Tastendrücke.
Effekt: Die LED wird zwar eingeschaltet, aber gleich darauf wieder aus. 
Wenn das schnell genug geht, merkst du das nicht wenn du nicht gaaaaaanz 
genau in die LED schaust um das kurze Aufblitzen zu sehen.

> Habt ihr eine Idee wie diese Aussetzer zustande kommen und wie ich sie
> beheben kann?

Soll ich dir den enstprechenden Zähler und die if Abfrage in deine ISR 
einbauen? Oder machst du das jetzt ganz einfach alleine und wir 
überlegen weiter, wenn das das Problem nicht löst.

: Bearbeitet durch User
von W. M. (muhh)


Lesenswert?

Hier "mein Code":
Vielleicht findet ihr ja einen Fehler
1
#include <stdint.h>
2
#include <avr/io.h>
3
#include <avr/interrupt.h>
4
5
#ifndef F_CPU
6
#define F_CPU           32000000                   // processor clock frequency
7
#warning kein F_CPU definiert
8
#endif
9
10
#define KEY_PIN      PORTD.IN
11
12
#define REPEAT_MASK     0xff                         // repeat: Pin 1.0
13
#define REPEAT_START1   50                         // after 500ms
14
#define REPEAT_NEXT1    20                          // every 200ms
15
#define REPEAT_NEXT2    5                          // every 200ms
16
17
#define TRUE      1
18
#define FALSE      0
19
20
/**************************************************/
21
22
volatile uint8_t key_state;                              // debounced and inverted key state: bit = 1: key pressed
23
volatile uint8_t key_press;                              // key press detect
24
volatile uint8_t key_rpt;                               // key long press and repeat
25
volatile uint8_t rpt_count;
26
27
/**************************************************/
28
29
ISR (TCC0_OVF_vect)                            // every 11ms
30
{
31
  static uint8_t ct0, ct1, rpt;
32
  uint8_t i;
33
  
34
  TCC0.PER = (uint8_t)(int16_t)-(F_CPU / 1024 * 1e-3 -1 + 0.5);  // preload for 1ms
35
  
36
  i = key_state ^ ~KEY_PIN;                       // key changed ?
37
  ct0 = ~( ct0 & i );                             // reset or count ct0
38
  ct1 = ct0 ^ (ct1 & i);                          // reset or count ct1
39
  i &= ct0 & ct1;                                 // count until roll over ?
40
  key_state ^= i;                                 // then toggle debounced state
41
  key_press |= key_state & i;                     // 0->1: key press detect
42
  
43
  if( (key_state & REPEAT_MASK) == 0 )            // check repeat function
44
  rpt = REPEAT_START1;                          // start delay
45
  if( --rpt == 0 ){
46
    rpt = REPEAT_NEXT1;                            // repeat delay
47
    key_rpt |= key_state & REPEAT_MASK;
48
  }
49
  
50
  PORTE.OUT ^= 0x01;
51
}
52
53
///////////////////////////////////////////////////////////////////
54
//
55
// check if a key has been pressed. Each pressed key is reported
56
// only once
57
//
58
uint8_t get_key_press( uint8_t key_mask )
59
{
60
  key_mask &= key_press;                          // read key(s)
61
  key_press ^= key_mask;                          // clear key(s)
62
  return key_mask;
63
}
64
65
///////////////////////////////////////////////////////////////////
66
//
67
// check if a key has been pressed long enough such that the
68
// key repeat functionality kicks in. After a small setup delay
69
// the key is reported being pressed in subsequent calls
70
// to this function. This simulates the user repeatedly
71
// pressing and releasing the key.
72
//
73
uint8_t get_key_rpt( uint8_t key_mask )
74
{
75
  key_mask &= key_rpt;                            // read key(s)
76
  key_rpt ^= key_mask;                            // clear key(s)
77
  return key_mask;
78
}
79
80
///////////////////////////////////////////////////////////////////
81
//
82
// check if a key is pressed right now
83
//
84
uint8_t get_key_state( uint8_t key_mask )
85
86
{
87
  key_mask &= key_state;
88
  return key_mask;
89
}
90
91
///////////////////////////////////////////////////////////////////
92
//
93
uint8_t get_key_short( uint8_t key_mask )
94
{
95
  return get_key_press( ~key_state & key_mask );
96
}
97
98
///////////////////////////////////////////////////////////////////
99
//
100
uint8_t get_key_long( uint8_t key_mask )
101
{
102
  return get_key_press( get_key_rpt( key_mask ));
103
}
104
105
int main( void )
106
{
107
   // internen Oszillator auf 32MHZ einstellen
108
   OSC.CTRL = 3;
109
   while(OSC.STATUS != 3)
110
   {
111
   }
112
   CCP = 0xD8;
113
   CLK.CTRL = 1;
114
115
  // Interrupts aktivieren und alle Level freigeben
116
  sei();
117
  PMIC.CTRL=0x07;
118
  
119
  TCC0.PER = 0x000f;
120
121
  TCC0.CTRLB = TC_WGMODE_NORMAL_gc;
122
  TCC0.INTCTRLA = TC_OVFINTLVL_HI_gc;
123
  TCC0.CTRLA = TC_CLKSEL_DIV1024_gc;
124
125
  
126
  PORTE.DIR = 0xff;            // kompletter Prot als Ausgang (LED-Port)
127
  PORTE.OUT = 0xff;            // LEDs ausschalten
128
  
129
  PORTD.DIR = 0x00;            // kompletter Port als Eingang (Taster)
130
  PORTD.PIN0CTRL = PORT_OPC_PULLUP_gc;
131
  PORTD.PIN1CTRL = PORT_OPC_PULLUP_gc;
132
  PORTD.PIN2CTRL = PORT_OPC_PULLUP_gc;
133
  PORTD.PIN3CTRL = PORT_OPC_PULLUP_gc;  // Pin3 mit Pull-Up beschalten
134
  PORTD.PIN4CTRL = PORT_OPC_PULLUP_gc;
135
  PORTD.PIN5CTRL = PORT_OPC_PULLUP_gc;
136
  PORTD.PIN6CTRL = PORT_OPC_PULLUP_gc;
137
  PORTD.PIN7CTRL = PORT_OPC_PULLUP_gc;
138
139
  while(1)
140
  {
141
    if(get_key_press(PIN3_bm))
142
    {
143
      PORTE.OUTTGL = 0x77;
144
    }
145
  }
146
}

von Karl H. (kbuchegg)


Lesenswert?

Da fehlt ja der ganze Drehencoder-Teil!

Kannst du mir mal erklären, warum du dann hier

>   TCC0.PER = (uint8_t)(int16_t)-(F_CPU / 1024 * 1e-3 -1 + 0.5);  // preload for 
1ms

auf 1 ms gehst?



Wie oft soll ich dir das jetzt eigentlich noch erklären?


Um den Drehencoder auszuwerten, das ist das Teil an dem du mit dem 
Patschehändchen drehst (!), benutzt du 1ms.
Wenn du mit dem Patschehändchen draufdrückst, also den Taster im 
Drehencoder betätigst, benutzt du so wie im Original die 10ms. Der 
Draufdrück-Knopf ist doch auch nichts anderes als ein Taster! Taster ist 
Taster. Ob der jetzt eigenständig ist oder in einen Drehencoder als 
zusätzliches Bedienelement eingebaut ist, ist doch Jacke wie Hose! Der 
Taster prellt doch nicht weniger, nur weil er in einen Encoder eingebaut 
ist.

So ein Encoder hat 3(!) Ausgänge

Spur A  -  Abtastung mit dem 1ms Timer
Spur B  -  Abtastung mit dem 1ms Timer
Taster  -    <---- Abtatsung wie jeden anderen Taster auch mit ca. 10ms

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

Und bevor das jetzt noch ein paar mal hin und her geht
1
ISR (TCC0_OVF_vect)
2
{
3
  static uint8_t keyPoll = 0;   // <------------
4
5
  static uint8_t ct0, ct1, rpt;
6
  uint8_t i;
7
  
8
  TCC0.PER = (uint8_t)(int16_t)-(F_CPU / 1024 * 1e-3 -1 + 0.5);  // preload for 1ms
9
10
11
  ... Auswertung des Drehteils des Drehgebers
12
13
  if( keyPoll++ >= 16 )
14
  {
15
    keyPoll = 0;
16
17
    ... Auswertung des Tasters am Drehgeber
18
  }
19
}


und wenn DAS nichts bringt, DANN müssen man weiter überlegen.

: Bearbeitet durch User
von W. M. (muhh)


Lesenswert?

Okay stoppppppp!!!!

Bevor hier Emotionen hochkochen muss ich nochmal was aufklären... ;)

Der jetzige Code bezieht sich nicht auf den Drehencoder :S
Sondern nur auf einen Taster, der auf dem xplained Board montiert ist.

Wenn ich den drücke, passiert das oben beschriebene Problem!
Den Drehgeber hatte ich noch gar nicht angeschlossen, den Code bekomm 
ich dafür aber auch alleine hin, wenn nicht melde ich mich desewegen 
auch nochmal, dann wird das vermutlich aber nur an Kleinigkeiten liegen 
:)

Entschuldigt, wenn ich mich vorher nicht klar ausgedrückt habe...

Also suche ich jetzt erstmal nach der Lösung für das Problem, dass nicht 
alle Tasterdrücke erkannt werden.

von Quak (Gast)


Lesenswert?

Willy M. schrieb:
> Also suche ich jetzt erstmal nach der Lösung für das Problem, dass nicht
> alle Tasterdrücke erkannt werden.

Dann setze doch mal um, was dir Karl-Heinz jetzt schon 5 Mal erklaert 
hat.

von Karl H. (kbuchegg)


Lesenswert?

Willy, kann es sein, dass dir nicht klar ist, dass es eine UNTERGRENZE 
gibt, unter die du mit dem Entprellcode nicht gehen darfst?


Denn das Prellen eines Tasters ist nicht beliebig schnell! Das bewegt 
sich so um die 5 bis 20ms rum. Kann auch ein bischen weniger oder ein 
bischen mehr sein.

D.h. wenn der Code zu schnell immer wieder auf den Taster schaut, dann 
kriegt der das Prellen nicht mit! Der Code sieht dann 2 Tastendrücke, 
anstatt nur 1 verprellten.

Entprellen bedeutet nichts anderes, als einen Zeitraum festlegen, indem 
mehrfache detektierte Tastendrücke nicht als mehrfach gewertet werden, 
weil sie physikalisch als gewollter Tastendruck nicht möglich sind. Wenn 
du diese Grenze zu niedrig ansetzt, dann passiert genau das, das das 
Programm ein einmaliges Drücken mit Prellen mit mehreren schnell 
hintereinander abgegebenen Tastendrücken verwechselt. Der einzige 
Unterschied: selbst bei Training wird es dir als Mensch kaum gelingen, 
einen Taster in weniger als 100ms 2-mal hintereinander zu drücken. D.h. 
wenn du die Entprellzeit auf 3ms festlegst, dann bist du von dieser 
Grenze unnötig weit entfernt. Und was noch viel schlimmer ist, du kommst 
dann in den Zeitbereich in dem ein prellender Taster tatsächlich 2 mal 
anschlägt.

Fazit. Mit deinen 1ms tust du dir KEINEN Gefallen. Das bringt ganz 
einfach nichts. Denn die Tastenbetätigung wird deswegen auch nicht 
besser. Sie wird höchstens schlechter, wie du ja am eigenen Leib 
erfahren hast.

Also: Rauf mit der Entprellzeit für den Taster!
Ob das jetzt alle 10ms statt findet, oder alle 20ms, oder alls 30ms, 
oder meinetwegen auch noch alle 5ms, spielt nicht die große Rolle.
Aber weniger darf es nicht werden! Sonst entprellt der Code nicht mehr 
richtig.
Länger darf es theoretisch werden, aber auch da gibt es eine sinnvolle 
Obergrenze, weil man ja als Benutzer nicht ewig warten will, bis das 
Programm dann endlich irgendwann mal den Tastendruck akzeptiert. Aber: 
Diese Grenze ist weit jenseits von 10 oder 20ms. 10ms ist eine 
Hunderstelsekunde. 100ms ist eine Zehntelsekunde. Wenn du eine Taste 
drückst und das Programm reagiert 1 Zehntelsekunde später, dann fällt 
dir das kaum auf. Noch länger und der Effekt wird merkbar.

d.h. sinnvolle Entprellzeiten liegen irgendwo in diesem Bereich zwischen 
20ms und sagen wir mal 80ms. Wo genau, ist nicht so wichtig. Aber in der 
Größenordnung muss es stimmen. Dein Code hat eine 4-fach Abtastung, also 
wird das Polling dann in den Bereich 20/4 ca. 5ms bis 80/4 ca. 20ms 
gelegt. Und wenn es mehr als 20ms sind, dann ist das auch noch kein 
Beinbruch.

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

> dass nicht alle Tasterdrücke erkannt werden.

Kann natürlich auch sein, dass dein Taster ein Kontaktproblem hat.
Aber davon geh ich erst mal nicht aus, sondern davon, dass es eben nicht 
so ist, dass ein Tastendruck nicht ewrkannt wird, sondern dass ein 
falscher Tastendruck (wegen Prellen) zusätzlich erkannt wird. Der sorgt 
dann dafür, dass die gerade eben eingeschaltete LED wieder ausgeschaltet 
wird. Und da sich das im Millisekundenbereich abspielt, kriegst du das 
optisch nicht mit.

von W. M. (muhh)


Lesenswert?

Nein, dass war mir nicht so ganz bewusst, ich dachte wirklich, dass je 
kleiner ich die Zeit mache, desto genauer wird das ganze...

Okay, Entprellzeit liegt bei 10,76ms... Passiert aber immer noch, wenn 
ich die Zeit ein WENIG niedriger mache (7-8ms), hilft es auch nicht, bei 
16ms auch keine Besserung...

Eigentlich will ich nur, dass der Entprellcode 100% funktioniert, bevor 
ich dann den Code für den Drehgeber erweitere, weil wenn beim langsamen 
Drücken schon Fehler auftreten, dann doch erst Recht beim Entprellen vom 
Drehcoder oder ist das schon wieder ein Irrtum?

von Karl H. (kbuchegg)


Lesenswert?

TCC0 ist auf deinem Prozessor was für ein Timer? Welche Bitbreite hat 
der?

Denn
1
32000000 / 1024 = 31250
2
31250 * 10e-3  = 312

einen 8 Bit Timer kannst du aber nicht mit 312 vorladen!

Mal ein bischen rumrechnen. Was ist wenn du den Timer einfach 
durchlaufen lässt?
1
32000000 / 1024 / 256 = 122  Überläufe pro Sekunde
2
1/122 = 0.008 Sekunden, oder 8ms

d.h. wenn du nichts tust und den Timer einfach machen lässt, dann 
kriegst du ca alle 8ms einen Overflow. Das sollte reichen. Länger 
kriegst du bei einem 8 Bit Timer, einem Vorteiler von 1024 und 32Mhz 
nicht hin.

Leg doch mal diese ganze TCC0 Zuweisung still.

: Bearbeitet durch User
von W. M. (muhh)


Lesenswert?

Hmmm... Also bei dem XMega 128A1 hat man 8x 16bit Timer.

Welche TCC0 Zuweisung?

Meinst du, dass ich die Zuweisung aus der ISR einfach zur 
Initialisierung des Timers schreiben soll, sodass nicht bei jedem ISR 
Durchlauf das TCC0.PER beschieben wird?

von Timmo H. (masterfx)


Lesenswert?

Das period Register brauchst du nur beschreiben wenn du die zeit/ticks 
ändern willst. In deinem Fall willst du aber ja nichts ändern. Es soll 
doch immer alle 10ms ein overflow Interrupt ausgelöst werden. Du 
brauchst das PER-Register nur einmal mit dem Wert beschreiben der deinen 
10ms entspricht und dann kannst du es so lassen und musst nicht bei 
jedem Interrupt das Register neu beschreiben.

: Bearbeitet durch User
von W. M. (muhh)


Lesenswert?

Jo, hab ich geändert, verändert sich aber leider auch nichts, das Ding 
ist, dass ich jetzt alle auf dem Board befindlichen Taster durchprobiert 
habe und das bei jedem die Aussetzer aufgetreten sind... Ich habe sogar 
schon externe Taster angeschlossen, bei denen das gleiche passiert...

Das passiert sogar, wenn ich die Pins direkt mit einem Kabel verbinde, 
manchmal erkennt er das einfach nicht und nichts passiert...

Leider hab ich kein Oszilloskop hier, mit dem ich vielleicht sehen 
könnte, ob die LEDs vielleicht doch einmal kurz aufblitzen, allerdings 
kann ich mir das jetzt nicht mehr vorstellen, habe eine Entprellzeit von 
16ms eingestellt.

von Karl H. (kbuchegg)


Lesenswert?

Ah, ok - 16 Bit


Ich seh schon, du weißt hier ja ans Period Register zu
1
  TCC0.PER = (uint8_t)(int16_t)-(F_CPU / 1024 * 1e-3 -1 + 0.5);  // preload for 1ms

ja, das geht aber so nicht.

Zum einen braucht das nicht bei jedem ISR Aufruf gemacht werden, sondern 
nur einmalig beim Programmstart.
Zum anderen ist diese Berechnung falsch, für deinen Zweck
(die Berechnung im Original ist für die 'alten' 8 Bit AVR gemacht, die 
einen 8 Bit Timer haben, bei denen man ins Zählregister einen Wert 
schreibt, von dem aus an der Timer bis 255 zählt, ehe der Overflow 
kommt. Daher auch das - in der Berechnung.

Bei dir muss das lauten
1
  TCC0.PER = (uint16_t)(F_CPU / 1024 * 10e-3 -1 + 0.5);

und diese Berechnung kommt einmalig in main() rein und flíegt aus der 
ISR raus

1
int main()
2
{
3
 ....
4
  TCC0.PER = (uint16_t)(F_CPU / 1024 * 10e-3 -1 + 0.5);
5
6
  TCC0.CTRLB = TC_WGMODE_NORMAL_gc;
7
  TCC0.INTCTRLA = TC_OVFINTLVL_HI_gc;
8
  TCC0.CTRLA = TC_CLKSEL_DIV1024_gc;
9
10
...

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

Willy M. schrieb:

> Leider hab ich kein Oszilloskop hier, mit dem ich vielleicht sehen
> könnte, ob die LEDs vielleicht doch einmal kurz aufblitzen, allerdings
> kann ich mir das jetzt nicht mehr vorstellen, habe eine Entprellzeit von
> 16ms eingestellt.


In dem Fall sind wir (ich?) von falschen Voraussetzungen ausgegangen.
Mit der Originalberechnung hast du tatsächlich eine Entprellzeit 
jenseits von gut und böse erhalten.


Daher ein gut gemeinter Rat:
WEnn du Timer aufsetzt und du bei den ISR Aufrufen auf eine bestimmte 
Zeit aus bist, dann überprüfe das! zb indem du in der ISR eine LED 
toggeln lässt. WEnn die Zeit zu kurz ist, als das du das Blinken siehst, 
dann verlängere dir die Zeit, zb auf das 1000-fache
1
ISR( .... )
2
{
3
  static int cnt = 0;
4
5
  cnt++;
6
  if( cnt == 1000 )
7
  {
8
    cnt = 0
9
    LED toggeln;
10
  }
11
}

dann brauchst du auch kein Oszi um das zu sehen. Eine gewöhnliche 
Armbanduhr reicht. Du zählst einfach die Sekunden und die ISR 
Aufrufhäufigkeit ist dann 1/1000 davon. So kannst du auch einzelne 
Millisekunden noch gut unterscheiden.

Aber gerade am Anfang ist es wichtig, alles und jedes zu überprüfen. Vor 
allen Dingen dann, wenn der Code ursprünglich gar nicht für deinen 
µC-Typ geschrieben war.


Edit:
Ich würde das sogar jetzt noch überprüfen, ob die 10ms jetzt stimmen.
genau nach diesem Muster. Vielleicht nicht mit 1000, aber mit 500. Die 
LED muss dann 5 Sekunden brennen und 5 Sekunden dunkel sein. Jegliche 
ABweichung von diesen Zeiten bedeutet, dass irgendwo in der 
Konfiguration was nicht stimmt.
Und erst dann, wenn ich sicher bin, dass die ISR Zeiten korrekt sind, 
gehts weiter mit der Entprellung.

: Bearbeitet durch User
von Jörg E. (jackfritt)


Lesenswert?

Stell doch endlich mal 50 bis 100 ms ein!
Nur zum Spaß für alle ;)
Und damit du dann auch mal den Unterschied merkst?

von W. M. (muhh)


Lesenswert?

Hey Karl,

also ich toogle in meinem Code den ich gepostet habe in der ISR eine 
LED, um zu sehen, ob der Timer beim Overflow auch wirklich die ISR 
aufruft. Dann messe ich mit meinem Multimeter die Frequenz an der LED 
und nehme den Kehrwert davon, deswegen konnte ich auch Aussagen wie 
meine Entprellzeit ist 10,76ms machen (abgesehen mal davon, dass die 
Genauigkeit meines Multimeters das garnicht zulässt ;) )

Und das mit dem Oszilloskop stimmt auch nicht ganz, ich habe zwar ein 
gaaaaaanz altes Grundig 20MHz Oszilloskop, aber damit kann ich mir nur 
noch Signalverläufe anschauen, leider nichts genauers mehr messen, 
allerdings weiß ich nicht wie ich ein so kurzes aufblitzen einer LED 
aufnehmen sollte, ich habe ja kein WafeformRecording.

von W. M. (muhh)


Lesenswert?

@Jörg:

Hatte ich schon, war bei 2s. War ganzschön nervig die 8s zu warten bis 
die LEDs angegangen sind ;)

von Jörg E. (jackfritt)


Lesenswert?

Und 50-100ms ? Ist was anderes wie 2s....

von c-hater (Gast)


Lesenswert?

Willy M. schrieb:

> Nein, dass war mir nicht so ganz bewusst, ich dachte wirklich, dass je
> kleiner ich die Zeit mache, desto genauer wird das ganze...

Du hast also das Prinzip wohl schon nicht richtig verstanden.

> Okay, Entprellzeit liegt bei 10,76ms...

Definitiv zu wenig für schlechte Schaltkontakte. Die prellen schonmal 
20, 30ms oder noch mehr.

Sinnvolle Werte für die Entprellung liegen so zwischen 50 und 100ms, 
wobei man mit 100ms leider schon in dem Bereich ist, der durchaus auch 
Nutzsignal sein könnte. Die Fire-Tasten von guten Joysticks aus der 
Homecomputer-Zeit z.B. erlaubten tatsächlich "Eingabe"raten in dieser 
Größenordnung. Allerdings gibt's sowas heute offensichtlich nicht mehr. 
Da wurde wohl massiv kostenoptimiert, sowohl bei der Kontaktgeometrie 
als auch bei der Wahl der Werkstoffe...

Wirklich schnelle, zuverlässige und langzeitstabile Mikrotaster kriegt 
man heute nur noch im Industriebereich (und auch dort nur mit etwas 
Glück oder Hintergrundwissen) und die kosten dann wirklich unanständig 
viel Geld. Wahrscheinlich, weil der Billichscheiß die guten Sachen zu 
Exoten mit sehr geringen Produktionszahlen gemacht hat.

> Eigentlich will ich nur, dass der Entprellcode 100% funktioniert, bevor
> ich dann den Code für den Drehgeber erweitere

Jetzt ist sicher: Du hast es nicht verstanden. Das coole an Drehencodern 
ist nämlich, daß die überhaupt nicht entprellt werden müssen...

von Karl H. (kbuchegg)


Lesenswert?

Willy M. schrieb:
> @Jörg:
>
> Hatte ich schon, war bei 2s. War ganzschön nervig die 8s zu warten bis
> die LEDs angegangen sind ;)

Ich denke es ist wieder mal an der Zeit, den Code in seiner jetzigen 
Form zu sehen :-)

von Karl H. (kbuchegg)


Lesenswert?

c-hater schrieb:

>> Okay, Entprellzeit liegt bei 10,76ms...
>
> Definitiv zu wenig für schlechte Schaltkontakte. Die prellen schonmal
> 20, 30ms oder noch mehr.

wenn ich ihn richtig verstehe, dann meint er damit die ISR 
Aufruffrequenz. Die Entprellzeit ist dann im Minimum das 4-fache davon.

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Willy M. schrieb:
>> @Jörg:
>>
>> Hatte ich schon, war bei 2s. War ganzschön nervig die 8s zu warten bis
>> die LEDs angegangen sind ;)
>
> Ich denke es ist wieder mal an der Zeit, den Code in seiner jetzigen
> Form zu sehen :-)

Vor allen Dingen weil Timmo gestern abend schon die korrekte Formel 
gepostet hat und der Code von heute Nachmittag wieder die falsche drinn 
hatte.

von W. M. (muhh)


Lesenswert?

Okay, 50...100 ms habe ich ausprobiert, erstmal fang ich an die in der 
ISR getoogelte LED blinken zu sehen und bei 100 muss ich anfangen etwas 
länger gedrückt zu halten, damit er das wirklich erkennt, aber auch hier 
besteht weiterhin das Problem, dass manche Tastendrücke??? nicht erkannt 
werden. Ich habe mir einfach mal versucht die Pegel mit dem Oszilloskop 
anzuschauen und zu gucken, ob der Taster jedes mal beim Drücken den Pin 
auf Masse zieht und das Tut er, trotzdem scheint der MC diesen Wechsel 
manchmal nicht mitzubekommen...

c-hater schrieb:
> Jetzt ist sicher: Du hast es nicht verstanden. Das coole an Drehencodern
> ist nämlich, daß die überhaupt nicht entprellt werden müssen...

Das kann gut sein, so dachte ich, dass der Drehencoder funktioniert:

Mein Drehencoder hat 12 Stellung, und ist 360° drehbar mit zusätzlicher 
Tasterfunktion. Wenn ich nun den Drehencoder nach Rechts drehe, wird am 
Pin A eine steigende Flanke erzeugt, phasenverschoben z.B. dem Pin A 
nacheilend wird an Pin B enbenfalls eine positive Flanke erzeugt. Durch 
den Phasenwinkel zwischen Pin A und Pin B kann ich feststellen in welche 
Richtung der Drehencoder gedreht wurde, d.h. wenn ich den Drehencoder 
nach links drehen würde, dann würde Pin B Pin A vorrauseilen...

Ist das so korrekt?

Und nun dachte ich, das es bei den Übergängen von einer Stellung zur 
nächsten unsaubere Flanken geben kann, die entprellt werden müssen...

von W. M. (muhh)


Lesenswert?

1
#include <stdint.h>
2
#include <avr/io.h>
3
#include <avr/interrupt.h>
4
5
#ifndef F_CPU
6
#define F_CPU           32e6                   // processor clock frequency
7
#warning kein F_CPU definiert
8
#endif
9
10
#define KEY_PIN      PORTD.IN
11
12
#define REPEAT_MASK     0xff                         // repeat: Pin 1.0
13
#define REPEAT_START1   50                         // after 500ms
14
#define REPEAT_NEXT1    20                          // every 200ms
15
#define REPEAT_NEXT2    5                          // every 200ms
16
17
#define TRUE      1
18
#define FALSE      0
19
20
/**************************************************/
21
22
volatile uint8_t key_state;                              // debounced and inverted key state: bit = 1: key pressed
23
volatile uint8_t key_press;                              // key press detect
24
volatile uint8_t key_rpt;                                // key long press and repeat
25
volatile uint8_t rpt_count;
26
27
/**************************************************/
28
29
ISR (TCC0_OVF_vect)
30
{
31
  static uint8_t ct0, ct1, rpt;
32
  uint8_t i;
33
  
34
  i = key_state ^ ~KEY_PIN;                       // key changed ?
35
  ct0 = ~( ct0 & i );                             // reset or count ct0
36
  ct1 = ct0 ^ (ct1 & i);                          // reset or count ct1
37
  i &= ct0 & ct1;                                 // count until roll over ?
38
  key_state ^= i;                                 // then toggle debounced state
39
  key_press |= key_state & i;                     // 0->1: key press detect
40
  
41
  if( (key_state & REPEAT_MASK) == 0 )            // check repeat function
42
  rpt = REPEAT_START1;                            // start delay
43
  if( --rpt == 0 ){
44
    rpt = REPEAT_NEXT1;                     // repeat delay
45
    key_rpt |= key_state & REPEAT_MASK;
46
  }
47
  
48
  PORTE.OUT ^= 0x01;      // Hier wird die LED getoogelt, an der ich die Frequenz messe
49
}
50
51
...
52
53
Die ganzen Funktionen aus P. Danneggers Coder
54
55
...
56
57
int main( void )
58
{
59
   // internen Oszillator auf 32MHZ einstellen
60
   OSC.CTRL = 3;
61
   while(OSC.STATUS != 3)
62
   {
63
   }
64
   CCP = 0xD8;
65
   CLK.CTRL = 1;
66
67
  // Interrupts aktivieren und alle Level freigeben
68
  sei();
69
  PMIC.CTRL=0x07;
70
  
71
  TCC0.CCA = 1.0*F_CPU /1024 /2 *30e-3 -1;
72
73
74
  TCC0.CTRLB = TC_WGMODE_FRQ_gc;    
75
  TCC0.INTCTRLA = TC_OVFINTLVL_HI_gc;
76
  TCC0.CTRLA = TC_CLKSEL_DIV1024_gc;
77
  
78
  PORTE.DIR = 0xff;            // kompletter Prot als Ausgang (LED-Port)
79
  PORTE.OUT = 0xff;            // LEDs ausschalten
80
  
81
  PORTD.DIR = 0x00;            // kompletter Port als Eingang (Taster)
82
  PORTD.PIN0CTRL = PORT_OPC_PULLUP_gc;
83
  PORTD.PIN1CTRL = PORT_OPC_PULLUP_gc;
84
  PORTD.PIN2CTRL = PORT_OPC_PULLUP_gc;
85
  PORTD.PIN3CTRL = PORT_OPC_PULLUP_gc;       // Pin3 mit Pull-Up beschalten
86
  PORTD.PIN4CTRL = PORT_OPC_PULLUP_gc;
87
  PORTD.PIN5CTRL = PORT_OPC_PULLUP_gc;
88
  PORTD.PIN6CTRL = PORT_OPC_PULLUP_gc;
89
  PORTD.PIN7CTRL = PORT_OPC_PULLUP_gc;
90
  
91
  
92
  PORTC.DIR = 0xff;
93
  PORTC.OUTCLR = 0xff;
94
  
95
  while(1)
96
  {
97
    if(get_key_press(PIN4_bm))
98
    {
99
      PORTE.OUTTGL = 0x77;
100
    }
101
  }
102
}

von Karl H. (kbuchegg)


Lesenswert?

>   TCC0.CCA = 1.0*F_CPU /1024 /2 *30e-3 -1;

wieso auf einmal CCA?

Bitte, mach keine unmotivierten Änderungen!
WIe soll man denn da als Aussenstehender, der nicht sieht, was du sonst 
noch so alles änderst noch mitkommen.

Jetzt muss ich erst mal nachlesen, was eigentlich das CCA Register 
macht.

von W. M. (muhh)


Lesenswert?

Entschuldige, ich habe den zählmodus geändert, weil für den die 
Frequenzberechnung genau angegeben war.

TCC0.CCA ist für den FRQ Mode das gleiche wie TCC0.PER für den Normal 
Mode, also die obere grenze, mit der die Periodendauer T festgelegt 
wird.

Stimmt ihr mir zu, das wenn man davon ausgeht, das der Taster ideale 
Flanken (eindeutig zu interpretierende Signale) produziert, der MC bei 
jedem Tasterdruck die LEDs toggeln müsste?

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

Hmm

Der weigert sich hartnäckig.

Hast du eigentlich 8 Pins am bewussten Port mit den LED?

Lass dir mal key_state so wie es ist dort ausgeben.
Eigentlich solltest du dort sehen können, wie nach kurzer Zeit der 
Tastendruck von der ISR registriert wird

1
int main()
2
{
3
4
  while( 1 )
5
  {
6
    PORTE.OUT = key_state;
7
  }
8
}

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

Ich kenne diese XMega Sache nicht.
ABer.
Geht das überhaupt?

  PORTE.OUT ^= 0x01;      // Hier wird die LED getoogelt, an der ich die 
Frequenz messe


Kann man mittels des OUT den aktuellen Zustand der Ausgangspins 
zurücklesen?

von Timmo H. (masterfx)


Lesenswert?

Das geht schon, aber für das toggeln geht es einfacher und schneller so 
beim xmega:
PORTE.OUTTGL = 0x01;

von Karl H. (kbuchegg)


Lesenswert?

Timmo H. schrieb:
> Das geht schon,

ok.
nicht dass er sich unabsichtlich in der ISR die LED wieder abschaltet, 
die er in main getoggelt hat.

Ich seh im Code jetzt nämlich auch nichts mehr.
Drum falle ich in den Modus "Hinterfrage alles und zieh alles in 
Zweifel" zurück.

: Bearbeitet durch User
von W. M. (muhh)


Angehängte Dateien:

Lesenswert?

Karl Heinz Buchegger schrieb:
> Hast du eigentlich 8 Pins am bewussten Port mit den LED?

Ja, genau. Auf dem Board sind an PORTE acht LEDs angeschlossen, die 
neben den 8 Tastern die an PORTD angeschlossen sind liegen.

Erstmal zum Verständnis, die Funktionen aus P. Danneggers Code dienen 
nur dazu um z.B. einmal abzufragen, ob ein Taster gedrückt wurde oder ob 
der Zustand länger gehalten wird (für die Repeat Funktion), dass ganze 
müsste aber auch ohne die Funktionen funktionieren?

Ich könnte z.B. anstatt
1
if(get_key_press(Pin4_bm))

auch
1
if(key_state & Pin4_bm)

schreiben?


Folgendes passiert wenn ich den Taster drücke:

Taster gedrückt halten: Die LED toggelt gedimmt immer hin und her, auf 
dem Osilloskop sieht man ein "schönes" 50% PWM Signal

Taster kruz drücken: Für kurze Zeit sieht man das oben beschriebene PWM 
Signal, es ist Zufall in welchem Zustand (Ein,Aus) die LED bleibt.

Ich habe das Bild mal mit angehängt.

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

Willy M. schrieb:

>
1
> if(get_key_press(Pin4_bm))
2
>
>
> auch
>
>
1
> if(key_state & Pin4_bm)
2
>
>
> schreiben?

Ist aber eine andere Funktionalität.


> Folgendes passiert wenn ich den Taster drücke:
>
> Taster gedrückt halten: Die LED toggelt gedimmt immer hin und her, auf
> dem Osilloskop sieht man ein "schönes" 50% PWM Signal
>
> Taster kruz drücken: Für kurze Zeit sieht man das oben beschriebene PWM
> Signal, es ist Zufall in welchem Zustand (Ein,Aus) die LED bleibt.

Das ist interessant.
Das sollte nämlich nicht so aussehen.

Wenn du die Taste drückst, dann sollte key_state am bewussten Pin mit 
ein wenig verzögerung den Zustand des Input Port Pins annehmen.


Kann es sein, dass dein µC zwischendurch Resettet?

: Bearbeitet durch User
von W. M. (muhh)


Lesenswert?

Okay... Das kann wirklich sein, aber wie finde ich das heraus? Das 
Problem hatte ich schonmal in der Simulation mit den MSP430 von TI...

von Karl H. (kbuchegg)


Lesenswert?

Willy M. schrieb:
> Okay... Das kann wirklich sein, aber wie finde ich das heraus?

Na zum Beispiel
1
int main()
2
{
3
  ....
4
5
  Ports initialisieren
6
7
  LED einschalten
8
  1 Sekunde warten
9
  LED ausschalten
10
11
  ...
12
13
  while( 1 )
14
  {
15
    ...
16
  }

wenn die LED immer wieder für 1 Sekunde an geht, dann läuft main() 
offenbar wieder von vorne an.

Auf der anderen Seite sind mir die Pulse zu regelmässig. Aber einen 
Versuch ist es wert.

key_state sollte eigentlich stabile Pegel zeigen, je nachdem ob die 
Taste gedrückt ist oder nicht. Im Grunde ist das nur eine bereinigte 
Version von KEY_PIN  (die könnte man auch mal ausgeben und nachsehen ob 
sich da dieselben Toggler zeigen)

von Gerhard G. (g_g)


Angehängte Dateien:

Lesenswert?

Hallo,

ich habe durch Zufall den selben Code benötigt.
Schau dir mal den lauffähigen Code an.
Funktioniert hundertprozentig!

Gruß G.G.

von Timmo H. (masterfx)


Lesenswert?

Hier mal ein Minimalbeispiel für den xmega welcher bei mir funzt:
1
#include <stdint.h>
2
#include <avr/io.h>
3
#include <avr/interrupt.h>
4
5
#define KEY_DIR         PORTC.DIR
6
#define KEY_PIN         PORTC.IN
7
#define KEY_SW3      3           
8
#define KEY_SW4      2
9
#define KEY_SW6      0
10
#define ALL_KEYS        (1<<KEY_SW3) || (1<<KEY_SW4) || (1<<KEY_SW6)
11
 
12
#define REPEAT_MASK     ALL_KEYS        // repeat: key0
13
#define REPEAT_START    50              // after 500ms
14
#define REPEAT_NEXT     20              // every 200ms
15
16
volatile uint8_t key_state;
17
volatile uint8_t key_press;
18
volatile uint8_t key_rpt;
19
20
uint8_t get_key_rpt( uint8_t key_mask ){
21
  cli();                                          // read and clear atomic !
22
  key_mask &= key_rpt;                            // read key(s)
23
  key_rpt ^= key_mask;                            // clear key(s)
24
  sei();
25
  return key_mask;
26
}
27
28
29
uint8_t get_key_press( uint8_t key_mask ){
30
  cli();                                          // read and clear atomic !
31
  key_mask &= key_press;                          // read key(s)
32
  key_press ^= key_mask;                          // clear key(s)
33
  sei();
34
  return key_mask;
35
}
36
37
uint8_t get_key_short( uint8_t key_mask ){
38
  cli();                                          // read key state and key press atomic !
39
  return get_key_press( ~key_state & key_mask );
40
}
41
42
uint8_t get_key_long( uint8_t key_mask ){
43
  return get_key_press( get_key_rpt( key_mask ));
44
}
45
46
47
void init_timer(){
48
  TCD1.CNT = 0;
49
  TCD1.CTRLA = TC_CLKSEL_DIV256_gc;
50
  TCD1.PER = (int16_t)(F_CPU/256L*10e-3+0.5); //=> 10ms
51
  TCD1.INTCTRLA = TC_OVFINTLVL_LO_gc;  // Low Level Interrupt
52
}
53
54
int main(void)
55
{
56
  /* 32 MHz internal enable und warten bis ready */
57
  OSC.CTRL = OSC_RC32MEN_bm;
58
  while(!(OSC.STATUS & OSC_RC32MRDY_bm));
59
60
  CCP = CCP_IOREG_gc;
61
  /*Clock auf 32Mhz einstellen*/
62
  CLK.CTRL = CLK_SCLKSEL_RC32M_gc;
63
64
  /* Pullup für alle Taster */
65
  PORTC.PIN3CTRL |= PORT_OPC_PULLUP_gc;  
66
  PORTC.PIN2CTRL |= PORT_OPC_PULLUP_gc;  
67
  PORTC.PIN0CTRL |= PORT_OPC_PULLUP_gc;  
68
  
69
  PMIC.CTRL |= PMIC_LOLVLEN_bm;  // Lo Interrupt Enable
70
71
  init_timer();
72
73
  sei();
74
75
  while(1)
76
  {
77
    if(get_key_press(1<<KEY_SW3) ){
78
      //Mach was
79
    }
80
    if(get_key_press(1<<KEY_SW6) ){
81
      //mach was anderes
82
    }
83
    if(get_key_press(1<<KEY_SW4) ){
84
      //mach was ganz anders
85
    }
86
  }
87
}
88
89
90
ISR(TCD1_OVF_vect){
91
  static uint8_t ct0, ct1, rpt;
92
  uint8_t i;
93
94
  i = key_state ^ ~KEY_PIN;                       // key changed ?
95
  ct0 = ~( ct0 & i );                             // reset or count ct0
96
  ct1 = ct0 ^ (ct1 & i);                          // reset or count ct1
97
  i &= ct0 & ct1;                                 // count until roll over ?
98
  key_state ^= i;                                 // then toggle debounced state
99
  key_press |= key_state & i;                     // 0->1: key press detect
100
  
101
  if( (key_state & REPEAT_MASK) == 0 )            // check repeat function
102
  rpt = REPEAT_START;                          // start delay
103
  if( --rpt == 0 ){
104
    rpt = REPEAT_NEXT;                            // repeat delay
105
    key_rpt |= key_state & REPEAT_MASK;
106
  }
107
}

: Bearbeitet durch User
von W. M. (muhh)


Lesenswert?

@Karl:

Der MC resetet nicht, ~KEY_PIN zeigt das gleiche verhalten wie 
key_state...


Ich glaube ich habe den Fehler gefunden...

Ich habe die Zeilen cli(); und sei(); aus den Funktionen rausgenommen, 
und das auch nur, weil ich als ich wieder mit den Atmels angefangen habe 
vergessen hatte, dass man die interrupts.h braucht, deswegen hat der mir 
ne Fehlermeldung ausgespuckt, dass er die nicht kennt, habe sie aber 
vergessen wieder reinzuschreiben.... vielleicht klappst ja jetzt

von W. M. (muhh)


Lesenswert?

Ohnein... Sorry Leute... Was für ein dummer Fehler :S
Jetzt funktioniert alles so wie es soll... Na toll!!!

Dann können wir ja gleich nochmal meine Frage klären, ob der Drehencoder 
sehr saubere Signale liefert oder ob man den doch entprellen muss :)

Und danke das ihr mir so tapfer geholfen habt :)

: Bearbeitet durch User
von Timmo H. (masterfx)


Lesenswert?

Ist doch schon alles fertig: Drehgeber

Kannst auch die gleiche Timer ISR dafür verwenden. Einfach auf 1ms 
Intervall verkürzen und nur jedes 10. mal die Taster abfragen.

: Bearbeitet durch User
von chaos (Gast)


Lesenswert?

Häng doch fix jeweils die Drehencoderkanäle an dein Oszi.
Wenn du dir überlegst, wie so ein Drehencoder arbeitet, solltest du 
darauf kommen, das der recht saubere Signale liefern sollte. Du hast ja 
quasi ne Optokopplerstrecke, auf der zwischen LED und Optotranse einfach 
ne Lochscheibe bzw Schlitzscheibe liegt. Schlitz geht auf, Licht trifft 
auf den Transistor, dein Signal schaltet sauber auf LOW/HIGH(je nach 
Architektur), Schlitz geht zu, Licht weg, Signal wechselt sauber auf den 
anderen Pegel=).

MfG Chaos

von chaos (Gast)


Lesenswert?

P.S. von den Schlitzscheiben hast du dann natürlich die 2 versetzten 
Spuren, um dein phasenverschobenes Signal auf den beiden Kanälen zu 
erhalten.

P.P.S. wenn du natürlich n mechanischen Drehencoder hast.... dann 
solltest du dir schon Gedanken ums Entprellen machen. Das Prellen ist 
halt ein Abart der Elektromechanik =), mit sowas hast du bei der 
LED-Optostrecke nicht zu kämpfen

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.