Hallo Gemeinde,
ich bin gerade dabei, mir den GCC mit einem Atmega8L anzueignen. Dabei
benutze ich das AVR Studio 4 sowie WINAVR. Das Brennen funktioniert
einwandfrei, LED´s
habe ich auf meinem myAVR USB Board auch schon zum Blinken gebracht ;-).
Nun habe ich aber eine Frage zum TuT zum Auswerten der PAx bzw. PINx.
Im TuT steht folgendes Bsp:
1
while(!(WARTEPIN&(1<<WARTEBIT)));
weiter unten:
1
#include<avr/io.h>
2
...
3
/* Fuehre Aktion aus, wenn Bit Nr. 1 (das "zweite" Bit) in PINC gesetzt (1) ist */
4
if(PINC&(1<<PINC1)){
5
/* Aktion */
6
}
7
/* Fuehre Aktion aus, wenn Bit Nr. 2 (das "dritte" Bit) in PINB geloescht (0) ist */
8
if(!(PINB&(1<<PINB2))){
9
/* Aktion */
10
}
11
...
Ich versteh leider den Zusammenhang für die Abfrage des z.B. PINB nicht,
wenn es expliziet um den PINB2 geht. ->(if (PINB & (1<<PINB2)) ..
Ich mit meinem Anfängerwissen hätte es so geschrieben:
1
if(PINB2==1)
.... hoffentlich hab ich mich jetzt nicht zum Affen gemacht :-)
Viele Grüße und Danke schonmal im Voraus..
Gruß, Marc
PINB2 ist lediglich die Position des Pins im I/O-Register, die in der
betreffenden Header-Datei definiert ist (Da steht irgendwo "#define
PINB2 2"). PINB2 ist lediglich eine Zahl (eine 2, um genau zu sein).
ANSI-C-Compiler wie der AVR-GCC können nicht auf einzelne Bits
zugreifen. Die kleinste verarbeitbare Datenmenge sind auf der
AVR-Plattform 8 Bit. Um einzelne Bits zu manipulieren, muss man deshalb
zu "Tricks" greifen. Im Artikel Bitmanipulation ist beschrieben, wie
und warum es geht.
Kommerzielle Compiler haben i.d.R. µC-spezifische Erweiterungen für
Bitzugriffe, die aber nicht Standard-konform und demzufolge auch nicht
portierbar sind. Die "1 << BIT"-Schreibweise hingegen versteht jeder
C-Compiler.
Kleine Anmerkung nur:
Johannes M. wrote:
> Kommerzielle Compiler haben i.d.R. µC-spezifische Erweiterungen für> Bitzugriffe, ...
s/i.d.R./manchmal/
Nicht jeder hat sowas, und bspw. ein IAR lebt auch komplett konform
mit dem Standard -- immerhin eine Art Flaggschiff unter den
kommerziellen Compilern (sowohl von der Codequalität als auch vom
Preis ;-).
Marc D. wrote:
> Ich mit meinem Anfängerwissen hätte es so geschrieben:>>
1
if(PINB2==1)
>> .... hoffentlich hab ich mich jetzt nicht zum Affen gemacht :-)
Nö, garnicht.
Allerdings ist PINB2 etwas anders definiert, als Du denkst.
Um es so zu schreiben, wie Du es vorhast, muß man es etwas anders
definieren (daher besser einen anderen Namen wählen).
So definiert und verwendet man Bitvariablen:
Hallo zusammen!
Besten Dank noch einmal für Eure Unterstützung!
@Peter: nochmehr vielen Dank für die Mühe :-)
Ich werd mich da eher an die Schreibweise wie im GCC-TUT halten :-).
Zu viele versch. Schreibweisen bringen mich im Moment noch ziemlich
durcheinander. Gerade auch bei den "einfachen" Sachen wie setzen von
Variablen
...die einen schreiben es so wie im TUT mit u_int8 usw.
da hab ich mich noch nicht daran gewöhnt. Bei mir ist´s noch immer das
unsigned int usw... ;-)
Ich denke, ich hab bis jetzt ganz gut Meter gemacht, was das lernen
betrifft. Mir fehlt jetzt nur noch die Routine.
Im Rahmen meiner Facharbeit für den Techniker will ich ein LCD-Display
für
mein Motorrad entwerfen.. Drehzal, Geschwindigkeit und eingelegte
Gangstufe
sollen dabei angezeigt werden. Den AD-Wandler hab ich jetzt soweit
fertig durchgearbeitet. Der sowie die ganzen LCD Sachen funktionieren
auch.
Jetzt fehlt nur noch die Interruptbehandlung mit den Timern und
Countern.
Könntet "Ihr" Euch aber vllt. mal meinen Code anschauen? Ich denke, der
ist einigermassen lesbar formatiert.
Wie gesagt, bin noch in der Lernphase und beschäftige mich damit seit
gut 1 Woche.
Danke schonmal für Eure Kritik!
Vielen Dank und Gruß, Marc
Kommentare zum Code:
F_CPU muß vor den #includes, oder besser noch gleich im Makefile
definiert werden. Wahrscheinlich ist es das auch bei dir, sonst hättest
du beim #include eine Fehlermeldung bekommen, daß es nicht definiert
ist.
Dein Einrückungs-Stil ist ziemlich chaotisch.
Verschachtelte Funktionen sind in C eigentlich nicht erlaubt. Es gibt
auch keinen wirklichen Grund, ReadChannel innerhalb von main zu
definieren, und es verwirrt auch eher. Stecke die Funktion nach außen.
Ein unsigned long ist für die Mittelwert-Bildung eigentlich nicht nötig,
(aber auch nicht wirklich schädlich). Der ADC arbeitet mit 10 Bit, daher
paßt die Summe zweier Wandlungen in 11 Bits, also reicht ein 16-Bit-Wert
dafür locker aus.
> gangstufe=0x4E; //wenn ja, ASCII für N wird gezeigt
Wenn du ein N haben willst, schreib das doch einfach hin:
1
gangstufe='N';
> else if(adcwert1<=365) //Vergleich mit ADC-Wert für Uadc=1,79V
Hier könnte man sich zur Übersichtlichkeit ein Makro schreiben, das die
Umrechnung des adc-Werts in Volt macht. Solange man mit
Compilezeit-Konstanten arbeitet, wird die Berechnung auch im Compiler
gemacht, es produziert also keinen Overhead.
Hallo Rolf,
vielen Dank für Deinen Beitrag!
Solche Kommentare helfen ungemein... weil ich wie gesagt noch
nicht so den Überblick habe, weder mit der Programmiersprache C noch
mit dem Atmel.
Also, ich gelobe Besserung und Deine Info´s werden natürlich in meine
zukünftige Schreibweise mit einfliessen ;-).
Also, wem noch mehr auffällt, nur zu!!!
Gruß, Marc
elseif(adcwert1>=891)//Vergleich mit ADC-Wert f�r Uadc=4,69V
2
gangstufe=0x36;//wenn ja, ASCII f�r 6 wird gezeigt
3
4
lcd_gotoxy(0,0);//Cursor erste Position
5
lcd_puts("km/h:");//Vorbereitung f�r Geschw.
6
7
8
lcd_gotoxy(10,0);//Cursor so ziemlich letzte Pos Zeile1
9
lcd_puts("Gang:");//dauerhaftes Anzeigen von "Gang:"
10
lcd_gotoxy(15,0);//Cursor hinter ":" setzen
11
lcd_putc(gangstufe);//Anzeigen des ASCII -Zeichens
12
13
lcd_gotoxy(0,1);//Cursor n�chste Zeile
14
lcd_puts("U/min:");//Vorbereitung Drehzahl
15
16
_delay_ms(60);//n�tig, da Clear-Screen als n�chstes
17
lcd_clrscr();// zuk�nftig noch n�tig f�r korr Drehzahl
18
}
Mir gehts um das lcd_clrscr().
Grundsätzlich bin ich kein Freund von ständigem Clear Screen.
Meist tendiert das zu mächtigem Geflacker.
Soviel aber nur als Einschub.
Überleg mal. Nach dem lcd_clrscr(). Was passiert alles bevor
wieder aufs Display geschrieben wird? Oder mit anderen Worten:
Was passiert alles, solange das Display leer ist?
Das ist ne ganze Menge: Da wird der ADC ausgelesen, da werden
auszugebende Buchstaben bestimmt, etc.
In dieser ganzen Zeit ist das Display leer. Gibt es einen Grund
dafür, warum das so sein muss? Nein, nicht wirklich.
Es reicht doch völlig aus, daß das Display gelöscht wird (wenn
es denn unbedingt sein muss, dass es komplett gelöscht wird) kurz
bevor die nächste Ausgabe hingepinselt wird. Auf diese Art ist
jede einzelne Ausgabe maximal lang zu sehen und das Display ist
nur minimal lang leer.
1
lcd_clrscr();// zuk�nftig noch n�tig f�r korr Drehzahl
2
3
lcd_gotoxy(0,0);//Cursor erste Position
4
lcd_puts("km/h:");//Vorbereitung f�r Geschw.
5
6
7
lcd_gotoxy(10,0);//Cursor so ziemlich letzte Pos Zeile1
8
lcd_puts("Gang:");//dauerhaftes Anzeigen von "Gang:"
9
lcd_gotoxy(15,0);//Cursor hinter ":" setzen
10
lcd_putc(gangstufe);//Anzeigen des ASCII -Zeichens
11
12
lcd_gotoxy(0,1);//Cursor n�chste Zeile
13
lcd_puts("U/min:");//Vorbereitung Drehzahl
14
15
_delay_ms(60);//n�tig, da Clear-Screen als n�chstes
Der erste lcd_gotoxy kann dann wahrscheinlich auch entfallen,
da der clrscr() den Cursor normalerweise in die Homeposition
bringt.
Ob der _delay_ms da am Ende noch notwendig ist, musst du ausprobieren.
Auf jeden Fall kann er aber wesentlich kürzer ausgeführt werden.
Kürzere delay -> mehr Rechenzeit für die wirklich wichtigen Dinge
wie zb. Messdaten besorgen und aufbereiten.