Forum: Mikrocontroller und Digitale Elektronik Universelle Tastenabfrage nach PeDa in AVR Assembler


von Bernd S. (Firma: Anscheinend Corner-Cases ;-)) (bernd_stein)


Angehängte Dateien:

Lesenswert?

Hallo zusammen,

leider programmiert PeDa ( Peter Dannegger ) ja nur noch in C.
Ich würde gerne als " AVR-ASM-Übender " die erweiterte Version von 
dieser hier verstehen und suche somit Leute die Lust und Können 
besitzen, dies einem AVR-Assembler-Übenden zu erklären :

Beitrag "Re: Tasten entprellen - Bulletproof"

Wie sieht der Logikplan mit den erweiterten Funktionen key_release, 
key_short, key_long und key_repeat aus ?

Beitrag "Universelle Tastenabfrage"

Das hier meine ich schon verstanden zu haben, es benögtigt ja auch nur 
ein Register ( key_reg ), wo alles untergebracht ist. Somit habt Ihr 
auch meinen Verständnisstand und wißt wo Ihr mich geistig abholen könnt.

Beitrag "Einzelnen Taster entprellen ASM"


Bernd_Stein

: Verschoben durch User
von spess53 (Gast)


Lesenswert?


von Bernd S. (Firma: Anscheinend Corner-Cases ;-)) (bernd_stein)


Lesenswert?

spess53 schrieb:
> Das
> 
http://www.mikrocontroller.net/articles/AVR-Tutorial:_Tasten#Erkennung_von_Flanken_am_Tasteneingang
>
> ist dir bekannt?
>
Nein, war es nicht.
Super, alles in Assembler.
Beim ersten Überfliegen raucht mir schon der Kopf. Scheint alles 
Angesprochene dabei zu sein, bis auf " Taster losgelassen "
( key_release ), aber das kann ich auch übersehen haben.

Melde mich dann wenn ich gezielte Fragen dazu habe oder meine etwas 
anders gestalten zu wollen.

Danke nochmals für diese schnelle und hilfreiche Antwort.


Bernd_Stein

von Rolf H. (flash01)


Lesenswert?

Hallo Bernd Stein,
hab mal den Code im AVR Tutorial ganz grob überflogen!
Und frage hier die Experten....warum ist besonders der Anfang
so kompliziert.
z.B. die .def Anweisungen wie:

.def key_old=r3 (warum nicht z.B. temp3)oder
.def temp1 = r17 (z.B temp17)oder
.def temp2 = r18 (z.B. temp18) oder

.equ led_ddr = DDRB (warum bleibt man nicht beim DDRB) usw.

Ich finde, es ist dann ein Wahnsinn, diese Verschlüsselungen
in der Loop....rjmp Loop Schleife auseinander zu Puzzeln.
Oder liege hier völlig daneben? Wie gesagt, das würde mich
verrückt machen.
Also nichts für UNGUT!

Grüße

Rolf

von Thomas F. (igel)


Lesenswert?

Rolf H. schrieb:
> .def key_old=r3 (warum nicht z.B. temp3)

Der Name temp3 würde bedeuten, dieses Register darf überall im Programm 
zerstört und beliebig neu beschrieben werden. Die Bezeichnung key_old 
zeigtr nun, r3 ist dauerhaft von der Tastenroutine belegt und kann für 
nichts anderes mehr verwendet werden.


> .def temp1 = r17 (z.B temp17)

Warum temp17? Das würde ja bedeuten, temp0 bis temp16 sind auch schon 
definiert. Tatsächlich werden dort aber irgendwelche anderen Variablen - 
z.B. Key_old, key_press,.. - liegen.

Der Name muss nicht zwangsläufig auf die tatsächliche Registeradresse 
hinweisen. Der Programierer legt Namen und Register einmal fest, beim 
weiteren programmieren kann man dann vergessen an welcher Adresse die 
Variable tatsächlich liegt.

von Bernd S. (Firma: Anscheinend Corner-Cases ;-)) (bernd_stein)


Lesenswert?

Rolf H. schrieb:
> .def key_old=r3 (warum nicht z.B. temp3)oder
> .def temp1 = r17 (z.B temp17)oder
> .def temp2 = r18 (z.B. temp18) oder
>
> Ich finde, es ist dann ein Wahnsinn, diese Verschlüsselungen
> in der Loop....rjmp Loop Schleife auseinander zu Puzzeln.
>
Man gibt den Arbeitsregistern für ein Selber " sinnvolle " Namen.
key_old steht z.B. für den Tasterzustand bevor der neue eingelesen 
wurde und somit ist key_old halt der alte Tasterzustand und der gerade 
eben erst eingelesene wird im Arbeitsregister key_now abgelegt.
Jetzt muß man nicht überlegen welches Arbeitsregister den Inhalt vom 
alten Tasterzustand hat, denn key_old ist für diesen Zweck 
sinnfälliger als r3 oder temp3.

Kannst Du mir z.B. sofort sagen in welchem Arbeitsregister
( r0 bis r31 ) der gerade eingelesene Tasterzustand abgelegt wurde ?

Ich auch nicht, aber auf Grund meiner Englischkenntnisse fällt mir da 
eher key_now ein als eines der 32-Arbeitsrgister. Deshalb versieht man 
diese Arbeitsregister mit für die Programmierung sinnfäligen Namen.

temp1 und temp2 sind Arbeitsregister die für temporere Aufgaben 
genutzt werden. Sie stehen also nicht für eine bestimmte Sache,
sondern für die momentan zu bewerkstelligende. Und auch hier ist es
( fast ) egal welches von den 32 Arbeitsregister ( r0-r31 ) dafür 
genutzt wird. Fast - weil die oberen 16 Arbeitsregiser ( r16-r31 ) mehr 
Adressierungsmöglichkeiten bieten. Zum Beispiel können erst ab r16 die 
bitweise arbeitenden Befehle sbr/cbr sowie sbrs/sbrc genutzt werden.

>
> .equ led_ddr = DDRB (warum bleibt man nicht beim DDRB) usw.
>
Auch hier wieder wegen des besseren Behaltens. So ein µC bietet auch mal 
mehr als einen Port. Damit man sich nicht merken muß, an welchem Port 
z.B. die LEDs, Taster, LCD usw. sind, gibt man auch diesen sinnvolle 
Abkürzungen. Led, Key, Lcd usw. Außerdem gibt es hierbei noch einen 
enormen Vorteil.
Nehmen wir einmal an, das LCD ist an einem anderen Port besser im Layout 
zu verdrahten, dann ordnet man dem LCD einfach einmalig den anderen Port 
in der Definition zu und muss sich im Programm um nichts weiter kümmern.

