Hallo zusammen,
ich bin noch etwas unbeholfen, daher vielleicht die dämliche Frage. Die
Suchfunktion bringt hier ja an die 10^10 Treffer beim Thema
Entprellroutine. Mir geht es aber auch nicht um deren Funktion oder
ähnliches, sondern nur um die korrekte Einbindung.
Ist es korrekt, dass ich die Entprellroutine als Headerdatei einbinde?
Oder gehört die Routine garnicht über eine zweite Datei eingebunden?
Oder als C-File?
Soweit ich bisher weiß, mache ich doch eigentlich in einer Headerdatei
nur die Funktionen dem Compiler/Präprozessor bekannt?
Hinzugefügt habe ich der beigefügten Haderdateie das typische
#ifndef KEY_ROUTINES_H_
#define KEY_ROUTINES_H_
#endif
Im Anhang sind meine beiden Dateien.
Was mich gewundert hat: Beim einbinden als C-File bekomme ich
Fehlermeldungen, als H-File keine. Gemeckert wurde (glaube ich) über die
doppelte Bekanntmachung der Funktionen und den Vektor 16 (TIMER0_OVF).
Scheinbar ist der Unterschied zwischen .h und .c doch größer.
Aufgespielt hatte ich den Code noch nicht, werde ich gleich mal
nachholen. Mir geht es natürlich auch um die Funktion, aber auch ob ich
das so richtig mache. Ich will ja nichts falsches lernen oder Unsinn
machen, den andere auf die Palme bringen ;) Daher lieber mal vorsichtig
nachgefragt.
Ich freue mich auf eure Antworten :)
Vielen Dank!
Schönen Abend,
Nils
PS: Ich hoffe das war das richtige Forum, war mir nicht sicher ob das
nicht nach Compiler/Ide gehört...
In Header-Dateien gehört kein Programcode, sondern nur
Funktions-Prototypen und Makros
Du solltest dich erstmal informieren wie man C-Programme strukturiert
Hallo Nils,
Ein C Programm kann aus unterschiedlichen C - Dateien bestehen, über die
H - Dateien deklariert man u.a. die Schnittstellen, also die
öffentlichen Funktionen oder auch öffentliche (global) Variable.
Die C - Dateien werden durch den Compiler übersetzt (*.o) und im
Linkerlauf verbunden und mit den noch benötigten Bibliotheken
"verbunden".
Daraus erhält man das ausführbare Programm.
Solange es bei einer C-Datei bleibt wird das funktionieren. Der Compiler
sieht ja nur ein langes Programm. Ab der zweiten, die auch "Keyboard"
inkludiert gibt es einige doppelte Labels, da die "Key"-irgendwas
Funktionen dann mehrfach übersetzt wurden. Deshalb Trennung von
Deklaration und Definition. Im .h stehen Funktionsprototypen und extern
deklarierte Daten. Ein .c enthält die (in nur genau diesem vorkommende)
Implementierung.
Nils R. schrieb:> war mir nicht sicher ob das nicht nach Compiler/Ide gehört...
Nur wenn du konkret Fragen zum Verhalten eines bestimmten Compilers oder
einer Toolchain hast.
Kirsch hat fast völlig Recht. Allerdings können einzelne Zeilen
Programmcode durchaus in Form von Makros in einem Headerfile auftauchen.
Keinesfalls aber komplette Funktionen...
Hallo Nils
In der Programmiersprache C ist es normalerweiße überlich die Funktionen
in eine c-Datei und die Funktionsdefinitionen für öffentliche Funktionen
in eine h-Datei zu schreiben.
Sprich, in deinem Fall müsstest du dir eine c-Datei anlegen und den Code
aus der h-Datei dort hinein kopieren.
In der main-Datei wie schon von dir richtig implementiert, die h-Datei
einbinden.
Der Include-Guard kommt / bleibt in der h-Datei.
Gruß Leo
OK, danke für die Ratschläge. Einiges war mir zwar bewusst, wusste es
aber aufgrund von Fehlermeldungen nicht umzusetzen. Nachdem ich nun
verstanden habe, warum die Fehlermeldungen da waren, habe ich es
entsprechend umgeschrieben.
Im Anhang nochmal die Dateien.
Die main.c bindet nur key-routines.h ein und erledigt die konfigartion
des Timers. In der key-routines.h sind jetzt nur #defines und die fünf
Funktionsprototypen.
Die Datei key-routines.c enthält die drei benötigen Variabeln, die ISR
und die fünf Funktionen. Weiterhin werden hier auch die für diese Datei
benötigten Headerdateien (wie auch key-routines.h) eingebunden.
Wäre das so jetzt richtig, oder ist das immer noch totaler Käse?
Tut mir leid für die Fragen, aber ich bin etwas erschlagen von der
schieren Informationsflut. Dafür reichen meine C-Kenntnise einfach noch
nicht aus.
Schonmal ein dickes Danke von mir! :)
Sieht gut aus.
Pack aber die includes in der key-routines.c noch in die Headerdatei mit
rein. Wenn man dein Modul "key-routines" in einem anderen main-Programm
einbindet hat man automatisch die notwendigen includes für das Modul
schon mit der einzigen Headerdatei key-routines.h erschlagen.
Vielleicht noch ein Tipp für die Zukunft: Du darfst bei deinem
Moduldesign nicht davon ausgehen, dass der User die notwendigen Includes
neben deiner Modulheaderdatei selbst einbindet.
Beispiel key-routines.h:
1
#define KEY_DDR DDRB
Hoppla, was ist denn "DDRB" ? => Du erwartest, dass <avr/io.h> vorher
eingebunden wird
1
uint8_t get_key_press( uint8_t key_mask );
Hoppla, was ist denn "uint8_t" ? => Du erwartest, dass <stdint.h> vorher
eingebunden wird.
Das ist schlechtes Design!
Ok, danke für die Hinweise. Das macht natürlich Sinn :)
Jetzt stehen alle includes, außer "#include key-routines.h", in der
Headerdatei.
Bleibt nur noch die Frage, ob das nicht trotzdem Blödsinn war, das ganze
auszulagern. Wie handhabt ihr das? Ich hatte das hier mal so versucht,
da auch die LCD-Routine ausgelagert war. Gut, die ist auch einiges
größer.
Und schreibt man eigentlich die Konfiguration der Ports und Pins in die
jeweilige Headerdatei, oder lieber alles an einer Stelle ins
Hauptprogramm? Bestimmt wird das schnell unübersichtlich, wenn alles auf
mehrere Dateien verteilt ist.
Gut, dass es so ein tolles Forum gibt. Da kann man einiges an Erfahrung
sammeln :)
Auslagern ist gut, wenn das Projekt dadurch übersichtlicher wird oder
wenn man den Quelltext dadurch leichter in andere Projekte kopieren
kann.
Lass den Compiler ruhig für Dich arbeiten.
Denk doch einfach mal daran, dass du im Laufe deines Lebens viele
Programme schreiben wirst für (erstmal) den selben Mikrocontroller.
Einfaches Beispiel: UART Modul zur Ausgabe von Daten am PC.
Wenn du dieses Modul so anwendungsunabhängig machst wie nur möglich,
kopierst du den UART Ordner in jedes neue Programm und hast sofort einen
Kommunikationskanal.
Nils R. schrieb:> OK, danke für die Ratschläge. Einiges war mir zwar bewusst, wusste es> aber aufgrund von Fehlermeldungen nicht umzusetzen.
Ein paar Ratschläge brauchst du aber noch.
Lies mal:
#define KEY_DDR DDRB
#define KEY_PORT PORTB
#define KEY_PIN PINB
#define KEY0 0
#define KEY1 1
#define KEY2 2
#define ALL_KEYS (1<<KEY0 | 1<<KEY1 | 1<<KEY2)
Nun?
Fällt dir was auf?
Ich sag's mal so: Wenn du ins Postamt gehst und dort einen Brief
abgibst, interessiert es dich eigentlich nur, daß er richtig ankommt.
Aber mit welchem Postauto er transportiert wird, sollte dich nix angehen
- das ist ne interne Sache der Post.
Übersetzt nach C lautet das:
1. Schreibe in ein Headerfile wirklich nur das hinein, was andere
Programmteile über das Innenleben der zugehörigen C-Datei unbedingt
wissen müssen - und nicht mehr.
2. Schreibe Treiber. Jaja, richtige Treiber. Das sind Programmteile, die
ein Stück Hardware abstrahieren. Für einen Tasten-Treiber brauchst du
eigentlich eher nur sowas (nimm mir das Neu-Denglisch mal nicht übel):
1
#define id_Enter 1
2
#define id_Rauf 2
3
#define id_Runter 3
4
// usw. je nach Gusto
5
6
// liefert TRUE, wenn ein neuer Tastendruck vorliegt
7
// oder die Repetierfunktion zugeschlagen hat
8
externboolKeyID_Available(void);
9
10
// liefert das Zeichen, was die gedrückte Taste
11
// geliefert hat
12
externcharGet_KeyID(void);
13
14
// liefert TRUE, solange die betreffende Taste gedrückt ist
15
externboolIsKeyPressed(charKeyID);
und mehr braucht in der Headerdatei nicht zu stehen. Schließlich ist es
dem aufrufenden Programm ja egal, an welchem Port des µC die Entertaste
oder die vier Cursortasten angelötet sind. Es will ja nur wissen, ob es
einen Tastendruck (und zwar einen NEUEN Tastendruck, deswegen ja die
Entprellung) zu verarbeiten hat oder nicht. Die letzte Funktion braucht
man nur, wenn man (wie bei PC-Spielen) irgendwas machen will, solange
irgend eine Taste im gedrückten Zustand ist.
Tja - und alles andere treiberinterne Zeugs kommt in die C-Datei.
W.S.