Guten Tag miteinander,
ich habe ein Problem mit der LCD Ansteuerung aus dem AVR-GCC Tutorial.
->
http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#Programmierung
Ich habe den Quellcode in zwei Dateien kopiert und den Dateinamen mit
lcd-routines.h bzw. lcd-routines.c versehen. In meinem Hauptprogramm
verwende ich nur den Testcode aus dem Tutorial. Das ganze Projekt läuft
unter AVR Studio 4.14 mit der neuesten Version von Win-AVR.
Leider compiliert das Ganze nicht und ich kann mit dem Fehlercode vom
Compiler nicht wirklich was anfangen. Vielleicht hat einer von euch ne
Idee:
PS: Ich verwende kein externes Makefile, sondern stelle in AVR Studio
unter "Configuration Option" mein Device (Atmega8) und meine
Taktfrequenz (8MHz) ein.
Fehlercode:
Von oben nach unten:
>../lcd-routines.h:15:1: warning: "F_CPU" redefined><command-line>: warning: this is the location of the previous definition
AVRStudio definiert F_CPU schon in der Kommandoszeile zum Compiler,
daher ist die erneute Definition im headerfile unnötig.
>../lcd-routines.c:126: warning: 'tmp' may be used uninitialized in this function
tmp wird nach Ansicht des Compilers vor seiner ersten Verwendung nicht
initialisiert. Hier irrt der gcc allerdings öfter mal.
Bisher waren das alles Warnungen.
>D:\Elektronik\AVR\AVR_LCD\default/../lcd-routines.c:56: multiple definition of >`lcd_enable'>AVR_LCD.o:D:\Elektronik\AVR\AVR_LCD\default/../lcd-routines.c:56: first >defined >here
und alle folgenden:
Der Linker findet alle Funktionen aus lcd-routines.c zweimal. Hat du
vielleicht sowas wie "#include lcd-routines.c" in AVR_LCD.c stehen? Oder
ist lcd-routines.c zweimal im source-Ordner angegeben?
Oliver
Vielen Dank für die Hilfe.
Hab den Fehler dadurch gefunden:
Ich war der Annahme, dass ich die include-files im "AVR GCC" Baum, der
standardmäßig auf der Linken Seite in AVR Studio platziert ist einfügen
muss. Habe dort die "lcd-routines.c" in den "Source-file" Ordner
geschoben.
Nachdem ich diese wieder gelöscht hatte geht es nun. Blöder Fehler
meinerseits.
Nochmals vielen Dank für deine Hilfe !!
Igor Metwet wrote:
> Vielen Dank für die Hilfe.> Hab den Fehler dadurch gefunden:>> Ich war der Annahme, dass ich die include-files im "AVR GCC" Baum, der> standardmäßig auf der Linken Seite in AVR Studio platziert ist einfügen> muss. Habe dort die "lcd-routines.c" in den "Source-file" Ordner> geschoben.>> Nachdem ich diese wieder gelöscht hatte geht es nun. Blöder Fehler> meinerseits.
Das allerdings war die falsche Korrektur.
Dieses File in den Baum mit aufzunehmen war schon richtig.
Was du entfernen hättest sollen ist der
#include "lcd-routines.c"
bzw. diesen durch ein
#include "lcd-routines.h"
ersetzen.
#include lcd-routines.h wird in lcd-routines.c aufgerufen
lcd-routines.h habe ich aber auch noch im Baum stehen. Dies stört den
Compiler dann anscheinend nicht, wenn dieses Doppelt aufgerufen wird.
Könntet Ihr mir noch Eines erklären:
Warum ist es besser wenn man die include-Dateien im Baum einfügt und
nicht über den C-Text.
Danke schonmal
Igor Metwet wrote:
> #include lcd-routines.h wird in lcd-routines.c aufgerufen
Ja, das ist auch korrekt so.
Was aber nicht korrekt ist, ist dass du in deinem Programm
einen
#include "lcd-routines.c"
***
stehen hast.
*.c Files werden nicht inkludiert! Immer nur die Header Files *.h
> lcd-routines.h habe ich aber auch noch im Baum stehen. Dies stört den> Compiler dann anscheinend nicht, wenn dieses Doppelt aufgerufen wird.
lcd-routines.h wird nicht compiliert (zumindest nicht einzeln)!
Immer nur im Zusammenhang mit einem *.c File, welches das *.h File
includiert.
> Könntet Ihr mir noch Eines erklären:> Warum ist es besser wenn man die include-Dateien im Baum einfügt und> nicht über den C-Text.
Jedes *.c File wird getrennt von allen anderen übersetzt. So ist
die Sprache C ausgelegt und so funktioniert das seit über 30 Jahren.
Die einzelnen *.c Files werden getrennt voneinander compiliert
und erst deren Ergebnisse (die Objekt Files) werden dann zum
vollständigen Programm zusammengebunden.
Bei 2 Dateien, wie bei dir, macht das noch keinen grossen Unterschied.
Aber wenn du 2000 Source Code Dateien (*.c) hast, dann bist du froh
darüber, dass jedes einzelne *.c einzeln compiliert werden kann.
Erst so ist es möglich die Compilierzeiten für ein grosses Projekt
in vertretbarem Rahmen zu halten. Warum sollen 200000 Lines of Code
compiliert werden, wenn es völlig ausreicht das eine *.c File, in
dem eine Änderung notwendig war und das vielleicht 500 Lines of Code
besitzt, neu zu compilieren und das Programm neu zu bauen.
Hallo Leute,
ich als µC Anfänger bin am verzweifeln. Ich möchte das Projekt von
www.mikrocontrollerspielwiese.de "Analog Spannung messen" compilieren
erhalte aber immer mehrfach im Build-Fenster von AVR Studio die
"multiple definition of ***" Fehlermeldung?
Habt ihr vielleicht einen guten Tipp, wo das Problem in der
lcd-routines.c sein soll? Irgendein #include ist unklar?
Vielen Dank und Grüße aus Dresden!
Metulski
Torsten Müller schrieb:
> Hallo Leute,>> ich als µC Anfänger bin am verzweifeln. Ich möchte das Projekt von> www.mikrocontrollerspielwiese.de "Analog Spannung messen" compilieren> erhalte aber immer mehrfach im Build-Fenster von AVR Studio die> "multiple definition of ***" Fehlermeldung?>> Habt ihr vielleicht einen guten Tipp, wo das Problem in der> lcd-routines.c sein soll? Irgendein #include ist unklar?
Auszug aus test1.c:
Oder etwas anders ausgedrückt:
Sich an einen alten fremden Thread zu hängen, ist nicht gut.
Obendrein diesen alten Thread nicht mal vorher richtig gelesen zu haben,
ist richtig böse.
... Tschuldigung, das grausam Kommentierte stammt von mir - da ich
probehalber mal auf die "lcd-routines.h" verwiesen habe -> da wird aber
kein ordentlicher Wert angezeigt, da kein string.
Aber original lautet der Quellcode:
#include "lcd-routines.c"
Somit fehlt mir immer noch die Lösung ...
Hat es vielleicht mal jemand im AVR Studio compiliert?
Grüße
metulski schrieb:
> ... Tschuldigung, das grausam Kommentierte stammt von mir - da ich> probehalber mal auf die "lcd-routines.h" verwiesen habe -> da wird aber> kein ordentlicher Wert angezeigt, da kein string.> Aber original lautet der Quellcode:> #include "lcd-routines.c">> Somit fehlt mir immer noch die Lösung ...
die Lösung lautet immer noch, dass
#include "lcd-routines.h"
richtig ist.
> verwiesen habe -> da wird aber> kein ordentlicher Wert angezeigt, da kein string.
Was immer das auch heissen mag.
metulski schrieb:
> #include "lcd-routines.c"
www.mikrocontrollerspielwiese.de inkludiert im test1.c immer
"lcd-routines.c", denn die verweist dann auf die header
"lcd-routines.h"?
Seltsam...
metulski schrieb:
> metulski schrieb:>> #include "lcd-routines.c">> www.mikrocontrollerspielwiese.de inkludiert im test1.c immer> "lcd-routines.c", denn die verweist dann auf die header> "lcd-routines.h"?>> Seltsam...
Nicht "seltsam"
"Planlos" trifft es eher (von dem was der Autor da in messen.h
aufgeführt hat, wollen wir erst gar nicht reden)
Edit: Ich hätte auch "Ahnungslos" schreiben können. Aber da kenne ich
den Autor zu wenig, um ihm das zu unterstellen und anhand der paar
Codezeilen will ich keine derart schwerwiegende Anschuldigung
vorbringen.
Ok mag sein, aber für den allerersten Einstieg ist das eine heilwegs
verständliche Seite.
Vielleicht kannst Du mir einen besseren Tipp für eine Seite (Bsp.
Analogmessung) geben?
Viele Grüße
metulski schrieb:
> Vielleicht kannst Du mir einen besseren Tipp für eine Seite (Bsp.> Analogmessung) geben?
Darum gehst doch gar nicht.
Es geht darum, wie man sinnvoll C-Projekte aufbaut, die aus mehr als
einem *.c File bestehen.
Und die Lösung dafür besteht eben nicht darin, alle einzelnen *.c
Dateien in einem Haupt-C-File zu includen sondern: Jedes einzelne *.c
dem AVR-Studio als einzelnes File in der Kategorie 'Source-Files'
bekannt zu machen (was du getan hast, sonst hättest du die Fehlermeldung
nicht) und immer nur die Header Files zu inkludieren.
Funktionsimplementierungen haben in Header Files in C nichts verloren!
Es sei denn, sie sind als inline-Code explizit markiert.
D.h. so wie du da gemacht hast, ist das schon richtig.
Noch was zum Lesen:
http://www.mikrocontroller.net/articles/FAQ#Ich_hab_da_mehrere_.2A.c_und_.2A.h_Dateien._Was_mache_ich_damit.3F
Die Frage ist jetzt, was du mit
> verwiesen habe -> da wird aber> kein ordentlicher Wert angezeigt, da kein string.
meinst.
Da steckt also noch irgendein Problem im Code, das raus möchte.
Aber dieses Problem hat wiederrum nichts damit zu tun, dass man
Header-Files includet und keine Source Files.
Als Vorschlag würde ich hier
1
intmain()
2
{
3
intx;
4
charmesswertstring[5];
als allererstes einmal das Array von 5 auf mindestens 20 Zeichen
anheben. Auch wenn der int x theoretisch niemals größer als 1024 sein
kann, ist es nicht besonders schlau, solche Arrays auf Knirsch zu
dimensionieren.
Und dann würde ich auch gleich die extern Deklaration von sprintf
rauswerfen und dafür den Weg gehen, der eigentlich dafür vorgesehen ist:
#include <stdio.h>
metulski schrieb:
> Ok mag sein, aber für den allerersten Einstieg ist das eine heilwegs> verständliche Seite.
Offensichtlich nicht, sonst kaeme ja nicht so ein Unsinn heraus. C lernt
man nicht mit Beispielen via Trial & Error, sondern mit einem guten
Buch.
Karl heinz Buchegger schrieb:
> Und die Lösung dafür besteht eben nicht darin, alle einzelnen *.c> Dateien in einem Haupt-C-File zu includen sondern: Jedes einzelne *.c> dem AVR-Studio als einzelnes File in der Kategorie 'Source-Files'> bekannt zu machen (was du getan hast, sonst hättest du die Fehlermeldung> nicht) und immer nur die Header Files zu inkludieren.
Hallo, ich hab den Code auf der mikrocontrollerspielwiese geschrieben
und hiermit verbessert. Ich würde mich tatsächlich noch als "im Stadium
eines Anfängers mit einwenig Erfahrung" beschreiben.
Mit dem in der Mikrocontrollerspielwiese beschriebenen Equipment traten
die hier diskutierten Fehler nicht auf. Und gesagt hat's mir auch
keiner.
Lieber Karl Heinz Buchegger,
vielleicht könntest Du mal einen kurzen Blick auf die geänderte Version
werfen. Da wäre ich Dir sehr dankbar.
http://www.sachsendreier.com/msw/projekte/analog_lcd/analog_lcd.html>> Als Vorschlag würde ich hier>>
1
>intmain()
2
>{
3
>intx;
4
>charmesswertstring[5];
5
>
> als allererstes einmal das Array von 5 auf mindestens 20 Zeichen> anheben. Auch wenn der int x theoretisch niemals größer als 1024 sein> kann, ist es nicht besonders schlau, solche Arrays auf Knirsch zu> dimensionieren.
Das mit dem "Knirsch" ist mir leider nicht ganz klar geworden.
Könntest Du das bitte noch mal erläutern?
Ich Danke Dir!
Steffen M. schrieb:
> vielleicht könntest Du mal einen kurzen Blick auf die geänderte Version> werfen. Da wäre ich Dir sehr dankbar.
Kein Problem. Gleich mehr dazu
>> Das mit dem "Knirsch" ist mir leider nicht ganz klar geworden.> Könntest Du das bitte noch mal erläutern?
:-)
Ich weiß nicht, ob man diesen Ausdruck in Deutschland kennt. In
Österreich ist er gebräuchlich.
Mit "auf Knirsch dimensionieren" meint man: genau passend, nicht zu groß
und auch nicht zu klein.
Wenn du dein Auto 'auf Knirsch' parkst, dann passt in der Parklücke kein
Blatt Papier mehr zwischen die Stossstangen. Und zwar vorne wie hinten.
Und da knirscht es dann beim Einparken tatsächlich :-)
So wie das dimensioniert ist, mit 5 chars, ist das gerade ausreichend.
Der theoretische Maximalwert 1024 passt da rein.
Aber: da darf nichts schief gehen!
Wenn dein Programmierer auf die Idee kommt, den sprintf zb so abzuändern
1
sprintf(messwertstring,"V: %dmv",x);
dann kracht es, weil das 5 Elemte Array überlaufen wird.
Wenn in der Testphase jemand die Mittelwertbildung aushebelt und die
abschliessende Division rausnimmt, und da kommt als Ergebnis 12876 raus,
dann kracht es, weil die 5 Zeichen nicht ausreichen.
Genau das ist mit 'auf Knirsch dimensionieren' gemeint. Man hat
keinerlei Spielraum. Alles muss glatt gehen und bei Änderungen muss man
höllisch aufpassen.
Dabei ist das aber gar nicht notwendig. Du kriegst von Atmel kein Geld
zurück für Speicher, der zwar da ist, den du aber nicht verbrauchst.
Benutze doch den Speicher und bau dir eine kleine Reserve in solche
Arrays ein. Dann endet eine kleine Änderung in der Ausgabe oder in der
Messwertberechnung nicht gleich in einem Fiasko. So etwas nennt man
'defensives Programmieren'. Ein wenig Spielraum für unbeabsichtigte
'Fehler' (sind ja eigentlich keine Fehler, nur arten sie in einem Fehler
aus wenn der Programmierer auf das Array vergisst) einplanen.
Karl heinz Buchegger schrieb:
> Steffen M. schrieb:>>> vielleicht könntest Du mal einen kurzen Blick auf die geänderte Version>> werfen. Da wäre ich Dir sehr dankbar.>> Kein Problem. Gleich mehr dazu
Nicht böse sein. Ich sehs mir morgen früh an.
Da gibt es mehrere Punkte, über die man ein paar Worte verlieren sollte.
Hätte da auch eine Frage:
Warum steht in der lcd-routines.h vom Tutorial #define F_CPU 8000000
und nicht #define F_CPU 8000000UL ?
Habe im WinAVR dies mit UL gesehen.
Die Definition an dieser Stelle in dieser Form ist IMHO unglücklich. Das
sollte aus der lcdroutines.h komplett raus.
Die Definition sollte in AVR Studio, AVR Eclipse oder im Makefile
gemacht werden und wenn eine Source ohne dort gesetztes F_CPU übersetzt
wird, soll eine Warnung+Defaultwert kommen. So wie es in util/delay.h
gemacht wird.
Oder besser noch ein Fehler, damit man diese Stelle in Ruhe nachsehen
kann und F_CPU bewusst auf den richtigen Wert setzt.
Jedenfalls finde ich ein pauschales Setzen des Werts in einem lokalen
Library-Includefile ohne Abfrage eines ggf. bereits gesetzten Werts
nicht so toll.
Zum Thema mit UL oder ohne...
In lcdroutines.h ist F_CPU überhaupt nur drin, weil die _delay_xx
Funktionen benutzt werden und die ein definiertes F_CPU brauchen. Diesen
Funktionen aus der avr-libc ist es egal, ob F_CPU mit oder ohne UL (oder
L) definiert ist. Der Wert wird zur Compilezeit als Gleitkommawert
interpretiert.
Kritisch wird es, wenn zusätzlich zu den LCD-Routinen auch UART-Routinen
zum Einsatz kommen und dabei die Baudratenmakros aus dem
AVR-GCC-Tutorial benutzt werden. Dort ist lt. Doku im Artikel die UL
Kennzeichnung notwendig.
Lange Rede kurzer Sinn: UL im Tutorial an die Definition anhängen, wenn
man die Definition dort stehen lassen will. Oder komplett dort
rausschmeissen und Warnung einfügen, wenn F_CPU nicht definiert ist.
OK.
Hier die Kritik.
Zunächst mal:
Du hast deine 'Zulieferroutinen', die LCD Funktionen und die ADC
Abfrage, in Header Files verpackt. Das macht man so nicht.
Einer der wesentlichen Punkte in C ist es, dass einzelne Code-Teile
unabhängig voneinander compiliert werden können.
Das bedeutet: Code kommt immer in *.c Files, die einzeln compiliert
werden. In Header Files kommt alles, was ein Benutzer der Funktionen
wissen muss. Das sind die Funktionsprototypen, können irgendwelche
Konstanten sein oder Strukturdefinitionen etc. Aber kein Code!
Sinn der Sache ist es, einzelne Codeteile möglichst voneinander zu
entkoppeln, so dass sie tatsächlich einzeln compilierbar sind.
Bei dir ist es so, dass du im Grunde nur eine Source-Code Datei hast,
die du auf mehrere physikalische Dateien aufgeteilt hast. Das ist nicht
Sinn der Sache! Gut. Bei den relativ kleinen Programmen, die auf einem
AVR entstehen, spielt das keine große Rolle. Aber warum den Mechanismus
nicht so umsetzen wie er gedacht ist. Stell dir vor, dein Programm
besteht tatsächlich aus 2 Millionen Lines of Code (das hört sich jetzt
groß an, aber so groß ist das gar nicht). Bei jeder kleinsten Änderung
muss ALLLES neu compiliert werden, weil es ja im Grunde nur eine
logische *.c Datei gibt, die compilliert wird. Das muss nicht sein. Wenn
deine LCD Funktionen in einer lcd-routines.c Datei gesammelt sind, muss
auch nur diese Datei compiliert werden, wenn du etwas an der
Implementierung der LCD Funktionen änderst. Warum soll der ADC Code
deswegen neu compiliert werden? Der hat doch nichts damit zu tun.
Der Weg den C (und viele andere Hochsprachen) gehen, ist hier kurz
skizziert
http://www.mikrocontroller.net/articles/FAQ#Ich_hab_da_mehrere_.2A.c_und_.2A.h_Dateien._Was_mache_ich_damit.3F
Also: Einzelne *.c Dateien werden unabhängig coneinander compiliert. Die
daraus resultierenden Object-Files werden zum eigentlichen Programm
zusammengelinkt. Wird eine C Datei geändert, dann wird nur diese Datei
neu compiliert und mit den noch vorhandenen Object Files der anderen
'Module' erneut zu einem neuen Programm zusammengelinkt.
Auf diese Art sind dann auch Programme mit ein paar Millionen Lines of
Code handhabbar.
In der ADC Funktion:
Es gibt eine Konvention, an die sich so gut wie alle C Programmierer
halten. Und zwar: Namen die komplett in Grossbuchstaben gehalten sind,
sind ausschliesslich für Makros reserviert. Sehe ich also in einem Code
so etwas
1
k=MAX(i,j);
dann weiß ich, dass MAX als Makro implementiert ist.
Und dieses Wissen kann wichtig sein!
Nehmen wir zb genau dieses MAX Makro. Wie implementierst du es.
Naheliegend ist zb
1
#define MAX(x,y) ( (x) > (y) ? (x) : (y) )
Bei diesem Makro gibt es jetzt aber ein Problem. Benutze ich es zb so
1
inti=5;
2
intj=6;
3
intk;
4
5
k=MAX(i++,j++);
welche Werte haben i und j nach der Bestimmung des Maximums. Wenn du
jetzt sagst: i ist dann 6 und j gleich 7, dann mag man das zwar anhand
der Verwendung so denken, aber es ist falsch! i ist 6 aber j ist danach
8!
Dies deshalb, weil das Makro ja nur eine Textersetzung ist. Für den
Compiler steht da in Wirklichkeit
1
k=((i++)>(j++)?(i++):(j++));
und im Zuge dieser Auswertung wird j zweimal inkrementiert. Es kann
allerdings auch i zweimal inkrementiert werden, abhängig von den
tatsächlichen Werten von i und j.
Von daher ist das etwas völlig anderes als
1
intmax(intx,inty)
2
{
3
returnx>y?x:y;
4
}
5
6
....
7
8
k=max(i++,j++);
das funktioniert genau so wie erwartet. Von daher kann es eminent
wichtig sein, dass man an der Stelle der Verwendung mit einem Blick
erkennen kann, was eine echte Funktion ist, und was ein Makro ist.
Mit dieser Konvention geht so etwas
1
intMESSWERT(intkanal)
daher überhaupt nicht. Das ist eine echte Funktion und kein Makro. Ein
Name mit nur Grossbuchstaben ist daher nicht angebracht.
Auch ist der Funktionsname 'Messwert' nicht allzu glücklich gewählt.
Funktionen führen eine Aktion aus, sie tun etwas. Funktionsnamen werden
dadher gerne so gewählt, dass sie ein Verb (ein Zeitwort) enthalten:
Gehe..., Hole..., Setze..., Lese...
Stell dir bei der Wahl von Funktionsnamen am besten einfach die Zeile
beim Aufrufer vor. Wenn man sich da ein paar unbedeutende Füllwörter
reindenkt und sich einfach nur durch Lesen der Wörter ein sinnvoller
Satz ergibt, dann hast du einen guten Namen gewählt.
i = GetADC( PotiChannel );
oder in Langform (mit den dazugedachten Füllwörtern):
i erhält den Wert, der sich beim Lesen des ADC vom Kanal an dem das Poti
hängt, ergibt.
Perfekt. Die Codezeile ist ihr eigener Kommentar. Da muss man nichts
dazu schreiben.
i = GetVoltage( PotiChannel );
wäre auch nicht schlecht, allerdings etwas misveständlich. Denn von der
Funktion bekommt man ja nicht die Spannung direkt als Zahlenwert (also 5
für 5 Volt), sondern in einer Codierung.
i = GetFilteredADC( PotiChannel );
wäre auch nicht schlecht. Dann sieht man nämlich beim Aufrufer, dass da
nicht einfach nur der ADC einmal abgefragt wird, sondern dass da eine
Filterung passiert (in deinem Fall eine Mittelwertbildung)
Weiter in der Funktion MESSERT
Wenn etwas eine for Schleife ist, dann schreib es auch als for-Schleife
und betreibe nicht die Taktik der maximalen Konfusion indem du
Schleifenkonstruktionen benutzt die man so sicher nicht erwarten würde.
Was spricht gegen:
1
intGetADC(unsignedcharkanal){
2
3
inti,j;
4
longintanalogwert=0,analogwert2=0;
5
6
for(j=0;j<512;j++){
7
8
analogwert=0;
9
for(i=0;i<512;i++){
10
11
ADCSRA=0x80;// ADC eingeschaltet, kein Prescale
12
ADMUX=kanal;// ADC Ref auf Avcc, PC0 gewaehlt, normale Formatierung
13
ADCSRA|=_BV(ADSC);// single conversion mode ein
14
15
while(ADCSRA&(1<<ADSC)){
16
;
17
}// auf Abschluss der Konvertierung warten
18
19
analogwert+=ADCW;
20
}
21
22
analogwert2+=analogwert/512;
23
}
24
25
returnanalogwert2/512;
26
}
Jeder C Programmierer, der sein Handwerk länger als 3 Tage macht,
erkennt sofort eine Schleife
for( j = 0; j < 512; j++ ) {
und weiß, dass diese Schleife 512 mal ausgeführt wird. Bei deiner while
Konsturuktion fragt man sich als allererstes sofort: Warum? Was wird
spezielles mit dem j gemacht, dass man nicht eine stink normale
Zählschleife einsetzen kann. Wie ist das? Wenn i in jedem Durchlauf um 1
erniedrigt wird und bei 512 startet, wie oft wird dann die Schleife
durchlaufen?
Da muss man viel zu viel darüber nachdenken. Obige for-Schleife hingegen
ist das Standardkonstrukt für eine Schleife, die so oft ausgeführt wird,
wie die Zahl in der Vergleichsbedingung angibt.
By the way. Ist dir eigentlich aufgefallen, dass du in deinem Code
analogwert nie auf 0 zurücksetzt, aber munter immer weiter ADC Werte
darin aufsummierst? Selbst dann, wenn in analogwert eigentlich die
nächste Summe der nächsten 512 ADC Werte entstehen soll? Wie gut, dass
in main() defensiv programmiert wurde :-)
beachte auch, wie ich dir
1
while(ADCSRA&(1<<ADSC)){
2
;
3
}// auf Abschluss der Konvertierung warten
umgebrochen habe. Sei bei Code-Formatierungen konsequent!
Deine Formatierung sagt: Die öffnende { kommt als letztes Zeichen in die
Zeile, der Blockinhalt kommt eingerückt in die nächste Zeile und die
Block-schliessende } kommt wieder auf eine eigene Zeile, aber wieder
ausgerückt. genau das habe ich durchgezogen. Das dein Block nur aus
einer einsamen, leeren Anweisung, bestehend aus dem ; besteht, ist kein
Grund das Formatierschema über den Haufen zu werfen.
Der nächste Punkt ist zugegebenermassen etwas Geschmackssache.
1
return(analogwert);
return ist kein Funktionsaufruf. Also lass ihn auch nicht wie einen
aussehen! Die Klammern sind nicht notwendig und werden, anders als bei
for und if, von der Sprache nicht gefordert. Sie schaden allerdings auch
nicht, so wie sie bei
1
analogwert=(analogwert2/512);
auch nicht schaden. Allerdings bringen sie auch nichts. Gerade letzteres
würde allerdings durch das Weglassen der Klammern und hinzufügen von 2
Leerzeichen gewinnen
1
analogwert=analogwert2/512;
gewöhn dir wenigstens an, links und rechts eines = ein Leerzeichen zu
machen. Seit deiner Volksschulzeit hast du dein Gehirn darauf trainiert,
dass es einzelne Wörter in einem Text anhand von Leerräumen schnell als
eigenständiges Wort identifizieren kann. Nutze doch dieses Training um
dir selbst das Lesen des Quelltextes einfacher zu machen. Nichts ist so
schlimm wie eine Zeile Quelltext, in der man erst mal 10 Sekunden mit
den Augen links/rechts die Zeile absuchen muss, um die einzelnen
Bestandteile der Anweisung zu identifizieren.
OderfindestdudiesenTexthieretwaleichterzulesen als diese Fortsetzung?
So würde ich den Code aufbauen. Da könnte man sicherlich noch eine Menge
anderer Dinge am Code tun. Aber fürs erste solls das sein.
Makefile anpassen nicht vergessen!
Die *.c Files werden einzeln compiliert und die entstehenden *.o Files
zusammengelinktr
Hier noch das App-Studio File, für diejenigen die wissen wollen, wie man
mehrere Source/Header Files im App Studio benutzt.
Einfach in den "Source File" / "Header File" Abschnitt einfügen.
Beim Build mal darauf achten. Wird irgendetwas verändert, so wird auch
nur das absolut Notwendige nachcompiliert und neu gelinkt.
Lieber Karl Heinz Buchegger,
da hast Du Dir ja ein ganz schönes Stückchen Arbeit gemacht.
Ich danke Dir dafür recht herzlich!
Und ich werde mich auch gleich mal daran setzen, einen großen Teil
Deiner Vorschläge umzusetzen.
Bei den .h und .c Dateien dachte ich einfach: man lagert aus, was man
immer wieder braucht. Was wohl richtig ist aber nicht so, wie ich es
letztendlich umsetzte.
Das mit der Groß-/Kleinschreibung von Makros und Funktionen hatte ich
noch gar nicht gewußt.
Die Hinweise zu mnemotechnisch gewählten Funktionsnamen und homogener
Struktur incl. strikt verwendeter Leerzeichen werden mich hoffentlich
einwenig mehr an das Ziel bringen, Code zu schreiben, der Klarheit
ausstrahlt.
Die for-next-Schleife funktionierte in den ersten Versionen des gcc-avr
unter Linux nicht richtig und etliche meiner Bekannten benutzen noch
immer die alte Linux-Live-CD von Guido Socher (tuxgraphics.org), die
seinerzeit (und noch heute) einen genial schnellen Einstieg in die
Mikrocontrollerprogrammierung bietet: Live CD booten, Controller
anstöpseln, in ein Projektverzeichnis wechseln, make load eingeben -
fertig. Nix installieren und funktioniert sogar in der Schule, wo man
dann auch niemanden um irgendwelche Erlaubnis fragen muß. Und die läuft
wirklich auf jedem alten Schrottrechner.
Danke nochmal!
Jürgen D. schrieb:
> Hallo>> Hätte da auch eine Frage bezüglich LCD Tutorial.> In diesem Tutorial gibt es die Funktion lcd_clear, um ein Display zu> löschen.>
1
>voidlcd_clear(void)
2
>{
3
>lcd_command(CLEAR_DISPLAY);
4
>_delay_ms(5);
5
>}
6
>
>> Wie kann ich aber nur die zweite Zeile löschen?
Lauter Leerzeichen in die Zeile schreiben
Steffen M. schrieb:
> Bei den .h und .c Dateien dachte ich einfach: man lagert aus, was man> immer wieder braucht. Was wohl richtig ist
Ja. Gegen die Grundidee ist absolut nichts einzuwenden. Ganz im
Gegenteil
> aber nicht so, wie ich es> letztendlich umsetzte.
Siehs einfach so.
Im Header File steht alles drinnen, was derjenige benötigt, der deine
Funktion benutzen will. Ich C File ist alles enthalten, was die
tatsächliche Implementierung dieser Funktionalität braucht. Im Grunde
das, was der Verwender gar nicht wissen muss, er sich aber ansehen kann,
wenn es ihn interessiert.
Sieh dir auch an, wie ich die lcd-routines zerteilt habe. Insbesondere,
was ich mit den Makros gemacht habe. Ein paar der Makros sind im Header
File, einige andere im C File. Je nachdem wer sie kennen muss. Die
Makros, die einzelnen Bytes, die als Kommandos an das LCD geschickt
werden, in Namen verpacken, muss jemand der die LCD Funktionen benutzt,
nicht kennen. Ergo haben sie im Header File nichts verloren. Sie werden
nur im C File gebraucht, also sind sie auch dort drinnen.