Forum: Compiler & IDEs Stecke seit Tagen fest Hilfe !


von makkes (Gast)


Angehängte Dateien:

Lesenswert?

Hallo,

ich übersetze derzeit meine BASCOM-Programme für den ATTiny2313 nach C. 
Ich benutze den gcc-avr 4.5.1 auf Arch-Linux.

Im Moment arbeite ich an einer 5x5-Led-Multiplex-Matrix. Die Schaltung 
ist 100% in Ordnung, mit den BASCOM-Programmen läuft es.

Ich finde einfach den Fehler nicht. Ich habe zwar einen Hinweis, aber 
ich kann es nicht interpretieren
1
#include <stdlib.h>
2
#include <stdio.h>
3
#include <string.h>
4
#include <avr/io.h>
5
#include <util/delay.h>
6
7
// Zeiger auf das aktuell anzuzeigende Bitmuster
8
int (*thechar)[5];
9
10
//nachfolgend Bitmuster für alle Buchstaben
11
const int A[5]={ 0b00001110,
12
              0b00010001,
13
              0b00011111,
14
              0b00010001,
15
              0b00010001};
16
const int B[5]={ 0b00011110,
17
              0b00010001,
18
              0b00011110,
19
              0b00010001,
20
              0b00011110};
21
const int C[5]={ 0b00001111,
22
              0b00010000,
23
              0b00010000,
24
              0b00010000,
25
              0b00001111};
26
const int D[5]={ 0b00011110,
27
              0b00010001,
28
              0b00010001,
29
              0b00010001,
30
              0b00011110,};
31
const int E[5]={ 0b00011111,
32
              0b00010000,
33
              0b00011110,
34
              0b00010000,
35
              0b00011111,};
36
const int F[5]={ 0b00011111,
37
              0b00010000,
38
              0b00011110,
39
              0b00010000,
40
              0b00010000,};
41
const int G[5]={ 0b00001111,
42
              0b00010000,
43
              0b00010011,
44
              0b00010001,
45
              0b00001111,};
46
const int  H[5]={ 0b00010001,
47
              0b00010001,
48
              0b00011111,
49
              0b00010001,
50
              0b00010001,};
51
const int  I[5]={ 0b00001110,
52
              0b00000100,
53
              0b00000100,
54
              0b00000100,
55
              0b00001110};
56
const int  J[5]={ 0b00001110,
57
              0b00000010,
58
              0b00000010,
59
              0b00010010,
60
              0b00001100};
61
const int  K[5]={ 0b00010001,
62
                  0b00010010,
63
                  0b00011100,
64
                  0b00010010,
65
                  0b00010001};
66
const int  Lima[5]={ 0b00010000,
67
                  0b00010000,
68
                  0b00010000,
69
                  0b00010000,
70
                  0b00011111};
71
const int  M[5]={ 0b00010001,
72
                  0b00011011,
73
                  0b00010101,
74
                  0b00010001,
75
                  0b00010001};
76
const int  N[5]={ 0b00010001,
77
              0b00011001,
78
              0b00010101,
79
              0b00010011,
80
              0b00010001};
81
const int  O[5]={ 0b00001110,
82
              0b00010001,
83
              0b00010001,
84
              0b00010001,
85
              0b00001110};
86
const int  P[5]={ 0b00011110,
87
              0b00010001,
88
              0b00011110,
89
              0b00010000,
90
              0b00010000};
91
const int  Q[5]={ 0b00001110,
92
              0b00010001,
93
              0b00010101,
94
              0b00010011,
95
              0b00001111};
96
const int  R[5]={ 0b00011110,
97
              0b00010001,
98
              0b00011110,
99
              0b00010010,
100
              0b00010001};
101
const int  S[5]={ 0b00001111,
102
              0b00010000,
103
              0b00001110,
104
              0b00000001,
105
              0b00011110};
106
const int  T[5]={ 0b00011111,
107
              0b00000100,
108
              0b00000100,
109
              0b00000100,
110
              0b00000100};