Ich habe Dir jetzt mal als nicht Experte geantwortet und will Dir das 
von einem der Experten nochmal nahelegen. Da das alles für den Anfang 
sehr Viel ist nur ein Auszug für *Definitionen :*

 Definitionen:

Damit die Unterprogramme auch wirklich universell sind, sollte man so 
oft wie möglich mit Definitionen arbeiten. Z.B. werden sämtliche 
Anschlüsse des ATTINY12 über Definitionen verwendet. Dadurch ist es 
jederzeit möglich, die Anschlüsse umzulegen, wenn sich z.B. dadurch ein 
günstigeres Platinenlayout ergibt. Oder auch, wenn in einem anderen 
Programm die Zuordnung eine andere ist (anderer AVR, Konflikte mit den 
Sonderfunktionen bestimmter Pins).

Auch Konstanten innerhalb des Programms sollten nicht als Zahl 
eingegeben werden, wenn sie sich z.B. bei anderer Quarzfrequenz mit 
ändern. Auch kann der AVR-Assembler Berechnungen bis 32Bit für die 
Konstanten selber durchführen. Z.B. sind die benötigten Verzögerungen 
beim LCD oder 1-Wire-Bus über Berechnungen aus der Quarzfrequenz 
definiert. Man muß also nur z.B. 1.2MHz beim ATTINY12, 1.6MHz beim 
ATTINY15 oder 2MHz beim ATTINY26 angeben und schon werden die 
Verzögerungszeiten korrekt neu berechnet.

Beitrag "Zeit + Temperatur auf LCD mit AVR"


Bernd_Stein

: Bearbeitet durch User
von grummel (Gast)


Lesenswert?

Bernd Stein schrieb:
> Man gibt den Arbeitsregistern für ein Selber " sinnvolle " Namen.
> .
> ( r0 bis r31 ) der gerade eingelesene Tasterzustand abgelegt wurde ?
> .
> ( fast ) egal welches von den 32 Arbeitsregister ( r0-r31 ) dafür

Wer oder was ist Selber und "never seen before" plenking?

> Ich habe Dir jetzt mal als nicht Experte geantwortet und will Dir das
> von einem der Experten nochmal nahelegen.

Ansonsten kaum was zu deinem Beitrag zu bemerken, außer vielleicht, daß 
du dich wirklich weiter aufs Fragen und Lernen beschränken solltest.

von Rolf H. (flash01)


Lesenswert?

na, das muß ich erst mal innerlich verarbeiten!

In meinen Anwendungen, die sich ausschliesslich im Steuerungsbereich
bewegen, hatte ich da noch nie Probleme.

Aber bin ja belehrbar und werde es mal im Auge behalten...vielleicht 
macht
es KLICK.
Hatte mal von Hannes Lux ein Code für Modelleisenbahn vor mir,
mit den ich erst mal nicht zurecht kam.
Also umgestrickt auf meine Variante (tempx = rx)und dann gings los.
Es sollte aber keine Kritik sein!
Grüße

Rolf.

von Bernd S. (Firma: Anscheinend Corner-Cases ;-)) (bernd_stein)


Lesenswert?

grummel schrieb:
> Wer oder was ist Selber und "never seen before" plenking?
>
Hast recht - hört sich fürchterlich an. Aber plenken gefällt mir,
das werde ich wohl beibehalten ;-)

*Man gibt den Arbeitsregistern für sich Selbst " sinnvolle " Namen.*

Ich denke das liest und versteht sich wohl besser. Obwohl " für sich " 
schließt ja schon das " Selbst " mit ein, so das man sich dieses Wort 
sparen kann. Aber das ist wohl ähnlich wie mit dem Spruch :
" Ich persönlich ".

Rolf H. schrieb:
> na, das muß ich erst mal innerlich verarbeiten!
>
So geht es mir auch. Nur meistens arbeite ich nicht lange genug daran.
Und bevor ich es verinnerlicht hatte, hatte ich es leider wieder 
vergessen, womit ich wieder am Anfang stand.

*Also dranbleiben lautet die Devise.*

>
> Hatte mal von Hannes Lux ein Code für Modelleisenbahn vor mir,
> mit den ich erst mal nicht zurecht kam.
>
Oh ja, wirklich gute Assemblerprogramme. Nur das dahintersteigen habe 
ich nie ohne Seine Hilfe geschafft. Und fange fast jedesmal von vorne 
an, wenn ich mir Seine Programme anschaue, aber die Tricks sind einfach 
genial.

Aber nun merke ich wieder wie ich langsam Off-Topic werde ;-),
aber diese Tasterentprellung von PeDa macht es einem nicht einfach dran 
zu bleiben, weil hier auch so manche Tricks zum Tragen kommen, die mann 
immer wieder durchspielen muss um sie wirklich zu verinnerlichen.


Bernd_Stein

von wendelsberg (Gast)


Lesenswert?

Rolf H. schrieb:
> Also umgestrickt auf meine Variante (tempx = rx)und dann gings los.

Das ist aber auch Unfug, da kannst Du gleich rx (z.B. r17) ins Programm 
schreiben.

wendelsberg

von Rolf H. (flash01)


Lesenswert?

ja wendelsberg...hast Recht! Ich weiss heute auch garnicht, wo ich
den Blödsinn abgekupfert habe.
Aber irgendwo muß ich es her haben...von mir kommt das nicht.
Vor Jahren hab ich mit den r17 bis rxx gearbeitet,
allerdings r16 war für mich schon immer eine Ausnahme
und das wird es auch bleiben.
So, nun will ich das Thema aber beenden.

Grüße

Rolf

: Bearbeitet durch User
von Bernd S. (Firma: Anscheinend Corner-Cases ;-)) (bernd_stein)


Lesenswert?

Hallo,

könnte das bitte jemand als Logikplan erstellen, ich krieg's nicht hin.
Weiß zum Beispiel nicht woher key_state, iwr0, iwr1 und key_press ihren 
Ursprung haben sollen.

