Problemstellung: Der AVR-Takt soll bestimmt und in den Programmcode
eingepflegt werden. Gebraucht wird er für alles Mögliche, bei dem F_CPU
wichtig ist: ds1820, Datenaustausch, etc. - eigentlich immer.
Gemessen wird der Takt über eine RTC, die nach 1h Laufzeit die
Abweichung zwischen timer-Zeit und RTC-Zeit feststellt.
Wie bekomme ich die errechnete Taktrate in den Programmcode? bei ds1820
könnte ich die Zeiten im Programm anpassen. Geht es irgendwie besser?
(Jörg W.: Dynamische Anpassung geht nur mit einem Timer, dessen Wert zur
Laufzeit aus der tatsächlichen (ggf. im EEPROM hinterlegten) Frequenz
ermittelt wird.
Aber: das hat mit dem Thema dieses Threads (serielle Kommunikation)
rein gar nichts zu tun.)
Wenn F_CPU keine per #define bestimmte feste Konstante ist, fliegt Dir
auf dem AVR vieles auseinander.
Z.B. geht delay_ms() nur mit fester Konstante - aber das braucht man
i.d.R. nicht supergenau.
Man muss also manuell an den Stellen an denen dies möglich ist, F_CPU
durch seine eigene Variable ersetzen. Das setzt voraus dass man den
umgebenen Code auch versteht und die Folgen abschätzen kann.
ich kann delay.h kopieren und die Konstante durch eine Variable
ersetzen, die mit F_CPU vorbelegt ist.
Besser wäre es über den Makefile. Das ist ja auch Programmcode, in dem
Variablen abgearbeitet werden:
HEX_FILE_NAME ist eine Variable, die vor dem Programmstart abgearbeitet
wird. Wie bekomme ich Werte aus einer Datei auf dem PC in den Makefile?
Jeder avr bekommt dann eine Nummer der eine individuelle Taktrate auf
dem PC zugeordnet ist.
@ grundschüler (Gast)
>ich kann delay.h kopieren und die Konstante durch eine Variable>ersetzen, die mit F_CPU vorbelegt ist.
Und was soll das bei einer DYNAMISCHEN F_CPU nützen, wenn diese erst zur
Laufzeit gemessen wird?
>HEX_FILE_NAME ist eine Variable, die vor dem Programmstart abgearbeitet>wird. Wie bekomme ich Werte aus einer Datei auf dem PC in den Makefile?
Wozu?
>Jeder avr bekommt dann eine Nummer der eine individuelle Taktrate auf>dem PC zugeordnet ist.
Wozu?
Wenn schon, dann kalibriert man ALLE AVRs vorher auf Nennfrequenz und
fertig und muss dann mit den Toleranzen incl. Temperaturdrift leben.
Dann ist aber F_CPU wieder konstant und man muss keinerlei Problem
lösen.
Die meisten modernen AVRs sind schon vom Hersteller bei einer bestimmten
Spannung (meist 5V) auf +/-1% kalibriert, die Daten für die Einstellung
von OSCCAL liegen in speziellen EEPROM/FUSE Bytes. Je nach Typ werden
diese Einstellungen beim RESET schon geladen oder müssen per Firmware
geladen werden. Genaueres sagt das Datenblatt.
Mich würde interessieren, welches Problem damit eigentlich gelöst werden
soll.
Mal ganz grundsätzlich kann man beim Aufruf von make auch Variablen
setzen. Etwa mit "make target F_CPU=121324" was dann beim Aufruf des
Compilers auch mit "-D " übergeben werden muss.
Man kann auch in eine beliebige Header-Datei mit Perl oder Python
irgendeine Definition reinschreiben. Damit wäre ein Wert von irgendeiner
Instanz auf dem PC in den Code für den AVR transportiert.
Ganz ähnlich könnte ein Perl- oder Python-Script auch ein Makefile
erzeugen, wenn die Zieldatei einen individuellen Namen haben soll.
Oder etwa in der Regel für das Hex-File (oder was auch immer) nach, der
Erzeugung eben des Hex-Files, dieses noch einmal in eine Datei mit
individuellem Namen kopieren, der make in der Kommandozeile übergeben
worden ist.
Bemerkung:
Make-Dateien werden nicht ausgeführt sondern interpretiert. Auch werden
Variablen nicht ausgeführt. Den Unterschied sollte man gedanklich
berücksichtigen, denke ich.
Theor schrieb:> Mich würde interessieren, welches Problem damit eigentlich gelöst werden> soll.
Ich hab ca. 10 nanos rumfliegen, auf die unterschiedliche Programme
aufgespielt werden. Jeder soll mit dem gleichen Programmcode laufen. Die
Lösung: eine Datei fcpu.h, die von main.h nach Setzen von #define
board_nr x aufgerufen wird.
Nach jeweils einer Stunde Laufzeit wird durch Abgleich mit der RTC der
Timer kalibriert. Der Wert des jeweiligen nanos in fcpu.h eingetragen.
Was noch fehlt ist die Berechnung der Taktfrequenz aus der
Timerabweichung.
grundschüler schrieb:> ich kann delay.h kopieren und die Konstante durch eine Variable> ersetzen, die mit F_CPU vorbelegt ist.
Das kannst du, aber dann wirst du viel mehr Flash brauchen, und deine
Delays werden zu lang sein. In den delay-Funktionen werden nämlich
Gleitkomma-Operationen durchgeführt, die aber komplett im Compiler
berechnet werden können, da F_CPU ja eine Compilezeit-Konstante ist. Ist
es das nicht mehr, muss die Berechnung zur Laufzeit gemacht werden,
wofür dann zusätzlich die Floatingpoint-Lib benötigt wird und was auch
eine gewisse Zeit für die Berechnungen zusätzlich zum Delay braucht.
grundschüler schrieb:> #define F_CPU 8000000>> #if boar_nr == 1> #define F_CPU 7900000> #endif> ....
Dir ist aber klar, dass #if vom Präprozessor ausgeführt wird, der deine
Variable board_nr nicht sehen kann?
Rolf M. schrieb:> Dir ist aber klar, dass #if vom Präprozessor ausgeführt wird, der deine> Variable board_nr nicht sehen kann?
deswegen vorher
#define board_nr x
grundschüler schrieb:> Rolf M. schrieb:>> Dir ist aber klar, dass #if vom Präprozessor ausgeführt wird, der deine>> Variable board_nr nicht sehen kann?>> deswegen vorher> #define board_nr x
Und was ist x?
Ich würde Falks Vorschlag folgen:
Falk B. schrieb:> Wenn schon, dann kalibriert man ALLE AVRs vorher auf Nennfrequenz
Wenn das – aus welchen Gründen auch immer – keine Option ist, wäre
folgender Ansatz möglich, bei dem Make die ermittelten Frequenzen aus
einer Datei freqs liest und aus einer einzelnen Quellcodedatei prog.c so
viele Executables namens prog01.elf, prog02.elf usw. baut wie freqs
Einträge enthält:
Makefile (auf das Wesentliche reduziert):
1
PROGNAME = prog
2
3
FREQSFILE = freqs
4
FREQS = $(file <$(FREQSFILE))
5
INDICES = $(shell seq -f "%02.0f" $(words $(FREQS)))
Statt alle Frequenzen in eine einzelne Datei freqs zu schreiben könnte
man auch für jeden Controller eine eigene Datei freq01, freq02 usw.
mit jeweils nur einem Eintrag anlegen und das Makefile entsprechend
anpassen. Das hätte den Vorteil, dass bei Änderung einer Frequenz nur
das jeweils betroffene Executable neu gebaut wird.
Falk B. schrieb:> Meine Lösung, dein Problem!
war jedenfalls hilfreich, über das ganze noch mal nachzudenken. Die
nanos haben ja einen 16 Mhz Quarz. Da ich 3,3V Peripherie benutze soll
die mcu auch mit 3,3v arbeiten können. Deshalb ist der 16mhz
ungeeignet.
Dass man avrs kalibrieren kann, muss man wissen. Habe ich noch nicht
gemacht und hatte das zumindest nicht present. Werde ich ausprobieren.
Auch hier stellt sich noch die Frage der systematischen Messung der
Ausgangsfrequenz und Umrechnung auf OSCCAL.
Wenn alles nicht hilft, bliebe noch Auslöten von 16mhz und Ersatz durch
8mhz.
grundschüler schrieb:> Wenn alles nicht hilft, bliebe noch Auslöten von 16mhz und Ersatz durch> 8mhz.
Dun kannst auch die CKDIV8-Fuse aktivieren, dann startet er mit 2MHz.
Und nach dem Reset schaltest Du auf /2 um, das ergibt dann die
gewünschten 8MHz.
Peter D. schrieb:> Und nach dem Reset schaltest Du auf /2 um, das ergibt dann die> gewünschten 8MHz.
Danke, das wäre die perfekte Lösung. Aber wie schalte ich auf /2 um?
Peter D. schrieb:
danke, ich hab ja inzwischen einige Erfahrung mit avrs, aber man lernt
nie aus.
Danke für alle Beiträge und alle Anregungen. War - wieder mal - sehr
hilfreich.
Hallo,
sehr interessant !!!!
Aber an welcher Stelle setze ich den Befehl
""clock_prescale_set(clock_div_2); "" genau ins Programm ein.
Wenn ich ihn direkt am Anfang der "int main(void)" einsetze funktioniert
die serielle Ausgabe erst wenn ich die vordefinierte Baudrate der
Software Uart von 9600 auf die Hälfte, 4800 setze.
Oder doch einfacher den Quarz 8MHz gegen 4MHz austauschen ?
Schorsch schrieb:> Oder doch einfacher den Quarz 8MHz gegen 4MHz austauschen ?
Ich würde eine Zeile Code dem Umlöten vorziehen.
Ich benutze SMD-Quarze und die löten sich wirklich eklig, da die Pads
darunter liegen.
Der Prescaler muß natürlich in F_CPU mit eingerechnet werden.
Moin peda,
in der Tat ist es so einfacher, selbst mit einem HC49U-S Quarz.
Reale Taktrate des Quarz = 8MHz
Eintragung in F_CPU
F_CPU = 4000000
und hier
int main(void)
{
clock_prescale_set(clock_div_2);// Clock Divisor Faktor 2
So wird auch mit der definierten 9600 Baudrate die richtige Anzeige über
die Software Uart erreicht.
Manchmal hilft ein Tag Abstand
DANKE DIR !!!!!!