111
const int  U[5]={ 0b00010001,
112
              0b00010001,
113
              0b00010001,
114
              0b00010001,
115
              0b00011111};
116
const int  V[5]={ 0b00010001,
117
              0b00010001,
118
              0b00010001,
119
              0b00001010,
120
              0b00000100};
121
const int  W[5]={ 0b00010001,
122
              0b00010001,
123
              0b00010001,
124
              0b00010101,
125
              0b00001010};
126
const int  X[5]={ 0b00010001,
127
              0b00010001,
128
              0b00001110,
129
              0b00010001,
130
              0b00010001};
131
const int  Y[5]={ 0b00010001,
132
              0b00010001,
133
              0b00001010,
134
              0b00000100,
135
              0b00000100};
136
const int  Z[5]={ 0b00011111,
137
              0b00000010,
138
              0b00000100,
139
              0b00001000,
140
              0b00011111};
141
const int  SPACE[5]={ 0b00000000,
142
              0b00000000,
143
              0b00000000,
144
              0b00000000,
145
              0b00000000};
146
const int  DOT[5]={ 0b00000000,
147
              0b00000000,
148
              0b00000100,
149
              0b00000000,
150
              0b00000000};
151
152
// aktiviert eine Matrixzeile, und setzt alle anderen null. Lediglich Bit 
153
// D6 wird auf 1 gelassen, da er ein Eingang ist.
154
void activateRow(int row){
155
  switch(row){
156
    case 4:
157
      PORTD=0b01010000;
158
    break;
159
    case 3:
160
      PORTD=0b01100000;
161
    break;
162
    case 2:
163
      PORTD=0b01000100;
164
    break;
165
    case 1:
166
      PORTD=0b01000010;
167
    break;
168
    case 0:
169
      PORTD=0b01000001;
170
    break;
171
  }
172
}
173
//Alles aus, ausser dem Eingang auf Pin D6
174
void deactivateRow(void){
175
  PORTD=0b01000000;
176
}
177
178
// Hier kann per ASCII-Code der Zeiger auf ein Bitmuster gestellt werden.
179
// HIER STIMMT WAS NICHT
180
void getChar(int letter){
181
182
  switch(letter){
183
    case 65:
184
      thechar = (&A);
185
    break;
186
    case 66:
187
      thechar = (&B);
188
    break;
189
    case 67:
190
      thechar = (&C);
191
    break;
192
    case 68:
193
      thechar = (&D);
194
    break;
195
    case 69:
196
      thechar = (&E);
197
    break;
198
    case 70:
199
      thechar = (&F);
200
    break;
201
    case 71:
202
      thechar = (&G);
203
    break;
204
    case 72:
205
      thechar = (&H);
206
    break;
207
    case 73:
208
      thechar = (&I);
209
    break;
210
    case 74:
211
      thechar = (&J);
212
    break;
213
    case 75:
214
      thechar = (&K);
215
    break;
216
    case 76:
217
      thechar = (&Lima);
218
    break;
219
    case 77:
220
      thechar = (&M);
221
    break;
222
    case 78:
223
      thechar = (&N);
224
    break;
225
    case 79:
226
      thechar = (&O);
227
    break;
228
    case 80:
229
      thechar = (&P);
230
    break;
231
    case 81:
232
      thechar = (&Q);
233
    break;
234
    
235
    case 82:
236
      thechar = (&R);
237
    break;
238
    case 83:
239
      thechar = (&S);
240
    break;
241
    case 84:
242
      thechar = (&T);
243
    break;
244
    case 85:
245
      thechar = (&U);
246
    break;
247
    case 86:
248
      thechar = (&V);
249
    break;
250
    case 87:
251
      thechar = (&W);
252
    break;
253
    case 88:
254
      thechar = (&X);
255
    break;
256
    case 89:
257
      thechar = (&Y);
258
    break;
259
    case 90:
260
      thechar = (&Z);
261
    break;
262
  }
263
}
264
265
int main(void) {
266
  const uint8_t tic = 1; // const-wert für delay (siehe Doku delay.h)
267
  DDRB=0xFF;
268
  DDRD=0b10111111;
269
  PORTB=0x00;
270
  PORTD=0b01000000;
271
272
  volatile unsigned int i,j,l;    
273
  // Diese Schleife durchläuft das Alphabet
274
  for (l=65; l<90; ++l){
275
    // Zeiger updaten
276
    getChar(l);
277
    // Diese Schleife zeigt das Zeichen 20x an
278
    for (j=0; j<20;++j){
279
      // Diese Schleife durchläuft die 5 Zeilen
280
      for (i=0; i<5;++i){
281
        PORTB=(*thechar)[i];
282
        activateRow(i);
283
        _delay_ms(tic);
284
        deactivateRow();
285
      }
286
    }
287
  }
288
  return 0;
289
}

