Forum: Mikrocontroller und Digitale Elektronik Entprellen mit Sam µC


von Elektrotiger (Gast)


Lesenswert?

Ich suche eine gute Portierung der Entprellung von Peter Dannegger für 
ARM µC, da die ASF debouncing filter von Atmel nicht ausreichend sind.

Leider funktioniert der Link für die Portierung für den AT91SAM7 nicht 
mehr.

Hat jmd eine bereits gut funktionierende Lösung zum "parallelen" 
debouncing von Tasten ala Peter Dannegger für ARM programmiert?

Da ich bislang nicht wirklich eine zufriedene Lösung gefunden habe, 
bastel ich gerade selbst eins mittels Button Handler und TC Handler.

Die Idee war, dass bei Tastendruck ButtonHandler ausgelöst wird und 
dabei direkt erkannt wird welcher Button gedrückt wurde. Erst beim 
Auslösen des Buttonhandlers wird der Interrupt für den Overflow des TC0 
wieder erlaubt. So wird darüber die Taste entprellt. Sofern keine 
erneute Signale ankommen wird der TC0 Interrupt wieder deaktiviert.
Allerdings erscheint mir das alles bisl umständlich, vll hat jmd bessere 
Ideen :).

von Peter D. (peda)


Lesenswert?

Wo ist das Problem?
Das ist doch plain C, also direkt portierbar.
Und der Interrupthandler kommt in den SysTick mit rein.
Der einzige Unterschied ist, daß ein Port wohl nicht 8bit, sondern 16 
oder 32Bit breit sein wird, also die Typen entsprechend anpassen.

von Elektrotiger (Gast)


Lesenswert?

Nicht wenn ich die ASF von Atmel im allgemeinen nutze, bzw. habe das 
Problem, dass die Tasten nicht alle an einem Port liegen, sondern an 
unterschiedlichen. Ich kann nicht direkt mit Registern arbeiten sondern 
muss Arrays von den Tasten erstellen, die wiederrum müsste ich in eine 
binäre Zahl mit 8 Bit umwandeln.

Ich dachte, dass ich durch die Priorisierung der Interrupts das 
Entprellen von Tasten seperieren kann. Im Systick habe ich vorerst quasi 
nichts.
Nur eine LEDkette, die der Reihe nach an und aus geht, um zu gehen ob 
nicht irgendwo eine Endlosschleife ist.
Habe einen Buttonhandler der sofort anspringt wenn ein Pegel anliegt. 
Der wiederrum erlaubt TC0 Interrupts. Im TC0 Handler wollte ich die 
Tasten entprellen und sobald kein Bedarf mehr ist, den TC0 Interrupt 
wieder deaktivieren. Funktioniert nicht, da beim gedrückten Tastendruck 
Systik nicht mehr ausgeführt werden kann. (So bei mir zumindest)

Daher muss TC Handler mit in Systick rein oder TC Handler entfernen und 
über Systick entprellen?

von interrupt (Gast)


Lesenswert?

Klingt ja wahnsinnig kompliziert gedacht.

Warum?


Ports lesen, alle xmsec, vergleichen alter und neuer Zustand der Ports, 
auch öfters, ist der Zustand stabil dann die Änderung am Port als 
Tastendruck interpretieren.

von Peter D. (peda)


Lesenswert?

Elektrotiger schrieb:
> habe das
> Problem, dass die Tasten nicht alle an einem Port liegen, sondern an
> unterschiedlichen.

Das ist kein Problem.
Du bastelst dann eben durch Schieben und Verunden einen 16Bit Wert aus 
mehreren Portbits zusammen.
Bzw. wenn es mehr als 16 Tasten sind, einen 32 oder 64Bit Wert.

Elektrotiger schrieb:
> Ich dachte, dass ich durch die Priorisierung der Interrupts das
> Entprellen von Tasten seperieren kann.

Der Mensch ist schnarchlahm aus CPU-Sicht. Tasten kriegen, wenn 
überhaupt, nur die ganz unterste Priorität.
Im einfachsten Fall garkeine, sondern der Systick macht alle 100ms die 
super eiliegen Tastendrücke.
Ansonsten macht Tastenereignisse auswerten die Mainloop.

von Elektrotiger (Gast)


Lesenswert?

Peter D. schrieb:
> Der Mensch ist schnarchlahm aus CPU-Sicht. Tasten kriegen, wenn
> überhaupt, nur die ganz unterste Priorität.

Daher wollte ich das Entprellen auch mit einem TC Handler mit 
niedrigster Priorität trennen.

Systick hat stets die höchste Priorität?
Habe aktuell das Problem, dass beim gedrückt halten der Taste gerade 
permanent in Button Handler reinspringt, sodass ich meine LEDKette nicht 
mehr bewegen sehe, obwohl Button Handler Priorität 5 hat :/.
Allerdings TC0 Handler mit Priorität 4 verarbeitet wird.

Systick wird bei mir jede ms angesprungen, da ich dieses später zur 
Simulierung eines MRT Signals so genau brauche. Nun möchte ich ungern im 
Systick anfangen eine Variable hoch zu zählen bzw runter um dann über 
systick das Entprellen der Tasten zu steuern. Da später ggf mehr im 
Systick stehen wird, würde ich es gerne seperieren.

Peter D. schrieb:
> Schieben und Verunden

Und ich wollte schon mit 2^n rechnen :D... an shiften habe ich nicht 
mehr gedacht. Werde morgen mein Code auf deinen anzupassen.
Dennoch würde ich mich freuen zu verstehen wieso ich meine Interrupts 
nicht so getimet bekomme ich wie ich es mir vorstelle.

Danke :)

von W.S. (Gast)


Lesenswert?

Elektrotiger schrieb:
> Ich dachte, dass ich durch die Priorisierung der Interrupts das
> Entprellen von Tasten seperieren kann. Im Systick habe ich vorerst quasi
> nichts.

Oh mann, das schmerzt ja beim Lesen. Von wegen "Elektrotiger" ...
Eigentlich ist es ja so unsäglich einfach:
1. man tastet die betreffenden Portpins zyklisch ab, sowas macht man am 
sinnvollsten im Systick, der nebenbei auch noch die System-Uhrzeit 
führt, so daß man davon zeitabhängige Funktionalitäten ableiten kann.
2. beim allerersten Erscheinen eines Tastendruckes kann und soll man 
dies als Tastendruck-Ereignis an den Rest der Firmware weiterleiten.
3. ab einem erkannten Tastendruck muß man anschließend so lange keine 
neuen Tastendrücke aus dem Tastenzustand herleiten, bis die betreffende 
Taste für eine bestimmte Zeit AM STÜCK als ungedrückt erkannt wurde. 
Zumeist reicht hier 50..80 ms dicke aus. Fakultativ kann man bei länger 
als eine bestimmte Zeit gedrückt gehaltener Taste ein Repetieren 
veranstalten. Als erste Repetierzeit ist ne Sekunde ganz gut, folgende 
repetierzeiten dann deutlich kürzer.

Wo ist das Problem, sowas in aller Kürze als Quelltext hinzuschreiben?
Ich geb dir mal ein Beispiel:

#define LangeRepZeit 80
#define KurzeRepZeit 10
#define EntprellZeit  6
byte  Old, Rep;
bool  tastenrepetieren;
... alle 10 ms:
  L = PORT;               // Port lesen

  if (!(L & (1<<Tastennummer))) // Taste gedrückt ?
  { if (!Old)             // war vorher ungedrückt
    { Rep = LangeRepZeit;
      Add_Event(idDieseTaste);
    }
    else
    if (tastenrepetieren)
    { --Rep;
      if (!Rep)
      { Rep = KurzeRepZeit;
        Add_Event(idDieseTast);
      }
    }
    Old = EntprellZeit;
  }
  else
  { if (Old) --Old; } // entprellen

.. so etwa und fertig. Wie man das per Schleife auf N Tasten erwitert, 
sei dir überlassen.

W.S.

von Peter D. (peda)


Lesenswert?

Elektrotiger schrieb:
> Habe aktuell das Problem, dass beim gedrückt halten der Taste gerade
> permanent in Button Handler reinspringt

Der Trick an meiner Entprellung ist natürlich, daß sie nur die Flanke 
als Event ausgibt.
Egal wie lange Du drückst, es gibt nur genau ein Event (ohne 
Repeatfunktion).
Erst nach Loslassen kann ein erneutes Drücken ein weiteres Event 
generieren.

Durch die Eventsteuerung ergibt sich auch eine Entkopplung zwischen 
Drücken und Auswertung. D.h. auch wenn die Mainloop mal etwas busy ist, 
geht ein kurzes Drücken nicht verloren.

Bei vielen kommerziellen Geräten nervt es total, daß ständig Drücke 
verloren gehen, solange es noch mit der vorherigen Aktion beschäftigt 
ist.

: Bearbeitet durch User
von Elektrotiger (Gast)


Lesenswert?

Ich verstehe nicht wie ich die Pins unterschiedlicher Ports in ein 
Register bzw integer Variable speichern kann?
Die Pins zeigen doch nur ihren Pegel High:1 und Low:0 an.
Ich müsste die Zeiger auf die Pins in ein Array packen? Wenn ich dies 
wieder in ein integer Variable wie ein 8 Bit Register arbeitet, 
speichern würde, dann verliere ich doch den Bezug zu den Pins und habe 
nur noch die Pegel :/? Hier dürft ihr mir auf die Finger hauen^^

W.S. schrieb:
> Oh mann, das schmerzt ja beim Lesen. Von wegen "Elektrotiger" ...

