Datum:
Hallo, ich habe in GCC eine Funktion geschrieben, die ein Display ansteuert. Also der Funktion übergebe ich die zu adressierende Zeile und Spalte sowie das zu schreibende Symbol. Anschließend steuert die Funktion bei dem Display die Adresse an und übermittelt das Symbol. Das ganze funktioniert auch. Befindet sich ganz unten. Diese Funktion wird in der main zu Beginn mehrmals aufgerufen und schreibt an 6 Ausgewählte stellen eine 0.
Display_write(0b00110000,0,0); Display_write(0b00110000,0,1); Display_write(0b00110000,1,0); Display_write(0b00110000,2,0); Display_write(0b00110000,3,0); Display_write(0b00110000,3,1); |
Nach dem Einschalten des Controllers gibt es aber immer wieder einzelne Stellen (unterschiedlich), die nicht beschrieben werden. Kann mir das jemand erklären? Beim deuggen mittels Atmel Studio 6.0 werden immer nur die ersten beiden Funktionen aufgerufen.
void Display_write(uint8_t Symbol, uint8_t Zeile,uint8_t Spalte) //Zeile und Spalte beginnen mit 0 { uint8_t Adresse = 0; PORTC &= ~((1 << PORTC1) | (1 << PORTC6)); //RS und R/W auf 0 Adresse = 0b10000000;//DD RAM Address Set (Position zum Beschreiben) switch(Zeile)//Zeile anwählen { case 0: Adresse += 0x00;//Zeile 1 break; case 1: Adresse += 0x40;//Zeile 2 break; case 2: Adresse += 0x14;//Zeile 3 break; case 3: Adresse += 0x54;//Zeile 4 break; default: // Do nothing break; } Adresse += Spalte; //Spaltenadresse hinzufügen PORTD = Adresse; _delay_us(2); PORTC |= ((1 << PORTC7)); //Enable 1 _delay_us(50); PORTC &= ~(1 << PORTC7); //Enable 0 _delay_us(2); PORTC |= ((1 << PORTC1)); //RS auf 1 PORTD = Symbol;//Symbol schreiben _delay_us(2); PORTC |= ((1 << PORTC7)); //Enable 1 _delay_us(50); PORTC &= ~(1 << PORTC7); //Enable 0 _delay_us(2); } |
Datum:
A. R. schrieb: > Beim deuggen mittels Atmel Studio 6.0 werden immer nur > die ersten beiden Funktionen aufgerufen. und was passiert dann? also der der GCC hier einen fehler hat, ist zu 999.9999% ausgeschlossen.
Datum:
A. R. schrieb: > Nach dem Einschalten des Controllers gibt es aber immer wieder einzelne > Stellen (unterschiedlich), die nicht beschrieben werden. Kann mir das > jemand erklären? Sporadische Fehler am LCD sind des öfteren ein Hinweis darauf, dass das Timing etwas zu knapp sein könnte.
Datum:
>und was passiert dann?
Ich setzte auf alle 6 Funktionen in der main einen Breakpoint sowie
einen Breakpoint innerhalb der Funktion.
F5 --> Breakpoint auf der ersten Funktion in Main.
F5 --> Breakpoint in der Funktion.
F5 --> Breakpoint auf der zweiten Funktion in Main.
F5 --> Breakpoint in der Funktion
F5 --> Breakpoint auf der dritten Funktion in Main.
F5 --> Breakpoint auf der vierten Funktion in Main.
F5 --> Breakpoint auf der fünften Funktion in Main.
F5 --> Breakpoint auf der sechsten Funktion in Main.
Datum:
Karl Heinz Buchegger schrieb: > A. R. schrieb: > >> Nach dem Einschalten des Controllers gibt es aber immer wieder einzelne >> Stellen (unterschiedlich), die nicht beschrieben werden. Kann mir das >> jemand erklären? > Sporadische Fehler am LCD sind des öfteren ein Hinweis darauf, dass das > Timing etwas zu knapp sein könnte. Insbesonders nach dem Setzen des Cursors
PORTD = Adresse; _delay_us(2); PORTC |= ((1 << PORTC7)); //Enable 1 _delay_us(50); PORTC &= ~(1 << PORTC7); //Enable 0 _delay_us(2); |
solltest du dem LCD ein wenig Zeit geben um den Befehl auch auszuführen.
Datum:
Und tu dir selbst einen Gefallen und teile diese Funktion in 2 Teilfunktionen auf: die eine setzt den Cursor an eine bestimmte Stelle, die andere gibt ein Zeichen aus
void Display_write(uint8_t Symbol, uint8_t Zeile,uint8_t Spalte) //Zeile und Spalte beginnen mit 0 { Display_set_cursor( Zeile, Spalte ); Display_write_char( Symbol ); } |
Beide Teilfunktionen werden dir in weiterer Folge noch gute Dienste leisten.
Datum:
>Sporadische Fehler am LCD sind des öfteren ein Hinweis darauf, dass das >Timing etwas zu knapp sein könnte. Danke für den Hinweis. Da fällt mir ein, dass ich noch den Prozssortakt für die Funktion _delay_us() definieren muss. Sorry, habe bis jetzt noch recht wenig mit GCC gemacht. Ich denke folgendes sollte ausreichen:
#define F_CPU 16000000UL |
Was bedeutet das UL? @ Karl Heinz Buchegger, danke für den Tipp. Im Moment ging es mir ersteinmal darum, das Display überhaupt anzusteuern.
Datum:
A. R. schrieb: > Ich denke folgendes sollte ausreichen: > >
#define F_CPU 16000000UL |
> > Was bedeutet das UL? unsigned long http://www.mikrocontroller.net/articles/FAQ#Welche...
Datum:
Ich habe nun die Zeit nachgemessen.
#include <avr/io.h> #include <util/delay.h> #define F_CPU 16000000UL int main(void) { //Pullups und Ausgangssignale für die Ein- und Ausgänge setzten. PORTA = 0b11111111;//Pullups aktivieren PORTB = 0b00000000; PORTC = 0b00000000; PORTD = 0b00000000; //Port zu Eingang bzw. Ausgang definierten DDRA = 0b00000000; //Schalter DDRB = 0b10111010; //Sensoren + SD-Karte (SPI) DDRC = 0b11000011; //Display Ansteuerung + JTAG DDRD = 0b11111111; //Display Datenleitung while(1) { _delay_us(25); PORTD = 255; _delay_us(25); PORTD = 0; } } |
Statt einer Onzeit von 25µs ist das Rechteck nur 1,624µs on. Das ist etwas Faktor 15,39 zu kurz. Kann mir jemand erklären, woran das liegt? Optimization steht auf -O1. Der Systemtakt beträgt 16 MHz. Es ist auch das Fuse mit Vorteiler 8 ausgeschaltet.
Datum:
Ich habe nun die Daten delay.h etwas untersucht und dort die Funktion "__builtin_avr_delay_cycles()" gefunden. Wenn ich diese in der Main mit dem Wert 400 aufrufe erzeugt dies mein 25µs delay. Der Fehler muss also innerhalb der Bibliothek delay.h liegen. Scheinbar werden 60 und nicht 400 Takte gewartet.
Datum:
Schon mal dran gedacht, dass delay.h die Taktfrequenz wissen muss, um die Umrechnung korrekt durchführen zu können? Wenn du die aber erst danach bekannt gibst, dann kommt eben etwas Falsches raus. Aber such ruhig weiter den Fehler bei Anderen.
Datum:
>Schon mal dran gedacht, dass delay.h die Taktfrequenz wissen muss, um >die Umrechnung korrekt durchführen zu können? JA! Deswegen steht da auch
#define F_CPU 16000000UL |
. >Wenn du die aber erst danach bekannt gibst, dann kommt eben etwas falsches raus. Vielen Dank für den Hinweis! >Aber such ruhig weiter den Fehler bei Anderen. Wie kommst du darauf, dass ich jemand anderen für meine Fehler verantwortlich mache? Ich habe lediglich versucht den Fehler einzugrenzen.
Datum:
A. R. schrieb: > Wie kommst du darauf, dass ich jemand anderen für meine Fehler > verantwortlich mache? A. R. schrieb: > Der Fehler muss also innerhalb der Bibliothek delay.h liegen
Datum:
Dadurch das die Funktion "__builtin_avr_delay_cycles()" einwandfrei funktioniert ließ sich ein Hardwarefehler ausschließen. Mit dem Satz "Der Fehler muss also innerhalb der Bibliothek delay.h liegen" meinte ich nicht, dass die Bibliothek fehlerhaft programmiert ist!
Datum:
So erneut ein Problem. Diesmal macht mir die Optimierung von Atmel Studio 6.0 zu schaffen. Das Programm ist wie folgt aufgebaut: Defines Includes Globale Variablen (Benötige Zugriff im Interrupt und in der main) Unterfunktionen Interrupts Main Initiallisierungen vom Display, Interrupts aktivieren etc. Dauerschleife (agiert basierend auf den Interrupts) Die globalen Variablen habe ich "einfach" vor der main Platziert. Das sieht dann so aus:
uint16_t Millisekunden = 0; //Wird jede Millisekunde vom Interrupt um 1 erhöht. Zählt von 0 bis 999 uint64_t Zeit = 0; //Wird ggf. später implementiert uint8_t Sekunden = 0; uint8_t Minuten = 0; uint8_t Stunden = 0; uint8_t Trigger_Sekunde = 0; //Wird jede Sekunde vom Interrupt auf 1 gesetzt |
Die Variablen brauche ich um Informationen von den Interrupts in der main aufzurufen. Wenn das Falsch ist oder es bessere Methoden gibt bitte ich um eure Vorschläge. In Assembler könnte ich feste Register oder Adressen verwenden. Timer 1 wurde von mir so programmiert, dass er jede ms ein Interrupt auslöst. Erreicht ein Zähler die 1000 wird der Zähler auf 0 gesetzt und die Variable "Trigger_Sekunde" wird auf 1 gesetzt. In der main wird auf die Variable "Trigger_Sekunde" gepollt. Ist Trigger_Sekunde == 1, so wird der Temperatursensor aktiviert und ein externes Interrupt eingeschaltet. Über das Interrupt werden nun die seriellen Daten des Sensors erfasst. Wurden alle Bits empfangen wird der Sensor vom Interrupt deaktiviert. Das ganze funktioniert einwandfrei. Nur habe ich das Problem, dass der Compiler mir seit kurzem die komplette Dauerschleife wegoptimiert hat bzw. diese überhaupt nicht mehr aufgerufen wird.
while(1) { //Display_write_char(0b00110000); if(Trigger_Sekunde)//Wird wegoptimiert { // Tu etwas } } |
Wenn ich "//Display_write_char(0b00110000);" einfüge wird die if-Schleife aufgerufen. Wenn ich die Optimierung von -O1 auf -O0 stelle wird die if-Schleife auch aufgerufen. Hat jemand eine Idee, warum der Compiler die if-Schleife oder die while-Schleife für überflüssig erachtet? Die if-Schleife ist mittlerweile sehr lang geworden deswegen habe ich diese nich gepostet. Es wird aber mindestens ein Port gesetzt. Kann es sein, dass der Compiler denkt, dass die Bedingung (globale Variabel) immer 0 ist? Vielen Dank für eure Hilfe.
Datum:
A. R. schrieb: > Nur habe ich das Problem, dass der > > Compiler mir seit kurzem die komplette Dauerschleife wegoptimiert hat gähn... http://www.mikrocontroller.net/articles/Volatile
Datum:
Danke!
Datum:
Hat schonmal jemand mit dieser Bibliothek bezüglich SD-Karten gearbeitet? Bibliothek: http://www.mikrocontroller.net/articles/AVR_FAT32#Der_Status Thread: Beitrag "MMC SD library FAT16 FAT32 read write" Ich habe nun die Header wie folgt eingefügt:
//Includes für SD-Karte #define __AVR_ATmega644__ #include <stdlib.h> // In mmc_config.h werden alle nötigen Konfigurationen vorgenommen #include "mmc_config.h" #include "file.h" #include "fat.h" // Hardwareabhängig #include "mmc.h" |
Hierzu habe ich bei Toolchain/AVR/GNU C Compiler/Directories den entsprechenden "Include Path" eingesetzt. Die Headerdateien werden gefunden. Bei Toolchain/AVR/GNU C Compiler/Directories habe ich den Pfad mit den Headern und den *.c Dateien auch mal vorsichtshalber eingefügt. Wenn ich nun folgendes Programmiere:
uint8_t Initiallisierung = mmc_init(); |
bekomme ich die Fehlermeldung: "undefined reference to 'mmc_init'. Scheinbar fehlen die *.c Dateien? Weiß jemand, wo ich diese einbinden kann? Ich hatte nun einfach mal folgendes versucht:
#include "file.c" #include "fat.c" #include "mmc.c" |
Daraufhin kam mehrmals folgende Fehlermeldung: "undefined reference to 'TimingDelay' Das ist eine Variable die in mmc.c verwendet und in mcc.h deklariert wird. In mcc.h steht folgendes. Also normal sollte den der mcc.c die Variable bekannt sein.
// timer variable ( 10 ms intervall) extern volatile uint8_t TimingDelay; |
Datum:
Ein paar Bilder, damit man sieht, dass eure Hilfe nicht um sonst ist. Beitrag "Re: Datenlogger Temperatur"
Datum:
A. R. schrieb: >
> #include "file.c" > #include "fat.c" > #include "mmc.c" > |
Großer Unfug. Du musst die C-Dateien im AVR-Studio zum Projekt hinzufügen.
Datum:
Angehängte Dateien:>Großer Unfug. Ja! >Du musst die C-Dateien im AVR-Studio zum Projekt hinzufügen. Eben genau wie das geht wusste ich nicht! Ich habe mittlerweile den Projektmappen-Expolorer entdeckt. Dort habe ich nun alle Header und *.c Dateien eingefügt. Siehe Bild im Anhang. Nur bekomme ich die Fehlermeldungen, welche sich auch im Anhang befinden, in der Datei mmc.c obwohl die notwendigen defines in der Datei mmc.h gemacht werden. Hat jemand eine Erklärung dafür? Wenn ich die defines direkt in der Datei mmc.c ergänze kommen die Fehlmeldungen nicht.
Datum:
A. R. schrieb: > Ich habe mittlerweile den Projektmappen-Expolorer entdeckt. Dort habe > ich nun alle Header und *.c Dateien eingefügt. Siehe Bild im Anhang. Neeein! Nur die c-Dateien einfügen, die Header werden wo nötig vom Präprozessor eingefügt. Korrigier das erstmal, dann sehen wir weiter. Hilfreich ist bei solchen Sachen auch eine Minimalbeispiel z.B. 2 C-Dateien und 1 Header um die Grundlagen zu "erforschen".
Datum:
trollalala schrieb: > die Header werden wo nötig vom > Präprozessor eingefügt. mittels #include "header.h" Zu <> oder "" siehe Beitrag "Re: C-Header wird nicht gefunden"
Datum:
Was ist daran falsch die Headerdateien mit ins Projekt aufzunehmen? Wenn ich dort Änderungen vornehmen möchte ist es doch Sinnvoll, diese direkt im Projekt zu haben. Das Einbinden mit "" sollte auch richtig sein, wenn die Header im Projekt sind. Es gab auch keine Fehlermeldung, dass die Header nicht gefunden werden. Ich habe auch nochmal das angesprochene Minimalbespiel gemacht um zu zeigen das alles Funktionieren sollte. CFil1.c:
#include "IncFile1.h" void funktion(void) { Hallo = Hallo+1; Hallo = Test5; } |
IncFile1.h:
#ifndef INCFILE1_H_ #define INCFILE1_H_ #include <avr/io.h> uint8_t Hallo = 0; #define Test5 5; #endif /* INCFILE1_H_ */ |
Durch das Einfügen des Headers wird die Variable "Hallo" und das define Test5 gefunden. Ich sehe jetzt keinen Grund, warum das im richtigen Programm nicht funktioniert.
Datum:
A. R. schrieb: > Was ist daran falsch die Headerdateien mit ins Projekt aufzunehmen? > Wenn ich dort Änderungen vornehmen möchte ist es doch Sinnvoll, diese > direkt im Projekt zu haben. Es ist schlichtweg Unsinn. Headerdateien erzeugen keinen Code, warum sollte man sie also ins Projekt aufnehmen wo sie "compiliert" werden würden? > uint8_t Hallo = 0; Aua! Globale Variable und dann noch im Header deklariert (oder definiert, das verwechsel ich ständig). Ganz böse.
Datum:
Scheinbar hatte der Compiler damit ein Problem, dass der globalen Variable
extern volatile uint8_t TimingDelay; |
aus dem hinzugefügten Programmcode kein Wert zugewiesen worden ist. >Es ist schlichtweg Unsinn. Headerdateien erzeugen keinen Code, warum >sollte man sie also ins Projekt aufnehmen wo sie "compiliert" werden >würden? Also soll ich die Headerdateien im Notepad bearbeiten und nicht in der Entwicklungsumgebung? >> uint8_t Hallo = 0; >Aua! Globale Variable und dann noch im Header deklariert (oder >definiert, das verwechsel ich ständig). Ganz böse. Das war ein Testprogramm mit paar Zeilen um zu zeigen dass das includieren funktioniert. Außerdem wäre diese Variable nur der Datei CFil1.c gültig.
Datum:
A. R. schrieb: > Also soll ich die Headerdateien im Notepad bearbeiten und nicht in der > Entwicklungsumgebung? Bearbeiten kannst du sie in der IDE, aber dort nicht zum Projekt hinzufügen. > Außerdem wäre diese Variable nur der Datei CFil1.c gültig. Nein, in jeder Datei die IncFile1.h includiert. Das dürfte dann bei mehreren Dateien beim Linken Chaos erzeugen.
Datum:
trollalala schrieb: > A. R. schrieb: >> Was ist daran falsch die Headerdateien mit ins Projekt aufzunehmen? >> Wenn ich dort Änderungen vornehmen möchte ist es doch Sinnvoll, diese >> direkt im Projekt zu haben. > Es ist schlichtweg Unsinn. Headerdateien erzeugen keinen Code, warum > sollte man sie also ins Projekt aufnehmen wo sie "compiliert" werden > würden? Na, ja. Zumindest im 4-er AVR-Studio gab es im Projektbaum eine Unterabteilung "Header-Files" (oder so ähnlich). Damit hat man zumindest im Projekt die Information, welche Header Files zum Projekt dazugehören und kann sie bei Editierbedarf einfach annavigieren. Aber bitte in die Rubrik "Header Files" verschieben! > Aua! Globale Variable und dann noch im Header deklariert (oder > definiert, das verwechsel ich ständig). Ganz böse. An dieser Stelle meinst du "definieren". Deklaration ist alles nach dem Muster "Lieber Compiler, es gibt ..." Definition ist: "Hier musst du auch Speicher dafür reservieren." Denk einfach an Mathe: Eine Definition ist etwas, mit dem du einen Begriff in allen seinen Details in das Problem mit hineinziehst.
Datum:
Karl Heinz Buchegger schrieb: > An dieser Stelle meinst du "definieren". Danke Karl Heinz, auf dich ist Verlass. :-)
Datum:
trollalala schrieb: > A. R. schrieb: >> Was ist daran falsch die Headerdateien mit ins Projekt aufzunehmen? >> Wenn ich dort Änderungen vornehmen möchte ist es doch Sinnvoll, diese >> direkt im Projekt zu haben. > Es ist schlichtweg Unsinn. Headerdateien erzeugen keinen Code, warum > sollte man sie also ins Projekt aufnehmen wo sie "compiliert" werden > würden? Einen Header in ein Projekt aufzunehmen zu können finde ich sinnvoll. Wenn die IDE damit dann Unsinn anstellt, weil sie ein seltsames Konzept von "Projekt" hat, spricht das nicht für die IDE. Sinnvolle Aktionen mit einem header sind zum Beispiel: • Nicht compilieren, sondern nur die Abhängigkeiten (auch rekursiv im Build-Prozess beachten • Compilieren, wodurch gcc per default ein .h.gch erzeugt (Precompiled Header) • Andere, vom Benutzer zuortenbare Rolle. Beispiel: Behandlung wie eine .c-Datei, was u.U sinnvoll sein kann. • Weitere Aktion wäre statische Analyse (MISRA, lint, ...) • Eigenschaften einstellen, zB ob die Datei mit archiviert/versioniert wird, in Dokumentationserzeugung eingeht (doxygen), Coding-Style, ob es eine Binärdatei ist oder Text-Datei, welche Line Endings, ... Es gilt also viele Sachen, die man mit einem Header machen kann ausser mit dem Compiler-Hammer drauf zu hauen ;-)