Die Krux liegt jetzt scheinbar in der Funktion getChar. Wenn ich in 
dieser Funktion die mögliche Anzahl von switch-cases auf unter 11 
bringe, also zum Beispiel nur von A-J oder von L-T, ist alles prima.
Aber sobald in dieser Funktion mehr als 10 switch-cases auftauchen 
bekomme ich vielfältige Fehler. Vom Komplettausfall der Schaltung, bis 
hin zu Pixelfehlern in einzelnen Buchstaben. Selbst wenn ich dann in der 
äussersten Schleife in main() nur auf einen Buchstaben zugreife 
entstehen Fehler.

Es ist mir völlig unerklärlich, ich lese und probiere seit drei Tagen, 
und bin mittlerweile echt kurz vorm Ausrasten ...

Das Makefile anbei !

von Achim (Gast)


Lesenswert?

So einen langen Quelltext solltest du nicht direkt in den Text einfügen 
sondern anhängen!

Dein Problem ist das dir der RAM ausgeht. Die Variablen A-Z usw. werden 
nicht (nur) im Flash gespeichert sondern in den RAM kopiert, wenn du sie 
nicht mit dem PROGMEM Attribut versiehst. Das geht bei 10 case 
statements noch grade so gut, da die nicht verwendeten Variablen vom 
Compiler wegoptimiert werden. Wie das mit dem PROGMEM funktioniert und 
du nachher auf den Flash Speicher zugreifen kannst findest du im AVR GCC 
Tutorial.

Außerdem nutzt du als Datentyp überall int, deren Wertebereich größer 
ist als du benötigst. Das ist also auch Platzverschwendung. Im AVR GCC 
Tutorial findest du etwas zu Typen wie uint8_t, die z.B. für die A-Z 
Variablen besser geeignet sind.

von makkes (Gast)


Lesenswert?

Langen Code anhängen. Geht klar :-)

Am Anfang hatte ich mit den avr-typen gearbeitet. Bei der Fehlersuche 
habe ich dann auf mir bekanntere Datentypen zurückgegriffen.

Dass der RAM nur 128 Byte groß ist, war mir schlichtweg nicht klar... 
bzw. habe ich es seit den Zeiten meiner Bascomprojekte wieder vergessen. 
In BASCOM hatte ich das damals über eine Lookup gemacht, genau aus dem 
Grund, das diese dort auf dem Flash landen.

Dann merke ich mir jetzt:
Alle const-Variablen in den Flash ?
const wegen der begrenzten Anzahl von Schreibzylen?

Nun denn. 456983458 x Danke.
Jetzt kann ich wieder ruhig schlafen.

von Oliver (Gast)


Lesenswert?

makkes schrieb:
> const wegen der begrenzten Anzahl von Schreibzylen?

Nö. const, weil du in den Flash sowieso nicht schreiben kannst.

Oliver

von makkes (Gast)


Angehängte Dateien:

Lesenswert?

Also nochmals vielen Dank. Es läuft prima, und der Text scrollt sogar.
Da ich es immer doof finde, wenn in Foren geholfen wird, die Lösung vom 
Threadstarter aber dann nicht gezeigt wird, hänge ich meinen Code 
nochmal an.

Im Moment verschenke ich ja noch pro Bitmuster 15 Byte. Falls mich 
jemand in die richtige Richtung schubsen möchte...