Wenn ich solche Kommentare lese, könnte ich dem jenigen echt eine 
Ohrfeige geben! Dieser Bereich gehört erstens eher zur Informatik bzw. 
zur technischen Informatik. 2. verurteile nicht einfach solche User, ich 
selbst studiere an der RWTH Aachen im 6. Semester. Kann dir 
Elektromagnetische Wellen im freien Raum, Materie und Leitern 
berechnen....

W.S. schrieb:
> 1. man tastet die betreffenden Portpins zyklisch ab, sowas macht man am
> sinnvollsten im Systick, der nebenbei auch noch die System-Uhrzeit
> führt, so daß man davon zeitabhängige Funktionalitäten ableiten kann.

Die Idee hinter dem Algorithmus habe ich verstanden, hier mein Code.
Allerdings habe ich durch ASF gerade das Problem die Pins/Ports sinnvoll 
in einem "Register" bzw. 8Bit integer Variable sinnvoll zu verpacken. 
Dabei habe ich Tasten an bis zu drei unterschiedlichen Ports. Daher 
hatte ich überlegt meine Pins in Arrays zupacken und mit einander zu 
vergleichen. Das wird wirklich eine "schmerzliche, dumme" Lösung sein, 
daher frage ich hier nach...
1
void TC0_Handler(void)    // alle 10ms
2
{  
3
  for(uint16_t i=0; i<=sizeof(button_permission);i++)
4
  {
5
    if(debounce_status[i]>0) 
6
    {
7
      debounce_status[i]-=1;
8
      if((debounce_status[i]==0) && (button_level[i]==1))      // Gedrückthalten
9
      {
10
        debounce_status[i] = REPEAT_NEXT;
11
        button_permission[i] = 1;
12
        button_repeat[i] = 1;
13
      }
14
      else if((debounce_status[i]==0) && (button_level[i]==0))  // Taste nicht mehr gedrückt
15
      {
16
        button_permission[i] = 1;
17
        button_repeat[i]=0;
18
      }
19
    }    
20
    if(button_state[i] != button_level[i])
21
    {
22
      debounce_status[i] = REPEAT_START;      
23
    }
24
    button_state[i]=button_level[i];
25
  }
26
  
27
  tc0_status = 0;
28
  for(uint16_t i; i<=sizeof(button_permission); i++)
29
  {
30
    if(debounce_status[i]!=0) tc0_status++;
31
  }
32
  if(tc0_status==0) tc_disable_interrupt(TC0,0,TC_IER_CPCS);
33
  
34
  
35
  tc0_counts++;
36
  if(tc0_counts>=50)
37
  {
38
    tc0_counts=0;
39
    ioport_toggle_pin_level(LED0);
40
  }
41
  
42
  
43
  uint32_t dummy;
44
  dummy = tc_get_status(TC0,0);
45
  UNUSED(dummy);
46
  
47
  //ioport_toggle_pin_level(LED0);  
48
}
tc interrupt wird wieder erlaubt, sobald im Button_Handler ein 
Tastendruck registriert wird und direkt im Array gespeichert.



Peter D. schrieb:
> Bei vielen kommerziellen Geräten nervt es total, daß ständig Drücke
> verloren gehen, solange es noch mit der vorherigen Aktion beschäftigt
> ist.

Daher ist deine Idee und vorallem Codeumsetzung sehr gut :). Danke

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Peter D. schrieb:
> Der Mensch ist schnarchlahm aus CPU-Sicht.

Aber 100 ms ist auch für einen Menschen schon recht lang.  Mit einer
gutgehenden Morsetaste könnte man in 100 ms gut und gern wenigstens
zwei komplette Tastendrücke unterbringen. ;-)  Klar, Morsetasten
dienen üblicherweise nicht als Eingabegeräte an Controllern, aber ein
wenig schneller als 100 ms darf man schon reagieren, sonst kommt es
dem Bediener „zuckelig“ vor.

Elektrotiger schrieb:
> Wenn ich solche Kommentare lese, könnte ich dem jenigen echt eine
> Ohrfeige geben!

W.S. war schon immer ein ungehobelter Klotz.  Dabei schafft er's
nicht einmal, ein paar simple Code-Tags in seinen Beitrag zu
tippen, sodass sein Code völlig unleserlich ist (zumindest für
diejenigen, die die Fließschrift-Version des Forums nutzen).  Ignorier'
ihn einfach, wenn er dich stört, dann kann er vor sich hin blubbern, wie
er will.  Mit Peter hast du allemal nicht nur einen kompetenten
Diskutanten, sondern auch einen, der ein vernünftiges Benehmen an den
Tag legen kann.

von Peter D. (peda)


Lesenswert?

Elektrotiger schrieb:
> Ich verstehe nicht wie ich die Pins unterschiedlicher Ports in ein
> Register bzw integer Variable speichern kann?

Z.B. 8 Tasten an P0.0, P0.1, P0.2, P0.3, P1.3, P2.3, P2.4, P2.6, dann:
1
  uint8_t val = (P0 & 0xF) | ((P1 & 0x10)<<3) | ((P2 & 0x58)<<1);

von Konrad S. (maybee)


Lesenswert?

Peter D. schrieb:
> ... P1.3 ...
> ... ((P1 &  0x10)<<3) ...

?

von Peter D. (peda)


Lesenswert?

Jörg W. schrieb:
> aber ein
> wenig schneller als 100 ms darf man schon reagieren, sonst kommt es
> dem Bediener „zuckelig“ vor.

Dann kennst Du Heimelektronik nicht.
Wenn ich bei meinem HDD-Rekorder im Menü die ">" Taste drücke, dann 
dauert es ewig, eh mit viel Getöse (Animation) der Kursor auf den 
nächsten Menüpunkt schleicht.
Und erst dann darf man wieder auf ">" drücken.

Bei nur 100ms könnte ich mein Glück kaum fassen. Dann könnte man ja 
blind bedienen, wenn man die Tastenfolge schon kennt.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Peter D. schrieb:
> Dann kennst Du Heimelektronik nicht.

Du musst ja nun nicht die schlechten Beispiele als Vorbild nehmen,
wenn du auch weißt, dass man es besser machen kann. ;-)

Konrad S. schrieb:
>> ... P1.3 ...
>> ... ((P1 &  0x10)<<3) ...
>
> ?

Genau darin dürfte die Fratzenfalle liegen, wenn man das einfach
„zu Fuß“ codiert.

Etwas sauberer könnte man es mit einer Union schreiben, die zum einen
einen 32-bit-Integer enthält (den du in den Algorithmus reinwerfen
kannst), zum anderen eine Bitfield-Struktur, mit der man sich die
einzelnen Bits aus den gelesenen Ports zusammenfummelt.  Das ist
zwar nicht 100% portabel gemäß Standard, sollte aber für den 
Hausgebrauch
allemal genügen, und man überlässt es dem Compiler, die Bits an die
richtige Stelle ohne Überlappungen zu sortieren.

: Bearbeitet durch Moderator
von Elektrotiger (Gast)


Lesenswert?

Peter D. schrieb:
> Z.B. 8 Tasten an P0.0, P0.1, P0.2, P0.3, P1.3, P2.3, P2.4, P2.6, dann:
> uint8_t val = (P0 & 0xF) | ((P1 & 0x10)<<3) | ((P2 & 0x58)<<1);

Klasse danke :). Glaube du meintest P1 & 0x03 in Hexa 10 wäre es in 
Binär?
Bzw weil der erste Eintrag der Px.0 ist müsste man hier 0x04 nehmen?
0x04 = 4*16^0 = 4 = 2^2 = (00100000) in binär

0x58 = 88 = 2^6 + 2^4 + 2^3 = (000110100) in binär
Hier passt es :).

von Elektrotiger (Gast)


Lesenswert?

1
uint32_t val = (((PIOA & 0x05)<<4) | ((PIOA & 0x0C)<<10) | ((PIOA & 0x11)<<14) | ((PIOD & 0x1A)<<22)
2
        | ((PIOA & 0x10)<<11) | ((PIOA & 0x17)<<17) | ((PIOA & 0x16)<<15) | ((PIOA & 0x19)<<17) );
3
uint8_t button_register = (uint8_t)val;
4
// button_register: mitte,links,rechts,oben,unten,1,2,3 
5
//          PA4, PA11, PA16, PD25, PA15, PA22, PA21, PA24

Ist das so richtig? z.B. zweiter Eintrag: PA11 ist der 12. Pin, also 
somit das 12. Bit am PortA. 12 = 0x0C . Diesen möchte ich im selbst 
gebastelten button_register am zweiten Bit setzen. Muss ich jetzt um 10 
Schritte shiften oder 11?

von Elektrotiger (Gast)


Lesenswert?

Update: Funktioniert so leider nicht.
1
 error: invalid operands to binary << (have 'uint8_t* and 'int')

: Bearbeitet durch Moderator
von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

PIOA auf dem ARM ist ein Zeiger auf eine Struktur.

Du musst stattdessen das Eingaberegister der jeweiligen PIO benutzen.
Was für einen SAM benutzt du?  Auf den älteren (SAM3/4) wäre das
das Register PIOA->PIO_PDSR (pin data status register).

Auf den neueren (SAMD und Verwandte) gibt es PIOA eigentlich gar
nicht direkt, sondern dort müsste man PORT->Group[0].IN.bit.IN
einlesen.  (Zuweilen habe ich aber auch schon #defines gesehen, die
PORT->Group[0] als PIOA abkürzen.)

Edit: in deinem Beispiel liegt jetzt doch alles an PIOA, oder fehlt
da noch was?

: Bearbeitet durch Moderator
von Elektrotiger (Gast)


Lesenswert?

Jörg W. schrieb:
> Was für einen SAM benutzt du?

benutze SAM4e16e. Danke :).
1
initializer element is not constant

von Elektrotiger (Gast)


Lesenswert?

