Hallo, ich wundere mich jetzt bereits eine Weile über diverse Warnungen
des AVR-Studio6.1 Compilers. Da ich nun aber mal wieder beim debuggen
festhänge, komme ich wohl nun um die Warnungen nicht mehr herum.
Zum einen bekomme ich bei einer Übergabe eines Pointers auf ein
deklariertes Struct eine Warnung:
"Warning 1 'struct circular_buffer' declared inside parameter list
[enabled by default]"
Dabei ist mein struct ein ringpuffer (mit Redundanzen):
Wo liegt denn da das problem?
Dann ein zweites Problem (mit entsprechend vielen Warnungen):
Die Übergabe eines Struct-Pointers, der in der Funktion wiederum
übergeben wird, z.B.
gibt mir die Warnung
Warning 8 passing argument 1 of 'uart_TransmitByte' from incompatible
pointer type [enabled by default]
Kann mir da jemand zu helfen? Viele Grüße
Du kommst mir langsam vor wie der Bastel-Thomas hier.
Die Meldung sind doch klar verständlich. Wo ist da das Problem?
Lies mal ein C-Buch. Da wird Dir geholft.
Peter II schrieb:> das ein typedef hier falsch bzw. unnötig ist.
ich habe einfach die Ringpufferfiles aus der Dipl.Arbeit eines mir
bekannten Informatikers eingebunden und war davon ausgegangen dass der
weiß was er getan hat! Also nicht?
Verne schrieb:> Du kommst mir langsam vor wie der Bastel-Thomas hier.> Die Meldung sind doch klar verständlich. Wo ist da das Problem?>> Lies mal ein C-Buch. Da wird Dir geholft.
Das Problem ist, dass ich es nicht verstehe. Aber auch, dass ich keine
Zeit habe ein C-Buch zu lesen, weil die ganze Arbeit auf dem µC zu
meiner Masterthesis gehört, die sich EIGENTLICH um etwas ganz anderes
(Entwurf eines Infrarot-Spektroskopiegerätes) dreht. Weil das Institut
(besagte Informatiker) an dem ich die arbeit mache aber weniger
Elektronikzubehör hat als ich zu hause, geschweige denn eine
labviewkarte, muss ich hier eben ein Analog-Digitalwandlerboard mit UART
MAL EBEN ENTWICKELN (und das als SPI/UART neuling) um meine hardware
überhaupt evaluieren zu können - und das während mir der Arsch brennt
weil es gerade bei der Hardware noch wichtigere dinge gibt, die ich aber
nur bearbeiten kann, wenn ich sie evaluiert bekomme.
Ich würde mich also wirklich freuen nicht noch ein C-Buch lesen zu
müssen, auch wenn die Fragen euch reichlich dämlich vorkommen. Das
natürlich auch, weil ich hier nur reinschreibe wenn was nicht klappt -
dass ich aber innerhalb von 3 monaten bisher nach Rückmeldungen aller
Profs und Betreuer die mich kennen ungefähr das dreifache an Leistung
vollbracht habe wie normal lasse ich hier eben nicht dauernd raushängen.
Das nur, weil: BITTE stempelt mich hier nicht als zu faul ab, ich
arbeite hier von morgens bis abends - nur ist die µC programmierung eben
nicht mein Fachgebiet, so wie bei vielen von euch!!
> uart_TransmitByte(buf, sendbuf)
Wo ist der Kopf dieser Funktion? Der fehlt.
Dann sieht diese doch eher so aus, als erwarte die EIN Byte. Rein vom
Namen her. Aber kein Struct. Nur wir wissen es nicht. Weil wir die
Funktion nicht sehen.
Alex v. L. schrieb:> Das Problem ist, dass ich es nicht verstehe. Aber auch, dass ich keine> Zeit habe ein C-Buch zu lesen, weil die ganze Arbeit auf dem µC zu> meiner Masterthesis gehört, die sich EIGENTLICH um etwas ganz anderes
Eigentlich sollte man ein C-Buch bereits gelesen haben, bevor man eine
Mastherthesis anfängt, bzw. man fängt keine Masterthesis an in der man C
programmieren soll, wenn man keines gelesen hat.
Zeig mal mehr Code. So eindeutig ist der Wortlaut der Fehlermeldungen
nämlich meiner Meinung nach nicht. Für mich klingt das eher nach einem
vergessenen Strichpunkt da oder dort und die konkrete Fehlermeldung ist
ein Folgefehler davon.
Tippe den Code NICHT ab, sondern hänge die Files an.
Ok schon klarer. Die Übergabe an sich passt.
Woran sich Peter II stört ist, die Tatsache dass du mit typedef einen
Datentyp definierst, in den Funktionen allerdings weiterhin das nackte
Struct benutzt. Wozu? Du kannst direkt den Datentyp "TCircBuf" ohne das
Schlüsselwort "struct" nutzen.
cyblord ---- schrieb:> Woran sich Peter II stört ist, die Tatsache dass du mit typedef einen> Datentyp definierst, in den Funktionen allerdings weiterhin das nackte> Struct benutzt. Wozu? Du kannst direkt den Datentyp "TCircBuf" ohne das> Schlüsselwort "struct" nutzen.
Danke für die klare Ansage cyblord!!!
Die Deklaration von zwei eigenen Ringpuffern UART_rx_buffer und
UART_tx_buffer habe ich in der main gemacht, die werden dann auch immer
referenziert. Das TCircBuf war ein Überbleibsel aus der Headerfile, das
ich von jemandem bekommen habe. Der verwendet es interessanterweise in
seinem code auch nicht (eben mal nachgeschaut) sondern deklariert auch
seine eigenen structs in der main.
Karl Heinz schrieb:> Eigentlich sollte man ein C-Buch bereits gelesen haben, bevor man eine> Mastherthesis anfängt, bzw. man fängt keine Masterthesis an in der man C> programmieren soll, wenn man keines gelesen hat.
Da gebe ich dir recht. Ich kann auch eure Vorbehalte gegen Frager wie
mich wirklich verstehen.
Nun ist es aber eben so, dass ich in der Regel bei kleineren Projekten
auch immer zurandegekommen bin mit meinem C-Wissen aus eigener Bastelei
(die es recht viel gab bisher) und meinem C++ Wissen aus Uni und HiWi
jobs (und eigenen Programmen). Ein C-Buch habe ich tatsächlich mal
durchgearbeitet vor jahren - aber französisch habe ich auch mal sprechen
gekonnt, nur ist die schule schon so lange her. Mein Problem ist nun
eher der eigene Anspruch denke ich, der dafür gesorgt hat, dass es eine
wirklich fette Masterarbeit wird. Dazu gehört dann aber (inzwischen eben
leider auch zwingend) die komplexere Programmierung als mal geplant war.
Es hat mir aber schon jetzt unglaublich viel gebracht: In UART und SPI
eingearbeitet und weitgehend auch erfolgreiche kommunikation
zustandebekommen, das kann ja nun in alle weiteren Bastelprojekte von
mir einfließen, macht mich also happy! ;)
Das würde zumindest die Compiler-Meldungen erklären.
Schau noch einmal nach, ob die Reihenfolge der Deklarationen bzw. der
#include-Direktiven der entsprechenden Header-Files stimmt.
Ohne in den Code zu sehen:
Alex v. L. schrieb:> und die Funktion(en) z.B. so deklariert:uint8_t uart_ReceiveByte(struct> circular_buffer *buf );
Der Compiler hat an dieser Stelle noch keine Deklaration von "struct
circular_buffer" gesehen. Da der Parameter aber "nur" ein Pointer auf
eine struct ist, kann der Compiler sich den Parameter grundsätzlich
zusammenreimen, nämlich Pointer-auf-einen-irgendwie-geartete-Struktur.
Passt scho, wie der Bayer sagen würde.
Deshalb nur eine Warnung, der Compiler kommt schon irgendwie klar.
Gleichzeitig, da er "struct circular_buffer" zum ersten Mal sieht, nimmt
er das als (unvollständige) Deklaration der Struktur und verkündet das
in der Warnung.
Nur weil die geringe hoffnung besteht, dass jemand meinen Code
tatsächlich mal aufspielt und laufen lässt (da steckt jetzt schon
ziemlich viel arbeit drin):
Die Probleme die ich EIGENTLICH mit dem Code noch habe - und die die
Ursache dafür sind, dass ihc mich jetzt näher um die Warnungen kümmern
wollte sind zweierlei (vielleicht sieht ja jemand die ursache für eins
von beiden):
1. Sende ich nach Eingang des Kontrollbytes 0xAA über UART einen
20-Byte-Block mit Konfigurations- und ADC Daten, passiert es immer
wieder, dass diese irgendwann "verwürfeln". Im Beispiel über das Br@y
Terminal:
M0;C0;S0;301F;1032
M0;C0;S0;301F;00B3
0B
M0
0;S0;0CA1;0112
0;S0;0CA1;01M0
0;S0;0CA0;01M0;C0;S0;0CA3;0112
M0;C0;S0;0CA3;01F1
M0;C0;S0;0CA1;1ABE
Hierbei sind die ersten beiden und letzten Beiden Zeilen so, wie man es
erwarten würde, nachdem man einmal 0xAA an den Controller schickt.
Dazwischen wurde das selbe geschickt, kommt aber Gewurschtel an. Ich
dachte erst dass das evtl an meinen Interrupts liegt, da bin ich mir
aber inzwischen nicht mehr sicher - denn mit ausgeschaltetem
TimerInterrupt und auch mit der Interruptfreien SPI Kommunikation (die
ich mal eigentlich mit I.s umgesetzt hatte) sieht es genauso aus.
2. bekomme ich vom ADC (LTC2486) seltsame Werte und das liegt nicht an
der SPI-Schnittstelle. Wenn ich nämlich die Temperatur abfrage, stimmt
diese. Die Eingänge sind (inzwischen) alle auf masse oder an einem
spannungsteiler - und der ausgegebene ADC wert stimmt nur in der nähe
von ca. 0,6V. aber das wird sich hier nicht lösen lassen...
Hmm. Das ist ein seltsamer Fehler. Ich denke er kommt daher, dass du ein
wesentliches Prinzip nicht beachtet hast:
Man inkludiert nur das was man wirklich braucht!
Du hast hier zb circbuf.h
Braucht dieses Header File irgendwas aus SPI_functions.h? Nein! Warum
ist dann da ein include drinnen? Wird in diesem Header File irgendwas
benötigt, was in UART_functions.h steht? Nein! Was ist mit den anderen
includes? Kein einziger davon ist notwendig. Was also machen die da
drinnen.
Das Problem ist nämlich, dass du ganz schnell in zirkulären includes
landest. Denn UART_functions.h includiert seinerseits wieder die
circbuf.h usw. usw.
Und das ist nicht gut!
Löse das alles mal ordentlich auf. Jedes Header File, jedes C-File
includiert nur das, was es tatsächlich braucht.
Du hast in deinem Code offenbar eine Hierarchie. Ganz unten in der
Hierarchie stehen die Funktionen für Ringbuffer. Die sind von nichts
anderem abhängig. Also braucht es auch keinen Include, ausser den einen
oder anderen System-Header und natürlich im C-File das eigene
Header-File.
Darüber sitzen in der Hierarchie die UART Funktionen. Die brauchen die
Unterstützung durch einen Ringbuffer. Also ist es für die in Ordnung
circbuf.h zu inkludieren. Aber umgekehrt nicht. circbuf ist in keinster
Weise davon abhängig, dass er zusammen mit einer UART eingesetzt wird.
Also warum soll er dann den Header für UART Funktionen includieren?
Halte Ordnung in deinem Code, respektiere Hierarchien und du wirst
weniger von seltsamen Fehlermeldungen geplagt.
(Richte das mal her und dann schaun wir mal weiter, ob und wenn ja
welche Warnungen verschwinden)
Yalu X. schrieb:> Schau noch einmal nach, ob die Reihenfolge der Deklarationen bzw. der> #include-Direktiven der entsprechenden Header-Files stimmt.
Danke für deine Hilfe Yalu!
Die Reihenfolge in der Main hatte nicht gestimmt, da hat dein Punkt
exakt zugetroffen. Ich hatte aber (aus noob-vorsichtigkeit?) die
circbuf.h in allen headerfiles nochmal über ifdef eingebunden, wo der
struct verwendet wird. Dein Tip (d.h. einbinden der circbuf.h ganz zu
beginn) hat einige der Warnungen weniger werden lassen (insbesondere zum
pointer-type), dafür sind tatsächlich aber ein paar mehr
Warning 1 'struct circular_buffer' declared inside parameter list
[enabled by default]
aufgetaucht..
Karl Heinz schrieb:> (Richte das mal her und dann schaun wir mal weiter, ob und wenn ja> welche Warnungen verschwinden)
Danke Karl-Heinz! Mache ich.
Die includes im circbuf.h sind ein Überbleibsel meiner heutigen
Programmierarbeit: Ich hatte vorher die anderen files includiert um
während der Ringpufferzugriffe Interrupts ausschalten zu können (die
funktionen dazu im jeweiligen file).
was macht da F_CPU bzw. der include von util/delay.h da drinnen? Braucht
das irgendwer in DIESEM Header File?
Nein, kein Mensch braucht das in diesem Header File. Also weg damit!
Und so gehst du jedes einzelne C-File, jedes einzelne Header-File durch
und fragst dich bei jedem #include 'Brauch ich den da drinnen?', 'Wird
hier, in diesem File, irgendetwas verwendet, was diesen #include
notwendig machen würde?'. Wenn die Antwort 'Nein, nichts' lautet, dann
-> weg damit.
Alex v. L. schrieb:> Die includes im circbuf.h sind ein Überbleibsel meiner heutigen> Programmierarbeit: Ich hatte vorher die anderen files includiert um> während der Ringpufferzugriffe Interrupts ausschalten zu können (die> funktionen dazu im jeweiligen file).
Das würde maximal einen entsprechenden Include in den jeweiligen C-Files
erklären, aber nicht in den Header-Files.
im Ernst: du musst es dir zur Regel machen, jedes File für sich zu
betrachten. Ein Header File wird als in sich abgeschlossen betrachtet.
Es enthält nur die #include, die im Header-File notwendig sind, um
Begriffe zu definieren (wie zb Strukturnamen, die woanders herkommen).
Das Header File nimmt aber keine Rücksicht darauf, dass 'sein' C-File
vielleicht irgendwelche Dinge benötigen würde. Wenn dem so ist, dann
soll gefälligst das C- File den #include machen, aber das Header File
wird einen Teufel tun und für 'sein' C-File etwas inkludieren.
Karl Heinz schrieb:> Ein Header File wird als in sich abgeschlossen betrachtet.> Es enthält nur die #include, die im Header-File notwendig sind, um> Begriffe zu definieren (wie zb Strukturnamen, die woanders herkommen).> Das Header File nimmt aber keine Rücksicht darauf, dass 'sein' C-File> vielleicht irgendwelche Dinge benötigen würde. Wenn dem so ist, dann> soll gefälligst das C- File den #include machen, aber das Header File> wird einen Teufel tun und für 'sein' C-File etwas inkludieren.
Danke, so war mir das noch nicht klar. ich dachte immer: Wenn das c-file
ohnehin seine headerfile includiert, dann kann ich ja alle weiteren
includes auch in den header tun. Das werde ich in zukunft dann wohl
lassen ;)
Das Aufräumen nach deinen Anweisungen hat enorm etwas gebracht - es sind
nur noch zwei x zwei Warnungen übrig: jeweils hinter den zwei typedef
struct-deklarationen ohne variablendeklaration
1
typedefstructcircular_buffer{
2
charvolatile*data;
3
intsize;
4
charvolatilefillcount;
5
charhead;
6
chartail;
7
};
Bekomme ich einen "useless storage class specifier in empty
declaration".
Der kommt mir bekannt vor, ich hatte damals nämlich auch die nicht
verwendete TCircBuf deklaration gelöscht, dann aber wegen der warnung
wieder hingeschrieben... kann man die warnung verhindern, wenn man eben
trotzdem in einem anderen file deklarieren will?
spricht davon, dass da per default etwas enbled (also eingeschaltet)
wurde. Ich kann mir auch schon vorstellen, was das ist, und es ist IMHO
keine gute Idee dieses zuzulassen.
In C gibt es eine Grundregel, die da lautet:
Der Compiler liest den Code von oben nach unten und er liest ihn genau
ein einziges mal.
Weiters gilt: verwendet werden kann nur, was auch bekannt ist.
Wenn du also eine Funktion hast
1
voiddoIt(structxyz*abc);
und der Compiler hat an dieser Stelle vorher nicht erfahren, dass es
eine 'struct xyz' überhaupt gibt, dann ist das ein Fehler im Code! Die
Strukturdeklaration muss vor der ersten Verwendung erfolgt im zu
compilierenden File erfolgt sein.
Scheinbar gibt es da aber im Compiler eine Erweiterung, die zulässt,
dass der Compiler so etwas akzeptiert: Die Verwendung eines Datentyps
von dem im Code davor nicht klar gestellt wurde, dass er existiert.
Daher der Wortlaut in der Warnung "declared inside parameter list". Das
ist nichts anderes als eine implizite Deklaration basierend darauf, dass
dieser Strukturname in der Funktionsdeklaration benutzt wird.
Meiner Meinung nach ist das keine gute Idee. Eines der größten Probleme
im alten Kernighan&Ritchie C waren genau derartige impliziten Annahmen
und Zulassungen des Compilers. Eine der großen Errungenschaften von C++
war es, dass diese impliziten Annahmen und Zulassungen mehr oder weniger
alle gestrichen wurden. Im Laufe der Jahre hat sich nämlich
rausgestellt, dass eine Menge Fehler auf deren Konto gingen. Die jetzt
zumindest teilweise wieder über die Hintertür zuzulassen ist IMHO ein
Schritt in die falsche Richtung.
> spricht davon, dass da per default etwas enbled (also eingeschaltet)> wurde. Ich kann mir auch schon vorstellen, was das ist, und es ist IMHO> keine gute Idee dieses zuzulassen.
Das bedeutet IMO eigentlich nur, dass die Warnung per default an ist.
Seit einiger Zeit, gibt der GCC bei jeder Warnung noch an, wegen welchem
Flag diese Warnung enabled ist.
Alex v. L. schrieb:> nur noch zwei x zwei Warnungen übrig: jeweils hinter den zwei typedef> struct-deklarationen ohne variablendeklaration
:-)
Da gehört auch keine Variablendefinition hin
:-)
(Jetzt sind wir wieder an dem Punkt mit dem C-Buch)
In C definiert man so eine Struktur
1
structxyz
2
{
3
intmember;
4
};
So weit so gut.
Um diese Struktur zu verwenden, musst du überall schreiben
1
voidfoo(structxyzargument)
also immer das 'struct ...' ausschreiben. Eine Struktur definiert keinen
neuen Typ, der nur aus dem Namen der STruktur bestehen würde.
Aber: dagegen kann man was tun. Mit einem typedef kann man sich einen
echten neuen Namen für einen Datentyp definieren, der als Alias für
diesen Datentyp gilt.
Man kann also machen
1
structxyz
2
{
3
intmember;
4
};
5
6
typedefstructxyzneuerNameXYZ;
die Typedef-Syntax ist recht einfach. Stell dir einfach die Definition
einer entsprechenden Variablen vor
1
structxyzvariableA;
, schreib ein typedef davor und der Variablenname wird zum Namen dieses
neuen Datentyps.
Damit hast du dir einen echten neuen Datentyp geschaffen, der auf den
Namen 'neuerNameXYZ' hört, und der ein Alias (ein Stellvertreter) für
'struct xyz' ist.
Damit kannst du aber schreiben
1
voidfoo(neuerNameXYZargument)
und bist das ewige schreiben von 'struct' los.
Man kann auch weitergehen. Anstelle von 2 getrennten Dingen
1
structxyz
2
{
3
intmember;
4
};
5
6
typedefstructxyzneuerNameXYZ;
kann man auch die Strukturdfintion direkt in den typedef einbinden.
Quasi wie eine Text-Einsetzung ...
1
typedefstructxyz
2
{
3
intmember;
4
}neuerNameXYZ;
... und so Strukturdefinition und typedef miteinander verbinden.
Logischerweise macht es aber überhaupt keinen Sinn, einen typedef zu
machen und dann für diesen typedef keinen Aliasnamen anzugeben!
Zu "struct S ..." vs "typedef struct ... T":
Üblich ist es heute, mit den typedef Namen zu arbeiten. Die alte "struct
S" Variante wird kaum noch verwendet - es sei denn der Code stammt noch
aus grauer Vorzeit (Unix-API). Die typedefs gab es anfangs nämlich
nicht.
Nur bei Vorwärtsdeklarationen kommt man nicht gänzlich ohne aus:
typedef struct S T;
struct S {
T *next;
...
};
oder
typedef struct S {
struct S *next;
...
} T;
cyblord ---- schrieb:> Das bedeutet IMO eigentlich nur, dass die Warnung per default an ist.
Der springende Punkt ist aber, dass das laut C-Regeln keine Warnung sein
sollte, sondern tatsächlich ein waschechter Fehler sein müsste.
Und dafür muss es eine Option geben, die eingeschaltet ist.
Ich danke euch für eure Zeit! Zumindest in meinem Fall soll sie nicht
vergeudet gewesen sein ich schreibe mir so viel wie möglich davon hinter
die ohren!
Leider hat sich durch die Warnungsbehebung nicht der Fehler behoben
(kein Compilefehler), der mich gerade davon abhält hinter einem weiteren
großen Schritt einen haken setzen zu können.
Der Code ist inzwischen soweit gewachsen, dass ich nach einer Eingabe
eines Kontrollbytes die Werte eines SPI ADC abfragen und diesen
konfigurieren kann, die daten werden dann im ASCII mit timestamp ans
terminal geschickt.
Offen ist noch, an welcher Stelle (bei Ringpufferzugriffen?) das Senden
gestört wird.
Es ist an sich ganz leicht: Ich sende derzeit wiederholt ein 0xAA als
Request für einen Datenblock mit dem Format (in Bytes)
1
// Send ASCII DataBlock: [M|#|;|C|#|;|S|0/1|;|ADCVAL(Hex,dargestellt in 4ASCIIBytes)|;| |TIMERVAL(Hex,dargestellt in 4ASCIIBytes)|CR|LF]
Wobei M# eine Modulnummer, C# die aktive Channelnummer, S0/1 den
Speedmode des ADC und darauf für das CSV-Format mit Semikolon getrennt
der 16Bit ADC-Wert und Timestamp kommen.
Was ich also erwarte und in 50% der Fälle erhalte:
z.B.
1
M0;C0;S0;113D;3131
Was ich bekomme (nach hier 11 Requests):
1
M0;C0;S0;113D;3131
2
M0;C0;S0;113E;3101
3
;113E;31D0
4
M113E;31M0;C0;S0;113D;322A
5
M1;C0;S0;0000;0210
6
M1;C0;S0;113F;023B
7
M1;C0;S0;113F;02F1
8
;0000;002B
9
M0000;00M1;C0;S0;113E;0000
10
;113E;00DA
11
M113E;00;113F;0121
Ich möchte hier nicht überstrapazieren, deshalb die Frage: Neues Thema
aufmachen? Alle hier in Ruhe lassen? Oder hier ausbreiten?
Karl Heinz schrieb:> Logischerweise macht es aber überhaupt keinen Sinn, einen typedef zu> machen und dann für diesen typedef keinen Aliasnamen anzugeben!Lichtaufgeh
Karl Heinz, ich danke dir!
Alex v. L. schrieb:> Angehängt die aufgeräumte(re - man weiß ja nie) Version unter Befolgung> aller Tips von Karl-Heinz. Tatsächlich ohne Warnung compilierbar ;-)
Tja, kaum macht man es richtig, schon gehts ;-)
Karl Heinz schrieb:>> Leider hat sich durch die Warnungsbehebung nicht der Fehler> behoben>> Tja.>> Das hiervoid circbuf_add(struct circular_buffer *buf, char value) {> buf->data[buf->head] = value;> buf->head++;> buf->fillcount++;> }> ist ja auch kein Ringbuffer.
Irgendwie one-way, nicht?
Alex v. L. schrieb:> Karl Heinz schrieb:>>> Leider hat sich durch die Warnungsbehebung nicht der Fehler>> behoben>>>> Tja.>>>> Das hiervoid circbuf_add(struct circular_buffer *buf, char value) {>> buf->data[buf->head] = value;>> buf->head++;>> buf->fillcount++;>> }>> ist ja auch kein Ringbuffer.>> Irgendwie one-way, nicht?
Ich würd mal sagen:
Irgendwie 'mir doch scheissegal wie gross der Speicher ist, ich knall
das nächste Byte einfach hinten drann'.
Und von einem 'Ring' ist schon gleich gar nichts zu sehen.
Alex v. L. schrieb:> Das Aufräumen nach deinen Anweisungen hat enorm etwas gebracht - es sind> nur noch zwei x zwei Warnungen übrig: jeweils hinter den zwei typedef> struct-deklarationen ohne variablendeklaration>> typedef struct> circular_buffer {> char volatile *data;> int size;> char volatile fillcount;> char head;> char tail;> };>> Bekomme ich einen "useless storage class specifier in empty> declaration".
Lass einfach das typedef weg.
Du verwendest die Strukturtypen doch sowieso unter Angabe von
struct circular_buffer, dann ist das typedef unnötig.
Im oben zitierten Fall ist das typedef sogar unvollständig - Du gibst
zwar an, welcher Typ definiert werden soll (Dein struct), lässt aber
weg, als was (das ist das, was Du als "ohne Variablendeklaration"
bezeichnest).
So ein typedef hat folgende Syntax:
1
typedef [Kram, der als neuer Datentyp definiert werden soll] Name für neuen Typ
Also beispielsweise
1
typedefintbla;
Das erzeugt einen neuen Datentyp namens "bla", der fortan genauso
verwendet werden kann wie int:
1
blax;
2
3
x=4;
etc.
Bei einer Struktur und einem typedef davon sieht das genauso aus:
1
typedef
2
// --- ab hier folgt der "Kram, der als neuer Datentyp definiert werden soll"
3
structcircular_buffer{
4
charvolatile*data;
5
intsize;
6
charvolatilefillcount;
7
charhead;
8
chartail;
9
}
10
// --- das ist das Ende vom "Kram, der als neuer Datentyp definiert werden
11
TCircBuf;// das ist der Name unseres neuen Datentyps
Damit kannst Du fortan anstelle von "struct circular_buffer" einfach
"TCircBuf" schreiben:
Ja, ich glaube das reicht als hinweis. "wenn man nicht alles selber
macht" ist wohl in dem sinne falsch: Wenn man sich nicht die mühe macht
alles selber zu durchschauen. Ich habe ja als erstes selber einen
UART-puffer bauen wollen, worauf ich (richtigerweise) hier im forum
hingewiesen wurde doch nicht das rad neu zu erfinden. Und wenn man dann
den "Ringpuffer" von wem anders einfach einbaut ist man selber schuld.
Danke für die Geduld!
Rufus Τ. Firefly schrieb:> Damit kannst Du fortan anstelle von "struct circular_buffer" einfach> "TCircBuf" schreiben:
Danke Rufus! Ja, so hatte ich Karl Heinz vorhin auch verstanden - und
habe (weils schöner ist) jetzt überall im Code (auch in der aufgeräumten
version oben)
1
CircBuf*buf
stehen! ich bin ja echt überrascht und beeindruckt von eurem Feedback!
:)
Ich weiß ja nicht, wo du den her hast. Aber ich weiß mit Sicherheit,
dass das kein Ringbuffer ist :-)
Das ist selbst für einen normalen linearen Buffer ein bischen zu
schlampig geschrieben. Werte in ein Array schreiben, ohne zu prüfen ob
man nicht mit dem Index das Array überläuft, ist bei einer so unviersell
einsetzbaren Basiskomponente nicht tolerierbar. Das ist Mist, und zwar
einer von der großen Sorte.
Karl Heinz schrieb:> Das> ist Mist, und zwar einer von der großen Sorte.
Ich bin jetzt auch überrascht. Ist schließlich mist aus einer
diplomarbeit. Eventuell habe ich auch den unglaublich tollpatschigen
fehler begangen bei dem header/c-namen "circbuf" von "circular buffer"
und damit ringpuffer auszugehen. Ach nee, steht ja sogar im kommentar
oben. :D
Nun denn, zurück zu meiner eigenen version.
Karl Heinz schrieb:> Ich weiß ja nicht, wo du den her hast. Aber ich weiß mit Sicherheit,> dass das kein Ringbuffer ist :-)> Das ist selbst für einen normalen linearen Buffer ein bischen zu> schlampig geschrieben. Werte in ein Array schreiben, ohne zu prüfen ob> man nicht mit dem Index das Array überläuft, ist bei einer so unviersell> einsetzbaren Basiskomponente nicht tolerierbar. Das ist Mist, und zwar> einer von der großen Sorte.
Jetzt mal davon abgesehen, dass es sich hier nicht um einen Ringbuffer
handelt. Denn so ein Ringbuffer ist ja im Grunde nicht so schwer.
Er funktioniert wie das Zifferblatt einer Uhr, mit 60 Abstellplätzen und
wo der "Sekunden"-zeiger anzeigt, wo das nächste Element abzulegen ist
(und dann um 1 Stelle vorrückt). Logischerweise ist der Sekundenzeiger
aber irgendwann mal rum, und die 60 Plätze sind benutzt worden, der
Sekundenzeiger rückt ja immer nur vor und nicht zurück. Und so wie beim
Sekundenzeiger geht es dann wieder bei 0 weiter. Und weil das
Zifferblatt einer Uhr so schön rund ist und sich der Zeiger im Kreis
dreht, nennt man das einen 'RingBuffer', weil man sich das verwendete
Array wie zu einem Ring zusammengeklebt vorstellen kann. So wie die
Markierungen auf einem Uhrblatt. Ist man "am Ende" angelangt, geht es
"vorne" wieder weiter.
Alex v. L. schrieb:> Ich bin jetzt auch überrascht. Ist schließlich mist aus einer> diplomarbeit.
Jetzt wollen wir mal nicht unfair sein. Denn es gibt tatsächlich einen
speziellen Fall, in dem dieser Coed tatsächlich als Ringbuffer arbeitet.
Aber dazu müssen ein paar Voraussetzungen erfüllt sein
* char muss ein unsigned Datentyp sein
* die Länge des Arrays muss der 2-er Potenz der Bitzahl von char
entsprechen. Auf Deutsch: beim wohl häufigsten Fall, dass ein char 8 Bit
hat, muss das Array 256 Elemente gross sein.
Dann und nur dann ist das tatsächlich ein Ringbuffer, weil das
Rücksetzen des head auf 0 dann implizit im Inkrement mit enthalten ist.
Das natürlich die Strukturdefinition da etwas ganz anderes suggeriert
und nichts davon dokumentiert ist, ist allerdings eine ganz andere
Geschichte.
Ja, das Prinzip meinte ich auch schon verstanden zu haben. Ich hatte mir
nämlich damals unter Verwendung des hiesigen FiFo Eintrags
http://www.mikrocontroller.net/articles/FIFO meinen eigenen geschrieben.
Nur muss ich jetzt leider folgendes verkünden: Trotz verwendung des
"richtigen" Ringpuffers (will zumindest heißen meines eigenen auf basis
des µC.net eintrags) habe ich das selbe Verhalten am Terminal.
Wieder mal angehängt der aktuelle Satz files, jetzt mit dem eigenen
Ringpuffer.
Karl Heinz schrieb:> Auf Deutsch: beim wohl häufigsten Fall, dass ein char 8 Bit> hat, muss das Array 256 Elemente gross sein.Karl Heinz schrieb:> Dann und nur dann ist das tatsächlich ein Ringbuffer, weil das> Rücksetzen des head auf 0 dann implizit im Inkrement mit enthalten ist.
Ah das erklärt was, die länge war auf 256 Bytes definiert im
Originalfile.
Nunja, leider erklärt das dann das Problem (auch bei Verwendung des
anderen Buffers) nicht...
Mal eine andere Frage.
Musst du die UART Funktionen bzw. den Ringbuffer selber schreiben oder
darfst du auch auf externe Komponenten zurückgreifen?
Denn beim P.Fleury gibt es ein fix fertiges UART/Ringbuffer Modul,
welches erstklassig funktioniert und all die kleinen Fallen auch schon
umschifft hat. Es ist zwar nicht so schön universell in UART und Buffer
getrennt, hat dafür aber den Vorteil aus dem Stand heraus zu
funktionieren. Denn der Teufel steckt im Detail, dass sich der
Ringbuffer nicht selbst überholt, bzw. dass die Interrupts korrekt und
zum richtigen Zeitpunkt ein bzw. ausgeschaltet werden.
Karl Heinz schrieb:> Musst du die UART Funktionen bzw. den Ringbuffer selber schreiben oder> darfst du auch auf externe Komponenten zurückgreifen?
Müsste ich nicht. Das Fleury Package habe ich auch schon mal angeguckt,
ich muss aber zugeben dass es mich in seiner komplexität (wahrscheinlich
der allgemeingültigkeit geschuldet) etwas überfordert hat - und ich dann
auch nicht sicher gewusst habe wie ich es in mein bestehendes interface
einfüge.
Und dem Gefühl nach bin ich ja nur noch ganz dicht davor dass es einfach
läuft! Naja, vielleicht trügt es ja. :(
Karl Heinz schrieb:> Denn der Teufel steckt im Detail, dass sich der> Ringbuffer nicht selbst überholt, bzw. dass die Interrupts korrekt und> zum richtigen Zeitpunkt ein bzw. ausgeschaltet werden.
Ja, die Interrupts habe ich auch schon länger im Verdacht. Auch aus
diesem Grund bin ich von Interruptgesteuerter SPI zu einer schlichten
Funktion mit warten übergegangen. Der einzige Interrupt neben den UART
Interrupts, den es gibt, ist nun noch der von Timer1, den ich für
Timestamps verwenden will. Leider muss ich (soweit ich das bisher
überschaut habe) den Output Compare Interrupt nutzen, damit ich bei 16
bit und maximalem Clockdivider (1024) bei 20 MHz überhaupt auf einen
10ms Counter komme. D.h. aber: alle 10ms gibts einen interrupt.
Aber: Wenn ich den timer zu testzwecken einfach ausmache, ist das
problem auch nicht gelöst.
Wie könnte denn sich selbst überholen gehen?
Alex v. L. schrieb:> Müsste ich nicht. Das Fleury Package habe ich auch schon mal angeguckt,> ich muss aber zugeben dass es mich in seiner komplexität (wahrscheinlich> der allgemeingültigkeit geschuldet) etwas überfordert hat
alles halb so wild.
Die Grundfunktion ist auch nicht anders als das, was du gerade baust.
> auch nicht sicher gewusst habe wie ich es in mein bestehendes interface> einfüge.
Das sollte aber nicht wirklich ein Problem sein.
Am Anfang ist es etwas gewöhnungsbedürftig, die get FUnktion so zu
benutzen
1
intc;
2
3
c=uart_getc();
4
5
if(!(c&UART_NODATA))
6
{
7
// Juhu, da ist was vorrätig, verarbeite c
8
}
aber so schlimm ist das auch wieder nicht. Du machst ja im Grunde auch
nichts anderes, wenn du den Ringbuffer befragst, ob er empty ist oder
nicht. Peter hat halt beide Informationen zusammen in einen int
gesteckt: Ist ein Zeichen im UART-Modul vorrätig und wenn ja, welches
Zeichen ist das?
Soooo groß ist der Unterschied nicht. Es ist anders, eine andere Idee
der Realisierung. Aber bei genauerem Hinsehen ist es dieselbe
Funktionalität.
Der Sendecode hingegen unterscheidet sich kaum. Du rufst eine der
vorgefertigten Sendefunktionen auf und bist das zu sendende Zeichen
(oder den String) los.
Was beim Fleury Code hinzukommt ist, dass der Code auf mehreren
AVR-Typen einsetzbar ist und da Atmel die Dinge da unterschiedlich
macht, sind da ein paar #define bzw. #ifdef drinnen um die Anpassung zu
machen. Das dreht sich hauptsächlich um unterschiedliche Register- bzw.
Bitnamen bzw. ISR-Namen, die Atmel leider nicht einheitlich nach einem
Schema vergibt. Die kann man aber auch alle ausbauen bzw. entfernen,
wenn man das Gefühl hat, dass sie stören.
Na dann schaue ich mir das jetzt nochmal an, inzwischen bin ich zu allem
bereit! ;) (vielleicht verstehe ich es jetzt auch besser, die fleury
dateien habe ich am anfang meiner einarbeitung angesehen)
Im Zip-File ist ein Demobeispiel.
WEnn das compiliert und sauber funktioniert, dann hast du schon
gewonnen. Dann wird dein AVR-Typ unterstützt (wegen der
Registerbezeichnungen) und du kannst die Internals des Codes gleich mal
ignorieren. (wobei: so schwer sind die auch wieder nicht zu verstehen.
Peter kocht auch nur mit Wasser)
Der Code ist halt schon ein wenig älter. D.h. bei neueren Prozessoren
müsste man unter Umständen die Register bzw. Interrupt Bezeichnungen
nachtragen. Die hast du aber mit deinen 'Vorstudien' mitlerweile aber
sowieso intus :-)
Alex v. L. schrieb:> Danke für deine Hilfe! Ich grab mich rein. Ich werd schon rumschreien im> Notfall ;)
Ist kein Problem. Wirst sehen, das geht in 0-komma-nix. Und wenn nicht,
dann tragen wir deinen AVR einfach im Code nach und dann gehts in
0-komma-nix
Der AtMega644 ist in der uart.c zumindest mitdefiniert. Nur welcher
controller der zu verwendende ist ist mir unklar: Muss ich den angeben
oder wird der vom Compiler "erkannt" (ist ja im Projekt angegeben)?
(Gäbe es da einen Unterschied zwischen AVRGCC und AVRStudio6.1?)
AVRStudio verwendet auch den AVR-Gcc, wenn auch eine neuere Version
davon.
wird erkannt.
Für dich ist erst mal (bis zum Beweis des Gegenteils :_) nur das Header
File interessant. Alles was dort mit einem #define einstellbar ist,
darüber machst du dir Gedanken. Das C-File interessiert dich momentan
überhaupt nicht (ausser es gibt irgendwann mal Fehler oder man will im
Detail wissen, wie die Dinge funktionieren).
Denn genau so soll ja auch die Trennung C-File und Header-File sein: Das
Header-File ist die Schnittstelle nach aussen. Zum verwendenden Code.
Alles was der, bzw. der Programmierer desselben, wissen muss, findet er
im Header File. Das C-File braucht er im Idealfall nie angreifen. Das
wird einfach zum Projekt hinzugefügt, mitkompiliert und implementiert
das, was das Header File verspricht.
Karl Heinz schrieb:> File interessant. Alles was dort mit einem #define einstellbar ist,> darüber machst du dir Gedanken.
Wobei man natürlich darauf achten muss, was denn eigentlich wirklich
einstellbar ist und welche #define so eine Art Vereinbarung von
Benachrichtigungen sind. Aus dem Zusammenhang ist das aber normalerweise
recht eindeutig. Das hier
1
#define UART_FRAME_ERROR 0x1000 /* Framing Error by UART */
2
#define UART_OVERRUN_ERROR 0x0800 /* Overrun condition by UART */
3
#define UART_PARITY_ERROR 0x0400 /* Parity Error by UART */
#define UART_NO_DATA 0x0100 /* no receive data available */
ist ganz klar nichts, was du verändern kannst, sondern das sind Werte,
die du in deinem Programm benutzen kannst um die Returnwerte von den
Funktionen auszuwerten.
Alex v. L. schrieb:> Danke. Also erstmal compiliert er das noch nicht:> "Error 19 #error "no UART definition for MCU available"
Dann ist das Symbol
_AVR_ATmega644_
doch nicht definiert.
Wundert mich, sollte es eigentlich. Dem Compiler wird auf der Command
Line, beim Aufruf der Typ des µC mitgegeben. Je nachdem wird dann in
avr/io.h das zu diesem Prozessor passende spezielle Include File
includiert und das definiert dann diese Konstante.
Kannst du den Compiler Aufruf in der IDE sehen? (Output Fenster oder so)
Wie sieht der Aufruf aus?
mit dem wird das geregelt.
Jetzt weiß ich aber nicht, wie die entsprechende _AVR..... Konstante
dazu heißt, bzw. was der Unterschied zwischen einem 644A und dem
normalen 644 ist.
Eine Möglichkeit wäre (so hab ich auch gefunden, dass der P Typ
unterschieden wird):
Schau in die avr/io.h rein.
Bei mir findet sich da (ich hab hier noch eine ganz alte Version vom
avr-gcc)
1
....
2
#elif defined (__AVR_ATmega644__)
3
# include <avr/iom644.h>
4
#elif defined (__AVR_ATmega644P__)
5
# include <avr/iom644.h>
6
....
da sind also 2 verschiedene 644 eingetragen. Der normale und der P Typ.
Beide führen aber in jeweils dasselbe iom644.h, so dass man davon
ausgehen kann, dass die beiden softwaretechnisch identisch zu behandeln
sind.
Ich schätze mal, das wird beim 644A auch nicht anders sein.
Aber schau ins io.h. Wenn ich richtig liege, dann gibt es dort dann auch
noch ein #elif für den _AVR_ATmega644A_, welcher ebenfalls in iom644.h
weiter gibt.
Womit du mich darauf gebracht hast dass ich zu beginn des Projektes den
644A angegeben habe (register sind in meinem fall gleich) - habe jetzt
auf 644 umgestellt (das ist auch der tatsächliche controller):
Jetzt bekomme ich nur noch "undefined reference to PSTR" drei mal sowie
"ld returned 1 exit status"
Wobei ich wenn ic hdem fehler folge zur uart_puts_P(" ") Funktion in
der main komme..
Alex v. L. schrieb:> Womit du mich darauf gebracht hast dass ich zu beginn des Projektes den> 644A angegeben habe (register sind in meinem fall gleich) - habe jetzt> auf 644 umgestellt (das ist auch der tatsächliche controller):>> Jetzt bekomme ich nur noch "undefined reference to PSTR" drei mal sowie> "ld returned 1 exit status">> Wobei ich wenn ic hdem fehler folge zur uart_puts_P(" ") Funktion in> der main komme..
:-)
Da hat der Peter das nicht gemacht, was ich dir oben gepredigt habe.
PSTR ist ein Makro aus
1
#include<avr/pgmspace.h>
das Header File verwendet PSTR, also müsste das Header File diesen
Header inkludieren. Tut es aber nicht, statt dessen macht es die
test_uart.c, also das verwendende Programm.
jup, habe eben auch gesehen dass ich die pgmspace nicht includiert
hatte.
Gut, ich denke damit kann ich umrüsten, das terminal gibt mir meinen
input wieder aus, so wie der code es vorhersagt ;)
Die zwei funktionen, die für mich nun interessant sind, sind ja wohl
1
=uart_getc();
und
1
uart_putc((unsignedchar)c);
Wie ich getc verarbeite ist ja durch den kommentar im code klar: das
lower byte ist mein datenbyte.
putc ist ja dann eigentlich analog, ich gehe davon aus dass das higher
byte automatisch gefüllt wird oder leer bleibt - d.h. ich kann beide
funktionen nutzen wie meine alten write_byte und read_bytes korrekt? :)
Alex v. L. schrieb:> jup, habe eben auch gesehen dass ich die pgmspace nicht includiert> hatte.>> Gut, ich denke damit kann ich umrüsten, das terminal gibt mir meinen> input wieder aus, so wie der code es vorhersagt ;)>> Die zwei funktionen, die für mich nun interessant sind, sind ja wohl>>
1
=uart_getc();
> und>
1
uart_putc((unsignedchar)c);
>> Wie ich getc verarbeite ist ja durch den kommentar im code klar: das> lower byte ist mein datenbyte.
Exakt.
Daher auch der Return Typ von int.
Das macht aber nichts, du kannst das in weiterer Folge genauso
verwenden, wie wenn es ein char wäre. Wenn kein Fehler vorliegt und ein
Zeichen da ist, dann ist das High-Byte 0x00 und damit funktionieren alle
Vergleiche
1
if(c=='a')
wie bisher. Du kannst natürlich das High-Byte auch (nach Fehlerprüfung)
loswerden, indem du auf einen echten char umkopierst. Aus C Sicht ist es
aber nicht notwendig.
schreibe bekomme ich eine warnung
"passing argument 1 of 'uart_puts_p' makes pointer from integer without
a cast [enabled by default]"
Wie werde ich die los? Ich weiß, dass ich casten könnte - aber so war
die funktion ja eigentlich nicht gedacht (und wird ja auch im beispiel
so verwendet)..
So. Jetzt habe ich das alles übertragen und durchgeprügelt und freue
mich erst und könnte dann schreien. Denn:
Nach ca. 20 erfolgreichen Übertragungen bekomme ich den selben (sorry)
SCHEISS wieder, dann renkt es sich wieder ein, dann spinnts wieder:
1
M1;C0;S0;1B12;003A
2
M1;C0;S0;1B12;00AC
3
M1;C0;S0;1B12;00DE
4
M1;C0;S0;1B12;0110
5
M1;C0;S0;1B12;0101
6
M1;C0;S0;1B12;0133
7
M1;C0;S0;1B12;01A1
8
M1;C0;S0;1B12;01D3
9
M1;C0;S0;1B12;0201
10
M1;C0;S0;1B12;023B
11
M1;C0;S0;1B12;022D
12
1E
13
M1
14
0;S0;1B12;02D0
15
0;S0;1B12;02M0
16
0;S0;1B11;02M1;C0;S0;1B12;0302
17
30
18
M1
19
0;S0;1B12;03M1;C0;S0;1B12;0322
20
;1B12;0310
21
M1B12;03M1;C0;S0;1B11;03CA
22
FB
23
M1
24
0;S0;1B12;03;1B12;002D
25
0;S0;1B12;03M1B12;00M1;C0;S0;1B12;001F
26
M1;C0;S0;1B12;0011
27
;1B12;00C3
28
M1B12;00;1B12;00F1
29
M1B12;00M1B12;00M1;C0;S0;1B12;0122
30
;1B12;0110
31
M1B12;01M1;C0;S0;1B12;010A
32
M1;C0;S0;1B12;01BC
33
M1;C0;S0;1B12;01EE
34
M1;C0;S0;1B12;0A20
Woran kann das bitte liegen? Nun nicht mehr am Ringpuffer oder der
UART-Umsetzung, da habe ich ja jetzt zu 100% Peter Fleury's library
genommen.
Der Timer-Interrupt war beim ersten versuch auch aus (macht keinen
Unterschied), das heißt aktiv waren im ersten Testfall nur Peters
interrupts.
Ich mache jetzt schluss für heute, ich sitze seit knapp 10 stunden ohne
pause dran. Wenn hier noch irgendjemand hilfe weiß bin ich ihm mehr als
nur einen 3D Druck (oder zumindest den) schuldig.
Immerhin kann ich jetzt strings über UART schicken, ging vorher nicht.
War die Umstellung auf Fleury's library also nicht umsonst... Ha....
Kann es irgendwie noch an den Baudrateneinstellungen liegen?
Ich nutze einen 20MHz externen NX5032GA SMD Quarz mit C=12pF beschaltet.
Bei 9600 bps mit Baudratenregisterwert 130 gibt das nach µC-net Rechnung
(http://www.mikrocontroller.net/articles/AVR-Tutorial:_UART) 0,22%
fehler
Bei 38400 bps mit Registerwert 32 (-)0,157%.
Das sollte also eigentlich gehen oder nicht?!
du gibst hier einen Interrupt frei. Ich finde aber keine zugehörige ISR.
WEnn du tatsächlich keine ISR dafür hast, dann machts peng, sobald der
erste Compare Match vorliegt.
Hat das eigentlich einen Grund warum die send_ADC_Data so dermassen
komplex aufgebaut ist.
(Ist das gewollt, dass die interne Kanalnummer nicht mit der per UART
übertragenen übereinstimmt?)
Denn so ging das doch viel einfacher, wenn ich das richtig sehe
Zu dem PSTR Problem.
Ich weiß nicht, wo die Warnung herkommt.
Ich hab sie bei mir nicht und ich sehe in den Headerfiles auf meinem
System auch keinen Grund, warum die kommen würde.
Ich kann sie aber, wenn ich 'Gewalt anwende' forcieren. Aber da muss ich
die _p Funktion schon vergewaltigen.
damit gehts los
und dann wird sukzessive ein Teil nach dem anderen wieder eingebaut.
Wenn die Ausgabe problemlos funktioniert (wovon ich ausgehe), ist als
nächstes der Timer drann, der die Millisekunden hochzählt.
Dann SPI initialisieren
dann ADC abfragen
dann Abfrage auf Benutzerwunsch.
Nach jeder Erweiterung exzessiv testen. Lieber einmal zuviel testen und
die Erweiterungen nur in kleinen Schritten machen (selbst wenn damit
kein Fehler zu erwarten ist), als das Auftreten der Fehlersituation
übersehen.
Alex v. L. schrieb:> Bei 9600 bps mit Baudratenregisterwert 130 gibt das nach µC-net Rechnung
Dann schau mal ins Datenblatt... Da steht nämlich (fosc=20MHz)
129(U2X=0) bzw. 259(U2X=1), nicht 130! aber mit den 0,2% Fehler liegst
du richtig ;)
Grüße
Karl Heinz schrieb:> Hat das eigentlich einen Grund warum die send_ADC_Data so dermassen> komplex aufgebaut ist.
Nein, nur mal wieder meine begrenzten C-Kenntnisse! ;-)
> (Ist das gewollt, dass die interne Kanalnummer nicht mit der per UART> übertragenen übereinstimmt?)
Eigentlich nicht. Aber das ist mir bisher auch noch nicht aufgefallen!
Eigentlich hat die konfigurierte mit der ausgegebenen bisher immer
gestimmt (default 0)..?
Kaj schrieb:> Dann schau mal ins Datenblatt... Da steht nämlich (fosc=20MHz)> 129(U2X=0) bzw. 259(U2X=1), nicht 130! aber mit den 0,2% Fehler liegst> du richtig ;)
Interessant... ich hatte die
http://www.mikrocontroller.net/articles/AVR-Tutorial:_UART Formel
verwendet, da bekomme ich nach Rechnung exakt 129,7 raus (aufgerundet
130) aber: Kann in diesem fall auch nicht der punkt sein, die berechnung
übernimmt die (funktionierende) Fleury Lib.
Kaj schrieb:> Schonmal mit 22pF probiert?
Nein - Meinst du das macht sinn? Das könnte ich natürlich leicht
überprüfen - aber auch hier bin ich laut
http://www.mikrocontroller.net/articles/Quarze_und_AVR Erfahrungswert
auf C = 2·CL – (CP+CI) = 2*8pf -(5pF) = 11 gekommen und nutze 12. Aber
die C-Geschichte würde ja auch mit meiner Frage nach
Quarz/Baudratenquarz zusammenhängen. Was mich an der Annahme dass es der
quarz sein könnte allerdings stört ist, dass ich ja keine Bitfehler als
solches erkennen kann in der Übertragung - die ASCII-Symbole bleiben die
gleichen, nur wild zerhackt...
Alex v. L. schrieb:> Kaj schrieb:>> Dann schau mal ins Datenblatt... Da steht nämlich (fosc=20MHz)>> 129(U2X=0) bzw. 259(U2X=1), nicht 130! aber mit den 0,2% Fehler liegst>> du richtig ;)>> Interessant... ich hatte die> http://www.mikrocontroller.net/articles/AVR-Tutorial:_UART Formel> verwendet, da bekomme ich nach Rechnung exakt 129,7 raus (aufgerundet> 130) aber: Kann in diesem fall auch nicht der punkt sein, die berechnung> übernimmt die (funktionierende) Fleury Lib.
Ich denke nicht, dass es irgendwas mit dem Quarz zu tun hat.
Der mag ein wenig daneben sein, aber einen gewissen Fehler darf man sich
erlauben. DIe Ausgabe funktioniert ja grundsätzlich und dann ist ja auch
noch das Stoppbit, welches einen eventuellen Baudratefehler beim
nächsten Zeichen wieder ausnullt. Sprich: Wenn die ersten Zeichen
korrekt rüber kommen, dann gibt es keinen Grund, warum das in weiterer
Folge nicht auch so sein soll. Die Synchronisierung findet ja bei jedem
Zeichen erneut mit dem Startbit statt. Ist die Baudrate daneben, dann
wirkt sich das innerhalb eines Zeichens aus. Aber dann innerhalb jedes
Zeichens. Bei den allerersten genauso wie bei den folgenden.
Merkwürdig ist, dass diese umbruchfehler im Empfang mit der Länge des zu
sendenden Strings zu tun haben. Wenn ich mir z.B. nur die Temperatur
ausgeben lasse "TEMP:02D2" Dann klappt das ziemlich lange fehlerfrei.
Dabei allerdings hast du mich auf etwas gebracht und rate mal:
Wenn ich hyperterminal bekomme ist alles sauber. Gleiche einstellungen
(Jetzt mal mit 9600 bps, 8bits, kein parity, 1stopBit)...
Gott sagt mir jetzt nicht dass es am Terminalprogramm lag. ich glaubs
nicht. hat ja nur nen tag gedauert das zu bemerken (verstehen tu ichs
allerdings nicht so ganz ;-)
Alex v. L. schrieb:> Gott sagt mir jetzt nicht dass es am Terminalprogramm lag.
LOL
> ich glaubs> nicht. hat ja nur nen tag gedauert das zu bemerken (verstehen tu ichs> allerdings nicht so ganz ;-)
Ich kann dich beruhigen. Der Ringbuffer vom Diplomanden war mies. Deine
Version hab ich mir dann nicht näher angesehen, als klar war, dass du
auf Fleury wechseln wirst.
Zum Thema verstehen:
Jetzt wärs interessant zu wissen, ob dieses Terminalprogramm Handshake
benutzt um die Gegenstelle kurz ruhig zu stellen (was natürlich auf AVR
Seite niemanden interessiert).
Seltsam wärs aber doch: Auf einem GhZ Rechner kommt ein Terminalprogramm
mit einer 9600 Baud Übertragung nicht hinterher? Das klingt für mich
erst mal sehr an den Haaren herbeigezogen. Aber die Fakten sprechen
scheinbar eine deutliche Sprache.
Karl Heinz schrieb:> Jetzt wärs interessant zu wissen, ob dieses Terminalprogramm Handshake> benutzt um die Gegenstelle kurz ruhig zu stellen
Kann man alles einstellen, das Programm WIRKTE toll! ;)
Da kann ja mal wer (wenns denn von interesse ist) nen eigenen thread zu
aufmachen um das zu evaluieren :D
Und um noch ein bisschen TNT ins Feuer zu werfen: Ich habe windows 8.
Hyperterminal ist immerhin ein windoofs programm. man weiß ja nie ;D
Jetzt ist mir wirklich noch enorm ein Stein vom herzen gefallen. Das
wollte ich unbedingt vorm Wochenende fertig bekommen.
Allerherzlichen Dank für all die Hilfe, vorallem von dir Karl-Heinz!
Dazu noch einmal das ausdrückliche Angebot: Wenn du mal was kleines
3D-Gedruckt brauchst sag bescheid. Mann kann tolle Elektro-Basteleien
damit aufbauen an die man vorher gar nicht denken mochte (und das sogar
mir meinen bescheidenen c-kenntnissen): Ein beispiel was ich vor nem
halben jahr damit angestellt habe:
http://www.youtube.com/watch?v=9wgsGA2k9a4
Meld dich falls du mal interesse haben solltest! :)
Jetzt implementiere ich endlich mal das, was ich den ganzen tag
eigentlich machen wollte.
Gute Nacht zusammen!!
Alex v. L. schrieb:> Jetzt ist mir wirklich noch enorm ein Stein vom herzen gefallen. Das> wollte ich unbedingt vorm Wochenende fertig bekommen.
Dann liegst du ja gut in der Zeit.
Ich denke, es hat sich trotzdem gelohnt. Da war einiges am nebenbei
angefallenem 'Kollateralschaden' dabei, der dich auch ein wenig weiter
gebracht hat. Und alleine das ist ja auch schon was wert.
Allerdings muss ich jetzt erst mal meine gern ausgesprochene Empfehlung
überdenken, eine UART erst mal mit der Datenrichtung AVR->PC und einem
Terminalprogramm überdenken. Bisher bin ich immer davon ausgegangen, das
wäre die sichere Alternative, weil das PC-seitig auf jeden Fall erst mal
korrekt funktioniert.
> Dazu noch einmal das ausdrückliche Angebot: Wenn du mal was kleines> 3D-Gedruckt brauchst sag bescheid.
mach ich. Danke fürs Angebot.
Karl Heinz schrieb:> weil das PC-seitig auf jeden Fall erst mal> korrekt funktioniert.
Hängt dann wohl vom Terminalprogramm ab.
Ich muss mir jetzt auch erstmal ein neues suchen, mit dem ich
unproblematisch einzelne bytes an den µC schicken kann (beim
hyperterminal weiß ich zumindest noch nicht wie, das ist ja eher
puristisch und verlangt dann noch eine datei..)