Hallo zusammen,
bin gerade dabei, mich mit der Funktionsweise des ATtiny vertraut zu
machen. Dazu habe ich eine einfache Schaltung (siehe Anhang) und
folgendes kleine Programm geschrieben:
<c>#include <avr/io.h>
#include <avr/delay.h>
int main(void)
{
DDRB = 0x00111111;
while (1)
{
PORTB = 0x00111111;
_delay_ms(500);
PORTB = 0x00000000;
_delay_ms(500);
}
}</c>
Ziel ist es, an BP0 bis PB5 LEDs zum Blinken zu bringen. Dazu wechsele
ich das gelbe Kabel einfach an die einzelnen PINs. Seltsamerweise blinkt
die LED nur an PB0 und PB4. An BP1, PB2 und PB3 bleibt die LED aus.
Woran kann das liegen? Kann mir jemand helfen? Habe schon verschiedene
Variationen im Programm und in der Schaltung probiert, aber komme der
Sache nicht auf den Grund - was übersehe ich da?
Und noch eine kurze Frage: In vielen Beispielen wird der Reset-PIN über
einen 10kOhm Widerstand mit VCC verbunden - ist das unbedingt notwendig?
Und was ist der Grund dafür?
VG & danke für Eure Hilfe
Michael
Michael Becker schrieb:> Und noch eine kurze Frage: In vielen Beispielen wird der Reset-PIN über> einen 10kOhm Widerstand mit VCC verbunden - ist das unbedingt notwendig?> Und was ist der Grund dafür?
Weil der interne Pullup recht schwach ist. Notwendig ist das beim
Attiny13 meines Wissens nach nicht. Genaueres sagt dir das Datenblatt.
Darüber hinaus solltest du wissen, dass der PB5 für dich nicht nutzbar
ist. Oder hast du die entsprechende Fuse gesetzt?
Und was dein Problem angeht. Du benutzt Hexadezimale Zahlen willst aber
Binäre verwenden.
Vorwiderstand für die LED drin?
Die Programm ist falsch.
PORTB = 0x00011111 ist hexadezimal nicht binär !!
Probiers mal mit PORTB = 0b00011111;
Wenn du ISP verwendest, kannst du PB5 nicht nutzen, da er als Reset
arbeitet. Dieser wird normalerweise auch über einen Widerstand auf Vcc
gelegt, damit der Controller nicht durch äußere Einflüsse resetet wird.
Ahh, vielen Dank für die schnelle Hilfe - jetzt klappt's (natürlich)
:-)
Bzgl. Reset-PIN: nein, Fuse habe ich nicht gesetzt. Ich habe davon
gehört, aber was bedeutet das eigentlich? Und ISP benutze ich auch
nicht, ich mache das über ein myAVR MultiProg - bin absoluter Anfänger
(muss ich wohl nicht sagen...)
Michael Becker schrieb:> Und ISP benutze ich auch> nicht, ich mache das über ein myAVR MultiProg - bin absoluter Anfänger
Das ist ISP, was auch sonst?
Michael Becker schrieb:> Bzgl. Reset-PIN: nein, Fuse habe ich nicht gesetzt. Ich habe davon> gehört, aber was bedeutet das eigentlich?
Der Reset bin kann nur duch setzen einer bestimmten Fuse als normaler
I/O Pin benutzt werden. Danach kannst du den Controller NICHT mehr
programmieren.
Hier ein Link zum Datenblatt, wieso liest du das nicht?
http://www.atmel.com/Images/doc2535.pdf
> Das ist ISP, was auch sonst?
Ok, aber ich wechsel den Controller dann immer zwischen Programmierboard
und eigener Schaltung hin und her - dachte ISP wäre, wenn man den Chip
bei der Programmierung in der Schaltung drin lässt. Gibt's dann
überhaupt eine andere Möglichkeit neben ISP den Code auf den Controller
zu bringen?
> Hier ein Link zum Datenblatt, wieso liest du das nicht?
Das hatte ich teilweise gelesen - aber lesen und verstehen sind zwei
paar Schuhe (habe bisher nur grobes Grundverständnis...)
Michael Becker schrieb:> Ok, aber ich wechsel den Controller dann immer zwischen Programmierboard> und eigener Schaltung hin und her - dachte ISP wäre, wenn man den Chip> bei der Programmierung in der Schaltung drin lässt.
Ein Sofa ist ein Wohnzimmermöbelstück. Wenn du es jetzt in den Garten
stellst, was ist es dann? Eine Hollywoodschaukel oder immer noch ein
Sofa?
Dein Programmer ist ein ISP-Programmer.
Michael Becker schrieb:> Gibt's dann> überhaupt eine andere Möglichkeit neben ISP den Code auf den Controller> zu bringen?
Ja. Mit HV-Programming. Das kann dein Programmer aber nicht.
Also musst du, wie die meisten anderen auch, auf den Reset-Pin als Port
verzichten. Das ist einfach so.
mfg.
ok, verstehe...
Habe noch eine Frage/Problem: Eigentlich möchte ich eine kleine
Alarmanlage für die LEGO-Eisenbahn meines Sohnes basteln (hab's
versprochen...) - bei Druck auf einen Taster sollen 3 LEDs abwechselnd
blinken und Sound über Speaker.
Ich habe dann gestern Abend eifrig gelötet (siehe Foto). Leider
funktioniert das auch nicht so, wie ich es mir vorstelle. Das Programm
scheint soweit ok zu sein (läuft auf myAVR MK2 und auch der Einbau auf
der Steckplatine zeigt Symptome, dass es prinzipiell gehen sollte). Bei
Anschluss an die selbst zusammengeschweißte Platine passiert aber nix,
kein Leuchten, kein Sound.
Wie kann ich prüfen, ob die Anschlüsse richtig gepatched sind? Meine
Idee (siehe Foto) war, den Socket von GND mit (z. B.) PB2 zu verbinden
(gelbes Kabel), um zu sehen, ob die Verbindung im Prinzip richtig
gelötet ist... das funktioniert bei allen Pins. Oder ist das kein
valider Testansatz, bin ich auf dem Holzweg?
nein, aber habe auf der Platine passende Vorwiderstände (blau) eingebaut
(und auch einen Spannungswandler von 9 auf 5 V). Auf der
Test-Steckplatine lass ich sie manchmal (aus Faulheit) weg - wohl nicht
so gut für die Lebensdauer der Dinger...
Michael Becker schrieb:> Wie kann ich prüfen, ob die Anschlüsse richtig gepatched sind? Meine> Idee (siehe Foto) war, den Socket von GND mit (z. B.) PB2 zu verbinden> (gelbes Kabel), um zu sehen, ob die Verbindung im Prinzip richtig> gelötet ist... das funktioniert bei allen Pins. Oder ist das kein> valider Testansatz, bin ich auf dem Holzweg?
Wenn GND am Pin die Led zum leuchten bringen soll und sie mit Brücke an
GND auch leuchtet, ist das schon OK.
Die 3 blauen Widerstände sind wohl die Vorwiderstände für die Leds und
der braune der Basiswiderstand vom Transistor?
In der Schaltung fehlt noch ein 100nF-Stützkondensator zwischen Vcc und
GND so nah wie geht am Controller. Das ist das mit Abstand wichtigste
Bauteil der Digitaltechnik.
Zeig mal den Schaltplan und das Programm. Sonst kann man da nichts
weiter zu sagen.
mfg.
Michael Becker schrieb:> Test-Steckplatine lass ich sie manchmal (aus Faulheit) weg - wohl nicht> so gut für die Lebensdauer der Dinger...
Die können einiges ab. Aber der Controller muß den Strom dann auch
liefern können. Und dadei wird er dann recht warm.
mfg.
Michael Becker schrieb:> nein, aber habe auf der Platine passende Vorwiderstände (blau) eingebaut> (und auch einen Spannungswandler von 9 auf 5 V). Auf der> Test-Steckplatine lass ich sie manchmal (aus Faulheit) weg - wohl nicht> so gut für die Lebensdauer der Dinger...
Stimmt, auf der Platine sind welche. Aber du weißt ja anscheinend um die
Problematik, dann ist es natürlich deine Sache. Wollte nur nicht, dass
dir aus Unwissenheit was kaputt geht ;)
> Die 3 blauen Widerstände sind wohl die Vorwiderstände für die Leds
ja genau
> und der braune der Basiswiderstand vom Transistor?
Der braune Widerstand ist 10kOhm am Reset-PIN. Das schwarze Ding ist der
Spannungswandler 9V > 5V.
> In der Schaltung fehlt noch ein 100nF-Stützkondensator zwischen Vcc und
GND so nah wie geht am Controller. Das ist das mit Abstand wichtigste
Bauteil der Digitaltechnik.
Das sagt mir jetzt gar nix... gibt's dazu einen Link / Beitrag im Forum
/ Beispielschaltplan? Ich hab mir vor allem die Beispiele hier
angeschaut:
http://www.avr-asm-tutorial.net/avr_de/index.html
Kann das ein Grund sein, dass die Schaltung gar nicht geht? Zumal es ja
auf der Steckplatine soweit klappt (auch ohne dieses wichtige Teil)
> Zeig mal den Schaltplan und das Programm.
Programm siehe Anhang. Schaltplan hatte ich noch nicht aufgezeichnet,
sondern mir nur so überlegt und dann losgelötet - ist wohl etwas
"hemdsärmlig". Aber prinzipieller Aufbau ist so:
- Nach der Batterie kommt zunächst der Spannungswandler.
- Dann geht es von + Pol weiter an 5 der 10 bunten Kabel:
--> für die LEDs Vorwiderstände
--> für Speaker direkt ohne Widerstand
--> einer an VCC (auch ohne Widerstand)
- Die anderen 5 Kabel sind mit PB0 bis PB4 verbunden.
- GND führt an den - Pol der Batterie
- und dann noch der 10KOhm Widerstand zwischen VCC und Reset
Werde mal einen Schaltplan zeichnen, oder kannst Du mit der Beschreibung
was anfangen? Danke!!
und hier noch eine Skizze zum Aufbau - gibt's für Schaltpläne eigentlich
eine empfehlenswerte Software/Freeware? Und auch etwas für
Platinenlayout? Wäre natürlich cool, wenn so ein Programm auf "grobe
Fehler" in der Schaltung hinweisen würde... Oder einfach mit Visio
zeichnen?
Michael Becker schrieb:> Hier noch die Datei mit dem Coding...
Ist das das ganze Programm?
Wo ist F_CPU definiert?
Das ist wichtg für delay. Gibt auch Mecker, wenn das fehlt.
1
#ifndef F_CPU
2
#error F_CPU not defined.
3
#endif
4
#include<avr/io.h>
5
#include<avr/delay.h>
6
7
intmain(void)
8
{
9
//PIN Belegung
10
//
11
//PB0 LED grün
12
//PB1 LED rot
13
//PB2 LED blau
14
//PB3 Speaker
15
//PB4 Taster
16
17
DDRB=0b00001111;
18
PORTB=0b00010000;
19
//Gewöhn dir das ab
20
DDRB|=(1<<3)|(1<<2)|(1<<1)|(1<<0);
21
//Da sieht man sofort was Sache ist. Mit Copy&paste ist das kaum mehr Schreibaufwand und man kann sich nicht verzählen.
22
23
inti;
24
intalarmOnOff;
25
intcount;
26
//Recht verschwenderisch. Da keine Zahl >255 ist, reicht unsigned char.
27
//Du hast einen RAM-Mickerling vor dir.
28
//Und Zählvariablen immer lokal.
29
//Sonst suchst du dich irgendwann tot, wenn das Programm etwas größer wird.
30
while(1)
31
{
32
while(!(PINB&0b00010000))//Was soll das ein? Entprellung?
33
{
34
count++;
35
}
36
37
// if (count >> 200) //Count 200 mal nach rechts schieben? Sportlich!
// Macht keinen Unterschied in der Funktion, hat sich aber als Schreibweise so eingebürgert.
60
// Sonst muß man immer dreimal hingucken, ob das richtig ist
61
62
PORTB^=(1<<PB3);
63
64
}
65
66
PORTB=0b00000010;//siehe oben
67
68
//Dött
69
for(i=1;i<100;i++)
70
{
71
_delay_ms(3);
72
PORTB=PORTB^(1<<PB3);//siehe oben
73
}
74
75
76
PORTB=0b00000100;//siehe oben
77
78
//Diett
79
for(i=1;i<100;i++)
80
{
81
_delay_ms(2);
82
PORTB=PORTB^(1<<PB3);//etc.pp
83
}
84
85
}
86
else
87
{
88
PORTB=0b00000000;
89
}
90
}
91
}
Michael Becker schrieb:> Werde mal einen Schaltplan zeichnen, oder kannst Du mit der Beschreibung> was anfangen? Danke!!
Nee ist schon klar. Ist ja kein ganzes Stellwerk. Vielleicht auch besser
so. War ja gestern in Kiel wieder so weit. Totalabsturz. So gesehen bist
du jetzt in bester Gesellschaft.
http://www.mikrocontroller.net/articles/Entprellunghttp://www.mikrocontroller.net/articles/Timer
Noch was zum Lesen. Denn weder ohne Entprellung noch mit delay wirst du
lange glücklich sein. Willst ja nicht ewig mit deinem Sohn
Schienenersatzverkehr spielen.
Die Schaltung ist nichts großartiges. Nochmal alles durchmessen und
dann wird das schon. Und dann machst du Version 2 bei der Software. Dann
läuft das auch. Abgesehen von der merkwürdigen Entprellung, sollte das
auch jetzt schon piepsen. Manche Piezos brauchen ein paar KOhm parallel,
damit sie was von sich geben.
Michael Becker schrieb:> Das sagt mir jetzt gar nix... gibt's dazu einen Link / Beitrag im Forum> / Beispielschaltplan? Ich hab mir vor allem die Beispiele hier> angeschaut:> http://www.avr-asm-tutorial.net/avr_de/index.html> Kann das ein Grund sein, dass die Schaltung gar nicht geht? Zumal es ja> auf der Steckplatine soweit klappt (auch ohne dieses wichtige Teil)
Der verhindert, daß beim Schalten im Controller und das passiert min.
1Mio/s, die Spannung kurz zusammenbricht, da ein hoher Strom gezogen
wird. Ist extrem kurz aber immer noch lang genug, um Fehlfunktionen
auszulösen. Da kommt kein Netzteil hinterher. Deshalb 100nF, Keramik.
Gilt für alle digitalen Bauteile.
mfg.
Vielen lieben Dank für die Tipps zum Coding - da gibt es sicher noch
Verbesserungspotenzial für eine Version 2, 3, 4 usw. :-) ich beschäftige
mich erst seit ein paar Tagen mit C - und Assembler hatte ich in der
Jugendzeit mal auf dem C64 etwas programmiert. Ansonsten kenne ich eher
die höheren Programmiersprachen (C#, Java, VisualBasic) - und da kümmert
man sich um viele Aspekte ja gar nicht so. Generell wird das mit dem
Coding aber schon hinhauen - viel schwerer tue ich mir bei der Hardware
und den Grundlagen der Elektrotechnik...
Ich hatte das Programm (da es nicht gelaufen ist) testweise um die
ganzen Teile für den Taster und den Sound verkürzt - also nur noch 3
LEDs sollen blinken/leuchten. Das komische ist, dass das Programm auf
meinem Test-Steckboard funktioniert, aber auf der selbst gebastelten
Platine nicht. Ok, ich hatte auch vorgestern zum ersten Mal einen
Lötkolben in der Hand... da ich mir nicht 100% sicher bin, dass alles
richtig verbunden ist, habe ich über die Brücke getestet - und dann geht
die LED ja auch an. Kann mir einfach nicht erklären, warum das Programm
einmal funktioniert und einmal nicht (also wo genau der Unterschied
zwischen Steckplatine und verlöteter Platine steckt...)
> Nochmal alles durchmessen und dann wird das schon.
Was/wie kann bzw. soll ich messen? Mir ist nur die Brücke eingefallen
(habe auch kaum Gerätschaften..)
> Willst ja nicht ewig mit deinem Sohn Schienenersatzverkehr spielen.
Das war der Auslöser, mich in die Thematik einzuarbeiten. Mein
eigentliches "Projekt" ist eine Steuerung der Weichen über
IR-Fernsteuerung und Servo. Dazu gibt es ja eine gute Vorlage:
http://www.avr-asm-tutorial.net/avr_de/ir/ir_tx/ir_tx.html
Habe auch einen Plan im Kopf, wie das theoretisch gehen sollte, aber ist
wohl noch ein weiter Weg... jetzt muss ich erst mal eine LED auf meiner
selbstgebastelten Platine zum Strahlen bringen...
VG Michael
Erst mal nochmal vielen Dank für die nächtliche Unterstützung!!
Ich habe heute früh alles neu gelötet - und es klappt (fast alles) :-))
Lauflicht und Speaker funktionieren (alle Outputs). Der Taster zum Ein-
und Ausschalten leider noch nicht auf der selbst gelöteten Platine.
Vermutlich habe ich einen Fehler drin (?):
Der Taster hängt zwischen PB4 und VCC, und nicht (wie ich jetzt in
einigen Beispielen gesehen habe) zwischen PB4 und GND... zwischen PB4
und GND geht der Taster mit folgendem Code (auf Steckplatine getestet):
1
intmain(void)
2
{
3
DDRB=0b00000001;// LED an PB0
4
PORTB=0b00010000;// Taster an PB4
5
6
while(1)
7
{
8
if((PINB&0b00010000)!=0)
9
{
10
// Taste nicht gedrückt --> LED aus
11
PORTB=0b00010001;
12
}
13
else
14
{
15
// Taste gedrückt --> LED an
16
PORTB=0b00010000;
17
}
18
}
19
}
Frage: Wenn der Taster zwischen PB4 und VCC (statt GND) hängt, kann ich
da softwaremäßig noch etwas retten? Oder muss ich umlöten?
Noch eine Frage: Nach meinem Verständnis können LEDs zwischen Pin und
VCC oder zwischen Pin und GND hängen - die LED geht dann in einem Fall
bei gesetztem Bit an und im anderen Fall bei gelöschtem Bit. Stimmt das
so?
PS: Sorry, dass ich mir die 0bxxxxxx Schreibweise noch nicht abgewöhnt
habe ;-) die Syntax (0 << 2) versteh ich noch nicht ganz - bleiben da
alle Bits, die nicht explizit gesetzt/gelöscht werden, unverändert? Und
wie würde ich dieses Statement (Prüfen ob PB4 nicht gesetzt ist) in der
"eleganteren" Syntax formulieren:
if ((PINB & 0b00010000) != 0)
VG Michael
Entweder du benutzt die internen Pullups (Nach Vcc) dann muss der Taster
nach GND schalten oder du benutzt externe Pull up/down Widerstände, dann
kannst du dir aussuchen wohin der Taster schaltet.
Michael Becker schrieb:> Der Taster hängt zwischen PB4 und VCC, und nicht (wie ich jetzt in> einigen Beispielen gesehen habe) zwischen PB4 und GND...
Dafür gibt es einen Grund, warum der Taster üblicherweise nach GND
geschaltet wird: Auf die Art kann man die eingebauten Pullup Widerstände
benutzen, und braucht keine externen Pulldown-Widerstände.
Hast du eigentlich die Tutorien
AVR-TutorialAVR-GCC-Tutorial
schon entdeckt?
Fast alle deine Fragen, die du seit gestern vorgebracht hast, sind da
drinnen abgehandelt.
> Frage: Wenn der Taster zwischen PB4 und VCC (statt GND) hängt, kann ich> da softwaremäßig noch etwas retten? Oder muss ich umlöten?
Löte es um.
Ist einfacher. Denn löten musst du sowieso. Egal ob du jetzt einen
zusätzlichen Pulldown-Widerstand einlötest oder den Taster umlötest.
> Noch eine Frage: Nach meinem Verständnis können LEDs zwischen Pin> und VCC oder zwischen Pin und GND hängen - die LED geht dann in einem> Fall bei gesetztem Bit an und im anderen Fall bei gelöschtem Bit.> Stimmt das so?
Du hast das Steckbrett vor dir.
Steck die LED entsprechend und probier es aus. Da beißt nichts.
Frank O. schrieb:> Wieso schreibt ihr alle 8 Bit auf den Port B?> Das ist ein 6 Bit Port.
Weil die kleinste Einheit in der Programmierung nun mal ein Byte ist.
Und 1 Byte besteht aus 8 Bit.
Manche Controller, wie zb dein Tiny, kennen auch nocht Einzelbitbefehle.
Aber die kennt der Compiler auch und ersetzt einen Byte-Portzugriff
durch diese Befehle, wenn das möglich ist (und du das in C so
geschrieben hast)
Michael Becker schrieb:> PS: Sorry, dass ich mir die 0bxxxxxx Schreibweise noch nicht abgewöhnt> habe ;-)
Solltest du aber. Ganz schnell!
> die Syntax (0 << 2) versteh ich noch nicht ganz
Die ist auch unsinnig. Eine 0 kann man nach links oder rechts schieben,
so oft man will. Das Ergebnis ist wieder 0.
Die Syntax um die es geht ist
1 << 5 (wobei die 5 nur ein mögliches Beispiel sind)
> - bleiben da> alle Bits, die nicht explizit gesetzt/gelöscht werden, unverändert?
Ist doch ganz simpel.
<< ist der Verschiebeoperator. D.h.
1 nimm eine binäre 1, also binär 00000001
1 << diese 1 wird nach links geschoben
1 << 5 zum Beispiel 5 mal nach links 00100000
Das Ergebnis ist ein Byte, bei dem das Bit an der Bitposition 5 auf 1
steht und alle anderen Bits sind 0.
1 << 3 ergibt ein Byte, bei dem das Bit an Position 3 auf 1 ist
1 << 6 ergibt ein Byte, bei dem das Bit an Position 6 auf 1 ist
1 << n ergibt ein Byte, bei dem das Bit an Position n auf 1 ist
Vielleicht siehst du jetzt, warum diese Schreibweise besser ist.
1 << x
sagt mir auf einen Blick, an welcher Position das eine 1 Bit ist. Bei
00100000
muss ich erst mal die 0-en links von der 1 zählen(*), damit ich dieselbe
Information habe.
1 << PB4
ergibt also ein Byte, das wenn ich es ausgebe, den kompletten Port B auf
0 setzt, mit Ausnahme des Pins PB4, der dann 1 ist. Da muss ich nicht
großartig Bits zählen. Das richtet mir der Compiler alles entsprechend
richtig her.
(*) mit der latenten Gefahr, dass ich mich verzähle.
Karl Heinz Buchegger schrieb:> Frank O. schrieb:>> Wieso schreibt ihr alle 8 Bit auf den Port B?>> Das ist ein 6 Bit Port.>> Weil die kleinste Einheit in der Programmierung nun mal ein Byte ist.> Und 1 Byte besteht aus 8 Bit.>> Manche Controller, wie zb dein Tiny, kennen auch nocht Einzelbitbefehle.> Aber die kennt der Compiler auch und ersetzt einen Byte-Portzugriff> durch diese Befehle, wenn das möglich ist (und du das in C so> geschrieben hast)
Dachte ich mir schon, dass das der Compiler macht. Stand so im Buch und
ich hatte auch erst mit acht Bit geschrieben (klappte ja auch), nur
nachdem ich im Buch viel weniger Stellen sah, da hab ich im Datenblatt
gelesen, dass es ein sechs Bit Port ist und war mir nicht mehr ganz
sicher, ob es mit acht Bit nicht zu Fehlern kommen könnte.
Dann fülle ich die fehlenden Bits für den Port mit Nullen auf?
Ist das richtig?
Hab bis jetzt nur Arduino gemacht und gerade erst mi C begonnen.
Frank O. schrieb:> nachdem ich im Buch viel weniger Stellen sah, da hab ich im Datenblatt> gelesen, dass es ein sechs Bit Port ist
Der Port ist intern genauso 8 Bit breit.
Nur kannst du eben 2 Bits so nicht benutzen, weil sie nicht auf Pins
herausgeführt sind.
Das ist alles.
Karl Heinz Buchegger schrieb:> Frank O. schrieb:>>> nachdem ich im Buch viel weniger Stellen sah, da hab ich im Datenblatt>> gelesen, dass es ein sechs Bit Port ist>> Der Port ist intern genauso 8 Bit breit.> Nur kannst du eben 2 Bits so nicht benutzen, weil sie nicht auf Pins> herausgeführt sind.> Das ist alles.
Karl-Heinz,
schreib doch mal ein Buch! Ich bin der erste Käufer!!!!
Du kannst das alles immer so klasse erklären. Gut, dass wir dich
haben!:-)
Danke!
Noch weiter zur Syntax.
Den bisher war das ja nur die halbe Miete.
Denn in einem realen Programm werde ich nicht schreiben
1
PORTB|=(1<<PB4);
um den Portpin PB4 auf 1 zu setzen.
In einem realen Projekt hängt an diesem Pin eine Hardware. Zb eine LED.
Zb. eine rote LED.
Also definiere ich mir dafür ein #define
1
#define LED_ROT PB4
und verwende das entsprechend
1
#define LED_ROT PB4
2
...
3
4
5
PORTB|=(1<<LED_ROT);
und holla, jetzt kann ich ganz plötzlich im Code ablesen, was da
eigentlich an dieser Stelle passiert! In der Anweisung ist da jetzt
enthalten, dass da etwas mit der roten Led passiert. Und nicht mit der
gelben!
Dass diese rote LED am Pin PB4 hängt, ist zwar nett, aber es ist nichts
was mich beim Ein- Ausschalten der Led großartig interessieren müsste
1
#define F_CPU 1000000
2
3
#include<avr/io.h>
4
#include<utils/delay.h>
5
6
7
#define LED_ROT PB4
8
9
10
intmain()
11
{
12
DDRB|=(1<<LED_ROT);
13
14
while(1)
15
{
16
PORTB|=(1<<LED_ROT);
17
_delay_ms(500);
18
19
PORTB&=~(1<<LED_ROT);
20
_delay_ms(500);
21
}
22
}
Innerhalb des Programm-Codes arbeite ich nur noch mit der 'roten LED'
und nciht mehr mit PB4. Muss ich die LED von PB4 auf PB2 umlöten, dann
ändere ich genau 1 Stelle
1
#define LED_ROT PB2
und die restliche Programmanpassung erledigt mein C-Compiler.
(Ein #define macht einfach nur eine Textersetzung. Dort wo ich LED_ROT
geschrieben habe, wird dieser Text durch den Präprozessor dann durch PB4
ausgetauscht. D.h. Obwohl ich
1
PORTB|=(1<<LED_ROT);
geschrieben habe, kriegt der Compiler nach der Textersetzung wieder
1
PORTB|=(1<<PB4);
zu sehen. Dadurch ist beides gleichwertig. Aber der Gewinn an
Dokumenation, den ich durch LED_ROT habe (oder LED_ERROR oder SUMMER
oder ...) hebt das Programm von der Verstehbarkeit her gleich in eine
ganz neue Kategorie.
Karl Heinz Buchegger schrieb:> Innerhalb des Programm-Codes arbeite ich nur noch mit der 'roten LED'> und nciht mehr mit PB4. Muss ich die LED von PB4 auf PB2 umlöten, dann> ändere ich genau 1 Stelle>
1
>#defineLED_ROTPB2
2
>
> und die restliche Programmanpassung erledigt mein C-Compiler.
Das wäre schon mal ein (ganz kurzes) prägnantes Kapitel für dein neues
Buch.
Das hab ich in Arduino dann ja auch schon so gemacht.
Hier wollte ich mich erstmal an die Schreibweise des Buches halten und
auch so allmählich kapieren wie das in dem µC so richtig funktioniert.
Das war bei Arduino nicht erfoderlich.
Datenblatt liegt neben mir und ich hatte gestern schon mal von vorne
angefangen zu lesen.
Ich mache immer alles so crossover; mal hier ein wenig löten, gestern
den LA zum laufen gebracht, wieder etwas programmieren. Halt wie es
meine Zeit erlaubt. Außerdem lese ich ununterbrochen hier im
Mikrocontrollernet mit, damit ich dadurch vieles lerne.
Aber nun will ich nicht länger den Thread kapern, da sich das nicht
gehört.
Wirklich Karl-Heinz, schreib ein Buch! Du wirst viele Anfänger glücklich
machen.
Hallo Karl-Heinz,
vielen Dank für die sehr verständlichen Erläuterungen - langsam fällt
der Groschen bei mir, hoffe ich...
Mit der "kompakten" Schreibweise tue ich mir noch etwas schwer:
<c> PORTB |= ( 1 << LED_ROT );
_delay_ms( 500 );
PORTB &= ~( 1 << LED_ROT );
_delay_ms( 500 );</c>
In der ersten Zeile wird das LED_ROT Bit auf 1 gesetzt und der Rest des
Ports bleibt unberührt, da vor dem "=" dieser Strich "|" steht, oder?
Wenn ich PORTB = ( 1 << LED_ROT ); schreiben würde, würden allen anderen
Bits außer LED_ROT gelöscht, oder?
In der dritten Zeile wird das LED_ROT Bit auf 0 gesetzt, vermute ich -
aber verstehe nicht genau, warum...
--> (1 << LED_ROT) schiebt ein gesetztes Bit an die richtige Stelle
--> ~(..) --> was macht das? Aus 1 eine 0?
--> &= macht dann eine UND-Verknüpfung, damit der Rest des Ports
unverändert bleibt?
Ich weiß, dass diese Fragen in verschiedenen Tutorials etc. sicherlich
ausführlich erklärt werden. Habe auch die von Dir genannten Tutorials
(teilweise) gelesen, aber als Anfänger ist es oft schwierig, die
"theoretischen" Erklärungen auf den konkreten Anwendungsfall zu
übertragen...
Bei meinem kleinen Projekt "Alarmanlage", die per Tastendruck ein- und
ausgeschaltet werden soll, habe ich noch ein (hoffentlich letztes)
Problem. Ich habe mir die Anleitung zur Entprellung angeschaut
(http://www.mikrocontroller.net/articles/Entprellung) und in mein
Programm eingebaut.
entprellung( &PINB, (1<<PINB4) ); // da hängt der Taster dran
if( PINB & (1<<PINB4) ) // falls Taste gedrückt, Alarm an oder aus
(switch)
{if(alarmOnOff == 1) alarmOnOff = 0; else alarmOnOff=1;}
if (alarmOnOff == 1)
// LEDs und Speaker an
else
// alles aus
void entprellung( volatile uint8_t *port, uint8_t maske ) {
uint8_t port_puffer;
uint8_t entprellungs_puffer;
for( entprellungs_puffer=0 ; entprellungs_puffer!=0xff ; ) {
entprellungs_puffer<<=1;
port_puffer = *port;
_delay_us(150);
if( (*port & maske) == (port_puffer & maske) )
entprellungs_puffer |= 0x01;
}
}
Der Alarm soll über ersten Tastendruck eingeschaltet werden, über
nächsten Tastendruck wieder aus usw. (also immer abwechselnd). Leider
ist bei o. g. Code das Verhalten ziemlich unberechenbar (manchmal
passiert gar nix bei Tastendruck, dann geht der Alarm eine Zeitlang an
und ohne Tastendruck wieder aus etc.)
Hast Du eine Idee? Vermutlich ja :-))
Freue mich echt sehr über die Hilfsbereitschaft und Geduld hier im
Forum. Natürlich probier ich auch selbst immer wieder neue Korrekturen,
aber komme teilweise nicht weiter (nur damit nicht der Eindruck
entsteht, ich wäre zu "faul" zum selber lesen und probieren ;-)
VG