Forum: Mikrocontroller und Digitale Elektronik An die C-Profis: Datei einlesen und String teilen


von Borsty B. (mantabernd)


Lesenswert?

Hi,

wie hier schon beschrieben 
(Beitrag "Re: Anfänger braucht Hilfe mit TWI / I2C") versuche ich 
aktuell einen PCM3070 DSP Chip zu programmieren.

Die I2C Verbindung steht und ein Programm habe ich ebenfalls schon.

Mein Problem ist es nun die ca. 3000 Registerbefehle zu übertragen. Die 
Texas Instruments DSP Software gibt mir eine Config Datei mit allen 
Registern im folgenden Format aus:
1
w 30 01 01
2
>7b

Das heißt schreiben an die Adresse 30, Register 01, Wert 01 (alles in 
hex). Das >7b bedeutet dass das darauf folgende Register den Wert 7b 
erhält, ist also gleichbedeutend mit w 30 02 7b

Von diesen Befehlen gibt es wie gesagt ca. 3000 Stück.

Ich hab mir eine passende TWI Funktion geschrieben die ich mit 
TWI_send(add,reg,val) aufrufe.
Dem entsprechend müssten meine zwei TWI Befehle wie folgt lauten:
1
TWI_send(0x30,0x01,0x01);
2
TWI_send(0x30,0x02,0x7b);

Ich hab mir die Config Datei mit den Registern mit Hilfe der 
Find/Replace Funktion etwas angepasst. Die Befehle sehen nun so aus:
1
w,0x30,0x01,0x01
2
w,0x30,0x$$,0x07

Der erste Befehl ist klar, beim zweiten habe ich anstatt der 
Registeradresse $$ eingefügt, hier muss man erst das darauf folgende 
Register ermitteln (das kann Find/Replace ja leider nicht).

Ich hab nun zwei Probleme:

Zum einen brauch ich ein Programm dass mir Befehl für Befehl aus der 
Config Datei ausliest, beim Komma teilt, ein Array draus bildet und dann 
in den TWI_send Befehl packt.

Das Skript zum teilen hab ich mir bereits zurückgebastelt:
1
        char dsp_register[] = "w,0x30,0x01,0x01";
2
3
        char puffer_rw[10];
4
        char puffer_add[10];
5
        char puffer_reg[10];
6
        char puffer_val[10];
7
        
8
9
        if( sscanf( dsp_register,
10
        "%[^,],%[^,],%[^,],%[^,],",
11
        puffer_rw,
12
        puffer_add,
13
        puffer_reg,
14
        puffer_val
15
        )
16
        ==4
17
        )
18
        {
19
          sprintf(twi_register,"%H,%H,H%",puffer_add,puffer_reg,puffer_val);
20
        }

ABER wie schaff ich es dass die Daten von der Config Datei in das Skript 
kommen?

Das nächste Problem ist noch die Ermittlung der fehlenden Register. Man 
müsste sich also immer das vorherige Register merken und im Bedarfsfall 
eins hochzählen (geht das mit Hex überhaupt?!).

Ich hoffe ihr könnt mir helfen...


Vielen Dank schonmal und gute Nacht :)

von Borsty B. (mantabernd)


Angehängte Dateien:

Lesenswert?

So ich hab mich mal versucht und folgendes "gebastelt":

Die Werte aus der Configdatei habe ich mit Excel etwas bearbeitet und in 
die richtige Form gebracht, jeder Wert ist nun eine Variable und später 
soll in einer for() Schleife jede Variable aufgerufen, zerlegt und per 
TWI_send() abgearbeitet werden. Wenn eine Variable keinen Registerwert 
hat wird der zuvor gewählte um eins erhöht.
1
uint8_t i=1;
2
3
char puffer_rw[10];
4
char puffer_add[10];
5
char puffer_reg[10];
6
char puffer_val[10];
7
8
char *dspreg1="w,0x30,0x00,0x00";
9
char *dspreg1="w,0x30,0x00,0x00";
10
char *dspreg2="w,0x30,0x$$,0x01";
11
char *dspreg3="w,0x30,0x00,0x01";
12
char *dspreg4="w,0x30,0x$$,0x08";
13
char *dspreg5="w,0x30,0x$$,0x00";
14
char *dspreg6="w,0x30,0x47,0x32";
15
16
for (i=0; i<=6; i++)
17
    {
18
      
19
      sscanf(dspreg1,
20
      "%[^,],%[^,],%[^,],%[^,],",
21
      puffer_rw,
22
      puffer_add,
23
      puffer_reg,
24
      puffer_val);
25
      
26
        sprintf(ausgabe,"%s,%s,%s",puffer_add,puffer_reg,puffer_val);
27
      
28
      
29
      lcd_setcursor(0,1);
30
      lcd_string(ausgabe);
31
      lcd_setcursor(0,2);
32
      lcd_string(dspreg1);
33
      
34
      
35
    }

Ich gebe zur Kontrolle die Daten auf dem Display aus (sehe Anhang). 
Soweit klappt das ja alles recht gut, die Variablen werden korrekt 
zerlegt.

ABER wie schaff ich es dass die Variable dspreg1 hochzählt? Ich finde 
nirgends eine passende Funktion um das zu machen. Mit sprintf() hab ich 
es versucht, bringt aber nur Mist raus, strcat() klappt leider auch 
nicht. Aus php kenn ich es dass man z.b.
1
$dspregx = "dspreg'.$i.'";

schreiben kann. Das Ergebnis von $dspregx wäre dann beim ersten 
Schleifendurchlauf dspreg1, beim zweiten Durchlauf dspreg2, usw... Geht 
sowas bei c auch irgendwie?

Achja, wann verwende ich eigentlich char *variable; und wann char 
variable[]; und was hat es mit dem * auf sich?

Danke,
Gruß
Bernhard

von Christian H. (netzwanze) Benutzerseite


Lesenswert?

Kennst Du Arrays?

Bernhard W. schrieb:
> Achja, wann verwende ich eigentlich char *variable; und wann char
> variable[]; und was hat es mit dem * auf sich?

* bedeutet, dass es sich um einen Zeiger handelt.
Es wird kein Speicherplatz für das Ziel reserviert.

typ variable[10]
Reserviert 10 Speicherplätze des gegebenen Typs.
"variable" (ohne Klammern) ist ein Zeiger auf das erste Element.
Mit *variable hast Du direkt den Inhalt des ersten Elements.
Das ist gleichbedeutend mit variable[0].

"variable[2]" referenziert direkt direkt das dritte Element (Zählung 
beginnt bei 0).

Arrays verwendet man, wenn man weiß, wieviele Elemente vorhanden sind. 
Man reserviert hiermit auch gleich den Speicher.

Ich hoffe, das war soweit korrekt. Mein C hat schon Flugrost angesetzt.

von Markus M. (mark_m)


Lesenswert?

Du erzeugst aus deine Einzelnen Strings einfach ein Array.
1
char dspreg[] = {
2
"w,0x30,0x00,0x00",
3
"w,0x30,0x$$,0x01",
4
"w,0x30,0x00,0x01",
5
"w,0x30,0x$$,0x08",
6
"w,0x30,0x$$,0x00",
7
"w,0x30,0x47,0x32" };

Die Adresse des Arrays setzt Du nun bei sscanf ein. Mit Hilfe des Array 
Index wählst Du den gewünschten String.
1
for (i=0; i < 6; i++)
2
    {
3
      
4
      sscanf(dspreg[i],
5
      "%[^,],%[^,],%[^,],%[^,],",
6
      puffer_rw,
7
      puffer_add,
8
      puffer_reg,
9
      puffer_val);
10
11
...

Ein * vor einer Varibale bedeutet das es sich um einen Zeiger handelt. 
*variable ist aquivalent zu variable[]. Wärend variable[index] auf ein 
Element innerhalb eine Array zeigt.

von Josef (Gast)


Lesenswert?

kurz skizziert:

fopen(...);
while(fgets(...)) {
  sscanf(...);
  ...
)
}
fclose(...);

