Forum: Compiler & IDEs Von Arrays zu einem String


von Hendrik S. (gustaf3459)


Lesenswert?

Hoi,
ich habe mit eine Punktmatrix gebastelt (angesteuert von 4 max2719) 
Controller ist ein ATmega8. Aber zurück zu meiner Frage/mein Problem...
Bisher habe ich sowas hier getippt... bin noch neueinsteiger also sorry 
für das chaos ^^


char H[]={0b01111110,0b00010000,0b00010000,0b01111110,0b00000000};
char a[]={0b00011110,0b00010010,0b00011110,0b00000010,0b00000000};
char l[]={0b01111110,0b00000000};
char o[]={0b00011110,0b00010010,0b00011110,0b00000000};
char 
clr[]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 
0x00,0x00,0x00,0x00,0x00,0x00,0x00};

char j=0;

while(1)
{


  for (j=0;j<5;j++)         //H Ausgeben
  {
    Ausgabe(cursor,H[j]);
     weiter();
  }
  for (j=0;j<5;j++)           //a Ausgeben
  {
    Ausgabe(cursor,a[j]);
    weiter();
  }
  for (j=0;j<2;j++)           //l Ausgeben
  {
    Ausgabe(cursor,l[j]);
    weiter();
  }
  for (j=0;j<2;j++)           //l Ausgeben
  {
    Ausgabe(cursor,l[j]);
    weiter();
  }
  for (j=0;j<4;j++)           //o Ausgeben
  {
    Ausgabe(cursor,o[j]);
    weiter();
  }
  cursor=1;

  for (j=0;j<20;j++)           //löschen
  {
    Ausgabe(cursor,clr[j]);
    weiter();
  }
  cursor=1;
}
}

void weiter(void)
{
    cursor++;
    _delay_ms(100);
}

void Ausgabe(char Zeile,char MaxData)
{
char I=0;
char Tmp=0;
char Shift=0;
char MaxAdress=0;

  if (Zeile>20)    //maximale Spalten
  return;

  while (Zeile>5)    //Wenn in Zeile 6-10,11-15,16-20 müssen die Daten 
in den nächsten MAX geschoben werden
  {
  Zeile-=5;
  Shift+=16;
  }

  if (Zeile==5)      //Kleiner Entflechtungsfehler ^^
    MaxAdress=0x01;    //Sollte normalerweise so aussehen
              //12345 12345 12345...
  if (Zeile==4)      //Sieht aber von den zeilen so aus:
    MaxAdress=0x02;    //54321 54321 54321

  if (Zeile==3)
    MaxAdress=0x03;

  if (Zeile==2)
    MaxAdress=0x04;

  if (Zeile==1)
    MaxAdress=0x05;


  for(I=0;I<8;I++)        //Übtragung seriell an MAX
  {
    Tmp=MaxAdress;
    MaxAdress&=0x80;
    MaxAdress>>=7;
    PORTD=MaxAdress;  //DIN
    PORTD|=0x02;    //CLK
    PORTD=0x00;
    MaxAdress=Tmp;
    MaxAdress<<=1;
  }
  for(I=0;I<8;I++)
  {
    Tmp=MaxData;
    MaxData&=0x80;
    MaxData>>=7;
    PORTD=MaxData;    //DIN
    PORTD|=0x02;    //CLK
    PORTD=0x00;
    MaxData=Tmp;
    MaxData<<=1;
  }
  for(I=0;I<Shift;I++)  //daten in hinteren MAX weiterschieben
  {
  PORTD|=0x02;    //CLK
  PORTD=0x00;
  }

  PORTD=0x04;
  PORTD=0x00;

  for(I=0;I<64;I++)    //Schieberegister im MAX leeren
  {
  PORTD=0x02;
  PORTD=0x00;
  }
}


