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:
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 :)
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.
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
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.
Du erzeugst aus deine Einzelnen Strings einfach ein Array.
1
chardspreg[]={
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.
kurz skizziert:
fopen(...);
while(fgets(...)) {
sscanf(...);
...
)
}
fclose(...);
Aber, ich wuerde vorschlagen kauf dir ein C-Buch
und lerne die Grundlagen.
Viel Spass
Josef
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.
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.
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.
> 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
intaddr,reg,value,ch;
5
while((ch=getc(f))!=-1)
6
{
7
if(c=='w')
8
{
9
fscanf(f,"%x%x%x",&addr,®,&value);
10
}
11
elseif(c=='>')
12
{
13
fscanf(f,"%x",&value);
14
reg++;
15
}
16
elsecontinue;
17
TWI_send(addr,reg,value);
18
}
19
fclose(f);
20
}
Der code ist tolerant, man könnte auch bei einem Dateiformatfehler
unverzeihlich abbrechen.
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.:
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
> 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,®,&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);
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ß
>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.
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
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ß
>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).
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
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.
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
@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.
@ 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.
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
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.
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
charausgabe[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
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
typedefstruct
5
{
6
charRW;charADD;charREG;charVAL;
7
8
}dsp;
9
10
dspData[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.
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.
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.
>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.
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 :-)
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
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.
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
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)
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_ti;
12
int16_tsize;
13
14
int8_tcreg;
15
int8_tADD__;
16
int8_tREG__;
17
int8_tVAL__;
18
int8_terror=0;
19
int8_tresult;
20
int8_tTWBR_VAL=10;
21
22
charausgabe[34];
23
24
typedefstruct
25
{
26
int8_tRW;int8_tADD;int8_tREG;int8_tVAL;
27
28
}dsp;
29
30
31
intmain(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.
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
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 ... :/ !
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
typedefstruct
2
{
3
int8_tRW;int8_tADD;int8_tREG;int8_tVAL;
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.
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
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
;)
... 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).
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).
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.
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.
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
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.