Aber, ich wuerde vorschlagen kauf dir ein C-Buch
und lerne die Grundlagen.

Viel Spass
Josef

von Markus M. (mark_m)


Lesenswert?

Es muss
1
char *dspreg[] = {

heissen. Das Array enthält ja nur Zeiger.

von Michael P. (mipo)


Lesenswert?

Bernhard W. schrieb:
> ABER wie schaff ich es dass die Variable dspreg1 hochzählt?

Gar nicht;lege Deine Strings in eine Tabelle/Array ab und zähle den 
Index hoch. "Typ[7]" definiert übrigens ein Array mit 7 Elementen, 
"*Typ" einen Zeiger auf einen Wert des Datentypen "Typ". In C ist das 
ganze miteinander "verwoben", wobei man sich mit Zeigern leicht in den 
eigenn Fuss schießen kann. Für Details solltest Du ein C-Buch wie 
http://openbook.galileocomputing.de/c_von_a_bis_z/index.htm#_top oder 
ein/mehrere Tutorials durcharbeiten, das sind absolute Grundlagen!

Aber Wenn Du das ganze sowieso schon als Tabelle hast, spare Dir doch 
den ganzen Aufwand mit den String-Routinen und speicher das gleich als 
ein char-Array. Eventuell kannst Du noch einen Struct drum herum 
basetln.
1
#define WRITE 1
2
#define READ  0
3
4
struct tCom { char RW; char Addr; char Reg; char Val};
5
6
tCom Data[7] = {{ WRITE, 0x30, 0x00, 0x00},
7
                { WRITE, 0x30, 0x00, 0x00},
8
                { WRITE, 0x30, 0x01, 0x01},
9
                { WRITE, 0x30, 0x00, 0x01},
10
                { WRTIE, 0x30, 0x01, 0x08},
11
                { WRITE, 0x30, 0x02, 0x00},
12
                { WRITE, 0x30, 0x47, 0x32}};
13
14
for (int i=0; i < 7; i++)
15
  if ( WRITE==Data[i].RW )
16
  {
17
    // write
18
    sprintf(ausgabe,"W %h,%h,%h",Data[i].Addr, Data[i].Reg, Data[i].Val);
19
  }
20
  else
21
  {
22
    // read
23
    sprintf(ausgabe,"R %h,%h,%h",Data[i].Addr, Data[i].Reg, Data[i].Val);
24
  }
25
  lcd_setcursor(0,1);
26
  lcd_string(ausgabe);
27
}

von troll (Gast)


Lesenswert?

Michael Potthoff schrieb:
> [code]
> #define WRITE 1
> #define READ  0
>
> struct tCom { char RW; char Addr; char Reg; char Val};

Ich würde für RW einen typedef struct nehmen, dann haut einem der 
Compiler auf die Finger wenn man versucht ungültige Werte zuzuweisen.

von Borsty B. (mantabernd)


Lesenswert?

Ok danke für die Antworten, das hilft mir schon mal weiter! Ich denk da 
viel zu kompliziert glaub ich.

Michael Potthoff schrieb:
> Für Details solltest Du ein C-Buch wie
> http://openbook.galileocomputing.de/c_von_a_bis_z/... oder
> ein/mehrere Tutorials durcharbeiten, das sind absolute Grundlagen!

Auf der galileocomputing Website war ich die letzten Tage schon recht 
oft, ich mach insgesamt einfach zu wenig mit µC und wenn man alle halbe 
Jahr mal was programmiert dann tut man sich einfach schwer die 
Grundlagen zu vertiefen. Ich will aber versuchen das in Zukunft frisch 
zu halten.

Ich wollte das Anfangs sogar mit einem Array machen, aber es handelt 
sich um fast 3200 Einträge. Geht das überhaupt? Wenn ja wäre das 
natürlich das Einfachste.

von Markus M. (mark_m)


Lesenswert?

Wenn Du genug Flashspeicher zur Verfügung hast, kannst Du dort das Array 
ablegen. Wenn nicht musst Du noch einmal in dich gehen.

Grüsse

von MaWin (Gast)


Lesenswert?

> Zum einen brauch ich ein Programm dass mir Befehl für Befehl aus der
> Config Datei ausliest, beim Komma teilt, ein Array draus bildet und dann
> in den TWI_send Befehl packt.

Warum wandeln, warum nicht direkt lesen und senden ?
1
f=fopen(filename,"rt");
2
if(f)
3
{
4
  int addr,reg,value,ch;
5
  while((ch=getc(f))!=-1)
6
  {
7
    if(c=='w')
8
    {
9
      fscanf(f,"%x%x%x",&addr,&reg,&value);
10
    }
11
    else if(c=='>')
12
    {
13
      fscanf(f,"%x",&value);
14
      reg++;
15
    }
16
    else continue; 
17
    TWI_send(addr,reg,value);
18
  }
19
  fclose(f);
20
}
Der code ist tolerant, man könnte auch bei einem Dateiformatfehler 
unverzeihlich abbrechen.

von Borsty B. (mantabernd)


Lesenswert?

Danke MaWin große Augen krieg ...

Zur Verständnis ein paar Fragen:
1
f=fopen(filename,"rt"); //Was bedeutet rt hier? Ich kenen nur r...
2
if(f)
3
{
4
  int addr,reg,value,ch; //Können die int. Variablen den HexCode aufnehmen oder muss es hier char heißen? 
5
  while((ch=getc(f))!=-1)
6
  {
7
    if(c=='w') // Meintest du statt c ch? 
8
    {
9
      fscanf(f,"%x%x%x",&addr,&reg,&value); //das klappt nur wenn ich char als Datentyp genommen hab, richtig?
10
    }
11
    else if(c=='>')
12
    {
13
      fscanf(f,"%x",&value);
14
      reg++;
15
    }
16
    else continue; 
17
    TWI_send(addr,reg,value);
18
  }
19
  fclose(f);
20
}

von Markus M. (mark_m)


Lesenswert?

Im Ernst! File-I/O auf dem Microcontroller?

von Borsty B. (mantabernd)


Lesenswert?

Markus M. schrieb:
> Im Ernst! File-I/O auf dem Microcontroller?

Die Datei gib ich doch beim compilieren schon mit oder hab ich da was 
falsch verstanden?

Heißt doch dann z.b.:
1
f=fopen(C:/Programme/reigsterdatei.cfg,"r");

Oder hab ich das falsch verstanden?

von Markus M. (mark_m)


Lesenswert?

Wo soll den die Bearbeitung der Daten statt finden?

Auf dem PC und dann übertragen an den MC oder soll die Bearbeitung im MC 
statt finden. Beschreibe bitte mal das System.

Grüsse

von MaWin (Gast)


Lesenswert?

> f=fopen(filename,"rt"); //Was bedeutet rt hier? Ich kenen nur r...

reading text mode, wenn dein System nur r kann, reicht r.

>  int addr,reg,value,ch; //Können die int. Variablen den HexCode
>  aufnehmen

Ja, können sie. Nach dem Einlesen ist es eine Zahl, egal ob sie zuvor 
hex oder dez war.

> if(c=='w') // Meintest du statt c ch?

Szimmt. Ab hier ch verwenden.