ich habe um mein "Hallo" auszugeben muss ich also punktmatrixmäßig meine 
daten in die MAX-Bausteine schreiben. Wie ihr seht habe ich in meiner 
while-schleife jeden einzelnen buchstaben aufgerufen und ausgegeben... 
ich bin auf der suche nach einer vereinfachung durch einen String mit 
inhalt "Hallo". ich weiß aber nicht wie ich eine verbindung meiner 
binären inhalte zu den buchstaben schaffe. habe mir mal das programm des 
elektor-kreisels (falls bekannt) reingezogen und gesehen, dass es 
derartige möglichkeiten gibt =)
dort habe ich EIN array gefunden, worin alle buchstaben hintereinander 
hinterlegt waren und #define string_1 "Text". Woher weiß mein String , 
dass er erst an der bestimmten stelle für den buchstaben aus dem array 
auslesen soll ? wenn im array[]={0x00,0x00,0x00,0x00 //Space ,0x12,012 
//A, ... usw} steht ?

ich hab erst gestern von stück-für-stück-programmierung zum array 
gefunden. aus meinem lehrbuch "c für dummies" hab ich eine schöne 
erklärung für die funktionsweise von arrays gefunden. bin bei strings 
aber völlig ratlos. wenn mir da vielleich jemand auch ein bisschen was 
erklären könnte wär es ganz nett =) mein ziel ist es später einen 
beliebigen text auszugeben (später dann in laufschrift)

ich hoffe ihr könnt mir helfen

mfg hendrik

von Udo R. S. (Gast)


Lesenswert?

Die Lösung deines Problems heisst Sprungtabelle.
Jedes Zeichen ist eigentlich eine 8 Bit Zahl. Stichwort ASCII Code. die 
'0' z.B. ist 30h (=48 dezimal) das große 'A' ist 41h.
Du legst die Codierung der Zeichen in einem großen Array ab.
In einem weiteren Array von Shorts (Der Sprungtabelle) legst Du jetzt 
die Anfangsadresse der Codierung des entsprechenden Zeichens an genau 
der Stelle im Array ab, das dem ASCII Code des Zeichens entspricht.
In Deinem Codierungsarray musst Du jetzt noch eine Möglichkeit vorsehen 
zu erkennen wann die Codierung des Zeichens fertig ist. Das kannst Du 
entweder so machen, daß das erste Byte der Anzahl der folgenden Bytes 
entspricht, oder Du weisst daß das letzte Codierungsbyte null ist (der 
Abstand zum nächsten Zeichen).
Jetzt brauchst Du nur eine Funktion schreiben, die einen String oder ein 
Einzelzeichen nimmt und entsprechend die Codierung herausfindet.

Beispiel:
Du willst ein 'c' ausgeben:
Deine Funktion macht jetzt folgendes:
Ein 'c' hat den Code 63h. Du holst die 16Bit Wert (unsigned short) an 
der Stelle 63 deiner Sprungtabelle. Dieser Wert ist der Offset in deinem 
(großen) Array mit den Codierbytes. Ab dieser Stelle liest Du jetzt 
solange die aufeinanderfolgenden Bytes und gibst sie aus, bis ein Byte 
mit dem Wert 0 kommt.

Versuch das zu verstehen und probiere es erst mal nur mit ein paar 
Buchstaben.
Das Ganze kann man natürlich noch optimieren, wenn man nur einen Teil 
der Zeichen (nur Buchstaben und Zifferen) oder nur großbuchstaben 
benutzen will. Dann implementiert man nur den Teil der Sprungtabelle den 
man braucht und zieht entsprechend einen Offset von dem Buchstaben ab.

von Karl H. (kbuchegg)


Lesenswert?

Hendrik S. schrieb:

> inhalt "Hallo". ich weiß aber nicht wie ich eine verbindung meiner
> binären inhalte zu den buchstaben schaffe.

Jeder 'Buchstabe' ist gleichzeitig auch eine Zahl. Siehe ASCII Code.

