Forum: Mikrocontroller und Digitale Elektronik [AVR][C] Tastenmatrix: Nur ein Taster wird nicht erkannt


von Andre G. (andgst01)


Lesenswert?

Schönen Mittwoch Nachmittag,

ich habe ein unerklärliches Problem:

Ich habe eine Tastenmatrix mit 4 Reihen und 3 Spalten aufgebaut.
Die Tastenmatrix hängt an einem AtMega2560, falls das relevant ist.

Alle Taster können korrekt ausgelesen werden, nur einer nicht.

Das macht doch keinen Sinn, oder?
Dann müssten doch ALLE Taster in der Spalte oder in der Reihe nicht 
ausgelesen werden können, oder?

Konkret sieht das folgendermaßen aus:

Taster "9" kann nicht ausgelesen werden.
1
+---+---+---+
2
| 7 | 8 | 9 | -->  PF6
3
+---+---+---+
4
| 4 | 5 | 6 | -->  PF5
5
+---+---+---+
6
| 1 | 2 | 3 | -->  PF4
7
+---+---+---+
8
| - | 0 | . | -->  PF3
9
+---+---+---+
10
11
  ^   ^   ^
12
  |   |   |
13
  |   |   |
14
15
  P   P   P
16
  F   F   F
17
  0   1   2

Hier der Code:
(die Initialisierung und all die Funktionen um das Display anzusteuern 
habe ich der Lesbarkeit halber weggelassen)
1
int main(void)
2
{
3
  Init();
4
  
5
  while (true)
6
    {    
7
      //Store the previous button states
8
      Numpad0Old = Numpad0New;
9
      Numpad1Old = Numpad1New;
10
      Numpad2Old = Numpad2New;
11
      Numpad3Old = Numpad3New;
12
      Numpad4Old = Numpad4New;
13
      Numpad5Old = Numpad5New;
14
      Numpad6Old = Numpad6New;
15
      Numpad7Old = Numpad7New;
16
      Numpad8Old = Numpad8New;
17
      Numpad9Old = Numpad9New;
18
      NumpadMinusOld = NumpadMinusNew;
19
      NumpadPointOld = NumpadPointNew;
20
      
21
      //Set all the "NumpadxNew" variables to false, if a button is pushed it will get overwritten to true
22
      //This is done to avoid writing lots of "if else"s
23
      Numpad0New = false;
24
      Numpad1New = false;
25
      Numpad2New = false;
26
      Numpad3New = false;
27
      Numpad4New = false;
28
      Numpad5New = false;
29
      Numpad6New = false;
30
      Numpad7New = false;
31
      Numpad8New = false;
32
      Numpad9New = false;
33
      NumpadMinusNew = false;
34
      NumpadPointNew = false;
35
      
36
      
37
      //PF6,PF5,PF4,PF3 are always inputs with pull-up
38
      DDRF = DDRF & 0b10000111;  //PF6,PF5,PF4,PF3 are inputs
39
      PORTF = PORTF | 0b01111000;  //PF6,PF5,PF4,PF3 have pullups
40
      
41
      
42
      //set PF0 low to check the left col
43
      // PF0 = 0
44
      //DDRF = XXXXXXX1
45
      //PORTF = XXXXXXX0
46
      DDRF = DDRF | 0b00000001;
47
      PORTF = PORTF & 0b11111110;
48
        
49
      // PF1 = HiZ
50
      //DDRF = XXXXXX0X
51
      //PORTF = XXXXXX1X
52
      DDRF = DDRF & 0b11111101;
53
      PORTF = PORTF | 0b00000010;
54
        
55
      // PF2 = HiZ
56
      //DDRF = XXXXX0XX
57
      //PORTF = XXXXX1XX
58
      DDRF = DDRF & 0b11111011;
59
      PORTF = PORTF | 0b00000100;
60
        
61
        
62
      if((PINF & 0b01000000) == false)
63
        {
64
          //Button 7 was pushed
65
          Numpad7New = true;
66
        }
67
        
68
      if((PINF & 0b00100000) == false)
69
        {
70
          //Button 4 was pushed
71
          Numpad4New = true;
72
        }
73
          
74
      if((PINF & 0b00010000) == false)
75
        {
76
          //Button 1 was pushed
77
          Numpad1New = true;
78
        }
79
        
80
      if((PINF & 0b00001000) == false)
81
        {
82
          //Button - was pushed
83
          NumpadMinusNew = true;
84
        }
85
        
86
        
87
      //set PF1 low to check the middle col
88
      // PF0 = HiZ
89
      //DDRF = XXXXXXX0
90
      //PORTF = XXXXXXX1
91
      DDRF = DDRF & 0b11111110;
92
      PORTF = PORTF | 0b00000001;
93
        
94
      // PF1 = 0
95
      //DDRF = XXXXXX1X
96
      //PORTF = XXXXXX0X
97
      DDRF = DDRF | 0b00000010;
98
      PORTF = PORTF & 0b11111101;
99
        
100
      // PF2 = HiZ
101
      //DDRF = XXXXX0XX
102
      //PORTF = XXXXX1XX
103
      DDRF = DDRF & 0b11111011;
104
      PORTF = PORTF | 0b00000100;
105
        
106
        
107
      if((PINF & 0b01000000) == false)
108
        {
109
          //Button 8 was pushed
110
          Numpad8New = true;
111
        }
112
        
113
      if((PINF & 0b00100000) == false)
114
        {
115
          //Button 5 was pushed
116
          Numpad5New = true;
117
        }
118
        
119
      if((PINF & 0b00010000) == false)
120
        {
121
          //Button 2 was pushed
122
          Numpad2New = true;;
123
        }
124
        
125
      if((PINF & 0b00001000) == false)
126
        {
127
          //Button 0 was pushed
128
          Numpad0New = true;
129
        }
130
        
131
        
132
      //set PF2 low to check the right col
133
      // PF0 = HiZ
134
      //DDRF = XXXXXXX0
135
      //PORTF = XXXXXXX1
136
      DDRF = DDRF & 0b11111110;
137
      PORTF = PORTF | 0b00000001;
138
        
139
      // PF1 = HiZ
140
      //DDRF = XXXXXX0X
141
      //PORTF = XXXXXX1X
142
      DDRF = DDRF & 0b11111101;
143
      PORTF = PORTF | 0b00000010;
144
      
145
      // PF2 = 0
146
      //DDRF = XXXXX1XX
147
      //PORTF = XXXXX0XX
148
      DDRF = DDRF | 0b00000100;
149
      PORTF = PORTF & 0b11111011;
150
        
151
        
152
      if((PINF & 0b01000000) == false)
153
        {
154
          //Button 9 was pushed
155
          Numpad9New = true;
156
        }
157
        
158
      if((PINF & 0b00100000) == false)
159
        {
160
          //Button 6 was pushed
161
          Numpad6New = true;
162
        }
163
        
164
      if((PINF & 0b00010000) == false)
165
        {
166
          //Button 3 was pushed
167
          Numpad3New = true;
168
        }
169
        
170
      if((PINF & 0b00001000) == false)
171
        {
172
          //Button . was pushed
173
          NumpadPointNew = true;
174
        }
175
      
176
      //Detect rising edges
177
      if(Numpad0Old < Numpad0New)
178
        {
179
          //´Rising edge at button Numpad 0
180
          LCD_WriteString(0,0,"Button 0 was pushed");
181
        }
182
      if(Numpad1Old < Numpad1New)
183
        {
184
          //´Rising edge at button Numpad 1
185
          LCD_WriteString(0,0,"Button 1 was pushed");
186
        }
187
      if(Numpad2Old < Numpad2New)
188
      {
189
        //´Rising edge at button Numpad 2
190
        LCD_WriteString(0,0,"Button 2 was pushed");
191
      }
192
      if(Numpad3Old < Numpad3New)
193
      {
194
        //´Rising edge at button Numpad 3
195
        LCD_WriteString(0,0,"Button 3 was pushed");
196
      }
197
      if(Numpad4Old < Numpad4New)
198
      {
199
        //´Rising edge at button Numpad 4
200
        LCD_WriteString(0,0,"Button 4 was pushed");
201
      }
202
      if(Numpad5Old < Numpad5New)
203
      {
204
        //´Rising edge at button Numpad 5
205
        LCD_WriteString(0,0,"Button 5 was pushed");
206
      }
207
      if(Numpad6Old < Numpad6New)
208
      {
209
        //´Rising edge at button Numpad 6
210
        LCD_WriteString(0,0,"Button 6 was pushed");
211
      }
212
      if(Numpad7Old < Numpad7New)
213
      {
214
        //´Rising edge at button Numpad 7
215
        LCD_WriteString(0,0,"Button 7 was pushed");
216
      }
217
      if(Numpad8Old < Numpad8New)
218
      {
219
        //´Rising edge at button Numpad 8
220
        LCD_WriteString(0,0,"Button 8 was pushed");
221
      }
222
      if(Numpad9Old < Numpad9New)
223
      {
224
        //´Rising edge at button Numpad 9
225
        LCD_WriteString(0,0,"Button 9 was pushed");
226
      }
227
      if(NumpadMinusOld < NumpadMinusNew)
228
      {
229
        //´Rising edge at button Numpad -
230
        LCD_WriteString(0,0,"Button - was pushed");
231
      }
232
      if(NumpadPointOld < NumpadPointNew)
233
      {
234
        //´Rising edge at button Numpad .
235
        LCD_WriteString(0,0,"Button . was pushed");
236
      }
237
          
238
      //wait some time for the button to stop oscillating
239
      _delay_ms(DEBOUNCETIME);
240
    }
241
}