> fscanf(f,"%x%x%x",&addr,&reg,&value); //das klappt nur wenn ich
> char als Datentyp genommen hab, richtig?

Nein, das liest die in hex-Ziffern und speichert als Zahl

> File-I/O auf dem Microcontroller?

Stimmt natürlich, wenn ihm file i/o fehlt, muss er von woanders lesen, 
daher das Array.

er könnte ja code generieren lassen:

 printf("TWI_send(%d,%d,%d)\n",addr,reg,value);

von Borsty B. (mantabernd)


Lesenswert?

Markus M. schrieb:
> Wo soll den die Bearbeitung der Daten statt finden?
>
> Auf dem PC und dann übertragen an den MC oder soll die Bearbeitung im MC
> statt finden. Beschreibe bitte mal das System.
>
> Grüsse

Alles im µC. Die ConfigDatei liegt ebenfalls auf dem µC, hab mir dafür 
einen ATMega128 mit 16KB Speicher vorgestellt. Die ConfigDatei nimmt 
etwa 11KB in Anspruch.

Das mit dem fopen(); klappt dann natürlich nicht.

Da ich die Configdatei sowieso anpacken und mit Excel bearbeiten muss um 
sie in ein Array zu bekommen brauch ich sie nicht vom µC umwandeln und 
auslesen lassen.

Alternativ: Geht es denn dass ich die Datei "roh", also so wie sie ist 
include und dann mit der von MaWin beschriebenen Methode umwandlen / 
verarbeiten lasse?

Danke, Gruß

von Hmm (Gast)


Lesenswert?

>Alles im µC.

Das wird so nur mit hohem Aufwand gehen. In der Regel ist kein 
Dateisystem implementiert so das fopen mit Dateinamen schonmal nicht 
geht.

Es mag ja sein, das ich was falsch verstehe, aber wenn Du ohnehin schon 
eine Vorverarbeitung machst, warum erzeugst Du dann nicht gleich eine 
Array-Initialisierung?

>Ich wollte das Anfangs sogar mit einem Array machen, aber es handelt
>sich um fast 3200 Einträge. Geht das überhaupt?

Natürlich geht das, solange Du genug Speicher hast. Pack' das Array doch 
einfach in den Flash-Speicher.

von Markus M. (mark_m)


Lesenswert?

Mit MaWins Methode kannst du aus der Config Datei eine Include Datei 
(.h) generieren, die der Compiler dann einfach benutzen kann.

Das Tool liest die Config-Datei, konvertiert diese in eine C .h Datei 
und legt diese in deinem Projektverzeichnis ab.

Das Tool kannst du dann in deine Tool-Chain einbinden. Entweder über die 
IDE oder das Makefile.

Grüsse

von Borsty B. (mantabernd)


Angehängte Dateien:

Lesenswert?

Markus M. schrieb:
> Das Tool kannst du dann in deine Tool-Chain einbinden. Entweder über die
> IDE oder das Makefile.

Ok das klingt gut, Theorie hab ich verstanden, das schreiben der Datei 
sollte ich nun auch hinkriegen aber wo binde ich im AVR Studio 6 die 
Datei mit ein?

Hab mal einen Screenshot mit angehängt, bin ich da schon mal 
einigermaßen richtig? Irgendwo im Unterpunkt "Compiler" denke ich mir, 
oder?

Danke, Gruß

von Hmm (Gast)


Lesenswert?

>Ok das klingt gut, Theorie hab ich verstanden, das schreiben der Datei
>sollte ich nun auch hinkriegen aber wo binde ich im AVR Studio 6 die
>Datei mit ein?

Welche Datei? Die erzeugte H-Datei includest Du einfach über das 
C-Preprozessor-Kommando "#include". Das Probgramm, das diese H-Datei 
erzeugt gehört unter Build. (Das allerdings weiss ich nicht genau, das 
ich noch ein 4er-Fan bin).

von Hmm (Gast)


Lesenswert?

Dir ist klar, das Du, um das Programm zu erstellen, das die H-Datei 
erzeugt einen Compiler für das Host-System brauchst?

von Markus M. (mark_m)


Lesenswert?

Ich denke es geht über "Tools→External Tools…".

http://www.atmel.no/webdoc/atmelstudio/atmelstudio.section.csl_qbq_kc.html

@Hmm
Eine Headerdatei ist nur Text. Wenn das Format stimmt reicht es wenn der 
Ziel-Compiler damit klar kommt. Atmel-Studio ist ja auch dem PC 
installiert also kann man im Projektordner auch beliebig generierte 
Dateien ablegen.

Grüsse

von Borsty B. (mantabernd)


Lesenswert?

Hmm schrieb:
> Dir ist klar, das Du, um das Programm zu erstellen, das die H-Datei
> erzeugt einen Compiler für das Host-System brauchst?

Nein das war mir bis grad eben noch nicht klar aber ist eigentlich ganz 
logisch.

Ich denke ich bleib dabei dass ich die ConfigDatei einfach mit Excel 
zurecht biete und sie dann als fertiges Array in mein Programm packe.

Es geht hier ja sowieso nur um die Grundkonfiguration des DSP Chips, 
einzelne Werte wie Lautstärke, EQ usw können dann ja während dem Betrieb 
geändert werden, dazu muss das Programm nicht neu geladen werden. Man 
ändert das Hauptprogramm ja nur sehr selten.

von Markus M. (mark_m)


Lesenswert?

Sorry @Hmm da hab ich Mist geschrieben. Natürlich muss ein Compiler für 
PC-Code vorhanden sein.

Ich persönlich würde aber Perl (Oder eine Scriptsprache der Wahl) für 
das Tool verwenden. Muss aber auch installiert sein.

Vielleicht kann Bernhard darüber berichten, was ihm zur Verfügung steht.

Grüsse

von Markus M. (mark_m)


Lesenswert?

@Bernhard
Du kannst Exel auch dazu bewegen dir das richtige Format zu generieren. 
Hat ja schließlich VBA eingebaut.

Ich würde aber immer über eine .h Datei gehen. Copy&Past wirst Du mit 
der Zeit verfluchen. Ist viel zu Fehleranfällig.

von Hmm (Gast)


Lesenswert?

@ Markus M.

>@Hmm
>Eine Headerdatei ist nur Text. Wenn das Format stimmt reicht es wenn der
>Ziel-Compiler damit klar kommt. Atmel-Studio ist ja auch dem PC
>installiert also kann man im Projektordner auch beliebig generierte
>Dateien ablegen.

Auf welchen meiner Beiträge beziehst Du Dich mit diesem Text?
Ich verstehe nicht, was Du mir sagen willst. :-)

Geht es darum? :
Wenn ein C-Programm benutzt werden soll um die H-Datei zu erzeugen, ist 
auch ein C-Compiler dafür nötig und das kann nicht AVR-Studio sein, denn 
das Programm soll ja auf dem Host laufen und nicht auf dem AVR.

von Markus M. (mark_m)


Lesenswert?

Hab mich oben doch schon Korrigiert. Sorry!!!! :-)=)

Grüsse

von Hmm (Gast)


Lesenswert?

@ Markus

Ach so. Na dann...

von Borsty B. (mantabernd)


Lesenswert?

Vielen Dank für eure regen Kommentare, ich finde dieses Forum echt 
Spitze!

Ich hab mir nun erstmal genug Anregungen geholt und werde versuchen die 
Kiste erstmal mit der Arraylösung zum laufen zu bewegen.

Wenn es dann läuft wie ich mir das vorstelle kann ich mich um das 
Handling kümmern :)

Schönen Abend noch, und nochmals vielen Dank für eure Tips! Ohne die 
fühlt man sich als Anfänger oft einfach verloren.