> dort habe ich EIN array gefunden, worin alle buchstaben hintereinander
> hinterlegt waren und #define string_1 "Text". Woher weiß mein String ,
> dass er erst an der bestimmten stelle für den buchstaben aus dem array
> auslesen soll ? wenn im array[]={0x00,0x00,0x00,0x00 //Space ,0x12,012
> //A, ... usw} steht ?

Wenn im Text der Buchstabe 'A' vorkommt, so steht im Speicher da in 
Wirklichkeit eine Zahl. Nämlich die Zahl die im ASCII Code für 'A' 
steht. In einem Computer gibt es keine Buchstaben, nur Zahlen. Erst dein 
Ausgabegerät weiß, dass wenn es die Zahl 0x41 erhält, dass es dafür ein 
bestimmtes Bitmuster auf den Schirm pinseln muss, bei dem genau die 
Pixel dunkel gesetzt sind, so dass dein Gehirn daraus ein 'A' macht.

-> Man kann auch mit 'Buchstaben' in ein Array indizieren, da ja ein 
Buchstabe im Computer nichts anderes als eine Zahl ist

  0x41,  65,  'A'
sind nur verschiedene Schreibweisen für immer dasselbe. Nämlich das 
Bitmuster 01000001. So liegt es im Speicher. Alles andere ist eine 
Interpretationsfrage und wird entschieden wenn es gilt dieses Bitmuster 
auf ein Ausgabegerät auszugeben. Erst dann erhebt sich die Frage: 
Welches ist die angemessene Anzeigeform dafür, was interessiert mich? 
Will ich das als Zahlenwert sehen? Hex oder Dezimal? Oder will ich 
dieses Bitmuster überhaupt nicht umgeformt sehen und das AUsgabegerät 
soll den zu diesem Bitmuster gehörenden 'Buchstaben' aus dem ASCII Code 
anzeigen.

von Karl H. (kbuchegg)


Lesenswert?

Udo R. S. schrieb:
> Die Lösung deines Problems heisst Sprungtabelle.

Ich denke für einen Einsteiger, der mit Arrays noch auf Kriegsfuss 
steht, ist es zunächst wesentlich einfacher sich zunächst an einem 
nicht-proportionalen Font zu versuchen.

In diesem Sinne hat man dann einfach nur ein 2D-Array
1
unsigned char BitCodes[255][5] = {
2
   { ..... }    // Die 5 Codes für das Zeichen mit dem ASCII Code 0
3
   ...
4
5
   { 0b01111110,0b00010000,0b00010000,0b01111110,0b00000000 }, // Die 5 Codes für das Zeichen mit dem ASCII Code 72, 'H'
6
   ...

zu haben und mit dem Character zu indizieren.
1
void putc( unsigned char c )
2
{
3
  for( unsigned char i = 0; i < 5; ++i )
4
  {
5
    // ausgabe von BitCodes[c][i]
6
  }
7
}
8
9
void puts( const char* s )
10
{
11
  while( *s )
12
    putc( *s++ );
13
}
14
15
16
int main()
17
{
18
  ...
19
  puts( "Hallo world" );
20
}

Und jetzt ran an die Bulletten und die Codetabelle für die noch 
fehlenden Zeichen ergänzt.

Wenn du das hast und begriffen hast, wie das mit den Arrays 
funktioniert, kannst du dich an Optimierungen versuchen (zb weil die 
ersten 32 Zeichen im ASCII Code keine sichtbare Darstellung haben und 
damit auch nicht in der Tabelle sein müssen), bzw. an einem 
proportionalen Font.

von Udo R. S. (Gast)


Lesenswert?

>Ich denke für einen Einsteiger, der mit Arrays noch auf Kriegsfuss
>steht, ist es zunächst wesentlich einfacher sich zunächst an einem
>nicht-proportionalen Font zu versuchen.

hast Du wahrscheinlich recht :-)

Wobei ein 2-dimensionales Array auch nicht gerade trivial ist.

> void putc( unsigned char c )

gibts da nicht Probleme, das ist eine Standardfunktion, besser für die 
Funktion einen eigenen Namen nehmen z.B. "myputc".

von Karl H. (kbuchegg)


Lesenswert?

Udo R. S. schrieb:

>> void putc( unsigned char c )
>
> gibts da nicht Probleme, das ist eine Standardfunktion, besser für die
> Funktion einen eigenen Namen nehmen z.B. "myputc".

Ooops. Hast recht.
Da hab ich geschlafen. puts() dasselbe.

von Hendrik S. (gustaf3459)


Angehängte Dateien:

Lesenswert?

hallo,
hat soweit alles funktioniert ABER mein problem ist momentan, dass ich 
meine Zeichenanzahl zählen lassen will und in der Zeile:

>#define text "-Das ist eine Laufschrift von Hendrik Schulz-"
......
>void zaehl_zeichen(char* k)
>{
>  if(merker==0)
>  {
>  while( *k )
>  {
>     *k++;      //<----------------------
>    Zeichenanzahl++;
>  }
>  time-=Zeichenanzahl;
>  Zeichenanzahl*=6;
>  if (time<=0)
>  time=1;
>  merker=1;
>  }
>}
.....
>zaehl_zeichen(text);

die warning vom compiler "../Dotmatrix.c:84: warning: value computed is 
not used" kommt ?! denke ich falsch ?? es geht bis zu einer 
zeichenanzahl von 45 in meinem string, dann kommt irgendetwas 
durcheinander und meine ausgabe fängt von vorne an (so als wär eine 
variable überfüllt)
habe auch mal das komplette programm angehängt.

wie mach ich überhaupt so ein weis hinterlegtes kommentar wie Karl heinz 
Buchegger? ^^

danke für antworten =)

