Nabend zusammen,
habe endlich mein Mini-Beispiel für eine funktionierende USART
Schnittstelle hinbekommen.
1
#include<avr/io.h>
2
#include<util/delay.h>
3
4
#define BAUD 9600UL
5
#define UBRR_VALUE ((F_CPU+BAUD*8)/(BAUD*16)-1)
6
#define BAUD_REAL (F_CPU/(16*(UBRR_VALUE+1)))
7
#define BAUD_ERROR ((BAUD_REAL*1000)/BAUD)
8
9
intmain(void){
10
if((BAUD_REAL<990)||(BAUD_ERROR>1010)){
11
DDRD|=(1<<PD6);
12
PORTD|=(1<<PD6);
13
}
14
15
UBRR0H=(uint8_t)(UBRR_VALUE>>8);
16
UBRR0L=(uint8_t)UBRR_VALUE;
17
UCSR0C=(1<<UCSZ01)|(1<<UCSZ00);
18
UCSR0B=(1<<RXEN0)|(1<<TXEN0);
19
20
while(1){
21
UDR0='B';
22
_delay_ms(2000);
23
}
24
}
Funktioniert und macht genau das was es soll. Ich verwende hier einen
sh-u09c5 zum Lesen.
Jetzt wollte ich das Ganze natürlich erweitern auf Strings und habe
folgende Funktionen hinzugefügt:
1
intuart_putc(unsignedcharc);
2
voiduart_puts(char*s);
3
4
intuart_putc(unsignedcharc)
5
{
6
return0;
7
}
8
9
voiduart_puts(char*s)
10
{
11
while(*s)
12
{
13
uart_putc(*s);
14
s++;
15
}
16
}
Es kompiliert-ich bekomme per avrdude keine Fehler o.Ä. Aber es wird
nichts mehr gesendet. Ich rufe beide Funktionen nicht einmal auf und
dennoch macht es irgendwie alles kaputt.
Wenn ich die beiden Funktionen lösche und den Atmega erneut bespiele
klappt alles wieder wunderbar. Ich kann es mir absolut nicht erklären.
Ich hoffe ihr könnt mir einen Tipp geben.
Da dies aber zum selben Ergebnis führte - nämlich dass nichts mehr
gesendet wird (obwohl beide Funktionen erneut nirgendwo aufgerufen
wurden) - habe ich die while Schleife aus uart_putc entfernt. Ich
dachte, dass ich irgendwas mit UCSR0A oder UDRE0 falsch mache und habs
dann auf das nötigste reduziert.
Thomas F. schrieb:> Vergleich mal Zeile 11 mit Zeile 36.
Ja - und praktisch ist auch immer, wenn man Funktionen, die ausgeführt
werden sollen, (aus MAIN heraus) aufruft :-)
Dann funktioniert das Beispiel auch ...
Nicht genutzter Code / Variablen werden nicht compiliert - macht ja auch
wenig Sinn.
Thomas F. schrieb:> Vergleich mal Zeile 11 mit Zeile 36.
Im obigen Original war das noch anders.
Ja, da wäre es manchmal sinnvoller, einfach die *.c Datei anzuhängen...
Udo F. schrieb:> Sehr gerne
Und was tut jetzt der Code? Oder was erwartest du dass der tut?
Udo F. schrieb:> habe ich die while Schleife aus uart_putc entfernt. Ich dachte, dass ich> irgendwas mit UCSR0A oder UDRE0 falsch mache und habs dann auf das nötigste> reduziert.
Genau das, was du da entfernt hast, ist "das Nötigste", denn diese Zeile
sorgt dafür, dass der UART nicht einfach überfahren, sondern die
Übertragung jedes einzelnen Bytes abgewartet wird.
In dem ganz Code vom ersten Post übernimmt das Delay das Abwarten auf
das Freiwerden des UART-TX-Registers.
Hugo H. schrieb:> Thomas F. schrieb:>> Vergleich mal Zeile 11 mit Zeile 36.>> Ja - und praktisch ist auch immer, wenn man Funktionen, die ausgeführt> werden sollen, (aus MAIN heraus) aufruft :-)>> Dann funktioniert das Beispiel auch ...>> Nicht genutzter Code / Variablen werden nicht compiliert - macht ja auch> wenig Sinn.
Nein weil genau das will ich ja damit zeigen. Es gibt Funktionen, die
eben nicht aufgerufen werden und es aber nicht mehr funktioniert.
Ich erwarte doch, dass wenn ich Code habe, der nicht aufgerufen wird,
somit nicht compiliert wird, keine Änderung im Programm bewirkt.
Ohne die beiden uart Funktionen wird alle 2 Sekunden ein B geschrieben
was ich auch mittels sh-u09c5 und hterm lesen/sehen kann.
Mit diesen Funktionen, die ja nichts machen und auch nicht aufgerufen
werden wird nichts mehr vom Controller geschickt. Obwohl die main ja
unangetastet ist.
Udo F. schrieb:> Es gibt Funktionen, die> eben nicht aufgerufen werden und es aber nicht mehr funktioniert.
Nach Änderung mit den unsinnigen Funktionen:
Zeige mir bitte den Unterschied (außer den Debug-Angaben) - es gibt
keinen. Du zeigst schlicht nicht alles und damit brauchst Du scheinbar
auch keine Hilfe.
Stimmt. Ich verheimliche bei meinem geheimen, komplexen Programm teile
damit ihr die bloß nicht seht.
Ich bin Anfänger in Mikrokontroller-Entwicklung und komme nicht weiter.
Ich kenne mich mit höheren Sprachen wir Java etc. aus aber eben nicht
mit so low level Programmierung. Und deshalb ist ja meine Verwunderung
so groß, dass Funktionen, die nichts machen, nicht aufgerufen werden,
dennoch alles kaputt machen.
Es gibt exakt eine c-Datei, die ihr inzwischen vollständig habt.
Dazu gibt es die 4 Zeilen, mit denen ich den Code auf den Atmega88A
bespiele. Das wars. Mehr ist nicht.
Ich glaube dir ja, dass, nachdem du das File analysiert hast, es keine
Unterschiede gibt, aber dann kannst du mir doch auch glauben, dass ich
nichts "verstecke".
Meiner Meinung nach kann es ja dann nur am Atmega88 liegen. Ich habe
hier nochmal den output von avrdude als Anhang mitgegeben. Keine Ahnung
ob das weiter hilft.
Udo F. schrieb:> Meiner Meinung nach kann es ja dann nur am Atmega88 liegen.
Meiner Meinung nach liegt es an Dir und Du nimmst Du das falsche
Hex-File
"avrdude: writing flash (66 bytes)"
Wenn ich compiliere komme ich auf
"Program Memory Usage : 124 bytes 1,5 % Full"
Mit _delay... kann es nicht so kurz (66 bytes) sein (Meiner Meinung
nach).
Hugo H. schrieb:> "Program Memory Usage : 124 bytes 1,5 % Full"> Mit _delay... kann es nicht so kurz (66 bytes) sein (Meiner Meinung> nach).
Das Assembler Listing endet bei 0x7a (=122) mit 2 Bytes, kommt also hin.
Da ist das delay auch drin. Die 124 sind alle belegt, da kann es nicht
in Ordnung sein, dass er nur 66 Bytes davon in den Flash schreibt.
Ich würde da mal weiter nachforschen, bin ziemlich sicher dass Hugo es
auf den Punkt gebracht hat.
Die Berechnung der Baudrate überlässt man normalerweise der AVR
Bibliothek
https://www.nongnu.org/avr-libc/user-manual/group__util__setbaud.html
Stefan ⛄ F. schrieb:> Ich würde da mal weiter nachforschen, bin ziemlich sicher dass Hugo es> auf den Punkt gebracht hat.
Dazu wäre auch mal interessant wie das compiliert wurde.
Makefile?
Und auch wie avrdude aufgerufen wurde.
Da fehlt das Ganze drumherum.
Andreas B. schrieb:> Dazu wäre auch mal interessant wie das compiliert wurde.> Makefile?> Und auch wie avrdude aufgerufen wurde.> Da fehlt das Ganze drumherum.
Das hatte ich bereits geschrieben:
Andreas B. schrieb:> Laß hier mal:> avrdude -c usbasp -pm88 -U flash:w:uart_verysimple.hex:a;> das :a am Schluß weg.
Hab ich. Leider selbes Ergebnis.
Bzgl. der Anzahl der Bytes (von weiter oben). Ich habe mal die beiden
Funktionen entfernt und mit/ohne :a den Chip bespielt.
In beiden Fällen läuft der Code wie geplant und avrdude sagt mir, dass
er 48 Bytes geschrieben hat. Mit den Funktionen sind es 66.
Udo F. schrieb:> In beiden Fällen läuft der Code wie geplant und avrdude sagt mir, dass> er 48 Bytes geschrieben hat. Mit den Funktionen sind es 66.
Dass der Maschinencode eine andere Größe hat als bei Hugo mag an den
Compiler Optionen oder der Version liegen.
Bei dir werden die unbenutzten Funktionen offenbar nicht entfernt. Ich
denke das liegt daran, dass du die sonst üblichen Compiler-und Linker
Flags nicht verwendet hast. In meinem Makefile sind es diese
1
FLAGS += -ffunction-sections -fdata-sections
2
LDFLAGS += -Wl,--gc-sections
Das erklärt aber noch nicht, warum die größere Datei mit den ungenutzten
Funktionen nicht funktioniert. Kannst du mal das Assembler-Listing
zeigen, dass dein Rechner generiert (sie wie Hugo oben seins gezeigt
hat)?
Udo F. schrieb:> Mit den Funktionen sind es 66
Selbst wenn ich "Optimize most" einstelle - -O3 - sind es immer noch 122
Bytes. Daher gehe ich immer noch davon aus, dass Du das falsche
.HEX-File flasht.
Zeige doch bitte mal die Compiler-Meldungen und das .LSS-File.
Hugo H. schrieb:> Selbst wenn ich "Optimize most" einstelle - -O3 - sind es immer noch 122> Bytes.
Kein Wunder. -O3 optimiert für maximale Performance auf Kosten der
Programmgröße.
Wenn du es möglichst klein haben willst, musst du -Os verwenden, wie Udo
es getan hat.
Udo F. schrieb:> Habe es so kompiliert
Leider stehen in dem Listing nicht die Adressen. Aber ich sehe da
ungefähr 25 Befehle. Die meisten brauchen 2 Bytes, dazu kommt noch die
Interrupt-Tabelle. Da sind die 66 also schon plausibel.
Das bringt mich aber auf eine Idee: Woher weiß der Linker, wie viel
Platz er für die Interrupt-Tabelle reservieren muss, obwohl sie nicht im
Assember Listing enthalten ist?
Kann es sein, dass du beim Linken
> avr-gcc uart_verysimple.o -o uart_verysimple.elf;
den µC Typ angeben musst? Ich mache das jedenfalls immer in meinem
Makefile.
Vielleicht profitierst du auch davon, ein erprobtes Makefile zu
benutzen. Meine persönliche Kopiervorlage findest du dort:
http://stefanfrings.de/avr_hello_world/index.html
Stefan ⛄ F. schrieb:> Kein Wunder. -O3 optimiert für maximale Performance auf Kosten der> Programmgröße.
Das spielt bei dem Mickey-Maus-Programm überhaupt keine Geige.
Stefan ⛄ F. schrieb:> Vielleicht profitierst du auch davon, ein erprobtes Makefile zu> benutzen. Meine persönliche Kopiervorlage findest du dort:> http://stefanfrings.de/avr_hello_world/index.html
Genau die Idee kam mir vor 10 Min. auch und .... es funktioniert. Ich
fass es nicht!!!
Stefan ⛄ F. schrieb:> Sieht nach 64 Bytes aus.Stefan ⛄ F. schrieb:> Da sind die 66 also schon plausibel
Gut dann ist in den verbliebenen 2 Bytes der komplette Code versteckt.
Das möchte ich auch können - wie geht das?
Hugo H. schrieb:> Gut dann ist in den verbliebenen 2 Bytes der komplette Code versteckt.> Das möchte ich auch können - wie geht das?
Quatsch
Die Interrupt-Tabelle hat 64 Bytes.
Der Programmcode hat 66 Bytes.
macht zusammen ungefähr die 124 bytes, die bei dir als
> "Program Memory Usage : 124 bytes 1,5 % Full"
gemeldet wurden.
Stefan ⛄ F. schrieb:> Quatsch>> Die Interrupt-Tabelle hat 64 Bytes.> Der Programmcode hat 66 Bytes.>> macht zusammen ungefähr die 124 bytes, die bei dir als>> "Program Memory Usage : 124 bytes 1,5 % Full"> gemeldet wurden.
Und was schiebt AVR-Dude auf den Controller? Nur den Programmcode?
Spielt die Interrupt-Tabelle keine Rolle? Erhält der MC diese intuitiv?
Hugo H. schrieb:> Und was schiebt AVR-Dude auf den Controller? Nur den Programmcode?
Das komplette gelinkte Programm, samt Interrupt Tabelle und
Initialisierungs-Daten für Variablen (falls vorhanden).
> Spielt die Interrupt-Tabelle keine Rolle?
Ich habe dir doch gerade vorgerechnet, dass der Programmcode +
Interrupt-Tabelle zusammen die gesamt-Größe ausmachen, die in den Flash
übertragen werden müssen.
Stefan ⛄ F. schrieb:> Ich habe dir doch gerade vorgerechnet, dass der Programmcode +> Interrupt-Tabelle zusammen die gesamt-Größe ausmachen, die in den Flash> übertragen werden müssen.
Und warum sind dann die 66 übertragenen Bytes plausibel? Addieren ist
Dir bekannt?
Du hättest Politiker werden sollen - vielleicht sucht Armin ja noch
Helfer :-)
Ich glaube, Du wohnst sogar in der Ecke - oder? Dann passt es ja.
Hugo H. schrieb:> Und warum sind dann die 66 übertragenen Bytes plausibel?
Weil er falsch (ohne Interrupt Vektoren) gelinkt hat. Ohne Interrupt
Vektoren flasht er nur den Programmcode und der umfasst halt die 66
Bytes.
Stefan ⛄ F. schrieb:> Weil er falsch (ohne Interrupt Vektoren) gelinkt hat. Ohne Interrupt> Vektoren flasht er nur den Programmcode und der umfasst halt die 66> Bytes.
Ja - also nicht plausibel. Kannst Du es nicht zugeben, wenn Du Müll
erzählt hast?
Hugo, ich weiß nicht was das werden soll. Entweder tust du so doof um
mich zu ärgern, oder du versteht es wirklich nicht. Es hat keinen Sinn
darauf weiter einzugehen.
Stefan ⛄ F. schrieb:> Hugo, ich weiß nicht was das werden soll. Entweder tust du so doof um> mich zu ärgern, oder du versteht es wirklich nicht. Es hat keinen Sinn> darauf weiter einzugehen.
Lies bitte mal Deine Posts durch und reflektiere diese - das reicht
schon.
Nu schlagt euch doch nicht die Köpfe ein! Der To hat doch einen völligen
Humbug gepostet!! Natürlich bin ich auch immer baff, wenn mein Programm
nicht läuft. Neu ist die Variante, natürlich die hinterhältige Variante,
dass das geniale Programm kompiliert werden kann und dennoch nicht
läuft! Wenn das jetzt nicht mal dem Fass den Boden ausschlägt...anders
herum gehts immer ganz einfach :-) aber sowas habe ich noch nicht
erlebt!!!
Gruß Rainer
Rainer V. schrieb:> Nu schlagt euch doch nicht die Köpfe ein! Der To hat doch einen völligen> Humbug gepostet!! Natürlich bin ich auch immer baff, wenn mein Programm> nicht läuft. Neu ist die Variante, natürlich die hinterhältige Variante,> dass das geniale Programm kompiliert werden kann und dennoch nicht> läuft! Wenn das jetzt nicht mal dem Fass den Boden ausschlägt...anders> herum gehts immer ganz einfach :-) aber sowas habe ich noch nicht> erlebt!!!
GRIN. Wenn's so einfach wäre, dass erfolgreiches Kompilieren schon
sicher die Programmfunktion herstellen könnte: Wer bräuchte denn dann
überhaupt noch Programmierer? Code kann man generieren lassen oder
klauen.
Aber ja, ICH habe schon verstanden, dass dein Beitrag eher sarkastisch
gemeint war.
c-hater schrieb:> Aber ja, ICH habe schon verstanden, dass dein Beitrag eher sarkastisch> gemeint war.
ist doch aber wirklich kaum anders zu ertragen oder?? Endlich postet
jemand einen Code, der anstandlos übersetzt wird...und er läuft nicht.
Ich frage mich jetzt ernsthaft, wie ich das sagen soll...Ich sage "there
is no understanding in the world" und das ist definitiv im Einklang mit
den neusten Erkenntnissen von CERN über die wackelige 8te bis 12te
Stelle im Welbild der momentan geltenden Physik. Ist doch Scheissegal,
höre ich die Kandidaten schon schreien...aber ist es das wirklich...was
wäre, wenn es einen Cetaur doch gegeben hätt? OK LG
Rainer
Ich finds ziemlich krass was hier aus diesem Post - Zitat 'Mikey Maus
Code' (was er definitiv ist!) - am Ende passiert ist.
Ich wollte mich auf jeden Fall bei euch Allen für die Hilfe bedanken, da
ich alleine nicht weiter gekommen wäre.
Ich muss zugeben, dass ich bis jetzt nicht weiß, warum das Makefile es
am Ende gerockt hat. Ich habe definitiv nichts am Code verändert.
Auf jeden Fall werde ich jetzt immer das besagte Makefile nutzen, da ich
dann zur Not auch alle Informationen wie z.B. das LSS File bekomme und
es bei weiteren Fragen dann zur Hand habe.
Wie gesagt-ich bin Anfänger und muss noch dazu lernen.
Udo F. schrieb:> Ich muss zugeben, dass ich bis jetzt nicht weiß, warum das Makefile es> am Ende gerockt hat
Sorry, das habe ich wohl nicht deutlich genug erklärt.
Du hast versäumt, beim zweiten Aufruf des gccc (Linker) anzugeben, für
welchen Mikrocontroller das *.elf File erzuegt werden soll. Deswegen
fehlte dort die Interrupt-Vektor Tabelle, also dieser ganze Block:
1
00000000<__vectors>:
2
0:19c0rjmp.+50;0x34<__ctors_end>
3
2:20c0rjmp.+64;0x44<__bad_interrupt>
4
4:1fc0rjmp.+62;0x44<__bad_interrupt>
5
6:1ec0rjmp.+60;0x44<__bad_interrupt>
6
8:1dc0rjmp.+58;0x44<__bad_interrupt>
7
a:1cc0rjmp.+56;0x44<__bad_interrupt>
8
c:1bc0rjmp.+54;0x44<__bad_interrupt>
9
e:1ac0rjmp.+52;0x44<__bad_interrupt>
10
10:19c0rjmp.+50;0x44<__bad_interrupt>
11
12:18c0rjmp.+48;0x44<__bad_interrupt>
12
14:17c0rjmp.+46;0x44<__bad_interrupt>
13
16:16c0rjmp.+44;0x44<__bad_interrupt>
14
18:15c0rjmp.+42;0x44<__bad_interrupt>
15
1a:14c0rjmp.+40;0x44<__bad_interrupt>
16
1c:13c0rjmp.+38;0x44<__bad_interrupt>
17
1e:12c0rjmp.+36;0x44<__bad_interrupt>
18
20:11c0rjmp.+34;0x44<__bad_interrupt>
19
22:10c0rjmp.+32;0x44<__bad_interrupt>
20
24:0fc0rjmp.+30;0x44<__bad_interrupt>
21
26:0ec0rjmp.+28;0x44<__bad_interrupt>
22
28:0dc0rjmp.+26;0x44<__bad_interrupt>
23
2a:0cc0rjmp.+24;0x44<__bad_interrupt>
24
2c:0bc0rjmp.+22;0x44<__bad_interrupt>
25
2e:0ac0rjmp.+20;0x44<__bad_interrupt>
26
30:09c0rjmp.+18;0x44<__bad_interrupt>
27
32:08c0rjmp.+16;0x44<__bad_interrupt>
Den siehst du in deinem C-Quelltext nicht, weil er eben vom Linker
automatisch ergänzt wird. Aber nur, wen man dem Linker sagt, für welchen
Mikrocontroller er das tun soll.