BTW: Spricht man bei den AVR-Riscs dann von Harvard-Architektur ?
Sind die 128 Byte lediglich sowas wie der Stack?

von makkes (Gast)


Lesenswert?

makkes schrieb:
> 15 Byte.

ich meinte Bit

Ich bitte um Verzeihung, sollte ich jetzt gerade die Edit-Funktion nicht 
finden.

von ThomasH (Gast)


Lesenswert?

bitte das nicht falsch verstehen, so wie du das ganze geschrieben hast 
funktioniert es zwar, aber schön ist es nicht.
1
#include "*.c"

tut einem schon ziemlich weh. C Dateien soll man nie einbinden, nur 
Header Dateien mit Definitionen. C Dateien werden nie eingebunden. Wenn 
es nicht anders geht kann man globale Variablen aus einem C file mittels 
einer extern Deklaration im H File einbinden, aber das ist auch nicht so 
schön.

Am schönsten wäre du gibst die getchar Funktion in das C File und gibst 
damit einen char pointer auf das gewünschte Zeichen zurück.

von Karl H. (kbuchegg)


Lesenswert?

Das hier
1
// Kopiert ein Bitmuster in einen Zwischenspeicher, da die Buchstaben per shift gescrollt werden.
2
void copyChar(void){
3
  uint8_t i;
4
  for (i=0; i < 5; i++){
5
    thecharcopy[i] = pgm_read_byte(ptr_to_array);
6
    ptr_to_array++;
7
  }
8
  ptr_to_array--;
9
  ptr_to_array--;
10
  ptr_to_array--;
11
  ptr_to_array--;
12
  ptr_to_array--;
13
}
ist nicht gerade ein Ruhmesblatt

1
// Kopiert ein Bitmuster in einen Zwischenspeicher, da die Buchstaben per shift gescrollt werden.
2
void copyChar(void){
3
4
  uint8_t i;
5
  for (i=0; i < 5; i++){
6
    thecharcopy[i] = pgm_read_byte(ptr_to_array + i);
7
  }
8
}

überhaupt hast du viele, viele globale Variablen, die so nicht sehr gut 
als globale aufgehoben sind und besser als Parameter an Funktionen 
übergeben werden sollten.