key_old macht mich ganz kirre, denn zum Einen ist es ja der " gerade " 
eingelesene Tasterzustand und zum Anderen ist er aber vorher nach iwr0 
kopiert worden.

Wie soll man sowas in einem Logikplan festmachen ?

Wo ist denn da der Prellzähler enthalten ?

Quelle ist hier :

http://www.mikrocontroller.net/articles/AVR-Tutorial:_Tasten#Kombinierte_Entprellung_und_Flankenerkennung
1
get8key:                       ;/old      state     iwr1      iwr0
2
    mov     iwr0, key_old      ;00110011  10101010            00110011
3
    in      key_old, key_pin   ;11110000
4
    eor     iwr0, key_old      ;                              11000011
5
    com     key_old            ;00001111
6
    mov     iwr1, key_state    ;                    10101010
7
    or      key_state, iwr0    ;          11101011
8
    and     iwr0, key_old      ;                              00000011
9
    eor     key_state, iwr0    ;          11101000
10
    and     iwr1, iwr0         ;                    00000010
11
    or      key_press, iwr1    ; gedrückte Taste merken


Bernd_Stein

von Karl H. (kbuchegg)


Lesenswert?

Bernd Stein schrieb:
> Hallo,
>

Sieh dir bitte die Erläuterungen zum C-Code an, die du hier 
Entprellung finden kannst. Diese Assemblr-Implementierung ist meiner 
Erinnerung nach so ziemlich eine 1:1 Kopie davon in Assembler.

Und nein. Es ist nicht tragisch, wenn du den Code nicht durchblickst. 
Der ist tatsächlich von der Idee her recht trickreich aufgebaut.

von Bernd S. (Firma: Anscheinend Corner-Cases ;-)) (bernd_stein)


Lesenswert?

Karl Heinz schrieb:
> Sieh dir bitte die Erläuterungen zum C-Code an, die du hier
> Entprellung finden kannst.
>
Habe ich gemacht, bin aber nun nach gut 2 Std. nicht weitergekommen,
als bisher. Ich zitiere :

Zum Verständnis empfiehlt es sich daher, die Logikgleichungen mit 
Gattern für ein Bit = eine Taste aufzumalen. Die Register kann man sich 
als Flipflops denken, die mit der Entprellzeit als Takt arbeiten.

http://www.mikrocontroller.net/articles/Entprellung#Timer-Verfahren_.28nach_Peter_Dannegger.29


Bernd_Stein

von Karl H. (kbuchegg)


Lesenswert?

Bernd Stein schrieb:
> Karl Heinz schrieb:
>> Sieh dir bitte die Erläuterungen zum C-Code an, die du hier
>> Entprellung finden kannst.
>>
> Habe ich gemacht, bin aber nun nach gut 2 Std. nicht weitergekommen,

iwr0 und iwr1 realisieren 8 STück 2 Bit Zähler.

Das besondere daran ist, dass die Zähler nicht wie gewohnt komplett in 
einer Variablen drinn sind
1
   uint8_t zaehler;
2
3
   zaehler++;

sondern die beiden Bits des Zählers auf 2 Variablen aufgeteilt sind
1
       Bit  7   6   5   4   3   2   1   0
2
                                     #=====#
3
 iwr0      +---+---+---+---+---+---+--!+---+!
4
           |   |   |   |   |   |   |  !|   |!
5
           +---+---+---+---+---+---+--!+---+!
6
                                      !     !
7
 iwr1      +---+---+---+---+---+---+--!+---+!
8
           |   |   |   |   |   |   |  !|   |!
9
           +---+---+---+---+---+---+--!+---+!
10
                                      !     !
11
 key_state +---+---+---+---+---+---+--!+---+!
12
           |   |   |   |   |   |   |  !|   |!
13
           +---+---+---+---+---+---+--!+---+!
14
                                      !     !
15
 key_press +---+---+---+---+---+---+--!+---+!
16
           |   |   |   |   |   |   |  !|   |!
17
           +---+---+---+---+---+---+--!+---+!
18
                                      !     !
19
 key_old   +---+---+---+---+---+---+--!+---+!
20
           |   |   |   |   |   |   |  !|   |!
21
           +---+---+---+---+---+---+--!+---+!
22
                                      #=====#
23
24
                                   ^ diese Bits sind für die Taste 0
25
                                     zuständig. iwr0 und iwr1
26
                                     bilden gemeinsam einen 2 Bit Zähler

In den beiden 8 Bit Werten sind also 8 Stück 2 Bit Zähler "versteckt".
Und der Code in der ISR realisiert das zählen in diesen 2-Bit Zählern. 
Und zwar alle 8 gleichzeitig parallel.

> Zum Verständnis empfiehlt es sich daher, die Logikgleichungen mit
> Gattern für ein Bit = eine Taste aufzumalen. Die Register kann man sich
> als Flipflops denken, die mit der Entprellzeit als Takt arbeiten.

Konzentrier dich auf eine Bitposition, zb das Bit 0 und verfolge, wie es 
sich durch die Anweisungen verändert. In allen Registern ist für eine 
bestimmte Taste immer nur 1 Bit interessant. Zb ist für die Taste am Pin 
3 eines Ports auch immer nur das Bit 3 in allen Registern interessant.

Und nein. Ich werd mich im weiteren raushalten. Der Code ist tricky, 
solange man ihn nicht komplett verstanden hat. Ich denke, ich bin recht 
gut im Analysieren von fremden Code. Aber bis ich eine ganz gute 
Vorstellung hatte, was da abgeht, hab ich auch 20 Minuten gebraucht. Für 
einen Lernenden ist dieser Code sowieso nichts. So wie ich dich 
einschätze fehlen dir da noch mindestens 10000 Lines of selbst 
programmierten Code, bis du die Übung hast, um das in allen Feinheiten 
zu verstehen. Das soll dich aber nicht abhalten, ihn zu verwenden. Dazu 
funktioniert er zu gut.

: Bearbeitet durch User
von Bernd S. (Firma: Anscheinend Corner-Cases ;-)) (bernd_stein)


Angehängte Dateien:

Lesenswert?

Karl Heinz schrieb:
> Aber bis ich eine ganz gute
> Vorstellung hatte, was da abgeht, hab ich auch 20 Minuten gebraucht. Für
> einen Lernenden ist dieser Code sowieso nichts.
>
Vielen Dank, das motiviert zwar nicht, aber Du hast Dir ja mühe gegeben.