Einen defekten Taster schließe ich aus, denn auch wenn ich den Taster 
mit einem Draht überbrücke dann wird das nicht als Tastendruck erkannt.

Ein Fehler in der Verdrahtung kann ebenfalls ausgeschlossen werden, dann 
würde ja die gesamte Reihe oder Spalte nicht funktionieren.

Was kann der Grund für dieses eigenartige Verhalten sein?

von Fabian H. (hdr)


Lesenswert?

Das sieht ja übel programmiert aus...
Aber ok.

Erstmal würde ich (NumpadxOld < NumpadxNew) durch (NumpadxOld != 
NumpadxNew)ersetzen.

Wo werden die Variablen initiialisiert?

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


Lesenswert?

Andre G. schrieb:
> Hier der Code:
Siehe die Bedienungsanweisung über jeder Eingabebox:
1
Antwort schreiben
2
Wichtige Regeln - erst lesen, dann posten!
3
    Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

> Was kann der Grund für dieses eigenartige Verhalten sein?
Was machst du denn da laufend zigmal hintereinander mit den DDR und 
Ausgangsregistern? Reicht da nicht 1 einziger definierter Zugriff?
1
      //PF6,PF5,PF4,PF3 are always inputs with pull-up
2
      DDRF = DDRF & 0b10000111;  //PF6,PF5,PF4,PF3 are inputs
3
      PORTF = PORTF | 0b01111000;  //PF6,PF5,PF4,PF3 have pullups
4
      //set PF0 low to check the left col
5
      // PF0 = 0
6
      //DDRF = XXXXXXX1
7
      //PORTF = XXXXXXX0
8
      DDRF = DDRF | 0b00000001;
9
      PORTF = PORTF & 0b11111110;
10
      // PF1 = HiZ
11
      //DDRF = XXXXXX0X
12
      //PORTF = XXXXXX1X
13
      DDRF = DDRF & 0b11111101;
14
      PORTF = PORTF | 0b00000010;
15
      // PF2 = HiZ
16
      //DDRF = XXXXX0XX
17
      //PORTF = XXXXX1XX
18
      DDRF = DDRF & 0b11111011;
19
      PORTF = PORTF | 0b00000100;