Jörg W. schrieb:
> in deinem Beispiel liegt jetzt doch alles an PIOA, oder fehlt
> da noch was?

ne eins liegt an PIOD: PD25,
Benutze das evoltionboard, da sind die extensions vorgegeben und meine 
Beschaltung an den Extensions war nicht zu ende gedacht^^.
Aber grundsätzlich hatte ich das Problem schon öffter, von 
unterschiedlichen PIOs Pins sinnvoll in ein Register ala AVR 
zsmzufassen.

von Elektrotiger (Gast)


Lesenswert?

1
error: initializer element is not constant
 -.-'

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Elektrotiger schrieb:

>
1
initializer element is not constant

Da fehlt mir völlig der Kontext …

Aber: das mit Bitmasken und -nummern darfst du nochmal durchdenken.
Der Kommentar
1
//          PA4, PA11, PA16, PD25, PA15, PA22, PA21, PA24

passt hinten und vorn nicht zu den Masken, die du da benutzt.

Mein Tipp: nimm die richtigen Namen aus den Headerdateien, also
1
uint32_t val = (PIOA->PDSR & (PIO_PA4 | PIO_PA11 | PIO_PA15 |
2
                              PIO_PA16 | PIO_PA21 | PIO_PA22 |
3
                              PIO_PA24)) |
4
               (PIOD->PDSR & PIO_PD25);

Da die Bits auf den beiden Ports, die du benötigst, sich nicht
überlappen, kannst du die für deinen internen Status einfach
verODERn (PD25 ist disjunkt von allen Bits auf PIOA).  Im Ergebnis
hast du dann einen „schwach besetzten“ 32-bit-Integer, mit dem du
in Peters Algorithmus reingehst.  Das auf 8 Bit herunter zu
„komprimieren“, hat auf dem 32-bit-Prozessor sowieso keinen Sinn,
also rechnest du einfach den kompletten Entprellalgorithmus mit
32 Bits durch.

von Peter D. (peda)


Lesenswert?

Beim ARM muß man nicht mit RAM geizen, sondern kann alle Variablen und 
Funktionen uint32_t machen.
Und die Tasten müssen auch nicht lückenlos sein, man wählt sie ja eh 
über Bitmasken aus.
Z.B.:
1
//          PA4, PA11, PA16, PD25, PA15, PA22, PA21, PA24
2
#define KEY0_mask (1<<4)
3
#define KEY1_mask (1<<11)
4
#define KEY2_mask (1<<16)
5
#define KEY3_mask (1<<25) // usw.
6
7
  uint32_t input = PIOA->PIO_PDSR & ~(1<<25) | PIOD->PIO_PDSR & (1<<25);

Für KEY0..7 nimmt man natürlich die Funktion beschreibende Namen, z.B. 
KEY_UP, KEY_OK, KEY_BACK usw.

: Bearbeitet durch User
von W.S. (Gast)


Lesenswert?

Elektrotiger schrieb:
> Wenn ich solche Kommentare lese, könnte ich dem jenigen echt eine
> Ohrfeige geben! Dieser Bereich gehört erstens eher zur Informatik bzw.
> zur technischen Informatik. 2. verurteile nicht einfach solche User, ich
> selbst studiere an der RWTH Aachen im 6. Semester. Kann dir
> Elektromagnetische Wellen im freien Raum, Materie und Leitern
> berechnen....

Ach Ohrfeigen willst du verteilen - wieso eigentlich? Was meinst du, was 
unsereiner sich dabei denkt, wenn er sowas lesen muß:

Elektrotiger schrieb:
> Ich dachte, dass ich durch die Priorisierung der Interrupts das
> Entprellen von Tasten seperieren kann. Im Systick habe ich vorerst quasi
> nichts.

Ich sag dir, was ich mir dabei denke: Der Junge hat sein Problem nicht 
im Mindesten durchdacht und kommt erwiesenermaßen mit Peters 
Entprellroutinen nicht zu Potte, weswegen er hier hilflos auftaucht - 
aber er spuckt große Töne, unangemessen große Töne. Ein Elektrotiger, 
der zum großen Sprung angesetzt hat und als Elektro-Bettvorleger 
gelandet ist. Geht es nicht ein wenig bescheidener, wenn man nix weiß 
und fragen muß? Also ein Danke für eine funktionable (allerdings aus dem 
Handgelenk geschüttelte) Entprellroutine anstelle angedrohter Ohrfeigen?

p.s.: "SEPARIEREN"

Wäre ich dein Professor, dann würde ich dir zu etwas mehr Systematik 
beim Systemkonzept raten.

So, das sollte genug sein. Wenn du mal sehen willst, wie man eine ganze 
Tastenmatrix entprellt, dann guck in die mittlerweile steinalte 
Lernbetty.

Und zu Peter und seiner Erfahrung mit Heimelektronik: Ja, die deutliche 
Lahmheit vieler Geräte kenne ich auch, ich kann dir das nachfühlen. 
Insbesondere DVD-Player. Wir hatten das Thema doch neulich schon mal: 
Die Hälfte meiner Anwender drischt auf die Tasten, was eine Schließzeit 
in der Nähe von 10..30 ms ausmacht - nicht mehr. Abhilfe: 100 nF oder 
etwas mehr über die Tastenkontakte, die Ungleichheit zwischen 
niederohmiger Entladung und Wiederaufladung per 22k Hochzieher sorgt 
dafür, daß man trotzdem zu auswertbaren Signalen kommt.

W.S.

von Peter D. (peda)


Lesenswert?

W.S. schrieb:
> Die Hälfte meiner Anwender drischt auf die Tasten, was eine Schließzeit
> in der Nähe von 10..30 ms ausmacht

Dann einfach das Timerintervall auf 25ms hochsetzen, d.h. alles <100ms 
wird unterdrückt.
Sollst mal sehen, wie schnell die Leute manierlich mit den Tasten 
umgehen, was sich positiv auf die Haltbarkeit der Tasten auswirkt.
Nicht immer muß man teure vandalensichere Tasten verwenden.

von Thomas H. (Firma: CIA) (apostel13)


Lesenswert?

Elektrotiger schrieb:
> Hat jmd eine bereits gut funktionierende Lösung zum "parallelen"
> debouncing von Tasten ala Peter Dannegger für ARM programmiert?

Das Prinzip des Entprellen ist weder schwer noch kompliziert. Wer auf 
einem 32'Bitter rumbastelt sollte das eigentlich selber können. Vor 
allem wenn er offensichtlich schon einen funktionierenden Algorithmus 
vorliegen hat den er nur noch etwas anpassen muss.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Thomas H. schrieb:
> Wer auf einem 32'Bitter rumbastelt sollte das eigentlich selber können.

Nachdem es hier schon deutlich konkreter geworden war, was meinst du,
welche großartige „Hilfe“ dieser dein Beitrag für den TE wohl ist?

Eine derartige Antwort hätte ich ja vielleicht noch als erste Antwort
im Thread verstanden, aber zwei Tage und 25 Beiträge später ist sie
einfach nur Gelaber.

von Thomas H. (Firma: CIA) (apostel13)


Lesenswert?

Jörg W. schrieb:
> Eine derartige Antwort hätte ich ja vielleicht noch als erste Antwort
> im Thread verstanden, aber zwei Tage und 25 Beiträge später ist sie
> einfach nur Gelaber.

Selbstverständlich ist und war die "Antwort" provokativ gemeint, ob am 
Anfang, oder zum aktuellen Zeitpunkt. Und auch nach der ganzen 
Diskussion sehe ich immer noch kein Problem in dem Entprellen. Das 
Prinzip ist und bleibt simpel. AFS und verteilte Pin's hin und her. Die 
Provokation geht in die Richtung, dessen was ich hier ständig beobachte. 
Die Leute verlernen heutzutage das eigenständige Denken und Problem 
lösen. Selbst beim lösen schulischer oder universitärer Aufgabenstellung 
wird das verwenden bereits vorhandener Lösungen oder der Gehirnschmalz 
anderer bevorzugt anstatt sich selbst mal mit einem Blatt Papier einem 
Bleistift und vielen Stunden Ruhe hinzusetzen und das Problem selber 
aufzurollen.  Das mag auch der Grund sein, warum es eine Menge 
kommerzieller Geräte am Markt gibt in denen das mit dem Entprellen nicht 
richtig funktioniert.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Thomas H. schrieb:
> Das Prinzip ist und bleibt simpel.

Trotzdem steckt der Teufel eben manchmal im Detail, und es ist
durchaus sinnvoll, eine vorhandene und gut erprobte Lösung zu
verstehen und dann zu verwenden, statt das Fahrrad jedesmal neu
zu erfinden und dabei die Fehler, die andere in der Vergangenheit
gemacht haben, alle nochmal zu durchlaufen.

Eine Taylor-Reihe ist auch simpel, trotzdem implementierst du dir
deine Winkelfunktionen sicherlich nicht jedesmal neu, oder?

Klar hat der TE anfangs eine gewisse Faulheit an den Tag gelegt, aber
seine späteren Beiträge zeigen, dass er zumindest versucht hat, da
mitzudenken.  Ich hoffe, dass er nun die Denkpause seit gestern nutzt,
um vielleicht endlich auch noch bitweise Logik zu verstehen. ;-)

von Elektrotiger (Gast)


Lesenswert?

Ich weiß nicht warum hier so viele auf den Algorithmus eingehen.
Vielleicht habe ich mich auch falsch ausgedrückt.

Meine Problematik war und ist es immmer noch die saubere Implementierung 
in ein 32Bit µC. Das erscheint mir noch peinlicher als den Algorithmus 
nicht zu verstehen.

