www.mikrocontroller.net

Forum: Compiler & IDEs Stecke seit Tagen fest Hilfe !


Autor: makkes (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht 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
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <avr/io.h>
#include <util/delay.h>

// Zeiger auf das aktuell anzuzeigende Bitmuster
int (*thechar)[5];

//nachfolgend Bitmuster für alle Buchstaben
const int A[5]={ 0b00001110,
              0b00010001,
              0b00011111,
              0b00010001,
              0b00010001};
const int B[5]={ 0b00011110,
              0b00010001,
              0b00011110,
              0b00010001,
              0b00011110};
const int C[5]={ 0b00001111,
              0b00010000,
              0b00010000,
              0b00010000,
              0b00001111};
const int D[5]={ 0b00011110,
              0b00010001,
              0b00010001,
              0b00010001,
              0b00011110,};
const int E[5]={ 0b00011111,
              0b00010000,
              0b00011110,
              0b00010000,
              0b00011111,};
const int F[5]={ 0b00011111,
              0b00010000,
              0b00011110,
              0b00010000,
              0b00010000,};
const int G[5]={ 0b00001111,
              0b00010000,
              0b00010011,
              0b00010001,
              0b00001111,};
const int  H[5]={ 0b00010001,
              0b00010001,
              0b00011111,
              0b00010001,
              0b00010001,};
const int  I[5]={ 0b00001110,
              0b00000100,
              0b00000100,
              0b00000100,
              0b00001110};
const int  J[5]={ 0b00001110,
              0b00000010,
              0b00000010,
              0b00010010,
              0b00001100};
const int  K[5]={ 0b00010001,
                  0b00010010,
                  0b00011100,
                  0b00010010,
                  0b00010001};
const int  Lima[5]={ 0b00010000,
                  0b00010000,
                  0b00010000,
                  0b00010000,
                  0b00011111};
const int  M[5]={ 0b00010001,
                  0b00011011,
                  0b00010101,
                  0b00010001,
                  0b00010001};
const int  N[5]={ 0b00010001,
              0b00011001,
              0b00010101,
              0b00010011,
              0b00010001};
const int  O[5]={ 0b00001110,
              0b00010001,
              0b00010001,
              0b00010001,
              0b00001110};
const int  P[5]={ 0b00011110,
              0b00010001,
              0b00011110,
              0b00010000,
              0b00010000};
const int  Q[5]={ 0b00001110,
              0b00010001,
              0b00010101,
              0b00010011,
              0b00001111};
const int  R[5]={ 0b00011110,
              0b00010001,
              0b00011110,
              0b00010010,
              0b00010001};
const int  S[5]={ 0b00001111,
              0b00010000,
              0b00001110,
              0b00000001,
              0b00011110};
const int  T[5]={ 0b00011111,
              0b00000100,
              0b00000100,
              0b00000100,
              0b00000100};
const int  U[5]={ 0b00010001,
              0b00010001,
              0b00010001,
              0b00010001,
              0b00011111};
const int  V[5]={ 0b00010001,
              0b00010001,
              0b00010001,
              0b00001010,
              0b00000100};
const int  W[5]={ 0b00010001,
              0b00010001,
              0b00010001,
              0b00010101,
              0b00001010};
const int  X[5]={ 0b00010001,
              0b00010001,
              0b00001110,
              0b00010001,
              0b00010001};
const int  Y[5]={ 0b00010001,
              0b00010001,
              0b00001010,
              0b00000100,
              0b00000100};
const int  Z[5]={ 0b00011111,
              0b00000010,
              0b00000100,
              0b00001000,
              0b00011111};
const int  SPACE[5]={ 0b00000000,
              0b00000000,
              0b00000000,
              0b00000000,
              0b00000000};
const int  DOT[5]={ 0b00000000,
              0b00000000,
              0b00000100,
              0b00000000,
              0b00000000};

// aktiviert eine Matrixzeile, und setzt alle anderen null. Lediglich Bit 
// D6 wird auf 1 gelassen, da er ein Eingang ist.
void activateRow(int row){
  switch(row){
    case 4:
      PORTD=0b01010000;
    break;
    case 3:
      PORTD=0b01100000;
    break;
    case 2:
      PORTD=0b01000100;
    break;
    case 1:
      PORTD=0b01000010;
    break;
    case 0:
      PORTD=0b01000001;
    break;
  }
}
//Alles aus, ausser dem Eingang auf Pin D6
void deactivateRow(void){
  PORTD=0b01000000;
}

// Hier kann per ASCII-Code der Zeiger auf ein Bitmuster gestellt werden.
// HIER STIMMT WAS NICHT
void getChar(int letter){

  switch(letter){
    case 65:
      thechar = (&A);
    break;
    case 66:
      thechar = (&B);
    break;
    case 67:
      thechar = (&C);
    break;
    case 68:
      thechar = (&D);
    break;
    case 69:
      thechar = (&E);
    break;
    case 70:
      thechar = (&F);
    break;
    case 71:
      thechar = (&G);
    break;
    case 72:
      thechar = (&H);
    break;
    case 73:
      thechar = (&I);
    break;
    case 74:
      thechar = (&J);
    break;
    case 75:
      thechar = (&K);
    break;
    case 76:
      thechar = (&Lima);
    break;
    case 77:
      thechar = (&M);
    break;
    case 78:
      thechar = (&N);
    break;
    case 79:
      thechar = (&O);
    break;
    case 80:
      thechar = (&P);
    break;
    case 81:
      thechar = (&Q);
    break;
    
    case 82:
      thechar = (&R);
    break;
    case 83:
      thechar = (&S);
    break;
    case 84:
      thechar = (&T);
    break;
    case 85:
      thechar = (&U);
    break;
    case 86:
      thechar = (&V);
    break;
    case 87:
      thechar = (&W);
    break;
    case 88:
      thechar = (&X);
    break;
    case 89:
      thechar = (&Y);
    break;
    case 90:
      thechar = (&Z);
    break;
  }
}

int main(void) {
  const uint8_t tic = 1; // const-wert für delay (siehe Doku delay.h)
  DDRB=0xFF;
  DDRD=0b10111111;
  PORTB=0x00;
  PORTD=0b01000000;

  volatile unsigned int i,j,l;    
  // Diese Schleife durchläuft das Alphabet
  for (l=65; l<90; ++l){
    // Zeiger updaten
    getChar(l);
    // Diese Schleife zeigt das Zeichen 20x an
    for (j=0; j<20;++j){
      // Diese Schleife durchläuft die 5 Zeilen
      for (i=0; i<5;++i){
        PORTB=(*thechar)[i];
        activateRow(i);
        _delay_ms(tic);
        deactivateRow();
      }
    }
  }
  return 0;
}

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 !

Autor: Achim (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: makkes (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Oliver (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
makkes schrieb:
> const wegen der begrenzten Anzahl von Schreibzylen?

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

Oliver

Autor: makkes (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht 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?

Autor: makkes (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
makkes schrieb:
> 15 Byte.

ich meinte Bit

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

Autor: ThomasH (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
bitte das nicht falsch verstehen, so wie du das ganze geschrieben hast 
funktioniert es zwar, aber schön ist es nicht.
#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.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das hier
// Kopiert ein Bitmuster in einen Zwischenspeicher, da die Buchstaben per shift gescrollt werden.
void copyChar(void){
  uint8_t i;
  for (i=0; i < 5; i++){
    thecharcopy[i] = pgm_read_byte(ptr_to_array);
    ptr_to_array++;
  }
  ptr_to_array--;
  ptr_to_array--;
  ptr_to_array--;
  ptr_to_array--;
  ptr_to_array--;
}
ist nicht gerade ein Ruhmesblatt

// Kopiert ein Bitmuster in einen Zwischenspeicher, da die Buchstaben per shift gescrollt werden.
void copyChar(void){

  uint8_t i;
  for (i=0; i < 5; i++){
    thecharcopy[i] = pgm_read_byte(ptr_to_array + i);
  }
}

ü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
//ermittelt das Zeichen des Ausgabetextes mit dem Index stringindex, und setzt den Array-Pointer auf 
//das erste Element des als nächstes anzuzeigenden Zeichens.
void getChar(uint8_t stringindex){
  uint8_t letter;
  const uint8_t* thecharadr;
  thecharadr = text;
  thecharadr += stringindex;
  letter = pgm_read_byte(thecharadr);

  switch(letter){
...

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

Besser
//ermittelt das Zeichen des Ausgabetextes mit dem Index index,
// und setzt den Array-Pointer auf 
//das erste Element des als nächstes anzuzeigenden Zeichens.
void getChar_p(const char* text, uint8_t index)
{
  char letter;
  letter = pgm_read_byte( &text[index] );
  getSingleChar( letter );
}

void getSingleChar( char letter )
{
  switch(letter){
....

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.


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

Autor: makkes (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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 ...

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: ThomasH (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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
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.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.