Ich glaube, es wäre sher sinnvoll, das zu bereinigen...

: Bearbeitet durch Moderator
von OMG (Gast)


Lesenswert?

Andre G. schrieb:
> Was kann der Grund für dieses eigenartige Verhalten sein?

Was kann der Grund dafür sein dass du die einfachen Regeln zum
Posten von Quellcode nicht berücksichtigst. Was ist daran nicht
zu verstehen? Kann es sein dass du die Reihenfolge von Lesen
und Posten verwechselt hast?

--------------------------------------------------------------
Wichtige Regeln - erst lesen, dann posten!
...................
    Längeren Sourcecode nicht im Text einfügen, sondern
    als Dateianhang
--------------------------------------------------------------

von Andre G. (andgst01)


Lesenswert?

Lothar M. schrieb:
> Andre G. schrieb:
>> Hier der Code:
> Siehe die Bedienungsanweisung über jeder Eingabebox:
>
1
> Antwort schreiben
2
> Wichtige Regeln - erst lesen, dann posten!
3
>     Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang
4
>
>
>> Was kann der Grund für dieses eigenartige Verhalten sein?
> Was machst du denn da laufend zigmal hintereinander mit den DDR und
> Ausgangsregistern? Reicht da nicht 1 einziger definierter Zugriff?
>
1
>       //PF6,PF5,PF4,PF3 are always inputs with pull-up
2
>       DDRF = DDRF & 0b10000111;  //PF6,PF5,PF4,PF3 are inputs
3
>       PORTF = PORTF | 0b01111000;  //PF6,PF5,PF4,PF3 have pullups
4
>       //set PF0 low to check the left col
5
>       // PF0 = 0
6
>       //DDRF = XXXXXXX1
7
>       //PORTF = XXXXXXX0
8
>       DDRF = DDRF | 0b00000001;
9
>       PORTF = PORTF & 0b11111110;
10
>       // PF1 = HiZ
11
>       //DDRF = XXXXXX0X
12
>       //PORTF = XXXXXX1X
13
>       DDRF = DDRF & 0b11111101;
14
>       PORTF = PORTF | 0b00000010;
15
>       // PF2 = HiZ
16
>       //DDRF = XXXXX0XX
17
>       //PORTF = XXXXX1XX
18
>       DDRF = DDRF & 0b11111011;
19
>       PORTF = PORTF | 0b00000100;
20
>
> Ich glaube, es wäre sher sinnvoll, das zu bereinigen...

Abwechselnd die Ausgänge PF0,PF1,PF2 auf 0 setzen um die Taster in den 
jeweiligen Spalten zu überprüfen.

Ja, es ist sehr verbos angeschrieben, aber das habe ich gemacht damit 
ich sicher bin dass nicht da irgendwo ein Fehler drinn ist.


Das am Anfang mit PF6, ..., PF3 als Eingänge mit Pullups setzen sollte 
eigentlich in der init Funktion stehen, stimmt.

Bezüglich dem "langen Sourcecode":
Als ich das eingefügt habe hat das nicht so "lang" ausgesehen, aber 
irgendwie zieht das hier ab einem gewissen Punkt alles in die Länge und 
fügt komische leere Zeilen ein ...

von Andre G. (andgst01)


Lesenswert?

Aber gut, ich werde diesen Thread löschen und das nochmal "ordentlich" 
versuchen.

Ok, sieht aus als könnt man das nur wenn noch niemand geantwortet hat 
...

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


Lesenswert?

Andre G. schrieb:
> Abwechselnd die Ausgänge PF0,PF1,PF2 auf 0 setzen um die Taster in den
> jeweiligen Spalten zu überprüfen.
Ja, dann musst aber schon zwischendurch mal was Einlesen.
Aber du setzt da nur zigmal hintereinander irgendwas um und fertig.

Wie gesagt: sieh dir das mal genau an. Spiele selber µC und mache das, 
was der entsprechend deiner "Anweisungsliste" nacheinander tun muss.

Abzüglich der Kommentare bleibt da von deinen Zeilen 40-60 z.B. sowas 
übrig:
1
       DDRF = DDRF & 0b10000111;
2
       PORTF = PORTF | 0b01111000;
3
       DDRF = DDRF | 0b00000001;
4
       PORTF = PORTF & 0b11111110;
5
       DDRF = DDRF & 0b11111101;
6
       PORTF = PORTF | 0b00000010;
7
       DDRF = DDRF & 0b11111011;
8
       PORTF = PORTF | 0b00000100;
Und weil dazwischen eben sonst nichts passiert, kann man das auch 
schadlos so umsortieren:
1
       DDRF = DDRF & 0b10000111;
2
       DDRF = DDRF | 0b00000001;
3
       DDRF = DDRF & 0b11111101;
4
       DDRF = DDRF & 0b11111011;
5
       PORTF = PORTF | 0b01111000;
6
       PORTF = PORTF & 0b11111110;
7
       PORTF = PORTF | 0b00000010;
8
       PORTF = PORTF | 0b00000100;
Und das sieht jetzt irgendwie arg unkoordiniert und seltsam aus.

Andre G. schrieb:
> aber irgendwie zieht das hier ab einem gewissen Punkt alles in die Länge
> und fügt komische leere Zeilen ein ...
Ab der 100. Zeile. Aber eigentlich sind auch 99 Zeilen schon ziemlich 
lang.

: Bearbeitet durch Moderator
von Georg (Gast)


Lesenswert?

Andre G. schrieb:
>>       DDRF = DDRF | 0b00000001;
>>       PORTF = PORTF & 0b11111110;

Warum ist hier | und & vertauscht?

Georg

von Andre G. (andgst01)


Lesenswert?

Lothar M. schrieb:

> Und das sieht jetzt irgendwie arg unkoordiniert und seltsam aus.

Was ich da den µC machen lasse ist folgendes:
1
Setze pin 0 von port F als Ausgang.
2
Setze pin 0 von port F auf 0.
3
4
Setze pin 1 von port F als Eingang.
5
Deaktiviere den pullout von pin 1 port F.
6
7
...