Ich analysiere gerade den orginal Code mit hilfe des Logikplans ( siehe 
Anhang ). Ich bin mir nämlich gar nicht sicher, ob dieser Code überhaupt 
den Entprellzähler enthält.
Beim orginal Code habe ich bisher den 2-Bit Abwärtszähler 
herauskristallisiert ( IC3A, IC4A, IC5A, IC7A, IC14A und IC15A ) was den 
folgenden ASM-Befehlen entsprechen dürfte :

    AND   key_ct0, iwr0
    AND   key_ct1, iwr0
    COM   key_ct0
    EOR   key_ct1, key_ct0

Und in diesem Program finde ich das nicht wieder, deshalb vermute ich 
das dieser Zähler hier gar nicht vorhanden ist, da in der Quelle zu 
lesen ist, das die IRQ alle 24ms aufgerufen wird. Wobei wohl davon 
ausgegangen wird, das das Prellen dann auf alle Fälle beendet ist.

http://www.mikrocontroller.net/articles/Entprellung#Timer-Verfahren_.28nach_Peter_Dannegger.29
1
.org OVF0addr    ;timer interrupt 24ms
2
      in     save_sreg, SREG
3
get8key:                               ;/old      state     iwr1      iwr0
4
      mov    iwr0, key_old             ;00110011  10101010            00110011
5
      in     key_old, key_port         ;11110000
6
      eor    iwr0, key_old             ;                              11000011
7
      com    key_old                   ;00001111
8
      mov    iwr1, key_state           ;                    10101010
9
      or     key_state, iwr0           ;          11101011
10
      and    iwr0, key_old             ;                              00000011
11
      eor    key_state, iwr0           ;          11101000
12
      and    iwr1, iwr0                ;                    00000010
13
      or     key_press, iwr1           ;store key press detect
14
;
15
;      insert other timer functions here
16
;
17
      out    SREG, save_sreg
18
      reti


Ach, Quelle orginal Code :

Beitrag "Re: Tasten entprellen - Bulletproof"


Bernd_Stein

: Bearbeitet durch User
von Peter D. (peda)


Lesenswert?

Bernd Stein schrieb:
> Und in diesem Program finde ich das nicht wieder, deshalb vermute ich
> das dieser Zähler hier gar nicht vorhanden ist

Das stimmt. Der Assemblercode entspricht funktional nicht dem C-Code. Er 
vergleicht nur 2 Samples und nicht 4.

von Bernd S. (Firma: Anscheinend Corner-Cases ;-)) (bernd_stein)


Lesenswert?

Peter D. schrieb:
> Das stimmt. Der Assemblercode entspricht funktional nicht dem C-Code. Er
> vergleicht nur 2 Samples und nicht 4.
>
Das mit den 4 Abtastungen ist mir wichtig, deshalb habe ich den 
AVR8ASM-Code leicht abgeändert, für dass bessere Nachvollziehens 
meinerseits.

Meine Zusammenfassung wäre, dass 4 gleiche Zustände hintereinander nötig 
sind, um als gültiges Drücken oder Loslassen, erkannt zu werden.

iwr0 und key_state müssen 1 sein, sowie der Zählerstand 0b11 bzw. 3,
um key_press gesetzt zu bekommen und um key_state toggeln zu können.

Wobei key_press = 1, erneutes Drücken bedeutet
und   key_state,     ist der entprellte, invertierte Tastenzustand.

Taster gedrückt    = 0 -> key_state = 1.
Taster losgelassen = 1 -> key_state = 0.

Damit eine bereits vor dem Einschalten bzw. RESET, gedrückte Taste 
ignoriert wird, sollte/kann key_state mit $FF initialisiert werden.
Zudem sollten key_ct0 und key_ct1, ebenfalls mit $FF initialisiert 
werden,
damit eine bereits vor dem Einschalten bzw. vor einem RESET, gedrückte 
Taste, nicht unentprellt, sofort wirksam wird.

Der Code in der ISR braucht nur 12 CPU-Takte und 4 untere Register ( 
<r16 ).

Eine fallende Flanke ( Tater gedrückt bzw. Tastenpegel von 1 -> 0 ), 
läßt den 4-Bit-Abwärtszähler mit 0b10 bzw. bei 2 starten, 1, 0, und beim 
Überlauf auf 0b11 bzw. 3, wird key_state = 1 und key_press 
ebenfalls.

Eine steigende Flanke ( Taste losgelassen bzw. Tastenpegel von 0 -> 1 ),
setzt den Zählerstand auf 0b11 bzw. 3, es sei denn, key_state ist zu 
diesem Zeitpunkt = 1, dann wird der Zählerstand auf 0b10 bzw. 2 gesetzt 
und beginnt dann herunter zu zählen ( 1, 0, 3 ), was aber nichts an den 
4 Abtastungen ändert ( 2, 1, 0, 3 ).

1
;
2
;Stapelzeiger initialisieren (fuer Unterprogramme und / oder Interrupts)
3
;Ist beim ATmega 2560 bereits auf $21FF eingestellt
4
;
5
_reset:
6
 ;ldi  a,High(RAMEND)    ;RAMEND, also das Ende vom SRAM, ist in der.. 
7
 ;out  SPH,a             ;..Definitions-datei festgelegt  
8
 ;ldi  a,Low (RAMEND)
9
 ;out  SPL,a
10
11
;
12
;Arbeitsregister (r0 bis r31 ) haben nach dem RESET einen unbestimmten Inhalt
13
;
14
clr  key_state          ;Variable loeschen           
15
clr  key_press          ;Variable loeschen
16
clr  key_ct0            ;key_ct0 & key_ct1 sind nicht direkt ladbar ( < r16 )
17
dec  key_ct0            ;Verhindern dass ein bereits gedrueckter Taster nach..
18
mov  key_ct1, key_ct0  ;..einem RESET nicht entprellt durchkommt.
19
20
;-------------------------------------------------------------------------------
21
;-------------------------------------------------------------------------------
22
; Hauptprogrammschleife
23
;-------------------------------------------------------------------------------
24
;-------------------------------------------------------------------------------
25
_main:
26
  
27
 clr  key_press         ;clear, if key press action done
28
;
29
; Replace with your application code
30
;
31
 rjmp _main             ;Endlosschleife