Gruß
Bernhard

von Borsty B. (mantabernd)


Lesenswert?

Ich brauch eure Hilfe leider doch nochmal:
1
typedef struct { char RW; char Addr; char Reg; char Val} dsp;
2
3
  dsp Data[7] = {{ WRITE, 0x30, 0x00, 0x00},
4
        { WRITE, 0x30, 0x00, 0x00},
5
        { WRITE, 0x30, 0x01, 0x01},
6
        { WRITE, 0x30, 0x00, 0x01},
7
        { WRITE, 0x30, 0x01, 0x08},
8
        { WRITE, 0x30, 0x02, 0x00},
9
        { WRITE, 0x30, 0x47, 0x32}};

bringt:
1
 expected ')' before ';' token
 und zwar vor dem WRITE.

Anfangs hat der struct Befehl noch Probleme gemacht aber im AVR Studio 6 
muss das wohl so sein wie ich hier gepostet habe. Jedenfalls macht der 
Datentyp dsp keine Probleme mehr, nur noch die Deklaration des Arrays. 
Statt den inneren, geschweiften Klammern hab ich es auch schon mit 
runden Klammern versucht.

von Borsty B. (mantabernd)


Lesenswert?

... ich werd verrückt ...

Aktuell sieht mein Code so aus:
1
#define WRITE 1;
2
#define READ  0;
3
4
char ausgabe[8];             //Warum brauch ich hier ein Array und wie groß muss es sein?
5
int8_t i;
6
  
7
typedef struct                 //Anders hat es nicht geklappt.
8
{
9
  char RW; char ADD; char REG; char VAL;
10
  
11
} dsp; 
12
13
14
dsp Data[7] = {
15
{"WRITE,0x30,0x00,0x00"},
16
{"WRITE,0x30,0x00,0x00"},
17
{"WRITE,0x30,0x01,0x01"},
18
{"WRITE,0x30,0x00,0x01"},
19
{"WRITE,0x30,0x01,0x08"},
20
{"WRITE,0x30,0x02,0x00"},
21
{"WRITE,0x30,0x47,0x32"}};
22
23
for (i=0; i < 7; i++) {
24
            
25
      sprintf(ausgabe,"%i",i);
26
      lcd_setcursor(15,1);
27
      lcd_string(ausgabe);
28
      _delay_ms(500);
29
      
30
        if ( "WRITE" == Data[i].RW )
31
        {
32
          // write
33
          sprintf(ausgabe,"W %h,%h,%h",Data[i].ADD,Data[i].REG,Data[i].VAL);
34
        }
35
        else
36
        {
37
          // read
38
          sprintf(ausgabe,"R %h,%h,%h",Data[i].ADD,Data[i].REG,Data[i].VAL);
39
          
40
        }
41
        lcd_setcursor(0,2);
42
        lcd_string(ausgabe);
43
}

Ich möchte mir jetzt erstmal die Ausgabe auf dem Display anschauen und 
prüfen ob das alles passt bevor ich es an die TWI_send(); Funktion 
übergib.

Leider zeigt mir mein Display teilweise nur Müll an, die Größe des 
Arrays ausgabe[]; und das Zusammenspiel mit der for Schleife ist dafür 
ausschlaggebend. Ich weiß, das klingt nach einem Stack Overflow aber 
warum? Wie groß muss das Array ausgabe[] denn sein?

Das nächste Problem ist auch dass er in der if-Schleife gar nicht in den 
Write Zweig geht weil er  anscheinend nichts mit dem Inhalt von 
Data[i].RW anfangen kann.

Ich hab mir dann mal Testweise Data[i].RW mit folgendem Befehl aufs 
Display geben lassen:
1
 else
2
 {
3
 // read
4
 sprintf(ausgabe,"R %s",Data[i].RW);
5
 }