Leider weiß ich jetzt nicht mals genau wo ich was falsch denke :/.
Hier meine Implementierung, die leider nicht funktioniert, es wird 
einfach kein Tastendruck wahrgenommen.
1
#include <asf.h>
2
#include <string.h>
3
4
#define LED0          IOPORT_CREATE_PIN(PIOA, 25)
5
#define LED_RED1        IOPORT_CREATE_PIN(PIOD, 17)
6
#define LED_RED2        IOPORT_CREATE_PIN(PIOD, 28)
7
#define LED_YELLOW1        IOPORT_CREATE_PIN(PIOD, 20)
8
#define LED_YELLOW2        IOPORT_CREATE_PIN(PIOE, 1)
9
#define LED_YELLOW3        IOPORT_CREATE_PIN(PIOA, 3)
10
#define LED_GREEN1        IOPORT_CREATE_PIN(PIOA, 5)
11
#define LED_GREEN2        IOPORT_CREATE_PIN(PIOD, 30)
12
#define LED_GREEN3        IOPORT_CREATE_PIN(PIOA, 12)
13
14
#define BUTTON_LEFT        IOPORT_CREATE_PIN(PIOA, 11)
15
#define BUTTON_LEFT_MASK    PIO_PA11
16
#define BUTTON_LEFT_ID      ID_PIOA
17
18
#define BUTTON_RIGHT      IOPORT_CREATE_PIN(PIOA, 16)
19
#define BUTTON_RIGHT_ATTR    (PIO_DEBOUNCE | PIO_IT_RISE_EDGE)
20
#define BUTTON_LEFT_ID      ID_PIOA
21
#define BUTTON_RIGHT_MASK    PIO_PA16
22
23
#define BUTTON_UP        IOPORT_CREATE_PIN(PIOD, 25)
24
#define BUTTON_UP_MASK      PIO_PD25
25
#define BUTTON_UP_ID      ID_PIOD
26
27
#define BUTTON_DOWN        IOPORT_CREATE_PIN(PIOA, 15)
28
#define BUTTON_DOWN_MASK    PIO_PA15
29
#define BUTTON_DOWN_ID      ID_PIOA
30
31
#define BUTTON_01        IOPORT_CREATE_PIN(PIOA, 22)
32
#define BUTTON_01_ATTR      (PIO_IT_RISE_EDGE)
33
#define BUTTON_01_MASK      PIO_PA22
34
#define BUTTON_01_ID      ID_PIOA
35
36
#define BUTTON_02        IOPORT_CREATE_PIN(PIOA, 21)
37
#define BUTTON_02_MASK      PIO_PA21
38
#define BUTTON_02_ID      ID_PIOA
39
40
#define BUTTON_03        IOPORT_CREATE_PIN(PIOA, 24)
41
#define BUTTON_03_MASK      PIO_PA24
42
#define BUTTON_03_ID      ID_PIOA
43
44
#define BUTTON_MID        IOPORT_CREATE_PIN(PIOA, 4)
45
#define BUTTON_MID_MASK      PIO_PA4
46
#define BUTTON_MID_ID      ID_PIOA
47
48
#define DEBOUNCE_THRESHOLD    50  // in ms
49
50
#define REPEAT_START      50  // after 500ms
51
#define REPEAT_NEXT        20  // every 200ms    
52
53
54
static const uint8_t dirOut = 1;  // Output
55
static const uint8_t dirIn = 0;    // Input
56
static uint8_t outputs[] = {LED0, LED_RED1, LED_RED2, LED_YELLOW1, LED_YELLOW2, LED_YELLOW3, LED_GREEN1,
57
              LED_GREEN2, LED_GREEN3};
58
static uint8_t inputs[] = {BUTTON_LEFT, BUTTON_RIGHT, BUTTON_UP, BUTTON_DOWN, BUTTON_01, BUTTON_02,
59
               BUTTON_03, BUTTON_MID};
60
61
62
uint16_t milliseconds =0;
63
uint8_t ampel_element=255;
64
uint32_t freq_tc0;
65
66
/* ISR */
67
volatile uint32_t key_state, key_press, key_rpt;
68
uint32_t button_repeatmask, button_register;
69
70
void SysTick_Handler(void)
71
{
72
  if(milliseconds%10==0)
73
  {
74
    static uint32_t ct0, ct1, rpt;
75
    uint32_t i;
76
    i = key_state ^ ~ button_register;                       // key changed ?
77
    ct0 = ~( ct0 & i );                             // reset or count ct0
78
    ct1 = ct0 ^ (ct1 & i);                          // reset or count ct1
79
    i &= ct0 & ct1;                                 // count until roll over ?
80
    key_state ^= i;                                 // then toggle debounced state
81
    key_press |= key_state & i;                     // 0->1: key press detect
82
    
83
    if( (key_state & button_repeatmask) == 0 )            // check repeat function
84
    rpt = REPEAT_START;                          // start delay
85
    if( --rpt == 0 )
86
    {
87
      rpt = REPEAT_NEXT;                            // repeat delay
88
      key_rpt |= key_state & button_repeatmask;
89
    }
90
  }
91
  
92
  
93
  milliseconds++;
94
  if(milliseconds>=500)
95
  {
96
    milliseconds=1;
97
    ampel_element++;
98
    if(ampel_element >= sizeof(ampel)) ampel_element=0;
99
    ioport_toggle_pin_level(ampel[ampel_element]);
100
  }
101
}
102
103
uint32_t get_key_press(uint32_t key_mask)
104
{
105
  cpu_irq_enter_critical();
106
  key_mask &= key_press;
107
  key_press ^= key_mask;
108
  cpu_irq_leave_critical();
109
  return key_mask;
110
}
111
112
uint32_t get_key_rpt(uint32_t key_mask)
113
{
114
  cpu_irq_enter_critical();
115
  key_mask &= key_rpt;
116
  key_rpt ^= key_mask;
117
  cpu_irq_leave_critical();
118
  return key_mask;
119
}
120
121
uint32_t get_key_state(uint32_t key_mask)
122
{
123
  key_mask &= key_state;
124
  return key_mask;
125
}
126
127
uint32_t get_key_long(uint32_t key_mask)
128
{
129
  return get_key_press( get_key_rpt(key_mask) );
130
}
131
132
int main (void)
133
{
134
  button_register = (PIOA->PIO_PDSR & (PIO_PA4 | PIO_PA11 | PIO_PA15 | PIO_PA16 | PIO_PA21 | PIO_PA22 | PIO_PA24)) |(PIOD->PIO_PDSR & PIO_PD25);
135
       ioport_init();
136
  wdt_disable(WDT);  // Disable Watchdog
137
  
138
  for(uint8_t i=0; i<sizeof(inputs); i++)
139
  {
140
    ioport_set_pin_dir(inputs[i], IOPORT_DIR_INPUT);
141
    //ioport_set_pin_mode(inputs[i], IOPORT_MODE_PULLUP);
142
  }
143
  for(uint8_t i=0; i<sizeof(outputs); i++)      ioport_set_pin_dir(outputs[i], IOPORT_DIR_OUTPUT);
144
  
145
  sysclk_init();
146
  SysTick_Config(sysclk_get_cpu_hz()/1000); // every ms or 0,96ms ?
147
while(1)                                                                                                                                                                   
148
  {
149
    if( get_key_press(1 << ((PIOA->PIO_PDSR) & PIO_PA16)) || get_key_rpt(1 << ((PIOA->PIO_PDSR) & PIO_PA16)) )
150
    {
151
      ioport_set_pin_level(LED0, HIGH);
152
    }
153
    else ioport_set_pin_level(LED0, LOW);    
154
    //if(get_key_short(1 << ((PIOA->PIO_PDSR) & PIO_PA4))) ioport_toggle_pin_level(LED0);  
155
  }
156
  
157
}
Habe hoffentlich alles wichtige hier aus meinem Programm 
rausgeschnitten.

button_register entspricht KEY_PIN, button_repeatmask dem REPEAT_MASK 
aus Peters Implementierung. Ich hätte gerne button_register vor der ISR 
zugewiesen, was allerdings zu Fehler führte, daher definiere ich es 
direkt am Anfang des Mainprogrammes.

W.S. schrieb:
> Ich sag dir, was ich mir dabei denke: Der Junge hat sein Problem nicht
> im Mindesten durchdacht und kommt erwiesenermaßen mit Peters
> Entprellroutinen nicht zu Potte

Die Problematik habe ich mir schon früher in AVR durchdacht gehabt. Hier 
bekomme ich die Anpassung einfach nicht hin. Wo möglich zu wenige C 
Kenntnisse.

W.S. schrieb:
> Geht es nicht ein wenig bescheidener, wenn man nix weiß
> und fragen muß?

? Beziehst Du Dich vll allgemein auf alle Nutzer hier und weniger auf 
mich? Ich sehe hier von meiner Seite aus keiner Provokation, bis auf 
meiner Reaktion auf Deinen mehr als unangenehmen Post und geprahlt habe 
ich erst recht nicht... wie auch wenn ich nicht mals einen Algorithmus 
richtig implementieren kann bzw einbinden kann :D......


Sorry für die späte Antwort, eine Hochzeit 800km ferne, ließ dies 
weniger zu...

von Elektrotiger (Gast)


Lesenswert?

1
  cpu_irq_enter_critical();
2
  key_mask &= key_press;
3
  key_press ^= key_mask;
4
  cpu_irq_leave_critical();
cli() wurde durch cpu_irq_enter_critical()
und sei() mit cpu_irq_leave_critical() ersetzt

von Thomas H. (Firma: CIA) (apostel13)


Lesenswert?