zb hier
1
//ermittelt das Zeichen des Ausgabetextes mit dem Index stringindex, und setzt den Array-Pointer auf 
2
//das erste Element des als nächstes anzuzeigenden Zeichens.
3
void getChar(uint8_t stringindex){
4
  uint8_t letter;
5
  const uint8_t* thecharadr;
6
  thecharadr = text;
7
  thecharadr += stringindex;
8
  letter = pgm_read_byte(thecharadr);
9
10
  switch(letter){
11
...

Deine Funktionen kommunizieren alle über globale Variablen und sind 
damit nicht sehr universell

Besser
1
//ermittelt das Zeichen des Ausgabetextes mit dem Index index,
2
// und setzt den Array-Pointer auf 
3
//das erste Element des als nächstes anzuzeigenden Zeichens.
4
void getChar_p(const char* text, uint8_t index)
5
{
6
  char letter;
7
  letter = pgm_read_byte( &text[index] );
8
  getSingleChar( letter );
9
}
10
11
void getSingleChar( char letter )
12
{
13
  switch(letter){
14
....

Zusätzlich:
Wenn du deine Buchstaben-Muster in einem 2D Array anordnen würdest, 
würdest du den ganzen riesigen switch-case gar nicht brauchen.


1
const uint8_t (*ptr_to_array);
mach besser die Klammern weg. Die verwirren hier

von makkes (Gast)


Lesenswert?

Huiuiui... harte Schule hier.

Also zu meiner Verteidigung möchte ich erstmal sagen, dass ich viel in 
C++ und Java programmiere. Auch komplexere Dinge. Objektorientierung, 
API und was so dazu gehört sind mir sicher keine Fremwörter. Allerdings 
habe ich da Konsole mit Debugger und dem ganzen Krempel.
Am uC habe ich keine Möglichkeit zu debuggen (programmiere per ISP), und 
das Programm ist erst mein zweites C-Programm.

@Klaus: YMMD ! Schon lustig....

@ThomasH
Hast ja recht. Auch wenn ich mich frage wo - technisch - der Unterschied 
sein soll. Wenn ich die Funktion getChar und die Bitmuster in eine .lib, 
.a, .o oder was auch immer kompiliere und das dann in meinem main.c 
includiere ist das doch genau das selbe?

@Karl h.
Also das mit der Schleife dem Pointer ... mea Culpa ... kommt davon wenn 
man die ganze Nacht vor den selben par Zeilen sitzt. Ich hasse Pointer !

Ihr habt natürlich beide mit allem völlig recht, es wäre sinnvoller sich 
- genau wie bei einem "richtigen" Projekt mit mehr als 500 Zeilen - eine 
vernünftige API und Headerfiles und allem drum und dran auszudenken. Von 
Anfang an... Beim Thema C und uC fehlt mir halt noch Routine. Ich denke 
noch mehr über Adressen und Casts und die Elektronik nach.

Im Moment grübel ich darüber wie ich die Bitmuster abspeicher ohne 
jedesmal 3 Bit zu verschenken.
Das einzige was mir einfällt, wäre halt 5x5=25Bit also 4 byte zu 
benutzen, die 25Bit darauf zu verteilen, und dann umständlich darin 
rumspringen.

Das ist trivial und kompliziert zu gleich. C ist nicht so mein Ding 
befürchte ich...

Ich melde mich dann nochmal mit einer aufgeräumten Version. Ich sehe es 
ja ein ...

von Karl H. (kbuchegg)


Lesenswert?

makkes schrieb:

> Im Moment grübel ich darüber wie ich die Bitmuster abspeicher ohne
> jedesmal 3 Bit zu verschenken.

Vergiss es. Das lohnt nicht.
Wenn du irgendwann die Muster ins Flash legst, ist das kein Thema mehr. 
Die 10 Bytes, die du in Summe vielleicht einsparen kannst lohnen nicht. 
Die gehen dann nämlich für den Code drauf, den du brauchst um wieder 
alles auseinanderzupfriemeln. Dafür zwirbelst du dir aber eine 
unwartbare Tabelle auf.

von ThomasH (Gast)


Lesenswert?

makkes schrieb:
> @ThomasH
> Hast ja recht. Auch wenn ich mich frage wo - technisch - der Unterschied
> sein soll. Wenn ich die Funktion getChar und die Bitmuster in eine .lib,
> .a, .o oder was auch immer kompiliere und das dann in meinem main.c
> includiere ist das doch genau das selbe?

Wie oben schon gesagt, hier funktioniert das ganze noch und ich hätte 
vielleicht gleich alles in ein File geschmissen, dass ist ja auch das 
was du mit dem #include erreichst. Einen Unterschied macht es erst so 
richtig wenn du deine Bitmuster in zwei C Files verwenden willst. Denn 
da generierst du durch das inkludieren von C Code in jedem File wo du 
etwas einbindest deine Bitmuster und alles was sonst noch so in dem 
eingebundenen C File stehen würde erzeugt für jedes mal einbinden Code.

Noch schlimmer wird es, weil zB globale Variablen in den verschiedenen 
eingebundenen C Files unabhängig voneinander sind, dh wenn teil1.c und 
teil2.c ein anderes File funktion.c einbinden und teil1.c eine globale 
Variable in funktion.c verändert, sieht das teil2.c nicht, weil alles 
jeweils nur in teil1.c bzw teil2.c passiert.

Darum werden C Files nicht eingebunden. Wenn man jetzt auf globale 
Variablen aus anderen Source Files zugreifen will, zB weil man sich eine 
Wrapper Funktion sparen will, schmeißt man eine
1
extern const uint8_t A[5]=...;
Deklaration in das Headerfile und inkludiert das. Oder man schreibt 
gleich das gewünschte Interface, dass einem Pointer, oder wenn die Daten 
klein sind die Daten selbst, zurück liefert.

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.