von Hendrik S. (gustaf3459)


Lesenswert?

>es geht bis zu einer zeichenanzahl von 45 in meinem string,...

ich hatte in meinem 2D array eine zeile zu viel oben in der eckigen 
klammer angegeben... jetzt ist meine maximale länge um ca 10 zeichen 
gestiegen

kann es sein, dass das "char * k" überläuft, da char ja nur bis +127 
geht ??

von Karl H. (kbuchegg)


Lesenswert?

Hendrik S. schrieb:
>>es geht bis zu einer zeichenanzahl von 45 in meinem string,...
>
> ich hatte in meinem 2D array eine zeile zu viel oben in der eckigen
> klammer angegeben... jetzt ist meine maximale länge um ca 10 zeichen
> gestiegen
>
> kann es sein, dass das "char * k" überläuft, da char ja nur bis +127
> geht ??

Du solltest dir Konventionen für Variablennamen aneigenen.

1) einbuchstabige Variablennamen sind generell nicht so der Bringer

2) einbuchstabige Variablennamen werden normalerweise benutzt um
   Variablen mit lokalem kleinem Scope anzuzeigen. Also Funktions-
   lokale Variablen.
   Diese Variablen erfüllen aber nur Hilfsaufgaben. Wichtige Variablen
   darf man man schon mehr als nur ein Zeichen im Namen spendieren

3) die Variablennamen i, j, k, l, m, n  sind praktisch ausschliesslich
   für Zählvariablen reserviert. So wie in

   for( i = 0; i < 27; ++i )

   i ist also ein Zähler.

Bei dir ist k kein Zähler. k ist ein Pointer auf den Anfang des Strings, 
den die Funktion übergeben bekommt. Dieser Pointer hätte sich einen 
besseren Namen als k verdient

k++
stellt den Pointer um ein Zeichen weiter

Das * vor einem Pointer bedeutet den Pointer zu dereferenzieren.

*k++  hat also die Bedeutung: hole das Zeichen, auf das k zeigt und 
anschliessend stelle k um 1 Zeichen weiter.

Gut. Aber was machst du mit dem Zeichen, das hier geholt wird?
Die Antwort: Nichts!
Daher sagt dir der Compiler: Hey, du willst von mir, das ich da Zeichen 
hole aber du tust nichts damit. Also wozu dann überhaupt das Zeichen 
holen?


Wenn du die Länge eines Strings wissen willst, warum benutzt du dann 
nicht die Funktion strlen()? Genau dafür ist die da!

von Hendrik S. (gustaf3459)


Lesenswert?

> Wenn du die Länge eines Strings wissen willst, warum benutzt du dann
> nicht die Funktion strlen()? Genau dafür ist die da!

kannst du mit bitte ein beispiel für die funktion geben ? ^^
in meinem falle dann ein zeichenanzahl=strlen(text); ?!

ich dachte mit, dass ich einmal durch den string muss also jede stelle 
einmal  ansehen und meine zeichenanzahl so oft inkrementieren.. ^^

von Hendrik S. (gustaf3459)


Lesenswert?

Hendrik S. schrieb:
> kannst du mit bitte ein beispiel für die funktion geben ? ^^
> in meinem falle dann ein zeichenanzahl=strlen(text); ?!

:D ok nicht dumm rumfragen sondern einfach ausprobieren und geht ^^ zwar 
mit den warnings:
../Dotmatrix.c:121: warning: implicit declaration of function 'strlen'
../Dotmatrix.c:121: warning: incompatible implicit declaration of 
built-in function 'strlen'

