Forum: Mikrocontroller und Digitale Elektronik [C] Einbindung der Entprellroutine als Header-Datei?


von Nils R. (Gast)


Angehängte Dateien:

Lesenswert?

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...

von Kirsch (Gast)


Lesenswert?

In Header-Dateien gehört kein Programcode, sondern nur 
Funktions-Prototypen und Makros

Du solltest dich erstmal informieren wie man C-Programme strukturiert

von Karl M. (Gast)


Lesenswert?

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.

von Carl D. (jcw2)


Lesenswert?

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.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

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...

: Bearbeitet durch Moderator
von Leo (Gast)


Lesenswert?

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

von Nils R. (Gast)


Angehängte Dateien:

Lesenswert?

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! :)

von derjaeger (Gast)


Lesenswert?

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!

von Nils R. (Gast)


Lesenswert?

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 :)

von Stefan F. (Gast)


Lesenswert?

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.

von derjaeger (Gast)


Lesenswert?

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.

von W.S. (Gast)


Lesenswert?

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
extern bool KeyID_Available (void);
9
10
// liefert das Zeichen, was die gedrückte Taste
11
// geliefert hat
12
extern char Get_KeyID       (void);
13
14
// liefert TRUE, solange die betreffende Taste gedrückt ist
15
extern bool IsKeyPressed    (char KeyID);

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.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.