Dabei bekam ich den kompletten Arrayeintrag, also R Write,0x30,0x00,0x00 
(bzw. das was davon eben aufs Display passt. Interessanterweise stoppt 
die for() Schleife hierbei!! (zu sehen an der aktuellen Position die ich 
mir kurz nach Beginn der for() Schleife einblenden lasse.

Also irgendwie ist das alles sehr kurios... vernwede ich anstatt %s z.b. 
%i, %d, %u, ... passiert nichts bzw. nichts verwertbares.

Ich hau mich jetzt hin... Danke schon mal,

Gruß
Bernhard

von Markus M. (mark_m)


Lesenswert?

Hallo Bernhard,
1
char ausgabe[8];             //Warum brauch ich hier ein Array und wie groß muss es sein?
In das Array muss die maximale Anzahl auszugebender Zeichen + '\0' 
hineinpassen.

Beim ersten sprintf() ist es eine Zahl [0..6] + '\0'. Also 2 char.

Beim zweiten sprintf() bin ich mir nicht sicher wieviele Zeichen %h 
ausgibt. Falls du hier HEX ausgeben möchtest solltest Du es vieleicht 
mit %x versuchen. (http://en.cppreference.com/w/cpp/io/c/fprintf)
Es gibt auf jeden Fall mehr als 8 Zeichen.

Beim dritten sprintf() . Seihe zweiten sprintf().

1
if ( "WRITE" == Data[i].RW )
In dieser Zeile versuchst Du einen C-String mit einem Wert zu 
vergleihen. Das funktioniert so nicht. Für das Vergleichen von C-String 
steht die Funktion strcmp (String compare) zur Verfügung. Das ist es 
aber nicht was Du möchtest! Du möchtest an dieser Stelle das #define 
WRITE haben. Dazu musst Du nur die "" weg lassen. Ein #define ist 
einfach nur ein Textersatz. Der Präprozessor setzt für WRITE mittels 
Textersatz eine 1 in den Source Code, bevor die Datei an den Compiler 
weiter gereicht wird.

Richtig ist dann
1
if ( WRITE == Data[i].RW )

Und der Präprozessor generiert dieses
1
if ( 1 == Data[i].RW )

Grüsse

von Osterhasi (Gast)


Lesenswert?

Bernhard W. schrieb:
> Das nächste Problem ist auch dass er in der if-Schleife gar nicht in den

http://www.if-schleife.de/

von Borsty B. (mantabernd)


Lesenswert?

So, habs zum laufen gebracht.

Allerdings funktioniert das mit dem define nicht und ich musste im Array 
lauter Strings definieren.

Anders hab ich es einfach nicht hinbekommen.

Hier mein Code der funktioniert:
1
#define WRITE 1;
2
#define READ  0;
3
4
typedef struct
5
{
6
  char RW; char ADD; char REG; char VAL;
7
  
8
} dsp; 
9
10
dsp Data[7] = {
11
{"WRITE","0x30","0x00","0x00"}, //Wenn ich die "" weglasse dann meckert der Compiler.
12
{"WRITE","0x30","0x00","0x00"},
13
{"READ","0x30","0x01","0x01"},
14
{"WRITE","0x30","0x00","0x01"},
15
{"WRITE","0x30","0x01","0x08"},
16
{"WRITE","0x30","0x02","0x00"},
17
{"WRITE","0x30","0x47","0x32"}};
18
19
      for (i=0; i < 7; i++) {
20
            
21
      sprintf(ausgabe,"%i",i);
22
      lcd_setcursor(15,1);
23
      lcd_string(ausgabe);
24
      _delay_ms(500);
25
      
26
        if ( "WRITE" == Data[i].RW ) //sobald ich hier die "" weg mach meckert der Compiler mit expected ')' before ';' token
27
28
        {
29
          // write
30
          sprintf(ausgabe,"W %s,%s,%s",Data[i].ADD,Data[i].REG,Data[i].VAL); //%x funktioniert auch nicht, nur %s.
31
        }
32
        else
33
        {
34
          // read
35
          sprintf(ausgabe,"R %s,%s,%s",Data[i].ADD,Data[i].REG,Data[i].VAL);
36
          
37
        }
38
        lcd_setcursor(0,2);
39
        lcd_string(ausgabe);
40
      }

Ich hab den Sinn von #define zwar verstanden aber mein Compiler magt das 
überhaupt nicht.

von Thomas R. (Gast)


Lesenswert?

Der Präprozessor ändert nichts von dem, was zwischen "" steht.

von Lattice User (Gast)


Lesenswert?

Mach mal bei den #defines die ; weg, die sind da fehl am Platz und sind 
die da angemotzt werden.
1
#define WRITE 1
2
#define READ  0

Der sprintf sollte so aussehen:
1
          sprintf(ausgabe,"R %02x,%02x,%02x",Data[i].ADD,Data[i].REG,Data[i].VAL);

von Hmm (Gast)


Lesenswert?

Also jetzt muss man wohl doch mal ein offenes Wort schreiben, denke ich.

Nachdem was Du hier zeigst, beherschst Du die einfachen, um nicht zu 
sagen, einfachsten Grundlagen von C überhaupt nicht. Beinahe bei jedem 
Schritt, bei vielen absolut trivialen Dingen scheiterst Du und musst 
hier nachfragen.

Ich möchte Dir dringend empfehlen erstmal ein C Buch zu lesen. Dann die 
Beispiele und Aufgaben nachvollziehen. Und DANN gehst Du daran eigene 
Programme zu schreiben.

Das wird ja langsam echt aberwitzig hier.

von Karl H. (kbuchegg)


Lesenswert?

Bernhard W. schrieb:
> So, habs zum laufen gebracht.

das ist verwunderlich.


> typedef struct
> {
>   char RW; char ADD; char REG; char VAL;
>
> } dsp;
>
> dsp Data[7] = {
> {"WRITE","0x30","0x00","0x00"}, //Wenn ich die "" weglasse dann meckert
> der Compiler.
> {"WRITE","0x30","0x00","0x00"},
> {"READ","0x30","0x01","0x01"},
> {"WRITE","0x30","0x00","0x01"},
> {"WRITE","0x30","0x01","0x08"},
> {"WRITE","0x30","0x02","0x00"},
> {"WRITE","0x30","0x47","0x32"}};

das passt doch hinten und vorne nicht.
Wie willst du denn einen String wie zb "0x30", der aus 5 Zeichen besteht 
in einer Variablen ADD unterbringen, die als char gerade mal Platz für 
ein einzelnes Zeichen bietet?

>         if ( "WRITE" == Data[i].RW ) //sobald ich hier die "" weg mach
> meckert der Compiler mit expected ')' before ';' token

mann kann Strings nicht so vergleichen!


> Ich hab den Sinn von #define zwar verstanden aber mein Compiler magt das
> überhaupt nicht.

Ich glaub ehrlich gesagt nicht, dass du verstanden hast was ein #define 
macht. Und ich glaub ehrlich gesagt auch nicht, dass du auch nur 
irgendwas vom Thema "Stringverarbeitung in C" verstanden hast.

Unter Vorbehalt - denn das ist nur eine gekürzte Version dessen, was 
Stringverarbeitung in C ausmacht bzw. was man wissen muss - sozusagen 
das Allernotwendigste in aller Kürze:
String-Verarbeitung in C


Aber mal davon abgesehen, brauchst du die ganzen Strings überhaupt 
nicht.
Was du aber ganz dringend brauchen würdest, das ist ein C-Buch und 2 
Monate Zeit um mal die allereinfachsten Grundlagen von C mithilfe dieses 
C-Buches auf dem PC zu lernen. Vorher hat das alles keinen Sinn. Es 
hilft nichts. Programmieren, ganz speziell C Programmieren, ist mehr als 
einfach nur irgendwelche Sonderzeichen, die man mal irgendwo gesehen hat 
und irgendwelche Schlüsselwörter, die man irgendwo aufgeschnappt hat, 
aneinander zu reihen und zu hoffen, dass das schon irgendeinen Sinn 
ergeben wird.
Das muss man tatsächlich LERNEN! Und bei dir fehlts an allen Ecken und 
Enden an den einfachsten Dingen.

von Hmm (Gast)


Lesenswert?

>Vorher hat das alles keinen Sinn.

Genau. Ich meine, wir helfen ja gerne auch mal bei trivialen Sachen. 
Aber das muss ja mal ein Ende haben.
Man irrt sich mal oder verwechselt was oder übersieht was. Das ist OK. 
Aber bei Dir ist ja wirklich fast jeder Versuch voll von Fehlern die 
absolute Grundlagen betreffen. Lern' doch bitte erstmal C.

von troll (Gast)


Lesenswert?

Jetzt fehlt nur noch der obligatorische Buchtipp und alles ist gesagt. 
Von daher: Kernighan & Ritchie, Programmieren in C, 2. Edition oder auf 
Englisch The C Programming Language, 2nd ed.

scnr :-)

von Markus M. (mark_m)


Lesenswert?

Hallo Bernhard,

Mein Fehler: "WRITE" ist natürlich ein C-String und sollte mit einem 
strcmp verglichen werden. Was aber nicht funktionieren kann, weil 
Data[i].RW kein C-String ist.
1
if ( "WRITE" == Data[i].RW ) //sobald ich hier die "" weg mach meckert der Compiler mit expected ')' before ';' token


Im großen und ganzen gebe ich Karl Heinz Buchegger recht. Nur ist es 
besser einem Anfänger zu helfen seinen eigenen Ansatz zum laufen zu 
bringen, als ständig einen besseren Weg auf zu zeigen. Das baut nur 
Frust auf und hat keinen Lerneffekt. IMHO.

Grüsse

von Karl H. (kbuchegg)


Lesenswert?

Markus M. schrieb:

> Im großen und ganzen gebe ich Karl Heinz Buchegger recht. Nur ist es
> besser einem Anfänger zu helfen seinen eigenen Ansatz zum laufen zu
> bringen, als ständig einen besseren Weg auf zu zeigen. Das baut nur
> Frust auf und hat keinen Lerneffekt. IMHO.

Na ja.
Irgendwann muss aber auch mal gut sein.
Wenn sich ein angehender Arzt, der das erste mal auf Patienten los 
gelassen wird, bei der Schwester erkundigt, wie rum denn nun das 
Heftpflaster aufgeklebt werden muss, dann muss man eindeutig und klar 
sagen: So ist das sinnlos. Ein gewisses Mindestniveau muss schon sein. 
Und das hat dann auch nichts mehr mit Profi oder Nicht-Profi zu tun.

von Borsty B. (mantabernd)


Lesenswert?

Also erstmal danke für euren regen Bemühungen.

Ich hab nun gestern einen lauffähigen Code zusammengebracht, sogar mit 
Fehlerauswertung für die TWI Übertragung.

Werde ihn heute Abend posten wenn ich wieder zu Hause bin. Leider läuft 
mein DSP Chip trotzdem noch nicht da er mir gestern durch einen dummen 
Kurzschluss kaputt ging, ein neuer ist bestellt und dann kann ich 
endlich schauen ob alles einwandfrei läuft.

Eure Kritik ist ebenfalls gerechtfertig - anders als Andere hier im 
Forum sehe ich das auch als Ansporn.

Ich lern halt solche Dinge am einfachsten wenn ich sie brauche und auch 
direkt anwende - ich bin ein Try&Error Mensch und das geb ich auch ganz 
offen zu. Werde mir dennoch eines der oben genanten Bücher kaufen und 
mich einlesen. Ich denke mit den Grundlagen die ich nun habe fällt mir 
das auch leichter.

Wenn mir vor zwei Wochen jemand gesagt hätte ich solle mit einem µC 
einen DSP Chip steuern dann hätte ich ihn ausgelacht, heute kann ich 
stolz sagen dass ich den Grundstein dafür gelegt habe und bin stolz auf 
mich - auch wenn ich das Ergebnis nur zusammengestöpselt habe - mir hat 
es viel gebracht und ich weiß nun wie ich kommende Projekte anzugehen 
habe.

Gruß und Danke für Alles!

Bernhard

von Carsten (Gast)


Lesenswert?

Hallo Bernhard,

immerhin hast du jetzt ja schon mal kompilierbaren Code. Ob dieser dann 
tut, was er soll, steht auf einem anderen Blatt. Wie gut, dass du die 
Kritik hier sportlich siehst :)

Bernhard W. schrieb:
> Ich lern halt solche Dinge am einfachsten wenn ich sie brauche und auch
> direkt anwende - ich bin ein Try&Error Mensch und das geb ich auch ganz
> offen zu.

Aus Fehlern lernt man ja bekanntlichermaßen am besten. Allerdings ist 
die 'trial-and-error'-Methode vielleicht für einige Experimente ratsam 
um Erfahrungen zu sammeln*, zielführender wäre es aber wirklich, wenn du 
dir Grundlagen aneignen könntest.

Die 'C-Bibel' von Kernigham und Ritchie "The C Programming Language" 
oder übersetzt als "Programmieren in C" kann ich nur wärmstens 
empfehlen.

Ich gehe mal davon aus, dass du unter Windows arbeitest. Deshalb 
empfehle ich dir CygWin zu installieren und das Erlernte erst einmal in 
kleinen Konsolenprogrammen nachzuvollziehen. C ist eine systemnahe 
Sprache und ohne ein Verständnis der Zeigerarithmetik wird dir zum 
Beispiel die Stringverarbeitung in C (nicht zu verwechseln mit C++) ein 
ewiges Rätsel bleiben.

Ebenso scheint bei dir noch z.B. Wissen bezüglich der Unterschiede 
zwischen Variablen und Makros bzw. Präprozessor und Compiler zu fehlen.

Also, hilf deinem Gehirn und gib ihm Grundlagenfutter und suche nach 
'best-practice'-Methoden, statt das Rad neu erfinden zu wollen. Meistens 
lernt man mehr, wenn man einen eleganten Code analysiert und versteht, 
statt eine eigene naive Lösung zu versuchen. Um fremden Code verstehen 
zu können brauchst du aber - du wirst es erraten - Grundlagenkenntnisse.

Sieh's mal so: Bevor du eine dunkle Höhle erkundest, würdest du dir 
zumindest einen Plan und eine Lampe besorgen. Wenn du stattdessen mit 
einem Telefon in der Hand im dunkeln herumstolperst und ständig Leute 
anrufst um zu fragen, in welche Richtung du als nächstes tasten sollst, 
wirst du
a) nicht sehr schnell vorankommen
b) wenig vom Innenleben der Höhle erfahren
c) die angerufenen Menschen irgendwann zu tode genervt haben