Also einfach schön der Reihe nach die einzelnen DDRs und PORTs auf den 
gewünschten Zustand bringen.

Ja, das kann man alles "auf einmal" machen, aber ich wollte sichergehen 
dass ich da nicht einen Fehler habe.

von Andre G. (andgst01)


Lesenswert?

Georg schrieb:
> Andre G. schrieb:
>>>       DDRF = DDRF | 0b00000001;
>>>       PORTF = PORTF & 0b11111110;
>
> Warum ist hier | und & vertauscht?

Von welcher Zeile redest du?

von Spess53 (Gast)


Lesenswert?

Hi

An PortF befindet sich das JTAG-Interface. Ist das abgeschaltet?

MfG Spess

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


Lesenswert?

Andre G. schrieb:
> Ja, das kann man alles "auf einmal" machen, aber ich wollte sichergehen
> dass ich da nicht einen Fehler habe.
Und, bist du tatsächlich sicher? Ich nicht.

Denn weil du diese ganze Setzerei und Zurücksetzerei dann auch noch mit 
Verundungen und Veroderungen auf den "vorherigen" Wert aufsetzt, kann 
zumindest ich nicht mehr mit vertretbarem Aufwand nachvollziehen, was da 
passiert.

Am einfachsten wäre, jeweils genau 1 einzigen, richtig berechneten Wert 
auf DDR und PORT zu schreiben. Das kann jeder nachvollziehen.

Spess53 schrieb:
> An PortF befindet sich das JTAG-Interface. Ist das abgeschaltet?
Richtig, das kann man auch ganz leicht sehen, wenn man mit dem 
Oszilloskop misst. @Andre: hast du so ein Messgerät?

: Bearbeitet durch Moderator
von Andre G. (andgst01)


Lesenswert?

Ja, JTAG ist abgeschaltet (das JTAGEN fuse bit ist nicht gesetzt).
Das hatte ich am Anfang vergessen, da hat gar nichts funktioniert.
Aber das steht ja im Datenblatt, also da bin ich selbst draufgekommen.

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


Lesenswert?

Nochn Vorschlag.
Du hast da ab der Zeile 149 sowas:
1
      PORTF = PORTF & 0b11111011;
2
3
      if((PINF & 0b01000000) == false)