Warum lässt Du diesen bis zum letzten optimierten Algorhythmus nich mal 
außen vor und schreibst dir zum entprellen einfach fürs erste selbst 
eine Routine und im zweien Schritt gehst Du hin und versuchst dich damit 
einen nicht selbst erdachten und verstandenen komplexen Code auf eine 
andere Architektur anzupassen.

von Elektrotiger (Gast)


Lesenswert?

Thomas H. schrieb:
> Warum lässt Du diesen bis zum letzten optimierten Algorhythmus nich mal
> außen vor und schreibst dir zum entprellen einfach fürs erste selbst
> eine Routine

habe ich, die auch nicht funktioniert -.-... siehe oben zwischen Post:
1
void TC0_Handler(void)    // alle 10ms
2
{  
3
  for(uint16_t i=0; i<=sizeof(button_permission);i++)
4
  {
5
    if(debounce_status[i]>0) 
6
    {
7
      debounce_status[i]-=1;
8
      if((debounce_status[i]==0) && (button_level[i]==1))      // Gedrückthalten
9
      {
10
        debounce_status[i] = REPEAT_NEXT;
11
        button_permission[i] = 1;
12
        button_repeat[i] = 1;
13
      }
14
      else if((debounce_status[i]==0) && (button_level[i]==0))  // Taste nicht mehr gedrückt
15
      {
16
        button_permission[i] = 1;
17
        button_repeat[i]=0;
18
      }
19
    }    
20
    if(button_state[i] != button_level[i])
21
    {
22
      debounce_status[i] = REPEAT_START;      
23
    }
24
    button_state[i]=button_level[i];
25
  }
26
  
27
  tc0_status = 0;
28
  for(uint16_t i; i<=sizeof(button_permission); i++)
29
  {
30
    if(debounce_status[i]!=0) tc0_status++;
31
  }
32
  if(tc0_status==0) tc_disable_interrupt(TC0,0,TC_IER_CPCS);
33
  
34
  
35
  tc0_counts++;
36
  if(tc0_counts>=50)
37
  {
38
    tc0_counts=0;
39
    ioport_toggle_pin_level(LED0);
40
  }
41
  
42
  
43
  uint32_t dummy;
44
  dummy = tc_get_status(TC0,0);
45
  UNUSED(dummy);
46
  
47
  //ioport_toggle_pin_level(LED0);  
48
}

Des weiteren habe ich für AVR auch noch eine Implementierung von mir um 
nur eine Taste zu entprellen, welches funktioniert.

von Peter D. (peda)


Lesenswert?

