Moin!
Anfänger mit Atmega8 am Heulen:
PortB.0 soll TASTER, PortC.0 ne LED darstellen und auch so heissen.
(Aufs Minimum reduziert)
Aus zahlreichen Treats habe ich folgendes zusammengestellt:
struct bits
{
uint8_t b0:1;
uint8_t b1:1;
uint8_t b2:1;
uint8_t b3:1;
uint8_t b4:1;
uint8_t b5:1;
uint8_t b6:1;
uint8_t b7:1;
};
#define BIT(r,n) (((volatile struct bits *)&r)->b##n)
#define TASTER BIT(PORTB, 0)
#define LED BIT(PORTC, 0)
DDRB = 0b00000000; // PORTB als Eingang
DDRC = 0b11111111; // PortB als Ausgang
PORTB = 0b11111111; // PortB auf high schalten
PORTC = 0b00000000; // PortB auf low schalten
int main(void)
{
while (TASTER1)
{
LED = on;
}
return 0;
}
Es funzt aber nicht. Wo könnte der Fehler liegen?
Japp, das soll 1A ANSI-C sein. Oder mal werden.
Im Moment ist Hauptsache, dass es funktioniert. Wenn es denn mal
funktioniert.
@Holger: Danke für den PIN- Tipp!!
Prost!
>oder so:>>#define sbi(PORT, BIT) PORT=(1<<BIT)
Fein, gleich mal den kompletten Port plattmachen;)
So geht das:
#define sbi(PORT, BIT) PORT |= (1<<BIT)
Ich hab´s ja quasi mit Hilfe des structs schon hinbekommen. Bei LED= on
ging´s Lämpchen an...
Nur jetzt, wo ich mit Ein- UND Ausgängen arbeiten möchte, treten
Probleme auf.
Werd mir wohl morgen wirklich mal das Tutorial eingehend vornehmen
müssen...
>Holger, was heisst>>sbi(DDRC,PB1); ??>>Setze Bit PortB1 im DDRC?
Nö, setze in DDRC das Bit das mit der Konstanten
PB1 definiert ist.
Aufgelöst:
DDRC |= 1<<1;
oder
DDRC |= 2;
Alter Hase? Ich bin 16!
Das hat Performance Gründe. Zudem ist es in ANSI-C (ich bin nicht
sicher) nicht vorgeschrieben, dass das Struct auch nur den einen Bit
verwendet. Für 8 Bit verpulverst du mal eben 8 Byte... Das ist aufm AVR
ne Hausnummer.
Aber wie gesagt: ich bin nicht sicher!
>Was habt ihr alten Hasen nur dagegen, einem Bit einen Namen zu geben und>ihm zu sagen "Du, Bit, bist jetzt ne 1!" ?!
Nichts, viele Wege führen nach Rom.
#define LED_ON sbi(PORTC, 0)
#define LED_OFF cbi(PORTC, 0)
Da kannste auch ganz schnell wechseln wenn die LED an Plus hängt;)
#define LED_ON cbi(PORTC, 0)
#define LED_OFF sbi(PORTC, 0)
Ein Lichtblick!!
Ja warum sagst Du das denn nicht gleich?
Aber zum Abschluss noch mal ne richtig doofe Frage. Achtung, festhalten!
Sie lautet:
Muss ich LED_ON wie eine Funktion aufrufen?
(Ich verstand #define bisher nur in der Art "#define PI 3.14159")
1) 'TASTER1' gibts nicht, wenn Dein Compiler Dir das nicht um die Ohren
haut, schmeiß ihn weg
2) Preisfrage: Was macht Dein Programm wohl, wenn der Taster nicht
gedrückt ist?
Silvan König schrieb:> 1) Warum gibts TASTER1 nicht?? (Ich hab sogar zwei!) Wenn er doch> definiert ist?!
Du hast TASTER definiert, aber nicht TASTER1.
Der Compiler ist pingelich!
Stephan R. schrieb:> 1) Warum gibts TASTER1 nicht?? (Ich hab sogar zwei!) Wenn er doch> definiert ist?!
Wo ist er denn definiert? In Deinem ersten Post jedenfalls nicht! Und
auch in keinem anderen.
Stephan R. schrieb:> 2) Denke, dein Miniprogramm berücksichtigt keine Nichtgedrückt..
Das ist DEIN Programm nicht meins! Kennst Du Deine eigenen Posts nicht?
Ich dreh gleich durch!
Was passt Mr. Compiler an
main (void)
{
DDRC= 0xff;
PORTC= 0xff;
sbi (PORTC,0);
return 0;
}
nicht?? (undefined reference to sbi)
OK, wenn man es ganz genau nimmt ists dem Compiler eigentlich egal, der
sollte nur eine Warnung ausspucken. Die Fehlermeldung stammt vom Linker,
der nicht weis wo er die Implementation der Funktion sbi finden soll.
Hab das sbi- Problem gelöst, hängt wohl mit dem Alter (/Neuer) meines
Compilers zu tun.
Folgendes gefällt mir sehr gut und läuft auch:
#define led_on sbi(PORTC,1)
Nun möchte ich noch in der Art auch einen Eingang anfragen können.
#define led (PORTC,1)
funzt leider nicht. Was möchte Mr. Compiler da hören?
Das finde ich -soweit beurteilbar- auch.
Hier mein gesamtes Programm:
#include <avr/io.h>
#include <util/delay.h>
#include <stdio.h>
#define led (PORTC, 1)
#define taster (PINC, 0)
void main (void)
{
DDRC = 0b00000010;
PORTC = 0x00000010;
if (taster == 1)
led = 1;
}
aber: lvalue required as left operand of assignment
Ist er müde?
1) Du solltest lernen hier im Forum Code-Tags zu verwenden
2) Du solltest Dir angewöhnen Deinen Sourcecode korrekt einzurücken
Spiel doch einfach mal selbst Präprozessor.
Du hast da ein "#define taster (PINC, 0)" stehen, also ersetzt Du in
Deinem restlichen Code überall das Wort "taster" durch die Zeichenkette
"(PINC, 0)" (ohne die Anführungsstriche). Und dann siehst Du auch was da
rauskommt und was der Compiler dann nicht versteht.
Stephan R. schrieb:> if (taster == 1)
An der Stelle setzt der Compiler (eigentlich der Präprozessor, aber wir
wollns nicht übertreiben)
(PINC,0) ein.
Sieht also so aus:
Hier, ein Paste (nicht abgetippt):
void main (void)
{
DDRC = 0b11111110;
PORTC = 0b00000000;
if ((PINC, 0) == 0)
sbi (PORTC, 1);
if ((PINC, 0) == 1)
cbi (PORTC,1);
}
Einziges Prob: Es läuft nix. LED ist an. Immer.
Stephan R. schrieb:> Einziges Prob: Es läuft nix. LED ist an. Immer.
Genau das, was Du progrmmiert hast.
OK wenn man ganz pingellig ist hängt das auch noch von der
Compilerversion ab, entweder die LED ist tatsächlich immer an oder der
µC wird ständig resettet und die LED flimmert (unsichtbar, da zu schnell
fürs Auge).
1
((PINC,0)==0)
Dieser Ausdruck ist immer wahr!
1
((PINC,0)==1)
Dieser Ausdruck ist immer falsch!
Nachdem der Optimizer Dein Programm in der Fingenr hatte, bleibt davon
nur noch folgendes übrig:
1
voidmain(void)
2
{
3
DDRC=0b11111110;
4
PORTC=0b00000000;
5
sbi(PORTC,1);
6
}
Und jetzt sollte Dir auch klar werden, warum Deine LED immer leuchtet.
Huch, da war ich wohl zu langsam.
Das letzte sieht schon besser aus (bis auf die fehlenden Code-Tags hier
fürs Forum und die mißratenen Einrückungen).
Das mit bit_is_set/bit_is_clear ist aber etwas doppelt gemoppelt. Wenn
ein Bit gesetzt ist, ist es auf keinen Fall 'clear' und umgekehrt.
Anders gesagt, eins der beiden 'if's kann man sich sparen:
Hi,
ich hätte da mal 'ne Frage zu:
>#define led_on sbi(PORTC,1)
spricht eigentlich was gegen leere Klammern? So wie das da:
#define LED_AN() sbi(PORTC, 1)
so mach ich das nämlich immer, dann kann ich die defines wie Funktionen
aufrufen:
if (TASTET_IST_GEDRUECKT())
LED_AN();
else
LED_AUS();
...ok meist übertreibe ich etwas, dann sieht's etwa so aus:
#define PORT_LED_AUS PORTC
#define PORT_LED_EIN PINC
#define PORT_LED_OE DDRC
#define BIT_LED_ROT 0
#define BIT_LED_GELB 1
#define BIT_LED_GRUEN 2
#define LED_AN() SET_BIT(PORT_LED_AUS, BIT_LED_ROT)
oh Mist, 10-mal durchgelesen und doch noch Fehler:
TASTET_IST_GEDRUECKT() ist gedrückt sollte TASTER_IST_GEDRUECKT()
heissen
SET_BIT(...) ist natürlich auch eine Definition:
#define SETBIT(XREG,XBIT) XREG |= (1<<XBIT)
sorry
Ich persönlich finde es übertrieben, aber ich habe gesehen, dass das in
libs z.B. für das LCD des Nokia3310 genauso gemacht wird.
Daher würd ich sagen, es ist nicht übertrieben, sondern eine
Notwendigkeit. Damit kannst du deine LEDs schneller neu sortieren.
"Zudem ist es in ANSI-C (ich bin nicht
sicher) nicht vorgeschrieben, dass das Struct auch nur den einen Bit
verwendet. Für 8 Bit verpulverst du mal eben 8 Byte... Das ist aufm AVR
ne Hausnummer."
Gibt ja noch __attribute__((packed)). Ist zwar kein ANSI-C, aber der
AVR-GCC-Compiler machts trotzdem.
"Das hat Performance Gründe."
Wenn du mal in die Situation kommst, das du ein 60 seitiges Programm
(ausgedruckt) von nem 8051 auf einen AVR übertragen musst, wird dir
dieser Grund sicherlich recht schnell egal sein. Durch die Struktur sind
dann 8051 übliche sbit Konstrukte wie:
if(UEBERNAHME_PC_MC){ ... }
TAKT_MC_PC=1;
...
TAKT_MC_PC=0;
etc.
Möglich, ohne das du alle entsprechenden Stellen mit Makros wie
TAKT_MC_PC_ON bzw TAKT_MC_PC_OFF ändern musst. Das macht nämlich nach 10
Seiten keinen Spass mehr. Performance hin oder her.
Ansonsten stimme ich dir zu. Bei Programmen, die direkt für den AVR
entwickelt werden sind Makros mit cbi() und sbi() definitiv die bessere
Wahl.
Ohne nahetreten zu wollen, empfehle ich Dir,
mal die Grundlagen in C draufzuschaffen,
statt punktuell Problemchen rauszupicken,
die dann irgendwie mit Hilfe eines Forums gelöst werden.
Gruß
TAIL
bla schrieb:> "spricht eigentlich was gegen leere Klammern? So wie das da:> #define LED_AN() sbi(PORTC, 1)">> Mault den der Compiler rum? Nein? Dann wirds wohl gehen.
Warum probierst Du´s nicht einfach aus ?
Geht schneller als auf ne Antwort zu warten.
:-)
bla schrieb:>> Zudem ist es in ANSI-C (ich bin nicht>> sicher) nicht vorgeschrieben, dass das Struct auch nur den einen Bit>> verwendet. Für 8 Bit verpulverst du mal eben 8 Byte... Das ist aufm AVR>> ne Hausnummer.> Gibt ja noch __attribute__((packed)). Ist zwar kein ANSI-C, aber der> AVR-GCC-Compiler machts trotzdem.
Das ist auch eine der vielen Gimmicks die der GCC mit sich bringt.
Manche Compiler kennen #pragma pack(n) siehe auch [1].
Wenn ich mich nicht irre, ignorieren Compiler unbekannte pragmas und ich
weiß nicht, wie verbindlich _attribute_ und pragmas sind. Vielleicht
sind das nur Empfehlungen für den Compiler und er kann sie, ähnlich wie
inline bei Funktionen, ignorieren??
[1]
http://www.hs-augsburg.de/~sandman/c_von_a_bis_z/c_017_011.htm#RxxobKap017011040029B21F01F18C
dagger:
Ehrlich gesagt: Keine Ahnung. Ich habe zwar Vorlesungen wie
Programmieren 1, Programmieren 2, und Microprozessortechnik gehört, aber
auf µC spezifische Programmierung in C sind diese Vorlesungen leider
nicht eingegangen. In Micorprozessortechnik haben wir 8051 in Assembler
geproggt. Viel gebracht hat mir das nicht, weil ich voher schon mit dem
8085 umgehen konnte.
Ich habe mich zusammen mit einem Mitschüler in den letzten
Wochen/Monaten (Er: ca. 3 Monate. Ich: ca. 6 Wochen) eigenständig in das
Thema eingearbeitet, da wir es beide für notwendig erachteten. Hier
nochmal ein dickes Lob an die Autoren dieser Seite für ihre hilfreichen
Tutorials!
Ich werde mich aber noch tiefer reinarbeiten. C von A bis Z steht hier
im Regal nebem Kerningham/Ritchie. Danke für den Hinweis.
Bitte keine C Bitfields benutzen, das macht auf die Dauer nur Probleme:
- Genaues Layout ist implementierungsabhängig, erschwert Portierung auf
anderen Compiler / Prozessor
- Ein Sprachfeature mehr, dessen Feinheiten man sich merken muss und mit
dem Neulinge Probleme bekommen
- Indizierter Zugriff ist nicht möglich (kein Array von 5 bits in einem
Byte)
Benutzt Shift und Bitoperationen, da wisst ihr genau, was passiert.
Juergen:
Stichhaltige Argumente, die auch richtig sind. Aber ich sehe das ganze
so:
Man sollte schon wissen was Bitfelder sind, welche Vor- und Nachteile
sie besitzen und wie man mit ihnen umgeht. Ihren Einsatz sollte man aber
ähnlich sorgfältig durchdenken wie den Einsatz von goto oder globalen
Variablen, denn manchmal können sie durchaus elegante und effektive
Lösungen für Probleme sein.