32
33
;
34
;QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ
35
;Q Timer0 Overflow ISR ( Interrupt Service Routine )
36
;QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ
37
;
38
_OVF0addr:
39
 in   s_sreg, SREG       ;Statusregister retten
40
41
;
42
;Tasterverarbeitung nach PeDa ( Peter Dannegger )
43
;
44
_get8key:
45
 in   iwr0, KEY_PIN      ;Tasterzustand einlesen
46
 com  iwr0               ;low active
47
 eor  iwr0, key_state
48
 and  key_ct0, iwr0      ;reset counter
49
 com  key_ct0            ;count
50
 and  key_ct1, iwr0
51
 eor  key_ct1, key_ct0
52
 and  iwr0, key_ct0      ;input AND last counterstate
53
 and  iwr0, key_ct1
54
 eor  key_state, iwr0    ;toggle state
55
 and  iwr0, key_state    ;0-1-transition
56
 or   key_press, iwr0    ;store key press detect
57
58
 out  SREG,s_sreg           ;Statusregister wiederherstellen
59
 reti                       ;Ruecksprung aus _OVF0addr Interrupt Service Routine


Bernd_Stein

von Harald K. (kirnbichler)


Lesenswert?

Bernd S. schrieb:
> deshalb habe ich den AVR8ASM-Code leicht abgeändert

In neun Jahren? Respekt.

Beitrag #7387776 wurde vom Autor gelöscht.
Beitrag #7387782 wurde von einem Moderator gelöscht.
Beitrag #7387789 wurde von einem Moderator gelöscht.
Beitrag #7387792 wurde von einem Moderator gelöscht.
von M. K. (sylaina)


Lesenswert?

Direkt im Eröffnungspost wurde 2014 kritisiert, dass Peter Dannegger nur 
noch in C schreibt und es soll hier nicht um die Programmiersprache 
gehen…wer hat hier etwas nicht verstanden ;)

Beitrag #7387796 wurde von einem Moderator gelöscht.
Beitrag #7388084 wurde von einem Moderator gelöscht.
von Wegstaben V. (wegstabenverbuchsler)


Lesenswert?

um wieviel schneller oder kompakter (Anzahl bytes) ist denn die 
Assembler-Routine gegenüber der (kompilierten) C-Implementierung?

: Bearbeitet durch User
von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Wegstaben V. schrieb:
> um wieviel schneller oder kompakter (Anzahl bytes) ist denn die
> Assembler-Routine gegenüber der (kompilierten) C-Implementierung?

Wahrscheinlich um genau Null in beiden Fällen.
In diesem Fall ist C vielleicht sogar besser als ASM, weil der
C-compiler etliche Tricks kennt, gerade für solche Fälle.

von M. K. (sylaina)


Lesenswert?

Wegstaben V. schrieb:
> um wieviel schneller oder kompakter (Anzahl bytes) ist denn die
> Assembler-Routine gegenüber der (kompilierten) C-Implementierung?

Grade in solchen Fällen ist die C-Implementierung von PeDa genauso gut 
da die Compiler inzwischen erheblich besser geworden sind als sie es vor 
30 Jahren waren.

Beitrag #7388336 wurde von einem Moderator gelöscht.
Beitrag #7388371 wurde von einem Moderator gelöscht.
Beitrag #7388390 wurde von einem Moderator gelöscht.
von Peter D. (peda)


Lesenswert?

Marc V. schrieb im Beitrag #7388084:
> Und Tasterprellen ist damit auch gelöst, ohne EOR, AND, COM und
> solchen unnützen Blödsinn.

Schade, Du hast das vertical counter Prinzip in keinster Weise 
verstanden.
Die Statements sind alle sauschnell, so daß weiteres Rumoptimieren 
unnötig ist.
Der eigentliche Clou ist jedoch, daß beide Flanken entprellt werden und 
somit die Lib besonders störfest ist. Im Gegensatz zu den meisten Libs, 
die nur einen Zustand abzählen.

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Peter D. schrieb:
> Marc V. schrieb im Beitrag #7388084:
>> Und Tasterprellen ist damit auch gelöst, ohne EOR, AND, COM und
>> solchen unnützen Blödsinn.
>
> Schade, Du hast das vertical counter Prinzip in keinster Weise
> verstanden.

Sagt wer?

> Die Statements sind alle sauschnell, so daß weiteres Rumoptimieren
> unnötig ist.

Das stimmt.

> Der eigentliche Clou ist jedoch, daß beide Flanken entprellt werden und
> somit die Lib besonders störfest ist. Im Gegensatz zu den meisten Libs,
> die nur einen Zustand abzählen.

Prellen beim loslassen ist bei meinem Vorschlag uninteressant, da dies
nie registriert wird.
Prellen beim drücken wird 100% eliminiert.
Und das wichtigste:
a) Man kann immer feststellen, welcher Taster zuerst gedrückt wurde.
b) Man hat ohne zusätzlichen Aufwand eine "repeat key" funktion.

Beitrag #7388603 wurde von einem Moderator gelöscht.
von Bernd S. (Firma: Anscheinend Corner-Cases ;-)) (bernd_stein)


Lesenswert?

M. K. schrieb:
> Wegstaben V. schrieb:
>> um wieviel schneller oder kompakter (Anzahl bytes) ist denn die
>> Assembler-Routine gegenüber der (kompilierten) C-Implementierung?
>
> Grade in solchen Fällen ist die C-Implementierung von PeDa genauso gut
> da die Compiler inzwischen erheblich besser geworden sind als sie es vor
> 30 Jahren waren.
>
Oh, dass passt ja.
Alle die vom ATMEL STUDIO 7 C-Compiler Ahnung haben, möchte ich zu 
diesem Thread einladen :

Beitrag "Mit dem ATMEL STUDIO 7 klarkommen : Highlighting und C-Compiler ASM-Code"


Bernd_Stein

von C-hater (c-hater)


Lesenswert?

Wegstaben V. schrieb im Beitrag #7388371:

> Wenn es jedoch einen gut durchdachten Algorithmus in C gibt, und gut
> funktionierende Compiler von C nach AVR-Assembler, dann wäre es unter
> Umständen mal interessant, einen Blick auf das Compilat zu werfen.
>
> Vielleicht findet dann ja der geneigte Assembler-Liebhaber noch
> Verbesserungs-Potential in dem übersetzten Teil. Er kann sich dann
> darauf konzentrieren, gutes noch besser zu machen.