;)

Viele Grüße
Carsten

* Und wenn es nur die Erkenntnis ist, dass man den 'Magic Smoke', wenn 
er denn einmal entwichen ist, nicht mehr in den DSP zurückbefördern kann 
(SCNR)

von Borsty B. (mantabernd)


Lesenswert?

Hallo Carsten,

erstmal stimme ich dir in jedem Punkt zu. Danke dass du dir hier die 
Mühe gemacht hast einen solch langen Text für mich zu verfassen. Dass 
mir der DSP abgeraucht ist war übrigens nur ein Versehen, anscheinend 
ist ein eingestellter, max. Kurzschlussstrom von 100mA schon genug um 
das Teil zum schweigen zu bringen. Wir arbeiten hier halt mit sensibler 
Elektronik...

Hier übrigens noch mein Code ( das Registerarray habe ich etwas 
gekürzt):
1
#include <avr/io.h>
2
#include <util/twi.h>
3
#include <util/delay.h>
4
#include <avr/interrupt.h>
5
#include <avr/lcd-routines.h>
6
#include <stdio.h>
7
#include <string.h>
8
9
#define F_CPU 4000000;
10
11
int16_t i;
12
int16_t size;
13
14
int8_t creg;
15
int8_t ADD__;
16
int8_t REG__;
17
int8_t VAL__;
18
int8_t error = 0;
19
int8_t result;
20
int8_t TWBR_VAL = 10;
21
22
char ausgabe[34];
23
  
24
typedef struct
25
{
26
  int8_t RW; int8_t ADD; int8_t REG; int8_t VAL;
27
  
28
} dsp; 
29
30
31
int main(void)
32
{
33
  
34
  DDRA &= ~(1<<DDA0); //Port A Pin 0 als Eingang definieren.
35
  DDRB |= (1<<DDB0); //Port B Pin 0 als Ausgang;
36
  PORTA |= (1<<DDA0); //Pullup an Port A Pin 0 einschalten.
37
  TWBR = TWBR_VAL; // Bustakt festlegen.
38
  PORTB |= (1<<PINB0);
39
  
40
  lcd_init();
41
  lcd_clear();
42
43
  
44
  dsp Data[3144] = {
45
  
46
  {0,0x30,0x00,0x00},
47
  {1,0x30,0x00,0x01},
48
  {0,0x30,0x00,0x01},
49
  {1,0x30,0x00,0x08},
50
  {1,0x30,0x00,0x00},
51
  {0,0x30,0x54,0x00},
52
  {0,0x30,0x5e,0x20},
53
  {1,0x30,0x00,0xfe},
54
  {1,0x30,0x00,0x00},
55
  {1,0x30,0x00,0x68},
56
  {1,0x30,0x00,0xa8},
57
  {1,0x30,0x00,0x06},
58
  {1,0x30,0x00,0x00}
59
60
  };
61
62
  while (1)
63
  {
64
    if (!(PINA &(1<<PINA0))) 
65
    {
66
      size = (sizeof(Data)/sizeof(Data[0]));
67
      
68
      for (i=0; i < size; i++) {
69
            
70
        if ( 0 == Data[i].RW )
71
        {
72
          // write
73
          result = TWI_send(Data[i].ADD,Data[i].REG,Data[i].VAL);
74
          
75
          if (!(result == 0))
76
          {
77
            sprintf(ausgabe,"EW %d %x,%x,%x    ",result,Data[i].ADD,Data[i].REG,Data[i].VAL);
78
                    lcd_setcursor(0,1);
79
                    lcd_string(ausgabe);
80
            sprintf(ausgabe,"%i / %i   ",i,size);
81
                    lcd_setcursor(0,2);
82
                    lcd_string(ausgabe);
83
            PORTB &= ~(1<<PINB0); //LED leuchtet bei Fehler.
84
            _delay_ms(1000);
85
            break;
86
          }
87
          else
88
          {
89
            sprintf(ausgabe,"W %d %x,%x,%x    ",result,Data[i].ADD,Data[i].REG,Data[i].VAL);
90
                    lcd_setcursor(0,1);
91
                    lcd_string(ausgabe);
92
            sprintf(ausgabe,"%i / %i   ",i,size);
93
                    lcd_setcursor(0,2);
94
                    lcd_string(ausgabe);
95
            PORTB |= (1<<PINB0);
96
          }
97
          creg = Data[i].REG;  
98
        }
99
        else if ( 1 == Data[i].RW )
100
        {
101
          // calc
102
          creg ++;
103
          result = TWI_send(Data[i].ADD,creg,Data[i].VAL);
104
          
105
          
106
          if (!(result == 0))
107
          {
108
            sprintf(ausgabe,"EC %d %x,%x,%x    ",result,Data[i].ADD,creg,Data[i].VAL);
109
                    lcd_setcursor(0,1);
110
                    lcd_string(ausgabe);
111
            sprintf(ausgabe,"%i / %i   ",i,size);
112
                    lcd_setcursor(0,2);
113
                    lcd_string(ausgabe);
114
            PORTB &= ~(1<<PINB0); //LED leuchtet bei Fehler.
115
            _delay_ms(1000);
116
            break;
117
          }
118
          else
119
          {
120
            sprintf(ausgabe,"C %d %x,%x,%x    ",result,Data[i].ADD,creg,Data[i].VAL);
121
                    lcd_setcursor(0,1);
122
                    lcd_string(ausgabe);
123
            sprintf(ausgabe,"%i / %i   ",i,size);
124
                    lcd_setcursor(0,2);
125
                    lcd_string(ausgabe);
126
            PORTB |= (1<<PINB0);
127
          }
128
          
129
        }        
130
      }            
131
    }
132
  } return 0;    
133
}    
134
    
