Forum: Compiler & IDEs Anfängerfrage zu IO´s


von Marc D. (drebin)


Lesenswert?

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

von Johannes M. (johnny-m)


Lesenswert?

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.

von Marc D. (drebin)


Lesenswert?

Vielen vielen Dank!
Es hat sprichwörtlich "klick" gemacht.

Gruuß, Marc

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

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 ;-).

von Peter D. (peda)


Lesenswert?

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:
1
#include <io.h>
2
3
4
struct bits {
5
  uint8_t b0:1;
6
  uint8_t b1:1;
7
  uint8_t b2:1;
8
  uint8_t b3:1;
9
  uint8_t b4:1;
10
  uint8_t b5:1;
11
  uint8_t b6:1;
12
  uint8_t b7:1;
13
} __attribute__((__packed__));
14
15
16
#define SBIT(port,pin) ((*(volatile struct bits*)&port).b##pin)
17
18
19
#define PINB_2  SBIT( PINB, 2 )
20
#define PORTB_3 SBIT( PORTB, 3 )
21
22
23
void test( void )
24
{
25
 if (PINB_2 == 1){
26
   PORTB_3 = 1;
27
 }
28
}


Peter

von Marc D. (drebin)


Angehängte Dateien:

Lesenswert?

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

von Rolf Magnus (Gast)


Lesenswert?

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.
1
#define VOLT(wert) ((wert) * 1024.0 / 5.0)
2
...
3
 else if (adcwert1 <= VOLT(1.79)))

von Marc D. (drebin)


Lesenswert?

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

von Karl H. (kbuchegg)


Lesenswert?

Hier
1
     else if(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.

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
Noch kein Account? Hier anmelden.