Das ist ziemlich einfach zu schaffen. C-Compiler sind semmeldumm, wenn 
sie mit parallelem oder quasi-parallelem Code hantieren müssen, beim 
AVR8 insbesondere halt mit Code in ISRs (und viel von PeDas Code 
passiert typisch in einer Timer-ISR).

Und der Trick ist einfach: das Gesamtwerk NICHT in C verfassen und so 
die Einschränkungen des semmeldummen Compilers komplett zu umgehen. Dann 
stehen einem etliche Freiheitsgrade mehr zur Optimierung zur Verfügung, 
gerade auch im Bezug auf die effiziente Umsetzung von ISRs (aber 
beileibe nicht beschränkt darauf).

Siehe z.B.:

Beitrag "Audio Spektrum Analyzer mit ATtiny85"
Beitrag "Westminster Soundgenerator mit ATtiny85"

In Jahrzehnten der Existenz des avr-gcc ist es keinem der C-Fetischisten 
gelungen, das (oder etwas vergleichbar Anspruchsvolles) umzusetzen, 
obwohl es durchaus etliche Anfragen und Wünsche nach solchen Lösungen 
gab.

Bei größeren und komplexeren Architekturen als AVR8 wird es natürlich 
schwieriger, besser als die C-Compiler zu sein, zumal man hier eher 
nicht komplett auf C verzichten möchte, da das den Aufwand doch etwas 
über Gebühr in die Höhe treiben würde. Es bleibt aber möglich und wird 
auch oft gemacht. Siehe z.B. MP3-Decoder auf einem RaspiPico/RP2040. In 
plain stupid C fast unmöglich (jedenfalls für alle MP3-Bitraten), aber 
mit Rechenkernen in optimierten Assembler wird es machbar, sogar in der 
suboptimalen C-Umgebung.

Kapiere es einfach endlich: Das letzte aus einem Chip rausholen, wird 
immer nur in seiner nativen Sprache möglich sein. Jede Abstraktion (auch 
die eher Schwache, die C bietet) birgt nunmal auch den Ansatz der 
Suboptimalität in sich.

von Oliver S. (oliverso)


Lesenswert?

C-hater schrieb:
> Das letzte aus einem Chip rausholen, wird
> immer nur in seiner nativen Sprache möglich sein. Jede Abstraktion (auch
> die eher Schwache, die C bietet) birgt nunmal auch den Ansatz der
> Suboptimalität in sich.

Das hat ja auch nie jemand ernsthaft bestritten. Was diskutabel ist, ist 
die Praxisrelevanz solcher aufs letzte Bit ausgereizter Anwendungen. 
Manch einer nimmt dafür einfach einen größeren Prozessor, und hat 
bezüglich der Software andere Prioritäten.

Oliver

von C-hater (c-hater)


Lesenswert?

Oliver S. schrieb:

> Was diskutabel ist, ist
> die Praxisrelevanz solcher aufs letzte Bit ausgereizter Anwendungen.
> Manch einer nimmt dafür einfach einen größeren Prozessor, und hat
> bezüglich der Software andere Prioritäten.

Das ist sicherlich richtig. Aber auch denn gilt immer: mit Asm an den 
richtigen Stellen kann man noch mehr rausholen.

Klar, das kann man mit einer noch größeren, noch teureren und noch 
stromfressenderen MCU beantworten.

Usw. usf.

Genau das ist, was seit Jahrzehnten passiert. Jeder Fortschritt der 
Leistungsfähigkeit der Hardware wird durch noch mehr Abstraktionsebenen 
bei der Software umgehend wieder aufgefressen.

Muss man das gut finden? Ich jedenfalls finde das nicht gut.

Beitrag #7388870 wurde von einem Moderator gelöscht.
von Roland F. (rhf)


Lesenswert?

Hallo,
C-hater schrieb:
> C-Compiler sind semmeldumm, wenn sie mit parallelem oder
> quasi-parallelem Code hantieren müssen, beim AVR8 insbesondere
> halt mit Code in ISRs (und viel von PeDas Code passiert typisch
> in einer Timer-ISR).

Ich verstehe den Zusammenhang nicht. Kannst du mal an einem ein Beispiel 
zeigen was du genau meinst?

> Und der Trick ist einfach: das Gesamtwerk NICHT in C verfassen und so
> die Einschränkungen des semmeldummen Compilers komplett zu umgehen.

Was ist dann die Alternative zu C wenn man Maschinensprache mal außenvor 
lässt?

rhf

: Bearbeitet durch User
von Harald K. (kirnbichler)


Lesenswert?

Roland F. schrieb:
> Was ist dann die Alternative zu C wenn man Maschinensprache mal außenvor
> lässt?

Dann genau keine. Maschinensprache/Assembler ist die einzige 
Alternative. Andere Hochsprachen (Basic, Pascal etc.) oder gar 
Skriptsprachen (Python, Lua etc.) fallen sowieso raus.

von Wegstaben V. (wegstabenverbuchsler)


Lesenswert?

Harald K. schrieb:
> Roland F. schrieb:
>> Was ist dann die Alternative zu C wenn man Maschinensprache mal außenvor
>> lässt?
>
> Dann genau keine. Maschinensprache/Assembler ist die einzige
> Alternative. Andere Hochsprachen (Basic, Pascal etc.) oder gar
> Skriptsprachen (Python, Lua etc.) fallen sowieso raus.

wir reden hier aber von simplen Bits ein und aus schalten oder abfragen, 
stimmts?

Komplexere mathematische Aufgabenstellungen wie FFT, 
Matrixtransformation oder Sortieralgorithmen, oder auch "einfache" Dinge 
wie eine Tastaturmatrix Abfrage oder Segmentanzeigen-Multiplex 
schüttelst du dir vermutlich auch nicht ohne irgendeine Vorlage mal eben 
so aus dem Assembler-Ärmel ....

von C-hater (c-hater)


Lesenswert?

Wegstaben V. schrieb:

> Komplexere mathematische Aufgabenstellungen wie FFT,
> Matrixtransformation oder Sortieralgorithmen, oder auch "einfache" Dinge
> wie eine Tastaturmatrix Abfrage oder Segmentanzeigen-Multiplex
> schüttelst du dir vermutlich auch nicht ohne irgendeine Vorlage mal eben
> so aus dem Assembler-Ärmel ....