135
136
137
int TWI_send (ADD_,REG_,VAL_) {
138
  
139
      error = 0;
140
      TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN);   // send START condition
141
      while (!(TWCR & (1<<TWINT)));             // wait for response
142
      if ((TWSR & 0xF8) == TW_START)            // if START was successful
143
      {
144
        
145
        TWDR = (ADD_ & 0xFE);                // put slave address+WRITE to TWDR
146
        TWCR = (1<<TWINT)|(1<<TWEN);            // and start transmission
147
        while (!(TWCR & (1<<TWINT)));         // wait for response
148
        if ((TWSR & 0xF8) == TW_MT_SLA_ACK){     // if acknowledge ok
149
          
150
          //_delay_ms(5);
151
          TWDR = REG_;                      // put regbyte  to TWDR
152
          TWCR = (1<<TWINT)|(1<<TWEN);        // and start transmission
153
          while (!(TWCR & (1<<TWINT)));         // wait for response
154
          if ((TWSR & 0xE8) == TW_MT_DATA_ACK){   // if acknowledge ok
155
            
156
            TWDR = VAL_;              // put valbyte to TWDR
157
            //_delay_ms(5);
158
            TWCR = (1<<TWINT)|(1<<TWEN);    //start transmission
159
            while (!(TWCR & (1<<TWINT)));         // wait for response
160
            if ((TWSR & 0xE8) == TW_MT_DATA_ACK){   // if acknowledge ok
161
              //_delay_ms(5);
162
              
163
            }
164
            else
165
            {
166
              PORTB &= ~(1<<PINB0); //LED leuchtet bei Fehler.
167
              error = 1;  
168
            }
169
          }
170
          else
171
          {
172
            PORTB &= ~(1<<PINB0); //LED leuchtet bei Fehler.
173
            error = 2;
174
          }            
175
        }
176
        else
177
        {
178
          PORTB &= ~(1<<PINB0); //LED leuchtet bei Fehler.
179
          error = 3;
180
          
181
        }
182
      }
183
      else
184
      {
185
      error = 4;
186
      }
187
      while (!(TWCR & (1<<TWINT)));             // wait for response
188
      TWCR = (1<<TWINT)|(1<<TWSTO)|(1<<TWEN);   // transmit STOP condition
189
      
190
      //_delay_ms(5);              
191
192
return error;
193
194
}

Wenn im Array eine 0 an erster Stelle steht bedeutet das WRITE, eine 1 
bedeutet CALC (also muss das Register durch hochzählen ermittelt werden 
und eine 2 bedeutet READ (kommt nicht vor).

Auf dem Display kann man sehen wie weit die Datenübertragung 
fortgeschritten ist und bei einem Fehlerfall wird der Grund in Form 
eines Errorcodes eingeblendet und das Display bleibt 1s lang stehen (um 
die Position und den Grund des Fehlers zu sehen). Danach startet die 
Übertragung von vorne.

Was ich allerdings noch nicht so ganz verstehe ist die Arraygröße. Wenn 
ich die Klammern leer lasse, also dsp Data[] schreibe dann stoppt die 
Übertragung bei Zeile 911 weil die Geräteadresse nicht mehr stimmt. 
Statt 0x30 werden nur noch wirre Sachen ausgegeben. Trage ich dort 3144 
ein funktioniert alles wunderbar, owbwohl mir sizeof(data) 3143 ausgibt 
und das ist auch die tatsächliche Länge des Arrays. Trage ich 3143 in 
die Klammern ein dann passiert das Selbe wie wenn die Klammer leer ist.

Kann mir das jemand erklären?

Viele Grüße
Bernhard

von Michael (Gast)


Lesenswert?

Wichtige Regeln - erst lesen, dann posten!

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

von Borsty B. (mantabernd)


Lesenswert?

Ich hätte jetzt so gerne den Originalcode gepostet, grad aus Fleiß aber 
leider ist der zu lang für das Eingabefeld...

Das was ich hier gepostet hab lässt sich sogar auf meinem 13" Display 
super lesen, also bitte ...

 ... mann wie ich sowas hasse ... :/ !

von Karl H. (kbuchegg)


Lesenswert?

Bernhard W. schrieb:


> Was ich allerdings noch nicht so ganz verstehe ist die Arraygröße. Wenn
> ich die Klammern leer lasse, also dsp Data[] schreibe dann stoppt die
> Übertragung bei Zeile 911 weil die Geräteadresse nicht mehr stimmt.
> Statt 0x30 werden nur noch wirre Sachen ausgegeben. Trage ich dort 3144
> ein funktioniert alles wunderbar

das halte ich für ein Gerücht.

Mal ein bischen rechnen.

Du hast
1
typedef struct
2
{
3
  int8_t RW; int8_t ADD; int8_t REG; int8_t VAL;
4
  
5
} dsp;

d.h. ein so ein dsp Objekt hat schon mal mindestens eine Größe von 4 
Bytes.

Legst du ein Array mit 3000 Einträgen an, dann sind das schon mal 12000 
Bytes. Also um die 12Kb.

Dein Mega32 hat aber nur 2Kb SRAM. D.h. dieses Array passt da nie und 
nimmer hinein.

Du magst vielleicht auf deinem DIsplay sehen, dass du irgendwelche 
Zahlen hochzählen, aber die dahinter stehenden Werte im Array sind mit 
Sicherheit falsch.

Mach es dir zur Grundregel, dass du auf einem kleinen AVR große Arrays 
nie in Funktionen anlegst sondern immer als globale Variablen, damit sie 
in der Speicherstatistik aufscheinen, die dir die Toolchain zum Schluss 
auswirft. WEnn du dort einen SRAM Verbrauch von mehr als, sagen wir mal 
90% hast, dann heißt es schon vorsichtig zu sein. Mit deinem Array wirst 
du in der Größenordnung von weit über 600% sein.

von Carsten (Gast)


Lesenswert?

Bernhard W. schrieb:
> Was ich allerdings noch nicht so ganz verstehe ist die Arraygröße. Wenn
> ich die Klammern leer lasse, also dsp Data[] schreibe dann stoppt die
> Übertragung bei Zeile 911 weil die Geräteadresse nicht mehr stimmt.

Welchen µC benutzt du? Und welche Entwicklungsumgebung?

Wie ich das sehe, wird deine Tabelle in's RAM geschrieben. Das wird wohl 
zu klein sein. Such mal nach "PROGMEM" und wenn du's genau wissen willst 
nach "Von-Neumann-Architektur" und "Harvard Architektur".
> Statt 0x30 werden nur noch wirre Sachen ausgegeben. Trage ich dort 3144
> ein funktioniert alles wunderbar,

3144 Elemente hat also dein Array. Ein Element ist 5 Byte groß, deshalb 
muss diese Ausgabe falsch sein:
> owbwohl mir sizeof(data) 3143 ausgibt
Denn sizeof(data) sollte die Anzahl der Bytes und nicht der Elemente 
zurückgeben (3144 * 5 Bytes = 15720 Bytes).

Deshalb denke ich dass dein µC zuwenig RAM dafür hat. Du musst die Daten 
also im Flash speichern. Der Zugriff auf Daten im Flash funktioniert 
aber anders als wenn sie im RAM liegen. Ich rate Dir, den Code von MaWin 
noch einmal zu lesen, restlos zu verstehen und dann zu überlegen, wie du 
die Methode dort nutzen kannst, um deine Daten byteweise aus dem Flash 
lesen und zu verarbeiten.

Viel Erfolg,
Carsten

von Carsten (Gast)


Lesenswert?

Sorry, ist schon spät: Ein Element hat hier nur 4 Byte.

Aber es gilt, was Karl Heinz schrieb. Der Reiz, einen µC zu 
programmieren liegt u.A. darin, mit den Beschränkungen zurecht zu kommen 
;)