bleibt jedoch mein fehler mit der zeichenbegrenzung meines strings... 
also zur funktionserklärung habe ich eine art maske (meine anzeige ist 
7x20) konstruiert. der gesamte text wird also ausgegeben , fängt halt an 
der letzten stelle an, wird nach links durchgeschoben (auch weiter aus 
der anzeige, das jedoch einfach nicht angezeigt wird) und der rest 
(zeile>20) wird ebenfalls nicht angezeit. ^^
also wenn meine zeichenanzahl <= zeile 0 dann soll es erneut beginnen. 
warum also tut mein grogramm das schon mitten im text (abhängig von der 
anzahl an eingetippten buchstaben) ?? irgendetwas muss da doch 
"überlaufen" =(
das programm ist mittlerweile 5,604 kb groß ... kann es sein, dass da 
was mit dem speicher nicht passt ? (laut datenblatt hab ich aber 8kb ?)

von Karl H. (kbuchegg)


Lesenswert?

Hendrik S. schrieb:
> Hendrik S. schrieb:
>> kannst du mit bitte ein beispiel für die funktion geben ? ^^
>> in meinem falle dann ein zeichenanzahl=strlen(text); ?!
>
> :D ok nicht dumm rumfragen sondern einfach ausprobieren und geht ^^ zwar
> mit den warnings:
> ../Dotmatrix.c:121: warning: implicit declaration of function 'strlen'
> ../Dotmatrix.c:121: warning: incompatible implicit declaration of
> built-in function 'strlen'


Siehe zb jedes noch so schlechte C-Buch oder
http://www.mikrocontroller.net/articles/FAQ#Wie_funktioniert_String-Verarbeitung_in_C.3F
für die absolut notwendige Kurzfassung


#include <string.h>

> bleibt jedoch mein fehler mit der zeichenbegrenzung meines strings...

Ganz ehrlich. Der Code ist mir viel zu unübersichtlich als das ich da 
jetzt groß zu analysieren anfange, was da passiert.

Schaff dir ein paar vernünftige Schichten an

* Eine Funktion die aus einem String 20 Zeichen (so sie existieren) ab
  einer pestimmten Position auf dem LCD ausgibt.

* Darüber liegt eine Funktion, die einen beliebig langen String
  ausgeben kann, dass tut sie indem sie nacheinander die
  vorhergehende Funktion bemüht, wobei immer um 1 Zeichen
  weitergeschaltet wird, bis der String zu Ende ist.

Programmieren bedeutet nicht, möglichst viel Funktionalität in eine 
Funktion reinquetschen, sondern sich einen Baukasten aus Funktionen 
zurechtzuschneidern. Von einfachen Funktionen bis zu komplizierteren 
Funktionen, die die einfachen Funktionen benutzen um ihre komplizierte 
Arbeit zu erledigen.

Gib deinen Funktionen und Variablen vernünftige Namen.
Ausg, Ausg_1, Ausg_2 sind keine vernünftige Namen.
Ein Funktionsname soll beschreiben was die Funktion tut. Wenn es dabei 
eine Besonderheit gibt, dann soll sich diese Besonderheit im Namen 
wiederspiegeln. Den Unterschied zwischen Ausg_1 und Ausg_2 kann man am 
Namen nicht ablesen.

von Hendrik S. (gustaf3459)


Lesenswert?

ich denke mein problem ist es, dass ich mir das selbst beibringe und 
sonst keinen habe , der mich auf formfehler hinweist und mir iwas 
erklären kann =( ich würde gerne mein c-buch richtig durchackern und 
alles mal ausprobieren.. ich hab aber nur die möglichkeit direkt auf µc 
umzusteigen und zu testen ob ich irgendwas verstanden habe und dazu 
fehlen mir vielleich grundlegende dinge...
hierzu kommt: ich finde hier im forum einen batzen an lustigen befehlen, 
die ich noch nie gesehen habe und da ich mein c-buch (sofern es da 
irgendwo wirklich drinnen steht) noch nicht "auswendig" kann. ich würde 
gerne stück für stück sachen ausprobieren um mich an C zu gewöhnen ^^

darum entschuldige ich mich für jegliche verwirrungen und verplantheit 
in meinem code wenn du das jedoch so siehst , dann ist es nicht ganz wie 
ein lcd mit 20 stellen zu sehen sondern wie ein lcd mit 3,5 xD ich muss 
also buchstaben auch teilweise ausgeben

ich werde mich dann wohl mal an eine andere durchführung meiner ausgabe 
kümmern. die stand nämlich schon ganz am anfang und ich hab versucht 
mein programm darauf anzupassen...

dennoch kleine frage:

ich hab ja teilweise "prototyp"-Namensvergebungen gemacht oder wie man 
das wirklich nennt :D...
geht das auch mit dem hier ?
>void Ausg_1(char* stringzeiger)

hab da einige möglichkeiten ausprobiert finde dazu aber keine lösung 
oder vielleich eine ohne warnungen vom compiler ? oder muss ich das 
komplett anders schreiben ?

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.