Das ist nur eine Frage der Gewohnheit. Vorausgesetzt, man versteht den 
umzusetzenden Algorithmus und beherrscht beide Sprachen, ist es nicht 
schwerer, den in Assembler umzusetzen als in C. Es dauert nur länger.

Und zwar meist nicht nur deshalb, weil man mehr tippen muss (das ist 
leider fast unvermeidbar so), sondern vor allem auch, weil man über mehr 
Sachen nachdenken muss, die mit dem Algorithmus selber eigentlich nichts 
zu tun haben. Aber genau dieses Nachdenken ist, was letztlich der 
Effizienz des Codes in der geplanten Zielumgebung gut tut...

Ja, es kommt sogar recht häufig vor, dass erst dieses Nachdenken zur 
Wahl eines für die Aufgabe auf dem geplanten Target wirklich 
geeigneten Algorithmus führt. Weil man schon direkt beim Programmieren 
immer im Blick hat: schafft das Target das eigentlich? Dieser Überblick 
ist in C viel schwerer zu erhalten...

Beitrag #7389227 wurde von einem Moderator gelöscht.
Beitrag #7389232 wurde von einem Moderator gelöscht.
Beitrag #7389237 wurde von einem Moderator gelöscht.
von Roland F. (rhf)


Lesenswert?

Hallo,
Harald K. schrieb:
> ...oder gar Skriptsprachen (Python, Lua etc.) fallen
> sowieso raus.

Da hast du recht, aber gerade die Script/Interpretersprache BASIC hat 
nicht unwesentlich zum Siegeszug der Homecomputer beigetragen (und damit 
wurden durchaus brauchbare Programme erstellt).

rhf

von Harald K. (kirnbichler)


Lesenswert?

C-hater schrieb:
> ist es nicht
> schwerer, den in Assembler umzusetzen als in C.

Jetzt klingt unser "C-Hater" exakt so wie unser beliebter "Moby". Nur 
auf das Zwinker-Smiley verzichtet er. Noch.

von Bernd S. (Firma: Anscheinend Corner-Cases ;-)) (bernd_stein)


Lesenswert?

Auch sehr interessant, falls man nur 4 Taster benötigt und auch 
zusätzlich eine losgelassen-Funktion haben will. Manchmal möchte man ja 
etwas erst starten lassen, wenn der Taster logelassen wird.

Beitrag "Re: Tasten entprellen - Bulletproof"


Bernd_Stein

: Bearbeitet durch User
von Bernd S. (Firma: Anscheinend Corner-Cases ;-)) (bernd_stein)


Lesenswert?

Bernd S. schrieb:
> ...
> Beim orginal Code habe ich bisher den 2-Bit Abwärtszähler
> herauskristallisiert ( IC3A, IC4A, IC5A, IC7A, IC14A und IC15A ) was den
> folgenden ASM-Befehlen entsprechen dürfte :
>

Beitrag "Re: Universelle Tastenabfrage nach PeDa in AVR Assembler"

Dies stimmt leider nicht so ganz.
Der unterste Link half mir zum besseren Verständnis.
Es war erstaunlich zu entdecken, dass die Programmierreihenfolge,
darüber entscheidet, ob es ein Vertikal 2-Bit, Ab,- oder Aufwärtszähler 
wird.

Der Vertikal-Zähler enthält also nur die Bausteine IC5A und IC7A, also 
die folgenden beiden Befehle.

Abwärtszähler:
AVR8ASM
1
com key_ct0
2
eor key_ct1, key_ct0

Aufwärtszähler:
1
eor key_ct1, key_ct0
2
com key_ct0

https://www.compuphase.com/electronics/debouncing.htm


Bernd_Stein

: Bearbeitet durch User
von Bernd S. (Firma: Anscheinend Corner-Cases ;-)) (bernd_stein)


Lesenswert?

Bernd S. schrieb:
> Auch sehr interessant, falls man nur 4 Taster benötigt und auch
> zusätzlich eine losgelassen-Funktion haben will. Manchmal möchte man ja
> etwas erst starten lassen, wenn der Taster logelassen wird.
>
Was muss man an diesem Code verändern, damit nach einem Reset oder dem 
Einschalten, kein losgelassener Taster dedektiert wird (siehe Anhang ).
Sondern erst, wenn dieser zuvor gedrückt wurde.

Quelle :

Beitrag "Re: Tasten entprellen - Bulletproof"


Bernd_Stein

von Falk B. (falk)


Lesenswert?

Bernd S. schrieb:
> Was muss man an diesem Code verändern, damit nach einem Reset oder dem
> Einschalten, kein losgelassener Taster dedektiert wird (siehe Anhang ).
> Sondern erst, wenn dieser zuvor gedrückt wurde.

Man muss ein paar Dutzend Millisekunden warten und dann die Tasten 
auslesen und das Ergebnis ignorieren.

von Bernd S. (Firma: Anscheinend Corner-Cases ;-)) (bernd_stein)


Angehängte Dateien:

Lesenswert?

Hatte den Anhang vergessen.


Bernd_Stein

von Bernd S. (Firma: Anscheinend Corner-Cases ;-)) (bernd_stein)


Angehängte Dateien:

Lesenswert?

Bernd S. schrieb:
> Was muss man an diesem Code verändern, damit nach einem Reset oder dem
> Einschalten, kein losgelassener Taster dedektiert wird (siehe Anhang ).
> Sondern erst, wenn dieser zuvor gedrückt wurde.
>

Beitrag "Re: Tasten entprellen - Bulletproof"

Natürlich wieder ein Kardinalfehler meinerseits.
Der Simulator setzt natürlich zu beginn Variablen bzw. GPR = 0 ( General 
purpose register ). Aber eben nicht nach einem Reset, was übrigens der 
echte µC auch nicht tut.
Man sollte also GPR dementsprechend auch initialisieren.
Und ganz hilfreich ist es auch, auf den Simulator zu warten bis dieser 
fertig ist ( siehe unterste Zeile => Ready / Stop ). Warum mal Ready und 
mal Stop steht, ist mir noch ein Rätsel.

Der Code läuft ja .. :

