Hallo ich bin neu bei der µC Programmierung
Habe nun meine ersten Gehversuche jedoch sind Ein und Ausgaben komplett
invertiert!
Ich nutze Atmel Studio 6.1 mit dem STK500 und einem Atmel 8515 Chip
Hier ein kleiner Programm Schnipsel
1
intmain(void)
2
{
3
DDRD=0b00000000;// PORT D - Switche alles auf 'Eingang' setzen
4
DDRB=0xFF;// PORT B - LED's alle auf Ausgang setzten
5
while(1)
6
{
7
// PORTB=0b01010101; // wird invertiert angezeigt
8
if(PIND&0b00000001)// wenn Switch 0 betätigt
9
{
10
PORTB=~0b11111000;// wird immer angezeigt
11
}// Ausgabe nur richtig mit inverter ~!!!!
12
else
13
{
14
PORTB=~0b00000001;// wird angezeigt wenn SW 0 betätigt
15
}
16
}
17
}
Eigentlich sollte wenn PIND0-betätig --> doch die if - Anweisung
durchlaufen werden und nicht die else? oder
und auch hier sind die PORTB Bit Ausgaben nur 'richtig' wenn sie mit
~invertiert werden?!?
ich habe leider keinerlei Einstellung dafür gefunden? Aber so kann es
doch auch nicht richtig sein, oder? müsste man ja immer negiert
denken?!?
Was mache ich falsch?
Grüsse!!
Dirk
Dirk S. schrieb:> ich habe leider keinerlei Einstellung dafür gefunden? Aber so kann es> doch auch nicht richtig sein, oder? müsste man ja immer negiert> denken?!?
Nicht immer. Sonst kriegst du irgendwann Depressionen. Aber bei µC ist
es zu ca. 99,37468% so, daß mit dem Betätigen eines Tasters GND
geschaltet wird und eine LED in aller Regel auch mit GND angesteuert
wird.
mfg.
Dirk S. schrieb:>> Was mache ich falsch?>
Gar nichts :-)
Es ist alles richtig so. Schau dir mal die Schaltung vom STK500 an. Da
siehst du, daß die LED's an +5V hängen. Das heißt also, wenn sie
leuchten sollen, muß vom Controller ein LOW am Ausgang kommen.
Und mit den Tastern ist es genauso. Sie hängen zwischen dem Eingang und
GND. Wenn sie offen sind, sorgt ein Pull-up von 10k dafür, daß der
Eingang auf HIGH liegt. Und wenn du den Taster drückst, legst du LOW an
den Eingang.
Dirk S. schrieb:> ich habe leider keinerlei Einstellung dafür gefunden? Aber so kann es> doch auch nicht richtig sein, oder? müsste man ja immer negiert> denken?!?
Du gewöhnst dich daran.
Genauso wie du dich daran gewöhnt hast, die oberste Farbe in einer
Verkehrsampel 'rot' zu nennen. Man hätte sie genausogut auch 'blau'
nennen können. Dann würden wir eben von blauen Lippen sprechen und
hätten blaue Erdbeeren. Es ist eine reine Konvention, dass wir für eine
bestimmte Farbe das Wort 'rot' benutzen, aber beileibe kein Naturgesetz.
Und genauso auch hier.
Es ist kein Naturgesetz, dass eine 1 die Bedeutung hat 'eingeschaltet'.
Es ist eine reine Konvention, die man treffen kann, aber nicht muss. Und
wenn es Gründe gibt, warum anders rum (0 bedeutet eingeschaltet) besser
oder einfacher ist, dann macht man das eben so.
Und statt immer negativ zu denken, kannst du auch dem Compiler sagen,
dass er vor der Ausgabe invertieren soll. Den Taktzyklus hast du
sicherlich noch übrig. :-)
Noch einfacher kann man es sich machen, indem man sich gar nicht auf
"aus" oder "ein" festlegt. Man muß wissen, wie die Schaltung aussieht,
die am Controller dranhängt. Und das ist alles. Eine 1 bedeutet immer,
daß am entsprechenden Pin ein HIGH ausgegeben wird. Und bei einer 0 dann
eben LOW. Und wenn man jetzt weiß, daß die LED mit der Anode auch an
HIGH angeschlossen ist, dann weiß man auch, daß sie nicht leuchtet, wenn
auf beiden Seiten das gleiche Signal (nämlich HIGH) anliegt. Ok?
Und bei den Tastern ist es genauso. Wenn man weiß, daß bei nicht
betätigten Tastern immer ein HIGH am Eingang anliegt, muß man dann im
eigenen Programm auf "LOW" abfragen, wenn man wissen will, ob der Taster
gedrückt ist. Denk nochmal in Ruhe drüber nach, ist eigentlich ganz
einfach :-)
ZUmal man in C ja auch die Möglichkeiten hat, sich das ganze so zu
abstrahieren, dass man
* im Programmtext dieses 'Detail' gar nicht berücksichtigen muss
* man dieses 'Detail' an einer Stelle zentral zusammenfasst
* man Ausgangspins sowieso normalerweise nicht durch Zuweisung eines
Wertes an den kompletten Port erledigt
1
#define LED_PORT PORTB
2
#define LED_BIT PB1
3
4
#define TURN_LED_ON LED_PORT &= ~( 1 << LED_BIT )
5
#define TURN_LED_OFF LED_PORT |= ( 1 << LED_BIT )
6
7
#define KEY_PRESSED (PIND & ( 1 << PD0 ))
8
9
10
intmain(void)
11
{
12
DDRD=0b00000000;// PORT D - Switche alles auf 'Eingang' setzen
13
DDRB=0xFF;// PORT B - LED's alle auf Ausgang setzten
14
15
while(1)
16
{
17
if(KEY_PRESSED)// wenn Switch 0 betätigt
18
{
19
TURN_LED_ON;
20
}
21
else
22
{
23
TURN_LED_OFF;
24
}
25
}
26
}
So sieht das im eigentlichen Programmtext doch schon viel besser aus.
Karl Heinz Buchegger schrieb:> So sieht das im eigentlichen Programmtext doch schon viel besser aus.
Das ist für größere Programme aber bedingt Mist, weil Du dann immer
erstmal schauen musst, wie Du TURN_LED_ON definiert hast. Andererseits
kann es eine große Erleichterung sein, wenn Du es mehrmals benutzt, und
die LED dann an einem anderen Pin hängen soll.
Das muss man sich also gut überlegen, wie weit man hier abstrahieren und
wegdefinieren will. Ist für einen Anfänger vielleicht nicht so geeignet.
Timm Thaler schrieb:> Karl Heinz Buchegger schrieb:>> So sieht das im eigentlichen Programmtext doch schon viel besser aus.>> Das ist für größere Programme aber bedingt Mist, weil Du dann immer> erstmal schauen musst, wie Du TURN_LED_ON definiert hast.
Inwiefern muss ich das 'dauernd nachsehen'?
Wenn ich das eigentliche Programm schreibe, reicht mir das 'ON' um zu
wiss....
Ach jetzt versteh ich dich. (denke ich)
ON ist nicht eindeutig. Ist damit 'Bit auf 1' oder 'Licht einschalten'
gemeint.
OK. Das ist aber eine Frage von gut gewählten Bezeichnungen. Geb ich dir
recht - ON ist in diesem Zusammenhang vielleicht wirklich nicht so gut
gewählt. Für mich war zwar klar, dass TURN_LED_ON impliziert, dass
danach die LED leuchtet, aber das ist meine Konvention, die darauf
beruht, dass ich mich im Programmtext selber um so Kleinigkeiten wie
"0-Bit für einschalten" nicht mehr kümmern will. Eine LED auf ON setzen,
bedeutet für mich automatisch, dass sie danach leuchtet (egal ob das Bit
dazu auf 0 oder 1 gehen muss). Für jemand anderen mag das anders sein.
Karl Heinz Buchegger schrieb:> Eine LED auf ON setzen,> bedeutet für mich automatisch, dass sie danach leuchtet (egal ob das Bit> dazu auf 0 oder 1 gehen muss)
Das geht aber zum Beispiel bei LEDs noch weiter. Auch wenn das den TE
jetzt verwirren sollte.
Du kannst eine LED (geschalten gegen +5V) einschalten, indem Du das Pin
auf Ausgang setzt. Pin auf high => LED aus, Pin auf low => LED ein.
Du kannst diese LED aber auch einschalten, indem Du den Pin auf low
setzt. Pin auf Ausgang => LED ein, Pin auf Eingang => LED aus. Also
nicht über PORTx, sondern über DDRx. Der Ausgang wirkt dann wie ein
OpenCollector, nicht wie eine Push-Pull-Stufe.
Machst Du das jetzt mit einem Port, an dem noch andere Sachen hängen,
kann das eigentlich klare TURN_LED_ON, welches in Deinem Beispiel ja
schonmal den ganzen Port verändert, zu völlig unerklärlichen Fehlern
führen, weil plötzlich Ausgänge zu Eingängen werden, und sich das in
ganz anderen Programmteilen auswirkt. Und nach solchen Fehlern kann man
tagelang suchen... ;-)
Also Abstraktion ja, aber mit Bedacht.
Timm Thaler schrieb:> Machst Du das jetzt mit einem Port, an dem noch andere Sachen hängen,> kann das eigentlich klare TURN_LED_ON, welches in Deinem Beispiel ja> schonmal den ganzen Port verändert, zu völlig unerklärlichen Fehlern> führen, weil plötzlich Ausgänge zu Eingängen werden, und sich das in> ganz anderen Programmteilen auswirkt. Und nach solchen Fehlern kann man> tagelang suchen... ;-)
Schau nochmal genau.
Genau das hab ich ausgebaut um damit den 3.ten Punkt zu illustrieren,
dass man solche komplett-Portzuweisungen in der Praxis sowieso nicht
macht.
> Also Abstraktion ja, aber mit Bedacht.
Kein Einwand.
Danke schon mal für die vielen Antworten!!
Schön das man mit solchen Anfängerfragen nicht gleich 'gesteinigt' wird
:-)
Ok mit LOW und HIGH hab ich verstanden. Macht beim weiteren beschalten
von Transistoren und Relais usw. ja auch Sinn.
ABER wenn ich in meinem obigen Beispiel die If Anweisung wie folgt
abändere:
if (PIND & 0b11111110)
So sollte es doch funktionieren? oder? tut es aber nicht?
Des Weiteren auch bei dem Beispiel vom Karl Heinz sind alle LED's an un
bei "Key_Pressed" geht 1 aus!!
Habe ich noch ein weiteres Verständnis Problem?
Sorry für die wirklich blöde Fragerei!
Der Dirk
Schnellschuss:
Nur weil auf dem STK500 eine gedrückte Taste ein 0 liefert, bedeutet das
nicht, dass es dich vom Einschalten des Pullup Widerstandes entbindet
1
intmain()
2
{
3
DDRD=0x00;
4
PORTD=(1<<PD0);
5
6
while(1)
7
{
8
if(PIND&(1<<PD0))
9
....
Ohne Pullup wechelst der Eingangspin je nachdem ob die Taste gedrückt
ist oder nicht zwischen '0' und 'Eingang offen'.
'Eingang offen' ist aber kein definierter Pegel. Das kann 0 sein, das
kann 1 sein, je nachdem welches elektromagnetische Feld sich gerade in
der Gegend rumtreibt.
Und bitte: gewöhn dir Bitschreibweisen gleich wieder ganz schnell ab. Es
gibt Fälle, in denen sie sinnvoll ist. Aber in den meisten Fällen, ist
es die schlechteste Schreibweise, die du finden kannst.
> Nur weil auf dem STK500 eine gedrückte Taste ein 0 liefert, bedeutet das> nicht, dass es dich vom Einschalten des Pullup Widerstandes entbindet
Im Prinzip hat Karl-Heinz Recht, aber in diesem Falle muß man das nicht.
Die Pull-up-Widerstände sind hardwaremäßig auf dem STK vorhanden (10k).
In einer eigenen Schaltung kann man sich die aber (meist) sparen, denn
den µC hat schon welche integriert, die man softwaremäßig einschalten
kann. Das meinte Karl-Heinz.
Das es ohne Pullup zu undefinierten Zuständen kommt ist klar!
Aber ich möchte ja ja nicht die Pull Up's ein-/ausschalten sondern
lediglich die definierten Pegel abfragen und da hakt es bei mir zur
Zeit. Ich möchte Grundlegend das System verstehen bevor ich ernsthaft
beginne.
Ok die Bitschreibweise habe ich für mein Verständnis bisher genutzt. Ist
sicherlich nicht die übersichtlichste.
Danke für Eure Hilfe!!!
> Aber ich möchte ja ja nicht die Pull Up's ein-/ausschalten sondern> lediglich die definierten Pegel abfragen und da hakt es bei mir zur> Zeit. Ich möchte Grundlegend das System verstehen bevor ich ernsthaft> beginne.
Und genau für die definierten Pegel sorgen ja deine PullUps. Also
entweder hast du sie in deine Schaltung eingeplant oder du solltest sie,
meinetwegen auch ohne dir Gedanken drüber zu machen, einschalten. Denn
sonst hast du einem der Fälle Taster gedrückt/nicht gedrückt gar keinen
definierten Pegel.
> entweder hast du sie in deine Schaltung eingeplant
Nochmal: Sie sind bereits im STK körperlich vorhanden (10k), müssen also
nciht eingeschaltet werden. Ok?
Also so langsam komme ich dahinter :-)
Danke für Eure Hilfe
Hab mit eine uint Variable angelegt in die ich das 'Eingangsregister'
schreibe und dieses mit ein paar Test 'cases' wieder anzeigen lassen.
FUNZT!
1
uint8_tMein_PortD;
2
3
intmain(void)
4
{
5
DDRD=0x00;// PORT D - Switche alles auf 'Eingang' setzen
6
DDRB=0xFF;// PORT B - LED's alle auf Ausgang setzten
UNd als nächstes gewöhnst du dir diese 'kompletter Port' Rundumschlag
Geschichten ab. Das bringt dich nämlich nicht weiter.
Wenn du wissen willst, ob ein bestimmer Eingangspin zb. der Pin PD3, auf
1 ist
1
if(PIND&(1<<PD3))
2
tuwas
wenn du wissen willst, ob selbiger Pin auf 0 ist
1
if(!(PIND&(1<<PD3)))
2
tuwas
wenn du einen bestimmten Pin, zb PB5 am AUsgang auf 1 schalten willst
1
PORTB|=(1<<PB5);
wenn du denselben Pin auf 0 schalten willst
1
PORTB&=~(1<<PB5);
#Das# sind deine 'Arbeitspferde'. Diese Operationen musst du im Schlaf
beherrschen.
Bitmanipulation
Karl Heinz Buchegger schrieb:> #define KEY_PRESSED (PIND & ( 1 << PD0 ))
Bei einem Active-Low-Schalter (auf dem STK500?) müsste dies aber heißen:
#define KEY_PRESSED (!(PIND & ( 1 << PD0 )))
Gruß,
Frank
Hallo also ich finde Karl Heinz hat die 'Grundfunktionen' heute Mittag
sehr gut erklärt und zusammengefasst.
Jetzt nachdem ich gecheckt habe das das STK500 die Eingänge aktiv auf
High und durch gedrückte Switches auf LOW gezogen werden, fällt mir
vieles Leichter!!
Danke für diese ersten Erkenntnisse, jetzt fängt es an Spaß zu machen!!!