Elektrotiger schrieb:
> int main (void)
> {
>   button_register = (PIOA->PIO_PDSR & (PIO_PA4 | PIO_PA11 | PIO_PA15 |
> PIO_PA16 | PIO_PA21 | PIO_PA22 | PIO_PA24)) |(PIOD->PIO_PDSR &
> PIO_PD25);

Im AVR-Code steht das Einlesen doch in der ISR.
Warum wohl?

Elektrotiger schrieb:
> if( get_key_press(1 << ((PIOA->PIO_PDSR) & PIO_PA16))

PIOA->PIO_PDSR ist aber keine Bitmaske.
Wozu definierst Du dann BUTTON_xx_MASK, wenn Du sie nicht benutzt?

: Bearbeitet durch User
von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Elektrotiger schrieb:
> button_register entspricht KEY_PIN

Klar.  Zu dem Zeitpunkt, da main() startet.  Danach werden die Pins
nie wieder eingelesen …

Ein bisschen solltest du schon verstehen, was bei deinem Controller
der physische Zugriff auf die Peripherie ist und was nur eine dumme
Variable, in der man sich was merken kann.

von Elektrotiger (Gast)


Lesenswert?

Danke, leider noch immer Fehler :/, funktioniert leider noch immer 
nicht.
1
void SysTick_Handler(void)
2
{
3
  if(milliseconds%10==0)
4
  {
5
    button_register = (PIOA->PIO_PDSR & (PIO_PA4 | PIO_PA11 | PIO_PA15 | PIO_PA16 | PIO_PA21 | PIO_PA22 | PIO_PA24)) |(PIOD->PIO_PDSR & PIO_PD25);
6
    static uint32_t ct0, ct1, rpt;
7
    uint32_t i;
8
    i = key_state ^ ~ button_register;                       // key changed ?
9
    ct0 = ~( ct0 & i );                             // reset or count ct0
10
    ct1 = ct0 ^ (ct1 & i);                          // reset or count ct1
11
    i &= ct0 & ct1;                                 // count until roll over ?
12
    key_state ^= i;                                 // then toggle debounced state
13
    key_press |= key_state & i;                     // 0->1: key press detect
14
    
15
    if( (key_state & button_repeatmask) == 0 )            // check repeat function
16
    rpt = REPEAT_START;                          // start delay
17
    if( --rpt == 0 )
18
    {
19
      rpt = REPEAT_NEXT;                            // repeat delay
20
      key_rpt |= key_state & button_repeatmask;
21
    }
22
  }
23
  
24
  
25
  milliseconds++;
26
  if(milliseconds>=500)
27
  {
28
    milliseconds=1;
29
    ampel_element++;
30
    if(ampel_element >= sizeof(ampel)) ampel_element=0;
31
    ioport_toggle_pin_level(ampel[ampel_element]);
32
  }
33
}
34
35
int main (void)
36
{
37
[...]
38
while(1)                                                                                                                                                                   
39
  {
40
    if((get_key_press(1 << BUTTON_RIGHT_MASK) ) || ( get_key_rpt(1 << BUTTON_RIGHT_MASK ) ) )
41
    {
42
      ioport_set_pin_level(LED0, HIGH);
43
    }
44
    else ioport_set_pin_level(LED0, LOW);    
45
    //if(get_key_short(1 << ((PIOA->PIO_PDSR) & PIO_PA4))) ioport_toggle_pin_level(LED0);  
46
  }
47
  
48
}

von Thomas H. (Firma: CIA) (apostel13)


Lesenswert?

Elektrotiger schrieb:
> Thomas H. schrieb:
> Warum lässt Du diesen bis zum letzten optimierten Algorhythmus nich mal
> außen vor und schreibst dir zum entprellen einfach fürs erste selbst
> eine Routine
>
> habe ich, die auch nicht funktioniert -.

Das ist genau was ich vermutet habe. Du hast deinen Controller noch 
nicht richtig im Griff. Das solltest Du aber zuerst einmal hinbekommen. 
Dann komplexe Dinge, dann fremden Code portieren.

von Peter D. (peda)


Lesenswert?

Elektrotiger schrieb:
> #define LED0          IOPORT_CREATE_PIN(PIOA, 25)
> ...
> static uint8_t outputs[] = {LED0,

Ich kenne das Macro nicht, geht das im Array überhaupt und was willst Du 
damit bezwecken?

Ich denke nicht, daß das Entprellen Dein vorrangiges Problem ist, 
sondern eher das Verständnis von C.
Schreib erstmal ein Programm, was einfach nur die Tasten auf die LEDs 
ausgibt.

von Elektrotiger (Gast)


Lesenswert?

Habe button_repeatmask noch nicht zugewiesen -.-'.
Diese müsste einfach einmal ganz am Anfang zu button_register zu 
gewiesen werden?
In AVR waren es die PINs, die wiederholt betrachtet werden sollen. Da 
wurde es per #define definiert.
Hier reicht es wenn ich es einmal vor bzw nach Systick definiere?

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Elektrotiger schrieb:
> 1 << BUTTON_RIGHT_MASK

Mannomann!  Was steht da rechts drin?

"MASK"

Warum zum Geier™ schiebst du die (Bit-)Maske denn dann nochmal durch
die Botanik?

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Elektrotiger schrieb:
> Diese müsste einfach einmal ganz am Anfang zu button_register zu
> gewiesen werden?

Das button_register brauchst du nicht global.  Das ist eine
Zwischenvariable, die in die ISR gehört.

> In AVR waren es die PINs, die wiederholt betrachtet werden sollen. Da
> wurde es per #define definiert.

Warum willst du sie hier nicht einfach auch per #define festlegen?

Aber Thomas Holmes hat schon recht: du solltest erstmal mit deutlich
kleineren Brötchen anfangen.  Spiegele den Zustand einer der Tasten
in einer Endlosschleife auf eine der LEDs.  Vielleicht verstehst du
ja damit besser, wie die PIO des SAM4 so „tickt“, als durch trial &
error.

Eigentlich solltest du den ASF-Krempel gleich noch mit entsorgen, denn
der scheint dem Verständnis des Controllers alles andere als förderlich
zu sein.  Am Ende ist es sowieso nur eine umständliche Variante, um
über viele viele Schichten ein paar Bits in Steuerregistern zu
modifizieren.

von Elektrotiger (Gast)


Lesenswert?

Peter D. schrieb:
> Elektrotiger schrieb:
>> #define LED0          IOPORT_CREATE_PIN(PIOA, 25)
>> ...
>> static uint8_t outputs[] = {LED0,
>
> Ich kenne das Macro nicht, geht das im Array überhaupt und was willst Du
> damit bezwecken?

Dies ist aus der ASF von Atmel. Das Array war nur dazu da um alle 
Eingangs- bzw Ausgangspins über eine Schleife zu definieren:
1
  for(uint8_t i=0; i<sizeof(inputs); i++)
2
  {
3
    ioport_set_pin_dir(inputs[i], IOPORT_DIR_INPUT);
4
    //ioport_set_pin_mode(inputs[i], IOPORT_MODE_PULLUP);
5
  }
6
  for(uint8_t i=0; i<sizeof(outputs); i++) ioport_set_pin_dir(outputs[i], IOPORT_DIR_OUTPUT);

Peter D. schrieb:
> Schreib erstmal ein Programm, was einfach nur die Tasten auf die LEDs
> ausgibt.

Das ist mit der ASF relativ einfach.
1
  ioport_set_pin_level(LED0, ioport_get_pin_level(BUTTON_LEFT));
Die Verknüpfung hier mit dem fertigen ASF mit AVR... die ist mein 
Problem.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Elektrotiger schrieb:
> Das ist mit der ASF relativ einfach.

Genau.  Nur, dass du anschließend nach wie vor immer noch nicht
weißt, was du tust.

Das ist wie, wenn du auf den Hinweis, erstmal geradeaus fliegen zu
lernen antortest: „Das ist mit dem Autopiloten ganz einfach.“

von Elektrotiger (Gast)


Lesenswert?

In AVR weise ich einfach über dem Port den Pin zu den ich High setzen 
möchte bzw das Bit wieder löschen möchte...
1
  if( get_key_short( 1<<KEY_unten))
2
  {
3
    LED_PORT ^= 1<<LED0;
4
    countdown = 500; // 5 Sekunden
5
  }
6
  if( get_key_long( 1<<KEY_unten))
7
  {
8
    LED_PORT ^= 1<<LED1;
9
    countdown = 500;
10
  }
 Aus meinem AVRtest Programm...

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Ja, beim SAM3/4 ist es halt ein wenig umständlicher.  Dessen PIO
hat zwar allen möglichen Furz und Feuerstein eingebaut (bis eben hin
zu einer Entprellung in Hardware, die dir am Ende doch bloß nicht
ausreicht), aber sie fühlt sich ansonsten deutlich wie aus dem
vorigen Jahrtausend an: ein Register zum Setzen von Pins, eins zum
Löschen von Pins, den aktuellen Status liest man aus einem dritten
Register aus …

Kommt hinzu, dass du dich an dieses blöde „Ich muss mir meine Bitmaske
selbst erstellen“-Konzept des AVR (1<<KEY_unten) so sehr gewöhnt hast,
dass du das nun krampfhaft auf alles andere anwenden willst.  PIO_PA11
auf dem SAM4 ist aber bereits eine Bitmaske.  (Hätte man auch auf dem
AVR besser so definieren sollen, und dann den Assembler die Maske in
eine Bitnummer rückrechnen lassen für das bisschen SBI/CBI, aber das
haben sie halt beim AVR seinerzeit versaubeutelt, und stattdessen
Generationen von Programmierern mit diesem 1<< sich herumärgern lassen.)

Du musst dir einfach mal aus den zugehörigen Headerfiles die
lowlevel-Details ansehen, wenn du lowlevel-Funktionalität implementieren
willst, wie es die Tastenentprellung nun einmal ist.

von Karl H. (kbuchegg)


Lesenswert?

Und ich würde fürs erste auch empfehlen nicht gleich in die vollen zu 
gehen, sondern

1 Taste, 1 LED


in deinem ganzen Code-gewusel sieht man ja vor lauter 'gleichzeitig alle 
Pins bedienen'-Wollen gar nicht mehr, was du da alles eigentlich tust.

von Karl H. (kbuchegg)


Lesenswert?

Elektrotiger schrieb:

> Das ist mit der ASF relativ einfach.
>
1
  ioport_set_pin_level(LED0, ioport_get_pin_level(BUTTON_LEFT));
> Die Verknüpfung hier mit dem fertigen ASF mit AVR... die ist mein
> Problem.

Das glaub ich nicht, Tim.
Dein Problem ist, dass du nicht eine Zuordnung von gedrückter Taste zu 
LED-Leuchten machen willst, sondern die Zurodnung "1 Tastendruck -> 
Umschalten des Zustandes der LED".
Denn dazu, und nur dazu brauchst du eine Entprellung. Solange die LED 
leuchten soll, solange der Benutzer auf der Taste eingeschlafen ist, 
solange brauchst du auch keine Entprellung. Und dann reicht auch die ASF 
Lösung.

Also stell dich nicht dümmer als du bist und vertrau auf das, was dir 
erfahrene Programmierer raten.

: Bearbeitet durch User
von Elektrotiger (Gast)


Lesenswert?

Jörg W. schrieb:
> Kommt hinzu, dass du dich an dieses blöde „Ich muss mir meine Bitmaske
> selbst erstellen“-Konzept des AVR (1<<KEY_unten) so sehr gewöhnt hast,
> dass du das nun krampfhaft auf alles andere anwenden willst.  PIO_PA11
> auf dem SAM4 ist aber bereits eine Bitmaske.

Goldrichtig. Ich hatte gehofft mit den lowlevel-details aus AVR direkt 
auf ARM anwenden zu können oder sogar mit Hilfe der ASF die 
lowlevel-details komplett umgehen zukönnen indem ich nur die Pins 
zuweise...
Aber dem ist wohl leider nicht so.

Eine gründliche Entprellung ist zwingend notwendig um wie bei meinem AVR 
µC später via Tasten Signale mittels Display zu steuern und ein zu 
stellen.
Mittels Tasten wird ein Menü gesteuert. Zähler beim gedrückthalten 
hochgezählt usw...
Dazu ist die Entprellung über ASF einfach zu schlecht.

Danke für die Ratschläge und Mühen. Ich werde mich erst mal auf die 
Lowprogrammierung des ARMs einlassen und mich später wohl nochmal 
melden.
1
void SysTick_Handler(void)
2
{
3
  if(milliseconds%10==0)
4
  {
5
    uint32_t button_repeatmask, button_register;
6
    button_register = (PIOA->PIO_PDSR & (PIO_PA4 | PIO_PA11 | PIO_PA15 | PIO_PA16 | PIO_PA21 | PIO_PA22 | PIO_PA24)) |(PIOD->PIO_PDSR & PIO_PD25);
7
    static uint32_t ct0, ct1, rpt;
8
    uint32_t i;
9
    i = key_state ^ ~ button_register;                       // key changed ?
10
    ct0 = ~( ct0 & i );                             // reset or count ct0
11
    ct1 = ct0 ^ (ct1 & i);                          // reset or count ct1
12
    i &= ct0 & ct1;                                 // count until roll over ?
13
    key_state ^= i;                                 // then toggle debounced state
14
    key_press |= key_state & i;                     // 0->1: key press detect
15
    
16
    if( (key_state & button_repeatmask) == 0 )            // check repeat function
17
    rpt = REPEAT_START;                          // start delay
18
    if( --rpt == 0 )
19
    {
20
      rpt = REPEAT_NEXT;                            // repeat delay
21
      key_rpt |= key_state & button_repeatmask;
22
    }
23
  }
24
  
25
  
26
  milliseconds++;
27
  if(milliseconds>=500)
28
  {
29
    milliseconds=1;
30
    ampel_element++;
31
    if(ampel_element >= sizeof(ampel)) ampel_element=0;
32
    ioport_toggle_pin_level(ampel[ampel_element]);
33
  }
34
} [...]
35
36
int main (void)
37
{
38
39
  ioport_init();
40
  wdt_disable(WDT);  // Disable Watchdog
41
  
42
  for(uint8_t i=0; i<sizeof(inputs); i++)
43
  {
44
    ioport_set_pin_dir(inputs[i], IOPORT_DIR_INPUT);
45
    //ioport_set_pin_mode(inputs[i], IOPORT_MODE_PULLUP);
46
  }
47
  for(uint8_t i=0; i<sizeof(outputs); i++) ioport_set_pin_dir(outputs[i], IOPORT_DIR_OUTPUT);
48
  
49
  sysclk_init();
50
  SysTick_Config(sysclk_get_cpu_hz()/1000); // every ms or 0,96ms ?
51
while(1)                                                                                                                                                                   
52
  {
53
    if((get_key_press(BUTTON_RIGHT_MASK) ) || ( get_key_rpt(BUTTON_RIGHT_MASK) ) )
54
    {
55
      ioport_set_pin_level(LED0, HIGH);
56
    }
57
    else ioport_set_pin_level(LED0, LOW);    
58
    //if(get_key_short(1 << ((PIOA->PIO_PDSR) & PIO_PA4))) ioport_toggle_pin_level(LED0);  
59
  }
60
  ioport_set_pin_level(LED0, ioport_get_pin_level(BUTTON_LEFT));
61
}

Wer noch Nerv hat mir hier weiter zuhelfen, darf natürlich hier 
posten^^, Code funktioniert noch nicht.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Elektrotiger schrieb:
> uint32_t button_repeatmask, button_register;
>     button_register = (PIOA->PIO_PDSR & (PIO_PA4 | PIO_PA11 | PIO_PA15 |
> PIO_PA16 | PIO_PA21 | PIO_PA22 | PIO_PA24)) |(PIOD->PIO_PDSR &
> PIO_PD25);

Jetzt hast du aber das Kind mit dem Bade ausgeschüttet.

Bekommst du keine Warnung vom Compiler dafür, dass du eine
button_repeatmask benutzt, obwohl du ihr nichts zugewiesen hast
und sie eine auto-Variable ist?

Versuch doch erstmal alles (wie Karl Heinz schon schrieb) mit einer
Taste, ohne Auto-Repeat, und einer LED.

von Karl H. (kbuchegg)


Lesenswert?

Jörg W. schrieb:

> Versuch doch erstmal alles (wie Karl Heinz schon schrieb) mit /einer/
> Taste, ohne Auto-Repeat, und einer LED.

Das Konzept, Problemstellung erst einmal so zu vereinfachen (ohne 
Beschränkung der Allgemeinheit, wie die Mathematiker sagen würden), dass 
man es auch stemmen kann und sich mit dem Prinzip vertraut macht, 
scheint immer mehr aus der Mode zu kommen.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Karl H. schrieb:
> Das Konzept, […]
> scheint immer mehr aus der Mode zu kommen.

Nö, auch dahin, dass dieses Konzept eine sinnvolle Vorgehensweise ist,
muss man halt per Erkenntnisprozess hinkommen. :)

von Elektrotiger (Gast)


Lesenswert?

Jörg W. schrieb:
> Bekommst du keine Warnung vom Compiler dafür, dass du eine
> button_repeatmask benutzt, obwohl du ihr nichts zugewiesen hast
> und sie eine auto-Variable ist?

Das ist das Problem wenn ich zu viele Funktionen in einem Prgramm habe 
und gerade nicht nutze... da werden die Warnungen wegen unbenutzte 
Funktionen ignoriert...
Da ich zu nächst alle Button als Repeatbutton nutzen möchte habe ich nun 
in der isr dies hinzugefügt:
1
void SysTick_Handler(void)
2
{
3
  if(milliseconds%10==0)
4
  {
5
    uint32_t button_repeatmask, button_register;
6
    button_register = (PIOA->PIO_PDSR & (PIO_PA4 | PIO_PA11 | PIO_PA15 | PIO_PA16 | PIO_PA21 | PIO_PA22 | PIO_PA24)) |(PIOD->PIO_PDSR & PIO_PD25);
7
    button_repeatmask = button_register;
8
    static uint32_t ct0, ct1, rpt;
9
    uint32_t i;
10
    i = key_state ^ ~ button_register;                       // key changed ?
11
    ct0 = ~( ct0 & i );                             // reset or count ct0
12
    ct1 = ct0 ^ (ct1 & i);                          // reset or count ct1
13
    i &= ct0 & ct1;                                 // count until roll over ?
14
    key_state ^= i;                                 // then toggle debounced state
15
    key_press |= key_state & i;                     // 0->1: key press detect
16
    
17
    if( (key_state & button_repeatmask) == 0 )            // check repeat function
18
    rpt = REPEAT_START;                          // start delay
19
    if( --rpt == 0 )
20
    {
21
      rpt = REPEAT_NEXT;                            // repeat delay
22
      key_rpt |= key_state & button_repeatmask;
23
    }
24
  }
25
}

von Karl H. (kbuchegg)


Lesenswert?

Das hier
1
    if((get_key_press(BUTTON_RIGHT_MASK) ) || ( get_key_rpt(BUTTON_RIGHT_MASK) ) )
2
    {
3
      ioport_set_pin_level(LED0, HIGH);
4
    }
5
    else ioport_set_pin_level(LED0, LOW);

zeugt übrigens auch davon, dass da schon in der AVR Version so einiges 
nicht verstanden wurde.

von Karl H. (kbuchegg)


Lesenswert?

Elektrotiger schrieb:

> Das ist das Problem wenn ich zu viele Funktionen in einem Prgramm habe
> und gerade nicht nutze... da werden die Warnungen wegen unbenutzte
> Funktionen ignoriert...

Dann schmeiss sie raus!

Es ist sowieso ein Unsinn zu denken, man könne gerade als Anfänger 
Funktion an Funktion heften und das würde auf Anhieb funktionieren.

Programme werden schrittweise entwickelt.
Man beginnt mit einer leeren main() und arbeitet sich einen Schritt nach 
dem anderen vor.
Nur Anfänger kopieren ihren Code aus dem vorhergehenden Projekt und 
denken, dass sie mit ein paar geringfügigen Änderungen ein vollkommen 
neues Programm schreiben könnten. Aber alles was jetzt zur Zeit im Code 
steht ist unantastbar und bleibt dort stehen - ob es wer braucht oder 
nicht.


>     button_repeatmask = button_register;

nein.

In der Variablen button_repeatmask steht genaus wie in der AVR Version 
eine Bitmaske, die angibt, für welche Buttons überhaupt ein Repeat 
durchgeführt werden soll. Für eine Taste 'Links' kann ein Autorepeat 
sinnvoll sein, für eine Taste 'Enter' aber mglw. nicht. Genau das will 
man einstellen können.
Das ist aber eine Vorgabe und hat nichts damit zu tun, welche Buttons 
aktuell zur Zeit jetzt gerade hedrückt oder nicht gedrückt sind.

Wenn du nichts anderes hast, dann setz die Variable einfach auf 0. Dann 
ist erst mal für keine einzige Taste ein möglicher Repeat aktiviert.

: Bearbeitet durch User
von Elektrotiger (Gast)


Lesenswert?

PIO haben diverse Attribute hier die wohl vorerst wichtigen:
PIO_ELSR : Edge/LvL Status Register
PIO_LSR : Level Select Register
PIO_PDSR : Pin Data Status Register
PIO_PSR: PIO Status Register

PIO_OER: Output Enable Register
PIO_ODR: Output Disable Register
PIO_OWER: Output Write Enable

Nun will/soll ich eine LED ohne ASF ansteuern, als Kommentar wäre 
jeweils der Code von der ASF:
Habe Problem bei der Überlegung wie ich den Pegel der Rechten Taste 
abfrage. mit PIOA->PIO_LSR habe ich das Level Register von PIOA, davon 
will ich nur den Pin von Butten_Right, daher habe ich das Logische und 
Verknüpft... Ist wohl so falsch, da es nicht klappt^^.
1
#include <asf.h>
2
#include <string.h>
3
4
// #define IOPORT_CREATE_PIN(port, pin) ((IOPORT_ ## port) * 32 + (pin))
5
6
#define LED0          IOPORT_CREATE_PIN(PIOA, 25)
7
#define LED0_MASK        PIO_PA25
8
#define BUTTON_RIGHT      IOPORT_CREATE_PIN(PIOA, 16)
9
#define BUTTON_RIGHT_MASK    PIO_PA16
10
11
  PIOA->PIO_OER = LED0_MASK;  
12
  PIOA->PIO_ODR = BUTTON_RIGHT_MASK;
13
  PIOA->PIO_OWER = LED0_MASK;
14
  PIOA->PIO_OWER = BUTTON_RIGHT_MASK;
15
  //ioport_set_pin_dir(LED0, IOPORT_DIR_OUTPUT);
16
  //ioport_set_pin_dir(BUTTON_RIGHT, IOPORT_DIR_INPUT);
17
18
int main (void)
19
{
20
  ioport_init();
21
  wdt_disable(WDT);  // Disable Watchdog  
22
23
    PIOA->PIO_OER = LED0_MASK;  
24
  PIOA->PIO_ODR = BUTTON_RIGHT_MASK;
25
  PIOA->PIO_OWER = LED0_MASK;
26
  PIOA->PIO_OWER = BUTTON_RIGHT_MASK;
27
  //ioport_set_pin_dir(LED0, IOPORT_DIR_OUTPUT);
28
  //ioport_set_pin_dir(BUTTON_RIGHT, IOPORT_DIR_INPUT);
29
  
30
  while(1)                                                                                                                                                                   
31
  {
32
    if(PIOA->PIO_LSR & BUTTON_RIGHT_MASK) PIOA->PIO_LSR |= LED0_MASK;
33
    else PIOA->PIO_LSR &= ~ LED0_MASK;
34
    //ioport_set_pin_level(LED0, ioport_get_pin_level(BUTTON_RIGHT));
35
  }  
36
}

von Elektrotiger (Gast)


Lesenswert?

PIO_SODR: Set Ouput Date Regiser
PIO_CODR: Clear Data Register

Register schon mal falsch.... die Überprüfung wohl weiterhin
1
  while(1)                                                                                                                                                                   
2
  {
3
    if(PIOA->PIO_LSR & BUTTON_RIGHT_MASK) PIOA->PIO_SODR = LED0_MASK;
4
    else PIOA->PIO_CODR = LED0_MASK;
5
    //ioport_set_pin_level(LED0, ioport_get_pin_level(BUTTON_RIGHT));
6
  }

von Elektrotiger (Gast)


Lesenswert?

1
  while(1)                                                                                                                                                                   
2
  {
3
    if(PIOA->PIO_PDSR & BUTTON_RIGHT_MASK) PIOA->PIO_SODR = LED0_MASK;
4
    else PIOA->PIO_CODR = LED0_MASK;
5
    //ioport_set_pin_level(LED0, ioport_get_pin_level(BUTTON_RIGHT));
6
  }
Läuft endlich :D....
Verstehe nun was Ihr meint, mit war das mit den ganzen Registern nicht 
bewusst. DANKE! :)

von Elektrotiger (Gast)


Lesenswert?

So jetzt könnte ich erst selbst eine Taste nochmal entprellen... oder 
versuche Peters Algorithmus jetzt zu benutzen...
1
  
2
main:
3
  ioport_init();
4
  wdt_disable(WDT);  // Disable Watchdog
5
  sysclk_init();
6
  SysTick_Config(sysclk_get_cpu_hz()/1000); // every ms or 0,96ms ?
7
while(1)                                                                                                                                                                   
8
  {
9
    /*if(PIOA->PIO_PDSR & BUTTON_RIGHT_MASK) PIOA->PIO_SODR = LED0_MASK;
10
    else PIOA->PIO_CODR = LED0_MASK;*/
11
    //ioport_set_pin_level(LED0, ioport_get_pin_level(BUTTON_RIGHT));
12
    
13
    if(get_key_press(PIOA->PIO_PDSR & BUTTON_RIGHT) || get_key_rpt(PIOA->PIO_PDSR & BUTTON_RIGHT))
14
    {
15
      PIOA->PIO_SODR = LED0_MASK;
16
    }
17
    else PIOA->PIO_CODR = LED0_MASK;
18
  }
 Geht nicht... müsste aber wohl noch die ISR falsch sein :/.
1
void SysTick_Handler(void)
2
{
3
  if(milliseconds%10==0)
4
  {
5
    button_register = (PIOA->PIO_PDSR & (PIO_PA4 | PIO_PA11 | PIO_PA15 | PIO_PA16 | PIO_PA21 | PIO_PA22 | PIO_PA24)) |(PIOD->PIO_PDSR & PIO_PD25);
6
    button_repeatmask = button_register;
7
    static uint32_t ct0, ct1, rpt;
8
    uint32_t i;
9
    i = key_state ^ ~ button_register;                       // key changed ?
10
    ct0 = ~( ct0 & i );                             // reset or count ct0
11
    ct1 = ct0 ^ (ct1 & i);                          // reset or count ct1
12
    i &= ct0 & ct1;                                 // count until roll over ?
13
    key_state ^= i;                                 // then toggle debounced state
14
    key_press |= key_state & i;                     // 0->1: key press detect
15
    
16
    if( (key_state & button_repeatmask) == 0 )            // check repeat function
17
    rpt = REPEAT_START;                          // start delay
18
    if( --rpt == 0 )
19
    {
20
      rpt = REPEAT_NEXT;                            // repeat delay
21
      key_rpt |= key_state & button_repeatmask;
22
    }
23
  }
24
  
25
  
26
  milliseconds++;
27
  if(milliseconds>=500)
28
  {
29
30
    milliseconds=1;
31
    ampel_element++;
32
    if(ampel_element >= sizeof(ampel)) ampel_element=0;
33
    ioport_toggle_pin_level(ampel[ampel_element]);
34
  }
35
}
36
37
uint32_t get_key_press(uint32_t key_mask)
38
{
39
  cpu_irq_enter_critical();
40
  key_mask &= key_press;
41
  key_press ^= key_mask;
42
  cpu_irq_leave_critical();
43
  return key_mask;
44
}
45
46
uint32_t get_key_rpt(uint32_t key_mask)
47
{
48
  cpu_irq_enter_critical();
49
  key_mask &= key_rpt;
50
  key_rpt ^= key_mask;
51
  cpu_irq_leave_critical();
52
  return key_mask;
53
}

von Karl H. (kbuchegg)


Lesenswert?

Oh mann

Was ist hier
1
    if(get_key_press(PIOA->PIO_PDSR & BUTTON_RIGHT) || get_key_rpt(PIOA->PIO_PDSR & BUTTON_RIGHT))
2
                     *****************************

wohl falsch.

Mich beschleicht schön langsam das Gefühl, wir sind hier an einem Punkt 
angelangt, an dem du nur noch im Forum nachfragst und nicht mehr 
eigenständig erst mal deinen Code kritisch unter die Lupe nimmst.

: Bearbeitet durch User
von Elektrotiger (Gast)


Lesenswert?

Sorry, das muss natürlich die Mask sein, so wie es dadrüber auch 
stand......

Karl H. schrieb:
> Mich beschleicht schön langsam das Gefühl, wir sind hier an einem Punkt
> angelangt, an dem du nur noch im Forum nachfragst und nicht mehr
> eigenständig erst mal deinen Code kritisch unter die Lupe nimmst.

Ja und nein, ich hatte gehofft dass sich jetzt alle Knoten lösen...
Tuts aber nicht.

von Karl H. (kbuchegg)


Lesenswert?

Auch wird das
1
    if(get_key_press( .... ) )
2
    {
3
      PIOA->PIO_SODR = LED0_MASK;
4
    }
5
    else PIOA->PIO_CODR = LED0_MASK;

nicht funktionieren.

Dir scheint nicht klar zu sein, dass diese Tastenerkennung und 
Entprellung deine Tasten insofern überwacht, dass sie einen Tasten-DRUCK 
erkennt. Also das einmalige Ereignis des Niederdrückens einer Taste. 
Genau das macht der Teil in der ISR. Er wertet den aktuellen Zustand der 
Portpins aus und hinterlässt sich in der Variablen key_press die 
Information, dass eine Taste niedergedrückt wurde.
Die Funktion get_keypress macht nichts anderes als in dieser Variablen 
nachzusehen, ob ein derartiges Niederdrück-Ereignis registriert wurde 
oder nicht. Wenn ja, dann meldet sie das und löscht gleichzeitig dieses 
Ereignis.

Das heisst: im Endeffekt läuft es darauf hinaus, dass nach dem der 
Benutzer eine Taste gedrückt hat, get_keypress genau 1 mal TRUE zurück 
liefert und ansonsten immer FALSE. Perfekt, wenn man mit einem 
Tastendruck eine Aktion einmalig auslösen will.

In deinem Fall schaltest du eine LED ein. Aber ein paar Hunderstel-µs 
später ist dieser Tastendruck dann eben auch schon wieder Geschichte, 
get_keypress wird FALSE liefern und die LED wird in deinem Code gleich 
wieder ausgeschaltet. Fazit: die LED wird ein paar Hunderstel oder 
Zehntel µs lang brennen, d.h. eigentlich mehr kurz aufflackern. Viel zu 
kurz, als das du das sehen kannst. Ok, wenn es sehr dunkel ist, du 
konzentriert direkt in die LED siehst, dann kannst du möglicherweise 
erahnen, dass da ein kurzes Aufleuchten war, aber so richtig bewusst 
wirst du das eher nicht sehen können.

von Elektrotiger (Gast)


Lesenswert?

Karl H. schrieb im Beitrag #4291597:
> get_keypress genau 1 mal TRUE zurück
> liefert und ansonsten immer FALSE. Perfekt, wenn man mit einem
> Tastendruck eine Aktion einmalig auslösen will.

Stimmt, daher wird diese auch mit dem get_key_rpt mit oder Verknüpft. So 
müsste zumindest die LED so lange leuchten bis ich die Taste wieder 
loslasse.... theoretisch... wenns fehlerfrei wäre -.-

von Karl H. (kbuchegg)


Lesenswert?

Elektrotiger schrieb:
> Karl H. schrieb im Beitrag #4291597:
>> get_keypress genau 1 mal TRUE zurück
>> liefert und ansonsten immer FALSE. Perfekt, wenn man mit einem
>> Tastendruck eine Aktion einmalig auslösen will.
>
> Stimmt, daher wird diese auch mit dem get_key_rpt mit oder Verknüpft. So
> müsste zumindest die LED so lange leuchten bis ich die Taste wieder
> loslasse.... theoretisch... wenns fehlerfrei wäre -.-

Nein.
Dann leuchtet deine LED im Abstand von ein paar Zehntel Sekunden immer 
noch nicht länger als ein paar Hundertsel-µs auf. Immer noch zu kurz. 
Das ist noch nicht mal ein Glimmen der LED.
Denn: einen Autorepeat stellt man sinnvollerweise ja so ein, dass er 
einem einigermassen flott tippendem Menschen entspricht. Wenn du auf 
deiner Tastatur auf einer Taste drauf bleibst, dann generiert deine 
Tastatur ja auch nicht in 1 Sekunde 2 Millionen Tastendrücke sondern 
höchstens 'ein paar'.

Warum schaltest du nicht einfach die LED jedesmal in den andern Zustand, 
wenn get_key_press TRUE liefert? Oder du benutzt 2 Tasten. Mit der einen 
wird eingeschaltet, mit der anderen ausgeschaltet.
Dann brauchen wir hier diese Diskussion überhaupt nicht führen.

Fazit: Auch das Generieren von Testcode um eine Funktionaität zu testen, 
will gelernt und überlegt sein.

: Bearbeitet durch User
von Elektrotiger (Gast)


Lesenswert?

Karl H. schrieb:
> Denn: einen Autorepeat stellt man sinnvollerweise ja so ein, dass er
> einem einigermassen flott tippendem Menschen entspricht. Wenn du auf
> deiner Tastatur auf einer Taste drauf bleibst, dann generiert deine
> Tastatur ja auch nicht in 1 Sekunde 2 Millionen Tastendrücke sondern
> höchstens 'ein paar'.

Stimmt, hatte damals meine Ampel bei jedem Repeattimerreset getoggelt...
oder hier counter hochgezählt:
1
else if(get_key_rpt(1<<KEY_links))
2
  {
3
    *pcountdown = 500; // 5 Sekunden
4
    flag_countdown=1;
5
    flag_firstcount=1;  // Erstmaliges Drücken
6
    
7
    if(pulsdauer<0)pulsdauer=0;
8
    else if(pulsdauer%1000==0)
9
    {
10
      pulsdauer-=1000;
11
    }
12
    else if(pulsdauer%100==0)
13
    {
14
      pulsdauer-=100;
15
    }
16
    else if(pulsdauer%10==0)
17
    {
18
      pulsdauer-=10;
19
    }
20
    else
21
    {
22
      pulsdauer--;
23
    }
24
.......

Fazit von meiner Seite aus:
Erst mal vielen, VIELEN Dank für alle Poster. Habt mein Verständnis zu 
ARM schon mal einen Boden gegeben um dort nun aufzubauen.
Es ist mir sehr peinlich..., aber ich musste es mal verstehen :/. Es 
gibt leider zu ARM µC kaum Tutorials, die ASF Atmel sind dafür richtig 
mies. Haben mich nicht sehr verwirrt.

Ich habe jedenfalls viel gelernt und bedanke mich noch für Eure Geduld.
Entprellung funktioniert. Topic somit abgeschlossen.

Da ARM noch "relativ" neu sind gegenüber AVR wären eventuell mehr 
Tutorial dazu sehr hilfreich. Zu AVR gab es genügend hier auf 
mikrocontroller.net und auch um Netz, vll kann man da was erweitern?

von Elektrotiger (Gast)


Lesenswert?

Elektrotiger schrieb:
> Haben mich nicht sehr verwirrt.

*Haben mich sehr verwirrt.
Wird Zeit, dass ich mich hier registriere :D...

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.