von Bernhard Wächter (Gast)


Lesenswert?

... sorry, es ist ein Mega1284P mit 16k SRAM.

Der Code geht drauf aber der Controller ist fast voll.

I2C Ausgabe wurde mit dem Oszi geprüft und stimmt (Stichprobenartig).

von Borsty B. (mantabernd)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Du magst vielleicht auf deinem DIsplay sehen, dass du irgendwelche
> Zahlen hochzählen, aber die dahinter stehenden Werte im Array sind mit
> Sicherheit falsch.

Einspruch! :) Ich hab den Controller an verschiedenen Positionen 
angehalten und die Ausgabe auf dem Display mit dem theroretischen Wert 
und sogar der Ausgabe am Oszi verglichen - hat immer gestimmt! (Solang 
ich im Array den Wert 3144 eingetragen habe).


> Mach es dir zur Grundregel, dass du auf einem kleinen AVR große Arrays
> nie in Funktionen anlegst sondern immer als globale Variablen, damit sie
> in der Speicherstatistik aufscheinen, die dir die Toolchain zum Schluss
> auswirft. WEnn du dort einen SRAM Verbrauch von mehr als, sagen wir mal
> 90% hast, dann heißt es schon vorsichtig zu sein. Mit deinem Array wirst
> du in der Größenordnung von weit über 600% sein.

Ich glaube beim letzten Kompilieren stand da ein Wert von knapp 75%, 
schau heute Abend oder morgen nochmal nach. Komprimiert der Compiler vom 
Atmel Studio 6 eigentlich x-fach vorhandene, identische Einträge in 
einem Array weg, also ersetzt sie durch Pointer auf gleichwertige 
Einträge?

Das was du schreibst bezieht sich natürlich auf einen Mega32, ist mir 
klar. Aber da ich mich grad noch in die Materie einarbeite wollte ich es 
einfach halten und hab das Array in den SRAM geladen. Da der µC in 
dieser Schaltung für nichts anderes verwendet wird außer den DSP zu 
steuern und ein paar Befehle auf dem Display auszugeben sehe ich das 
unkritisch. Wenn alles mal so läuft wie ich will kann ich damit anfangen 
das Array auf eine Speicherkarte oder auf einen externen Eeprom 
auszulagern. Aktuell bin ich froh dass es läuft :)

Carsten schrieb:
>> owbwohl mir sizeof(data) 3143 ausgibt
> Denn sizeof(data) sollte die Anzahl der Bytes und nicht der Elemente
> zurückgeben (3144 * 5 Bytes = 15720 Bytes).

Mir ist bewusst dass sizeof() die größe des gesamten Arrays in Bytes 
ausgibt, deshalb teile ich auch wieder durch die größe des 1. Eintrages 
im Array.
1
size = (sizeof(Data)/sizeof(Data[0]));

Mir ist nur nicht klar warum das Array um eins größer sein muss als es 
wirklich ist.

Ich arbeite übrigens mit dem Atmel Studio 6 und programmiere auch direkt 
daraus. (war vorhin mal gefragt).

von Karl H. (kbuchegg)


Lesenswert?

Bernhard W. schrieb:

> Einspruch! :)

OK.
Dann mach es dir zur Grundregel immer den Controller zu nennen.
Ich hab mit einen anderen Thread von dir rausgesucht (irgendwo hier war 
ein Link dazu) und dort war von einem Mega32 die Rede. Alles weitere 
basiert auf dem M32.

von Karl H. (kbuchegg)


Lesenswert?

Bernhard W. schrieb:


> Mir ist bewusst dass sizeof() die größe des gesamten Arrays in Bytes
> ausgibt, deshalb teile ich auch wieder durch die größe des 1. Eintrages
> im Array.

Das ist alles in Ordnung.

>
>
1
> size = (sizeof(Data)/sizeof(Data[0]));
2
>
>
> Mir ist nur nicht klar warum das Array um eins größer sein muss als es
> wirklich ist.

Muss es auch nicht.
Noch ist mir anhand des Codestudiums nicht klar, was da wirklich 
passiert.

von Karl H. (kbuchegg)


Lesenswert?

Das hat zwar jetzt mit dem Problem nichts zu tun, aber

> int TWI_send (ADD_,REG_,VAL_) {

Tu das nicht!
Nutze die implizite Int-Regel nicht aus!
Gib Datentypen immer explizit an.

Und achte drauf, dass du den Code von oben nach unten lesen kannst und 
immer alles deklariert ist.

Du willst eine Funktion TWI_send benutzen? Dann muss vor der Verwendung 
entweder die Funktion im Code sein, oder es muss einen Prototypen dafür 
geben. Dein Compiler sollte eine entsprechende Warnung ausgeben. Aber 
darauf zu vertrauen, dass sich mit den Standardannahmen des Compilers 
alles zum guten wendet, da fällt man öfter rein, als es gut ist
1
int TWI_send ( uint8_t ADD_, uint8_t REG_, uint8_t VAL_);
2
3
...
4
5
int main()
6
{
7
8
   .....
9
10
  
11
   result = TWI_send(Data[i].ADD,Data[i].REG,Data[i].VAL);
12
13
   .....
14
}
15
16
int TWI_send ( uint8_t ADD_, uint8_t REG_, uint8_t VAL_)
17
{
18
      error = 0;
19
      TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN);   // send START condition
20
 ....
21
}

jetzt kann man den Code von oben nach unten lesen (genauso wie es auch 
der Compiler macht, und vor der ersten Verwendung der Funktion gibt es 
einen Prototypen, der den Compiler darüber aufklärt, welche Datentypen 
die Argumente haben, damit er die angegebenen Parameter beim Aufruf 
prüfen und gegebenenfalls zurechtcasten kann.

(Und die Variable error in TWI_send, die darf ruhig innerhalb der 
Funktion definiert sein, so wie alle anderen Variablen in der Funktion. 
Gerade solche Sachen sollten wiederrum funktionslokal sein.
1
int TWI_send ( uint8_t ADD_, uint8_t REG_, uint8_t VAL_)
2
{
3
   int error = 0;
4
...

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.