4
        {
5
          //Button 9 was pushed

Probiers mal so:
1
      PORTF = PORTF & 0b11111011;
2
      PORTF = PORTF & 0b11111011; // gib der Hardware die Chance zur Reaktion
3
      PORTF = PORTF & 0b11111011; // dito
4
5
      if((PINF & 0b01000000) == false)
6
        {
7
          //Button 9 was pushed

: Bearbeitet durch Moderator
von Andre G. (andgst01)


Angehängte Dateien:

Lesenswert?

Gut, ich habe jetzt mal den Code ein wenig umgeschrieben.
(siehe Anhang)

Jetzt ist es Taster 8 der nicht funktioniert.

von S. Landolt (Gast)


Lesenswert?

Und wenn Sie den Tipp von Lothar Miller befolgen, m.a.W. den jeweils vor 
einem Abfrageblock befindlichen Befehl verdoppeln? Es sieht irgendwie 
nach dem von c-hater so gern herangezogenen Effekt bezüglich 
Synchronisation aus, s.a. Datenblatt unter 'Reading the Pin Value'.

von Andre G. (andgst01)


Lesenswert?

S. Landolt schrieb:
> Und wenn Sie den Tipp von Lothar Miller befolgen, m.a.W. den jeweils vor
> einem Abfrageblock befindlichen Befehl verdoppeln? Es sieht irgendwie
> nach dem von c-hater so gern herangezogenen Effekt bezüglich
> Synchronisation aus, s.a. Datenblatt unter 'Reading the Pin Value'.

Ich habe jetzt ein _delay_us(10) vor jedem Abfrageblock und damit 
funktioniert es!
Alle Taster lassen sich auslesen!

von Peter D. (peda)


Lesenswert?

Andre G. schrieb:
> Ja, es ist sehr verbos angeschrieben, aber das habe ich gemacht damit
> ich sicher bin dass nicht da irgendwo ein Fehler drinn ist.

Bei mir ist es immer umgekehrt, je länger der Code, umso mehr Fehler 
sind drin.
Hier mal meine Version:

Beitrag "Re: Tastenmatrix 3x4 Problem"

von Fabian H. (hdr)


Lesenswert?

Ich würde mir erstmal zwei Funktionen schreiben:
1
void SetRow(uint8_t row) { }
2
uint8_t GetCol(uint8_t col) { }

die SetRow Funktion sollte vor dem Return ein delay_ms(1); besitzen.
(Ja, delays sind hässlich, besser wäre eine State-Machine, aber zu 
deinem Code passt besser das delay).

Wie sieht deine Verkabelung aus?

Du benutzt nur die Pull-Up Widerstände, die ja relativ hochohmig sind. 
Diese wirken gegen die Leitungskapazität. Daher musst du dem ganzen 
schon Zeit geben sich auch umzuladen.

: Bearbeitet durch User
von Andre G. (andgst01)


Lesenswert?

Fabian H. schrieb:

> Wie sieht deine Verkabelung aus?
>
> Du benutzt nur die Pull-Up Widerstände, die ja relativ hochohmig sind.
> Diese wirken gegen die Leitungskapazität. Daher musst du dem ganzen
> schon Zeit geben sich auch umzuladen.

Ungefähr 10 cm Flachbandkabel zwischen µC-Board und "Tastatur-Board".
Nur die internen PullUps.

von Forist (Gast)


Lesenswert?

Wichtige Regeln - erst lesen, dann posten!
Groß- und Kleinschreibung verwenden
Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

von Andre G. (andgst01)


Lesenswert?

Forist schrieb:
> Wichtige Regeln - erst lesen, dann posten!
> Groß- und Kleinschreibung verwenden
> Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Ja, jetzt weiß ich auch warum:
Längere Code-Abschnitte werden hässlich in die Länge gezogen ...

von Fabian H. (hdr)


Lesenswert?

Ich würde mir erstmal zwei Funktionen schreiben:
1
void SetRow(uint8_t row) 
2
{ 
3
   if (row < 3)
4
   {
5
      DDRF = 0b10000111;
6
      PORTF = 0b01111000 | (1 << row);
7
      delay_ms(1);
8
   }
9
}
10
uint8_t GetCol(uint8_t col) 
11
{ 
12
    return (PINF >> 3) & (1 << col);
13
}

Dann kannst Du Dir bequem und übersichtlich die Werte holen:
1
SetRow(0);
2
Numpad7New = GetCol(0);
3
Numpad4New = GetCol(1);
4
Numpad1New = GetCol(2);
5
Numpad_New = GetCol(3);
6
7
SetRow(1);
8
Numpad8New = GetCol(0);
9
Numpad5New = GetCol(1);
10
Numpad2New = GetCol(2);
11
Numpad0New = GetCol(3);
12
13
SetRow(2);
14
Numpad9New = GetCol(0);
15
Numpad6New = GetCol(1);
16
Numpad3New = GetCol(2);
17
NumpadDotNew = GetCol(3);
(Ja, delays sind hässlich, besser wäre eine State-Machine, aber zu 
deinem Code passt besser das delay).

: Bearbeitet durch User
von Teo D. (teoderix)


Lesenswert?

Andre G. schrieb:
> Ja, jetzt weiß ich auch warum:
> Längere Code-Abschnitte werden hässlich in die Länge gezogen ...

Man sieht doch sofort, das die ForenSW "momentan" ne Macke hat. Drei o. 
mehr stellige Zeilennummern werden umgebrochen. Ist ein "neues" Future, 
das mit den Zeilennummern. :-{
Also für die Zukunft merken: "Längeren Sourcecode nicht im Text 
einfügen, sondern als Dateianhang!"

von Andre G. (andgst01)


Lesenswert?

Teo D. schrieb:
> Andre G. schrieb:
>> Ja, jetzt weiß ich auch warum:
>> Längere Code-Abschnitte werden hässlich in die Länge gezogen ...
>
> Man sieht doch sofort, das die ForenSW "momentan" ne Macke hat. Drei o.
> mehr stellige Zeilennummern werden umgebrochen. Ist ein "neues" Future,
> das mit den Zeilennummern. :-{
> Also für die Zukunft merken: "Längeren Sourcecode nicht im Text
> einfügen, sondern als Dateianhang!"

Ja, aus selbst gemachten Fehlern lernt man am meisten ...

von Andre G. (andgst01)


Lesenswert?

Fabian H. schrieb:
> Ich würde mir erstmal zwei Funktionen schreiben:
>
>
1
> ...
2
>
>
> Dann kannst Du Dir bequem und übersichtlich die Werte holen:
>
1
> ...
2
>

Ja, das ist viel kompakter.

Fabian H. schrieb:
> (Ja, delays sind hässlich, besser wäre eine State-Machine, aber zu
> deinem Code passt besser das delay).

Dem µC ist es egal ob der Code "hässlich" formatiert oder umständlich 
formuliert ist.
Ich schreibe eben so wie ich am Besten damit zurechtkomme.

von Teo D. (teoderix)


Lesenswert?

Andre G. schrieb:
> Ich schreibe eben so wie ich am Besten damit zurechtkomme.

Und bist damit auf die Nase gefallen.... "Ja, aus selbst gemachten 
Fehlern lernt man am meisten ..." Fällt mir irgendwie schwer, das zu 
glauben, also was dich betrifft. ;)

von Andre G. (andgst01)


Lesenswert?

Teo D. schrieb:
> Andre G. schrieb:
>> Ich schreibe eben so wie ich am Besten damit zurechtkomme.
>
> Und bist damit auf die Nase gefallen.... "Ja, aus selbst gemachten
> Fehlern lernt man am meisten ..." Fällt mir irgendwie schwer, das zu
> glauben, also was dich betrifft. ;)

Das verstehe ich jetzt nicht.
Der eigentlich Fehler hier war ja dass ich nicht auf die 
Eingangssynchronisierung gewartet habe und nicht meine "Formatierung", 
oder?

von schrieb (Gast)


Lesenswert?

Forist schrieb:
> Wichtige Regeln - erst lesen, dann posten!
> Groß- und Kleinschreibung verwenden
> Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Wurde hier im Thread schon mehrfach erwähnt und muss nicht nochmals 
geschrieben werden.

von Alois (Gast)


Lesenswert?

Andre G. schrieb:
> Dem µC ist es egal ob der Code "hässlich" formatiert oder umständlich
> formuliert ist.
> Ich schreibe eben so wie ich am Besten damit zurechtkomme.

Andre, dein Code ist schlecht, da unleserlich.

Nicht eingeschnappt sein - das ist absolut nicht gegen dich persönlich 
gerichtet. Ich sehe die Fehler aber viel zu oft - und ich sag auch 
gleich noch ein paar Worte zu ...

Die erste Anforderung an guten Code ist, dass er von einem Menschen 
gelesen und verstanden werden kann. Das fängt damit an, dass ein 
Code-Teil nicht länger als eine Seite sein soll - heißt: Spaghetti-Code 
vermeiden.
Das geht weiter über eine gute Strukturierung, treffende Namen sowie 
aussagekräftige Kommentare usw.

Ganz wichtig: Es muss Spaß machen, den Code zu lesen. Und noch mehr Spaß 
machen diesen zu verstehen.

Das ist wie bei einer guten Geschichte - denn eine *schlechte 
Geschichte* liest niemand zu Ende ...

Wenn du Code schreibst und Debug-Hilfe brauchst - wieso schreibst du den 
z.B. nicht in Kyrillisch? Weil es keinen Spaß macht das zu lesen, und 
sich nahezu unmöglich gestaltet, einen Fehler zu finden. Für dich selbst 
und für einen Fremden sowieso.

Ab den 80ern gab es mal, über zig Jahre, den IOCCC (International 
Obfuscated C Code Contest). Gewinnen konntest zu nur, wenn du möglichst 
"schlechen Code" produziert hast ...

Auf 
https://courses.cs.washington.edu/courses/cse142/97su/josh/obfuscate.html 
ist ein Beispiel gelistet. Das sieht so aus:
1
int i;main(){for(i=0;i["]<i;++i){--i;}"];
2
read('-'-'-',i+++"hell\
3
o,world!\n",'/'/'/'));}read(j,i,p){
4
write(j/p+p,i---j,i/i);}

Der Compiler (gcc) schmeißt zwar einige Warnings, aber das Programm 
compiliert - und funktioniert!

Ist dieser Code deshalb gut?
Und wirst du den auch lesen wollen?
Und wenn jemand auch nur ein Zeichen ändert, den Fehler finden und auch 
korrigieren können?

Ich hoffe du stimmst mir zu: Dieser Code ist richtig mies. Und 
unwartbar. Und niemand wird sich Mühe geben, dir bei der Korrektur zu 
helfen.

Alois

PS: Dir richtig schlimmen Beispiele findest du über 
https://www.ioccc.org

von Teo D. (teoderix)


Lesenswert?

Alois schrieb:
> Das fängt damit an, dass ein
> Code-Teil nicht länger als eine Seite sein soll - heißt: Spaghetti-Code
> vermeiden.

Nein, das ist kein Spagetti-Code! EDIT: Blödsinniges gelöscht :}
Bei Spagetti-Code gibt es keine vernünftige Funktionsstruktur, gern auch 
ganz ohne Funtionen oä, es wird einfach wild herum gesprungen. Goto ist 
dein bester Freund. Als BASIC noch keine Funktionen etc. kannte, war das 
ein seeehr beliebter Stil. Auch als die Kunden noch gutgläubig, billige 
SW in Auftrag gaben und noch keine Ahnung hatten was ne Dokumentation 
ist. Man waren die angeschißen, die mussten dann für 
Wartung/Anpassungen, zahlen was immer verlangt wurde. :DDD

: Bearbeitet durch User
von Andre G. (andgst01)


Lesenswert?

Ich habe nie behauptet dass mein Code "gut" ist.

Normalerweise bin ich der einzige (außer dem Compiler natürlich) der 
meinen Code zu Gesicht bekommt.
Das ist erst das zweite Mal dass ich hier bezüglich Code um Hilfe 
gefragt habe, bisher hatte ich noch nie solche Probleme bei etwas 
einfachem wie dem Auslesen von Tasterzuständen.

Und das Problem schien einfach unerklärlich, vor allem weil ich davon 
ausgegangen bin dass das Synchronisieren der Pinzustände schneller 
abläuft als meine ewigen if-Abfragen.
Deshalb war scheinbar der einzige Weg mal die kollektive Intelligenz 
dieses Forums um Hilfe zu bitten.

In Zukunft werde ich meinen Code vor dem Veröffentlichen "aufräumen" und 
ordentlich strukturieren.


All die "Eigenarten" in meinem Code sind da um die Lesbarkeit für mich 
zu verbessern. Ganz besonders wenn ich mir den Code in zwei Jahren 
nochmal ansehe.

Ich behaupte nicht dass mein Code effizient, elegant, für jeden lesbar 
oder objektiv betrachtet "gut" ist.
Das muss er ja auch nicht sein, solange das nur für ein kleines 
persönliches Projekt ist das nie irgendwie veröffentlicht werden sollte.
Oder?

von Alois (Gast)


Lesenswert?

Teo D. schrieb:
> Alois schrieb:
>> Das fängt damit an, dass ein
>> Code-Teil nicht länger als eine Seite sein soll - heißt: Spaghetti-Code
>> vermeiden.
>
> Nein [Blödsinn gelöscht]

Doch - Code muss übersichtlich und lesbar sein!

Alois

von Teo (Gast)


Lesenswert?

Alois schrieb:
>>
>> Nein [Blödsinn gelöscht]
>
> Doch - Code muss übersichtlich und lesbar sein!

Kopierst du Heini, dir die Zitate immer so zusammen, wie es dir gerade 
passt?

von Alois (Gast)


Lesenswert?

Andre G. schrieb:
> Ich behaupte nicht dass mein Code effizient, elegant, für jeden lesbar
> oder objektiv betrachtet "gut" ist.

Effizienz ist zweitrangig, hatte mich auch nie darüber ausgelassen ...

> Das muss er ja auch nicht sein, solange das nur für ein kleines
> persönliches Projekt ist das nie irgendwie veröffentlicht werden sollte.

Andre - das kannst du halten wie du willst. Es ist einzig dein Projekt. 
Ich einen Wust über 240 Zeilen nicht lesen. Du hast hier viele Tipps 
bekommen, wie man es besser machen könnte. Lerne draus oder lass es - 
mir ist das ziemlich egal.

Alois

von Alois (Gast)


Lesenswert?

Teo schrieb:
> Alois schrieb:
>>>
>>> Nein [Blödsinn gelöscht]
>>
>> Doch - Code muss übersichtlich und lesbar sein!
>
> Kopierst du Heini, dir die Zitate immer so zusammen, wie es dir gerade
> passt?

Nein, ich bin das - der Alois. Den Heini hab ich heute noch nicht 
gesehen.

Dafür aber einen offensichtlich kognitiv überforderten Foristen, der 
versucht sich über banale Kraftausdrücke zu atrikullieren, wenn ihm die 
Argumente ausgehen ...

Alois

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


Lesenswert?

Fabian H. schrieb:
> Ich würde mir erstmal zwei Funktionen schreiben: ...
> (Ja, delays sind hässlich, besser wäre eine State-Machine, aber zu
> deinem Code passt besser das delay).
Aber eben kein Delay im ms-Bereich, so langsam ist die Hardware mit 
Sicherheit nicht. Und in deinem Beispielfall mit den beiden 
Funktionsaufrufen kann ich mir gut vorstellen, dass allein der Overhead 
der Funktionsaufrufe zur Stabilisierung der Spannungspegel ausreicht.

S. Landolt schrieb:
> Es sieht irgendwie nach dem von c-hater so gern herangezogenen Effekt
> bezüglich Synchronisation aus, s.a. Datenblatt unter 'Reading the Pin
> Value'.
Dieses Einsynchronisieren(*) muss bei jedem Taktdomänenübergang gemacht 
werden, damit jeder "Abnehmer" dieses Signals im µC (z.B. Pin-Register, 
Capture, Interruptregister...) sicher den selben Pinzustand bekommt. Zum 
sicheren Eintakten werden 2 Flipflops verwendet(**).
Und das ist jetzt der Witz: dafür braucht man keine 10µs und auch keine 
Millisekunde, sondern eben einfach 2 Maschinentakte. Und die habe ich in 
meinem letzten Codeschnipsel durch das Verdreifachen der letzten 
Codezeile errreicht.

Kurz: 10µs oder 1ms sind Rechenzeitvergeudung, die geschieht, weil der 
Programmierer seine Hardware nicht kennt. Das ist dann auch ein Grund, 
warum Rechenboliden mit mehreren GHz-Kernen, die in Bruchteilen einer 
Sekunde jede Endlosschleife zigfach durchrechnen könnten, auf einmal 
"langsam reagieren": weil schon auf unterster Ebene jeder "zur 
Sicherheit" einfach zehnmal oder zehntausend mal mehr Zeit verplempert 
als die Hardware eigentlich bräuchte.

(*) 
http://www.lothar-miller.de/s9y/archives/41-Einsynchronisieren-von-asynchronen-Signalen.html)
(**) 
http://www.lothar-miller.de/s9y/archives/62-Testaufbau-Metastabilitaet.html

Andre G. schrieb:
> Alle Taster können korrekt ausgelesen werden
Zum Thema "Hardware kennenlernnen" noch eine weitere Anregung: welche 
Tasten bekommst du denn eigentlich von deiner Tastenauswertung 
zurückgemeldet, wenn du z.B. 7+8+2 gleichzeitig drückst?

: Bearbeitet durch Moderator
von Peter D. (peda)


Angehängte Dateien:

Lesenswert?

Lothar M. schrieb:
> dafür braucht man keine 10µs und auch keine
> Millisekunde, sondern eben einfach 2 Maschinentakte.

Nö, es braucht genau einen CPU-Takt, also 1 NOP.
Siehe Datenblatt.

von Fabian H. (hdr)


Lesenswert?

Lothar M. schrieb:
> Fabian H. schrieb:
>> Ich würde mir erstmal zwei Funktionen schreiben: ...
>> (Ja, delays sind hässlich, besser wäre eine State-Machine, aber zu
>> deinem Code passt besser das delay).
> Aber eben kein Delay im ms-Bereich, so langsam ist die Hardware mit
> Sicherheit nicht. Und in deinem Beispielfall mit den beiden
> Funktionsaufrufen kann ich mir gut vorstellen, dass allein der Overhead
> der Funktionsaufrufe zur Stabilisierung der Spannungspegel ausreicht.

Heute hat er nur 10cm Flachbandkabel an der Tastatur. Morgen baut er das 
Keypad an eine andere Stelle und hat plötzlich 2m Kabel dazwischen.
Persönlich würde ich weder das 1ms Delay, noch überhaupt ein Delay 
nehmen, aber passend zu seinem Code erscheint mir 1ms ok.

Das der Overhead der Funktionsaufrufe ausreicht, mag sein, muss aber 
nicht. Die Funktion ist zwar nicht als inline gekennzeichnet, aber dem 
Compiler steht es ja frei dies hinreichend zu optimieren, so dass es 
evtl. sogar am Ende den gleichen asm Code bringt, wie ursprünglich vom 
TO verfasst.

von Andre G. (andgst01)


Lesenswert?

J, ich weiß dass die 10ms oder 10µs viel zu lange sind, aber das ist 
keine zeitkritische Anwendung, es ist egal ob ein Durchlauf der main 
Funktion 100 ms, 20 ms oder 300 ms dauert.
Ich habe das auf zwei µCs aufgeteilt, einer macht das ganze "User 
Interface" (LCD, Taster, ...), der zweite macht alles was zeitkritisch 
ist.


Ich dachte nur "lieber ein wenig zu lange warten".


Nein, es werden nicht 2m Kabel zwischen Tastatur und µC sein, das bleibt 
so.

Wenn mehrere Taster "gleichzeitig" gedrückt werden / gedrückt sind, dann 
sollte nichts passieren.
Das muss ich aber erst noch implementieren.

Eines nach dem anderen.

Die Taster werden dann alle noch zusätzliche Funktionen haben (bei 
mehrfachem Drücken, ähnlich wie bei den alten Handy-Tastaturen).
Das umzusetzten sollte aber kein Problem für mich  sein ...

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


Lesenswert?

Peter D. schrieb:
> Nö, es braucht genau einen CPU-Takt, also 1 NOP.
Also haben die da nur 1 Eingangsflipflop zur Synchronisierung. Gut, das 
reicht, denn die Taktfrequenz ist nicht allzu hoch und das Flipflop 
nimmt hinreichend schnell einen stabilen Zustand an.

> Siehe Datenblatt.
Aber wenn ich bei 16MHz eine Taktzeit von 62ns habe und dann noch die 
Zeit zum Umladen der Kapazität von Leitung+Taster+Leitung+Eingang 
ebenfalls mit einrechne, dann kann ich mir durchaus vorstellen, dass in 
einer realen Schaltung eben ein zweites NOP nicht schadet.

Aber eben keine 10µs und auch keine ms.

Andre G. schrieb:
> habe das auf zwei µCs aufgeteilt, einer macht das ganze "User Interface"
> (LCD, Taster, ...), der zweite macht alles was zeitkritisch ist.
Mein Tipp: lass das alles auf 1 µC. In der Summe ist das viel einfacher 
als wenn du dir dann noch über Synchronisationsmechnismen zwischen UI 
und Steuerung Gedanken machen müsstest.

> habe das auf zwei µCs aufgeteilt
Welche Schnittstelle ist dazwischen?

> es ist egal ob ein Durchlauf der main Funktion 100 ms, 20 ms oder 300
> ms dauert.
Ich habe einen Programmfehler, wenn meine Hauptschleife länger als 10ms 
braucht. Denn wenn ich da eine Aufgabe zu bewältigen habe, die länger 
als 10ms dauert (das sind immerhin 160000 Maschinenzyklen), dann muss 
ich die in kleinere Schritte aufteilen.

Du musst es natürlich nicht so machen wie ich es machen würde. Aber 
ich habe solche Fehler auch schon gemacht...

: Bearbeitet durch Moderator
von Armin K. (-donald-) Benutzerseite


Lesenswert?

Andre G. schrieb:
> Normalerweise bin ich der einzige (außer dem Compiler natürlich) der
> meinen Code zu Gesicht bekommt.

Das habe ich früher auch gedacht. Auch wenn das so ist, schau dir deinen 
Code mal nach einem Jahr an, und dann wirst du es verstehen was hier 
gesagt wurde.

von Peter D. (peda)


Lesenswert?

Andre G. schrieb:
> Wenn mehrere Taster "gleichzeitig" gedrückt werden / gedrückt sind, dann
> sollte nichts passieren.
> Das muss ich aber erst noch implementieren.

Das brauchst Du nicht zu implementieren, weil kein Mensch aus CPU-Sicht 
Tasten gleichzeitig drücken kann. Es wird immer eine Taste zuerst 
erkannt.

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


Lesenswert?

Peter D. schrieb:
> weil kein Mensch aus CPU-Sicht Tasten gleichzeitig drücken kann.
Wenn die Tasten aber nur alle 100ms abgescannt werden, dann schon...

> Es wird immer eine Taste zuerst erkannt.
Allerdings geht es hier nicht um die im Scanprozess "zuerst" erkannte 
Taste, sondern die, die beim letzten Scannen als einzige betätigte Taste 
erkannt wurde.

Letztlich muss man eben den gesamten Scan ignorieren, wenn dabei mehr 
als 1 Taste als aktiv erkannt wird.

Aber Obacht: die Art des "Ignorierens" ist wichtig, denn sonst kann es 
passieren, dass beim Loslassen der vielen gleichzeitig betätigten Tasten 
die eine Taste, die zuletzt losgelassen wird, noch kurz als "betätigt" 
erkannt wird...

: Bearbeitet durch Moderator
von m.n. (Gast)


Lesenswert?

Lothar M. schrieb:
> Aber wenn ich bei 16MHz eine Taktzeit von 62ns habe und dann noch die
> Zeit zum Umladen der Kapazität von Leitung+Taster+Leitung+Eingang
> ebenfalls mit einrechne, dann kann ich mir durchaus vorstellen, dass in
> einer realen Schaltung eben ein zweites NOP nicht schadet.
>
> Aber eben keine 10µs und auch keine ms.

Ein bisschen Rechnen könnte nicht schaden. Geschätzer Pullup-Widerstand 
50 kOhm bei 20 pF Kapazität ergibt eine Zeitkonstante von 1 µs. Da 
reicht folglich ein weiteres NOP allein nicht aus.

10 µs sind da deutlich realistischer. Zudem muß man bei der Abfrage 
einer Tastatur in 10 ms Invervallen nicht besonders auf höchste 
Geschwindigkeit achten. Geschickterweise gibt man beim 
interruptgesteuerten Einlesen alle anderen Interrupts wieder frei.

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


Lesenswert?

m.n. schrieb:
> Ein bisschen Rechnen könnte nicht schaden.
War zu faul   ;-)

> Geschätzer Pullup-Widerstand 50 kOhm
Deshalb mache ich da extern niederohmigere Widerstände dran.

> bei 20 pF Kapazität
Dürfte hinkommen:
http://nerdralph.blogspot.com/2015/10/parasitic-capacitance-of-avr-mcu-pins.html

> ergibt eine Zeitkonstante von 1 µs.
Ja, tatsächlich.

> Da reicht folglich ein weiteres NOP allein nicht aus.
Wie schon öfters geschrieben: ich würde das Oszi anschließen.

> 10 µs sind da deutlich realistischer.
Allerdings hat es in der Praxis zuvor bei allen anderen Tasten mit 
deutlich weniger Zeit auch schon gereicht... ;-)

von Peter D. (peda)


Lesenswert?

m.n. schrieb:
> Ein bisschen Rechnen könnte nicht schaden. Geschätzer Pullup-Widerstand
> 50 kOhm bei 20 pF Kapazität ergibt eine Zeitkonstante von 1 µs. Da
> reicht folglich ein weiteres NOP allein nicht aus.

Kommt ganz auf Deine Programmierkünste an.
Mein obiges Beispiel zieht zwischendurch immer auf strong High 
(60mA@25°C)).
Die Pullups sollen also nur High halten oder werden strong auf Low 
entladen und das geht ratzfatz. Das eine NOP reicht dicke.

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


Lesenswert?

Peter D. schrieb:
> zieht zwischendurch immer auf strong High
Fast wie annodazumal bei den Pullups der 8051er.
Und wenn man die 60mA@5V in einen Rds mit ca. 100 Ohm umrechnet, dann 
gibt das eine Zeitkonstante von 20pF*100R = 2ns. Ergo ist nach 10ns der 
Käse geschnitten.

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.