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.
1
Display_write(0b00110000,0,0);
2
Display_write(0b00110000,0,1);
3
Display_write(0b00110000,1,0);
4
Display_write(0b00110000,2,0);
5
Display_write(0b00110000,3,0);
6
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.
1
voidDisplay_write(uint8_tSymbol,uint8_tZeile,uint8_tSpalte)//Zeile und Spalte beginnen mit 0
2
{
3
4
uint8_tAdresse=0;
5
PORTC&=~((1<<PORTC1)|(1<<PORTC6));//RS und R/W auf 0
6
Adresse=0b10000000;//DD RAM Address Set (Position zum Beschreiben)
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.
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.
>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.
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
1
PORTD=Adresse;
2
_delay_us(2);
3
PORTC|=((1<<PORTC7));//Enable 1
4
_delay_us(50);
5
PORTC&=~(1<<PORTC7);//Enable 0
6
_delay_us(2);
solltest du dem LCD ein wenig Zeit geben um den Befehl auch auszuführen.
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
1
voidDisplay_write(uint8_tSymbol,uint8_tZeile,uint8_tSpalte)//Zeile und Spalte beginnen mit 0
2
{
3
Display_set_cursor(Zeile,Spalte);
4
Display_write_char(Symbol);
5
}
Beide Teilfunktionen werden dir in weiterer Folge noch gute Dienste
leisten.
>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:
1
#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.
//Pullups und Ausgangssignale für die Ein- und Ausgänge setzten.
10
PORTA=0b11111111;//Pullups aktivieren
11
PORTB=0b00000000;
12
PORTC=0b00000000;
13
PORTD=0b00000000;
14
15
//Port zu Eingang bzw. Ausgang definierten
16
DDRA=0b00000000;//Schalter
17
DDRB=0b10111010;//Sensoren + SD-Karte (SPI)
18
DDRC=0b11000011;//Display Ansteuerung + JTAG
19
DDRD=0b11111111;//Display Datenleitung
20
21
while(1)
22
{
23
_delay_us(25);
24
PORTD=255;
25
_delay_us(25);
26
PORTD=0;
27
}
28
}
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.
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.
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.
>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
1
#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.
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
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!
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:
1
uint16_tMillisekunden=0;//Wird jede Millisekunde vom Interrupt um 1 erhöht. Zählt von 0 bis 999
2
uint64_tZeit=0;//Wird ggf. später implementiert
3
uint8_tSekunden=0;
4
uint8_tMinuten=0;
5
uint8_tStunden=0;
6
7
uint8_tTrigger_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.
1
while(1)
2
{
3
//Display_write_char(0b00110000);
4
5
if(Trigger_Sekunde)//Wird wegoptimiert
6
{
7
// Tu etwas
8
}
9
}
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.
// In mmc_config.h werden alle nötigen Konfigurationen vorgenommen
6
#include"mmc_config.h"
7
#include"file.h"
8
#include"fat.h"
9
10
// Hardwareabhängig
11
#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:
1
uint8_tInitiallisierung=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:
1
#include"file.c"
2
#include"fat.c"
3
#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.
>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.
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".
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:
1
#include"IncFile1.h"
2
3
voidfunktion(void)
4
{
5
Hallo=Hallo+1;
6
Hallo=Test5;
7
}
IncFile1.h:
1
#ifndef INCFILE1_H_
2
#define INCFILE1_H_
3
4
#include<avr/io.h>
5
6
uint8_tHallo=0;
7
#define Test5 5;
8
9
#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.
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.
Scheinbar hatte der Compiler damit ein Problem, dass der globalen
Variable
1
externvolatileuint8_tTimingDelay;
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.
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.
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.
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 ;-)