Hallo allerseits, ich hab schon oft gehört, dass es sinnvoll sei, im Code keine direkten Port-Bezeicher & Co. einzuarbeiten. Ist logisch. Nun hab ich aber das Problem, dass ich für eine Uhr so 17 LEDs und 2 Schlter (hört sich wenig an) an einen Mega8 rankriegen muss. Ich will aber, da ich noch nicht weiß, an welchen Ports welche LED rankommt (kann sein, dass sich da noch das ein oder andere ändert), das so programmieren, dass ich in der hardware.h-Datei (so heißt das Ding halt bei mir) alles eingeben kann. So nun zu meinem Problem: Ich hab es einmal geschrieben und gesen, dass es sehr viel Aufwand ist, wenn ich mir das alles als Makros definiere. Da muss ich dann Unmengen an #define-Anweisungen setzen und auch das Ansprechen ist nicht so ohne (Ich muss ja für jede LED einzeln prüfen, ob sie leuchten soll, und dann im jeweiligen IO-Register ein-/ausschalten.) Das ist im auskommentieren Code ja teilweise zu sehen! Daher dachte ich mir es ginge einfacher, wenn ich Arrays verwende. In die Arrays kommen die Zeiger auf verschiedene Register (DDR, Port, PIN, ...). Damit kann ich einzelne LEDs ihrer Priorität nach mit LED_SEC[0] bis LED_SEC[5] (z.B.) ansprechen. Ich hab also die Zeiger mithilfe der &-Operator in die Arrays eingegeben. (Vgl. Anhang; die erste Reihe an Arrays haben in Nachhinein einen * verpasst bekommen, dazu später) Nun zum ersten Problem, bei dem ich C nicht verstehe: wenn ich eine Funktion definiere mit test_func(int * param) {...} und mit test_func(a) aufrufe, "sieht" die Funktion: *param = <Wert von a> param = <Adresse von a> => *param = a könnte man sagen rufe ich aber nun test_func(&a) auf, ist das nicht mehr das selbe; die Funktion sieht (in Klammer: solle analog sehen): *param = <Wert von a> (<Adresse von a>) param = <Adresse von a> **param = >Mist< (<Wert von a>) => Auch hier könnte man *param = a sagen, obwohl eigentlich *param = &a logisch wäre, oder? Ziel sind die Funktionen LED_xxx_OFF und LED_xxx_ON. Hier wird die Adresse aus den Zeigern ausgewertet. Zuerst hatte ich hier die Parameter ohne die * angegeben. Dann bekam ich vom gcc eine Fehlermeldung. Nur interessehalber: Was hab ich da "falsch" gemacht? (Damit mir das nicht noch mal passiert? 2. Problem (viel wichtiger, da ungelöst!!!!!): Weiter unten (Z. 274ff) versuche ich auf die Werte der oben eingesetzten Zeiger zugreifen, um die jeweiligen LEDs ein-/auszuschalten. Da bekomme ich nur folgende Meldung vom gcc: hardware.h: In function 'Init_HW': hardware.h:274: error: assignment of read-only location Hier hab ich dann oben die * eingefügt, bei den Arrays, hat aber nix außer der zusätzlichen Meldungen des GCC gebracht: hardware.h:30: warning: initialization discards qualifiers from pointer target type Das wird dann für jedes Element wiederholt. Was kann ich da machen? Oder gibt es eine bessere Möglichkeit das mit dem HW-unabhängigen Code zu machen, so dass es auch Programmiertechnisch im Rahmen bleibt und möglichst übersichtlich bleibt (die Kommentare mit dem alten Code kommen klar noch raus, aber jetzt sind sie zu Debug-Zwecken noch drinnen)? MfG Christian PS: Mir wäre v.a. mit der 2. Antwort geholfen. Und noch eine Kleinigket: Ich habe hier kein C-Buch. Also so Kommentare wie "Schalg mal dein C-Buch auf und ließ!" ziehen nicht. Ich hab das bisschen C- das ich kann zum einen Lerning-By-Doing und zum anderen aus dem Netz gelernt. Und meine Quellen geben zu dem Thema nix her.
Sieht aus, als willst Du ne Binäruhr bauen. Ich programmiere ja schon viele Jahre, aber so auf die schnelle binär dekodieren zu müssen, wäre mir zu mühsam. Ich würde eine Ziffern- oder Zeigerdarstellung nehmen. Etwas grundsätzliches zu Feldern, sie beginnen immer bei 0 und gehen bis n-1. D.h. bei einer Feldgröße von 6 sind nur die Indizes 0..5 gültig. Was Du mit dem vielen Geschreibsel erreichen willst, ist mir nicht klar. Zumindest ist es sehr schwer zu verstehen. Ich würde den Portpins per define Namen zuweisen und sie dann im Programm direkt über ihren Namen ansprechen. Bevorzugt würde ich zusammengehörende Pins im gleichen Port unterbringen, muß aber nicht sein. Der Codeaufwand ist dann aber geringer. Peter
Genau darum geht's. Weil ich noch nicht weiß, ob die Pins so bleiben, will ich die Adresse zu jedem Pin (DDR-, PORT-Register, Pin-Nummer) in einer Definition am Anfang eingeben. Wenn ich das via #define mache, sind da ziemlich viele defines notwendig und v.a. ist das Problemchen, dass ich für jede LED einzeln mit if oder ?: prüfen muss, ob sie leuchten soll oder nicht. Das ist nicht wenig Tipparbeit. Da ist eine for-Schleife, die das ganze durchläuft deutlich praktischer. Das geht aber nicht mit #define-Anweisungen. zum Thema Anzeige: Das das Ding binär anzeigt, ist gewollt. Es ist eine Eigenkonstruktion, weil eine gute Freundin so ein Ding haben wollte. Ich allerdings sehe darin eine gute Übung und auch ggf. die Mgl das Ding auf Armabduhr-Format zu bringen. Dehalb der modulare Aufbau. Einen Teil der Probleme hab ich übrigens gelöst: Ich muss folgendes machen: Oben definieren: const uint8_t DDR_LED_SEC[6] = {&DDRC,&DDRC,&DDRC,&DDRC,&DDRC,&DDRC}; Weiter unten dann entweder verwenden: *(uint8_t *)DDR_LED_SEC[...] = abc; oder eben mit Unterfunktion: LED_OFF_ll(uint8_t LED,uint8_t * PORT){ *PORT |= _BV(LED); } aufzurufen mit LED_OFF_ll(2,&PORT_LED_SEC[...]); Es bleibt also die Frage, wie ich die Arrays in den Programmspeicher bekomme und ob es irgendwie besser geht. MfG Christian
» Etwas grundsätzliches zu Feldern, sie beginnen immer bei 0 und gehen bis n-1. » D.h. bei einer Feldgröße von 6 sind nur die Indizes 0..5 gültig. Was meinst du damit? Habe ich das irgendwo verletzt? Ich meine nämlich, mich immer an die Regel gehalten zu haben. MfG Christian
Hallo, Hier noch ein Gedanke um die defines zu vereinfachen: #define LED_MIN_PORT PORTB #define LED_HOUR_PORT PORTD #define SWITCH_PORT PORTC #define LED_MIN_1_pin 1 #define LED_MIN_2_pin 2 #define SW_1_pin 5 #define PIN(x) (*(&x - 2)) //address of input register port x #define DDR(x) (*(&x - 1)) //address of data direction register port x ... DDR(LED_MIN_PORT) |= _BV(LED_MIN1_pin); //MIN1 LED is output DDR(SWITCH_PORT) &= ~_BV(SW_1_pin); //SW_1 is input .... LED_MIN_PORT |= _BV(LED_MIN_1); //LED 1 on if (PIN(SWITCH_PORT) & SW_1) ...... Reiner
@Christian "Was meinst du damit? Habe ich das irgendwo verletzt?" Ja, so kann man die Leute verarschen. Du solltest lesbar schreiben, also nicht reservierte Syntaxelemente zweckentfremden. Jeder, der xx[1] sieht, denkt natürlich, das ist ein Feldelement und kein define. Peter
Wenn Du die LEDs binär ordnen würdest, könnte man mittels Schiebeoperatoren ausgeben. Für die wahlfreie Zuordnung, muß man aber jede LED per Abfrage separat schalten, das könnte z.B. so aussehen:
1 | #include <io.h> |
2 | |
3 | #define LED_MIN0 A, 0
|
4 | #define LED_MIN1 B, 6
|
5 | #define LED_MIN2 C, 5
|
6 | #define LED_MIN3 D, 0
|
7 | #define LED_MIN4 B, 7
|
8 | #define LED_MIN5 A, 1
|
9 | |
10 | |
11 | #define OUT_HIGH(x) _SH(x)
|
12 | #define OUT_LOW(x) _SL(x)
|
13 | #define OUT_DIR(x) _SD(x)
|
14 | |
15 | #define _SH(x,y) (PORT##x |= (1<<y))
|
16 | #define _SL(x,y) (PORT##x &= ~(1<<y))
|
17 | #define _SD(x,y) (DDR##x |= (1<<y))
|
18 | |
19 | |
20 | void out_minute( unsigned char val ) |
21 | {
|
22 | OUT_DIR( LED_MIN0 ); |
23 | OUT_DIR( LED_MIN1 ); |
24 | OUT_DIR( LED_MIN2 ); |
25 | OUT_DIR( LED_MIN3 ); |
26 | OUT_DIR( LED_MIN4 ); |
27 | OUT_DIR( LED_MIN5 ); |
28 | |
29 | val & 1 ? OUT_LOW( LED_MIN0 ) : OUT_HIGH( LED_MIN0 ); |
30 | val & 2 ? OUT_LOW( LED_MIN1 ) : OUT_HIGH( LED_MIN1 ); |
31 | val & 4 ? OUT_LOW( LED_MIN2 ) : OUT_HIGH( LED_MIN2 ); |
32 | val & 8 ? OUT_LOW( LED_MIN3 ) : OUT_HIGH( LED_MIN3 ); |
33 | val & 16 ? OUT_LOW( LED_MIN4 ) : OUT_HIGH( LED_MIN4 ); |
34 | val & 32 ? OUT_LOW( LED_MIN5 ) : OUT_HIGH( LED_MIN5 ); |
35 | }
|
Die doppelten Macros sind dazu da, um den Präprozessor zu überlisten, der macht die Argumentenüberprüfung nur bei der ersten Macroexpansion. Peter
P.S.: Überlisten ist nicht ganz richtig, sondern man nutzt aus, daß der Präprozessor mehrere Durchläufe macht: Im ersten Durchlauf stellt er fest, daß ein Macro mit einem Parameter auch einen Parameter bekommt und ist glücklich. Dann expandiert er die erste Instanz an Macros. Im nächsten Durchlauf findet er wieder ein Macro, aber diesmal mit 2 Parametern, das nun auch 2 Parameter bekommt und ist wieder glücklich. Peter
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.