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
intmain(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?
Das sieht ja übel programmiert aus...
Aber ok.
Erstmal würde ich (NumpadxOld < NumpadxNew) durch (NumpadxOld !=
NumpadxNew)ersetzen.
Wo werden die Variablen initiialisiert?
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...
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
--------------------------------------------------------------
> 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 ...
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
...
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.
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.
Georg schrieb:> Andre G. schrieb:>>> DDRF = DDRF | 0b00000001;>>> PORTF = PORTF & 0b11111110;>> Warum ist hier | und & vertauscht?
Von welcher Zeile redest du?
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?
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.
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'.
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!
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"
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.
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.
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 ...
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!"
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 ...
>> 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.
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. ;)
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?
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.
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
inti;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
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
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?
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
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?
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
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
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.htmlAndre 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?
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.
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.
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 ...
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...
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.
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.
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...
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.
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... ;-)
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.
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.