Hannes L. schrieb:
> Im vorliegenden Fall läuft die Routine auch nicht im Interrupt, sondern
> als Job der Mainloop, durch Timer und Jobflag synchronisiert.
> ...
>

wobei ich nicht verstehe, wie die Synchronisation durch Timer und 
Jobflag funktioniert. Leider kann der olle Brummbär dies auch nicht mehr 
erklären, aber vieleicht hier jemand.

http://www.hanneslux.de/index2.html

Der Code zum Durchtesten als Anhang.


Bernd_Stein

von Bernd S. (Firma: Anscheinend Corner-Cases ;-)) (bernd_stein)


Lesenswert?

Wenn man in Hannes Lux seinem Programm ein weiteres GPR einsetzt,
kann man noch 3 Takte rauskitzeln.

Für PUSH ein MOV weiteres_Register, tmp.
POP natürlich weg und ab praktisch dem EOR tas, weiteres_Register,
das tmp hierfür austauschen.


Bernd_Stein

: Bearbeitet durch User
von Peter D. (peda)


Lesenswert?

Bernd S. schrieb:
> Wenn man in Hannes Lux seinem Programm ein weiteres GPR einsetzt,
> kann man noch 3 Takte rauskitzeln.

micro-optimization at the worst.

Hört doch auf, die CPU im ppm-Bereich zu optimieren. Es bringt absolut 
nichts.
Optimieren kann man Tasks vielleicht ab 10% CPU-Auslastung. Darunter ist 
es einfach nur lächerlich.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Bernd S. schrieb:
> kann man noch 3 Takte rauskitzeln.
Völlig unnötiger Aufwand.

Denn sogar 160 Takte brauchen auf dem AVR bei 16 MHz nur 10µs. Und wenn 
die ISR alle 10ms aufgerufen wird, dann würde das komplette Weglassen 
dieser Funktion gerade mal 0,1% der Rechenleistung einsparen.

Oder konkret zu den heroisch eingesparten 3 Maschninenzyklen: die 
brauchen beim Aufruf in einer 10ms-ISR grade mal 0,002% der 
Rechenleistung.

Wenn es darauf auch nur ansatzweise ankommen würde, dann wäre der 
Controller sowieso völlig unterdimensioniert und mit der nächsten 
eingegebenen Codezeile eh' überlastet.

Eine einzige irgendwo im Programm falsch gewählte Operandengröße (int 
oder gar float statt eines simplen char) kostet da wesentlich mehr 
Rechenleistung.

: Bearbeitet durch Moderator
von Bernd S. (Firma: Anscheinend Corner-Cases ;-)) (bernd_stein)


Lesenswert?

Bernd S. schrieb:
> Hannes L. schrieb:
>> Im vorliegenden Fall läuft die Routine auch nicht im Interrupt, sondern
>> als Job der Mainloop, durch Timer und Jobflag synchronisiert.
>> ...
>>
>
> wobei ich nicht verstehe, wie die Synchronisation durch Timer und
> Jobflag funktioniert. Leider kann der olle Brummbär dies auch nicht mehr
> erklären, aber vieleicht hier jemand.
>
Könnte mir dies mal einer anhand eines AVR8ASM-Codes erklären und 
einfach meine Erbsenzählerei akzeptieren ?


Bernd_Stein

von Joachim B. (jar)


Lesenswert?

Bernd S. schrieb:
> Könnte mir dies mal einer ..... meine Erbsenzählerei akzeptieren ?

nö es wird langsam langweilig und artet immer mehr in Selbstgespräche 
aus, alles Wichtige wurde geschrieben!

Peter D. schrieb:
> Hört doch auf, die CPU im ppm-Bereich zu optimieren. Es bringt absolut
> nichts.
> Optimieren kann man Tasks vielleicht ab 10% CPU-Auslastung. Darunter ist
> es einfach nur lächerlich.

Lothar M. schrieb:
> Denn sogar 160 Takte brauchen auf dem AVR bei 16 MHz nur 10µs. Und wenn
> die ISR alle 10ms aufgerufen wird, dann würde das komplette Weglassen
> dieser Funktion gerade mal 0,1% der Rechenleistung einsparen.

von Bernd S. (Firma: Anscheinend Corner-Cases ;-)) (bernd_stein)


Lesenswert?

Joachim B. schrieb:
> nö es wird langsam langweilig und artet immer mehr in Selbstgespräche
> aus, alles Wichtige wurde geschrieben!
>
Mein Thread, falls es dir nicht aufgefallen ist.
Und wenn dir meine "Selbstgespräche" nicht passen und du hier trotzdem 
deinen Senf dazu gibst, hast du die 5 universellen Forumsregeln nicht 
beachtet oder verstanden.

Und bitte ordentlich zitieren, damit der Zusammenhang bleibt.

Bernd S. schrieb:
>>
>> wobei ich nicht verstehe, wie die Synchronisation durch Timer und
>> Jobflag funktioniert. Leider kann der olle Brummbär dies auch nicht mehr
>> erklären, aber vieleicht hier jemand.
>>
>> Könnte mir dies mal einer anhand eines AVR8ASM-Codes erklären und
>> einfach meine Erbsenzählerei akzeptieren ?
>>


Bernd_Stein

: Bearbeitet durch User
von Harald K. (kirnbichler)


Lesenswert?

Bernd S. schrieb:
> Und wenn dir meine "Selbstgespräche" nicht passen und du hier trotzdem
> deinen Senf dazu gibst, hast du die 5 universellen Forumsregeln nicht
> beachtet oder verstanden.

Daß diese Forenregeln auch für Dich gelten könnten, ist Dir noch nicht 
gekommen?

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Bernd S. schrieb:
> Mein Thread
Sicher nicht.

Falls dir das nicht aufgefallen ist: du hast den Thread zwar eröffnet, 
aber mit dem Absenden dieses Posts hast du  Andreas "ein einfaches, 
zeitlich und räumlich unbeschränktes und unentgeltliches Recht" 
eingeräumt, "den Beitrag im Rahmen des Forums zu nutzen" (Zitate aus den 
Nutzungsbedingungen). Und die im Rahmen des Forums vorgesehene 
Nutzung ist eben, dass sich alle daran beteiligen können. Auch mit 
Ansichten, die einem TO nicht 100% nach dem Strich gehen.

> und einfach meine Erbsenzählerei akzeptieren ?
Akzeptiert.

: Bearbeitet durch Moderator
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.