Forum: Compiler & IDEs Port als Variable


von Jürgen (Gast)


Lesenswert?

Hallo,

ich möchte gern Atmel-Controller (myAVR) in der Schule einsetzen und 
hatte dazu einen Lehrgang besucht, in dem mit E-Lab AVRco (Pascal) 
programmiert wurde.

Nun gefällt mir Pascal nicht sonderlich und ich würde gern in C/C++ 
programmieren, auch weil es da mehr Hilfe und mehr Beispiele gibt.

Soweit so gut, einige Testprogramme aus Pascal konnte ich bereits in C 
nachvollziehen, aber an einer Sache beiße ich mir gerade die Zähne aus. 
In AVRco kann man einfach einem Port eine Variable zuweisen und diese 
Variable 1 oder 0 setzen:

var ledrt[@PortB,0]:bit;  //Variable für rote LED an Port B0, Typ bit
var ledge[@PortB,1]:bit;
...
ledrt:=1;
ledge:=0;
mdelay(300);
ledrt:=0;
ledge:=1;
mdelay(300);

In Entwicklungsumgebungen, die auf avr-gcc beruhen, habe ich keine 
solche Möglichkeit gefunden. Ich kann zwar der Portnummer eine Variable 
zuordnen, die Zuweisung des Status an/aus ist aber dann wesentlich 
kryptischer:

#define ledrt PORTB0
#define ledge PORTB1
...
PORTB |= (1<<ledrt);
PORTB &= ~(1<<ledge);
_delay_ms(300);
PORTB |= (1<<ledge);
PORTB &= ~(1<<ledrt);
_delay_ms(300);

Der Pascal-Code ist deutlich anschaulicher, auch wenn man an dem 
C-Beispiel gleich die Boolesche Algebra erklären kann.

Gibt es eine Pascal-ähnliche Syntax in C/C++?

Vielen Dank schon mal!
Jürgen

von Karl H. (kbuchegg)


Lesenswert?

Jürgen schrieb:

> solche Möglichkeit gefunden. Ich kann zwar der Portnummer eine Variable
> zuordnen, die Zuweisung des Status an/aus ist aber dann wesentlich
> kryptischer:
>
> #define ledrt PORTB0
> #define ledge PORTB1
> ...
> PORTB |= (1<<ledrt);
> PORTB &= ~(1<<ledge);
> _delay_ms(300);
> PORTB |= (1<<ledge);
> PORTB &= ~(1<<ledrt);
> _delay_ms(300);

Gewöhn dich daran.


> Gibt es eine Pascal-ähnliche Syntax in C/C++?

Wie gut sind deine C-Kentnisse?
Klar kann man. Nur eben nicht 'out of the box'. Aber für einen C-Kenner 
ist das kein Problem.

Nur um mal die einfchste Variante zu zeigen
1
#define SET_BIT(p,b)  (p) |= (1<<(b))
2
#define CLR_BIT(p,b)  (p) &= ~(1<<(b))
3
4
#define ERROR_LED_PORT   PORTB
5
#define RED_LED          PB0
6
#define YELLOW_LED       PB1
7
...
8
9
10
int main()
11
{
12
  ...
13
14
15
  SET_BIT( ERROR_LED_PORT, RED_LED );
16
  CLR_BIT( ERROR_LED_PORT, YELLOW_LED );
17
18
  ...
19
}

Oder, das ganze noch eine Klkeinigkeit weiter getrieben
1
#define SET_BIT(p,b)  (p) |= (1<<(b))
2
#define CLR_BIT(p,b)  (p) &= ~(1<<(b))
3
4
#define ERROR_LED_PORT   PORTB
5
#define RED_LED          PB0
6
#define YELLOW_LED       PB1
7
...
8
9
#define RED_ERROR_LED_ON    SET_BIT( ERROR_LED_PORT, RED_LED )
10
#define RED_ERROR_LED_OFF   CLR_BIT( ERROR_LED_PORT, RED_LED )
11
...
12
13
int main()
14
{
15
  ...
16
17
  RED_ERROR_LED_ON;
18
19
  ...

oder man kann sich dafür Funktionen schreiben. Oder ....
Und man kann natürlich, wenn man es kann, sich auch etwas zurecht legen, 
so dass man schreiben kann
1
int main()
2
{
3
4
    ErrorPort.RedLed = ON;
5
6
...

Hängt alles nur davon ab, wie gut dein C ist.
Aber: Da jeder eine andere Vorstellung davon hat, wie sowas aussehen 
sollte, gibt es da kaum Standard-Verfahren, bzw. man landet auf 
unterster Stufe immer wieder beim

   PORTB |= ( 1 << PB0 );

das ist nun mal das universellste und alles weitere leitet sich davon 
ab. PS: Was machst du, wenn du wirklich mehrere Portpins auf einmal auf 
1 setzen willst? In C schreibst du

   PORTB |= ( 1 << PB0 ) | ( 1 << PB1 );

bzw. mit entsprechendem Makro-Ersatz dann eben auch mit sprechenderen 
Namen. Aber: es geht. Du kannst in einem Aufwasch mehrere Portpins auf 
einmal schalten.

von troll (Gast)


Lesenswert?

Jürgen schrieb:
> Gibt es eine Pascal-ähnliche Syntax in C/C++?
Über Bitfelder (eher was für Fortgeschrittene) 
Beitrag "Re: "Syntaxbefehl" erstellen" oder 
Präprozessormakros
#define AN(p,v) (p|=(1<<v))
#define AUS(p,v) (p&=~(1<<v))
und das Spiel kann man dann weiter treiben
#define PORTLED PORTB
#define LED1 3
#define LED1_AN AN(PORTLED,LED1)
usw.

von troll (Gast)


Lesenswert?

KHB war mal wieder schneller. :-)

von Karl H. (kbuchegg)


Lesenswert?

Und Ach ja.

Die Schwierigkeit bei Programmen aus der realen Welt besteht ja darin 
die Logik hinzukriegen und nicht welche Syntax man jetzt benutzt um 
einen Portpin auf 0 oder auf 1 zu schalten. In der Praxis sehen die 
wenigsten Programme nun mal so aus
1
int main()
2
{
3
  DDRB |= ( 1 << PB0 ) | ( 1 << PB1 );
4
5
  while( 1 ) {
6
7
    PORTB |= ( 1 << PB0 );
8
    PORTB &= ~( 1 << PB1 );
9
    _delay_ms( 1000 );
10
11
    PORTB &= ~( 1 << PB0 );
12
    PORTB |= ( 1 << PB1 );
13
    _delay_ms( 1000 );
14
  }
15
}

Sowas ist ja die Ausnahme. Reale Programme haben einen wesentlich 
höheren Logikanteil, so dass die paar Portzuweisungen kaum ins Gewicht 
fallen. Und wenns einen stört, dann versteckt man die eben hinter 
Makros.

von Julius (Gast)


Lesenswert?

Also Bitfelder finde ich gar nicht sooo schwierig besonders wenn die 
schon vordefiniert sind ;-) mit einem myAVR hast doch schon sowas schau 
mal hier: http://www.avr-cpp.de das sieht dann in etwa so  aus:
1
   ...
2
   ddrB.bit0=1;   // B.0 auf Ausgang
3
   portB.bit0=1;  // B.0 LED an
4
   ...

Gruß J.

von Peter D. (peda)


Lesenswert?

Jürgen schrieb:
> die Zuweisung des Status an/aus ist aber dann wesentlich
> kryptischer:

Nö, muß man nicht.
Es geht auch ähnlich einfach, wie unter Pascal:
1
#include "sbit.h"
2
#define IN_A      PIN_D2
3
#define OUT_A     PORT_D5
4
#define OUT_A_oe  DDR_D5
5
6
int main(void)
7
{
8
    OUT_A_oe = 1;
9
10
    while(1)
11
    {
12
        if(IN_A)
13
          OUT_A = 1;
14
        else
15
          OUT_A = 0;
16
        // oder so:
17
        OUT_A = IN_A; // ist aber mehr Code
18
    }
19
}

http://www.mikrocontroller.net/attachment/157663/sbit.h

von Jürgen (Gast)


Lesenswert?

Danke für den Tip mit sbit.h - das ist genau was ich will und dazu (so 
hoffe ich) auch frei.
1
#include  <avr\io.h>
2
#include  <avr\sbit.h>
3
#define Taster  PIN_D2  
4
#define LED     PORT_D5
5
6
int main(void)
7
{
8
    PORT_D2 = 1;     // Pull-Up-Widerstand 
9
    DDR_D5 = 1;       // Ausgang setzen
10
11
    while(1)
12
    {
13
        if(Taster)
14
          LED = 1;
15
        else
16
          LED = 0;
17
    }
18
}

SiSy (http://sisy.de) gefällt mir zwar noch besser (objektorientiert), 
kostet aber als Schulversion 49 EUR je Arbeitsplatz und zeigte unter Win 
7 Probleme bei normalen Benutzerrechten.

Jürgen

von iab (Gast)


Lesenswert?

> #include  <avr\io.h>

Besser:

#include  <avr/io.h>

da portabler.

Noch besser:

#include  <io.h>

und den Includepfad per Compileroption auf .../avr
setzen.

von Oliver (Gast)


Lesenswert?

iab schrieb:
> Noch besser:
> #include  <io.h>
>
> und den Includepfad per Compileroption auf .../avr
> setzen.

Warum sollte das noch besser sein? Das einzige, was du damit erreichst, 
ist, daß sich deinen Programme auf keiner anderen 
avr-gcc-Standardinstallation ohne Anpassungen compilieren lassen.
1
#include  <avr/io.h>
ist Standard, und dabei solte man auch bleiben.

Oliver

von Julius (Gast)


Lesenswert?

Hallo,

ich halte die GCC-Standard-Installation nicht unbedingt für den Stein 
der Weisen und das oberste Ende der Entwicklung. Der GCC ist eher eine 
Basis von der aus man ausgehen kann und etwas auf seine Bedürfnisse 
zuschneiden  oder weiterentwickeln kann. Das Sieht man deutlich bei den 
kommerziellen oder herstellerspezifischen Umgebungen. Es taucht hier 
immer wieder das Bedürfnis ich nenne es mal "moderneren" 
Sprachkonstrukten als Shift-Opreationen zu benutzen. Solche Angebote 
wie:

http://www.luna.de
http://www.avr-cpp.de
http://sourceforge.net/projects/veavrcclasslibr/
http://www.mySTM32.de
usw. usw.

kann man nicht einfach wegbügeln mit "das ist kein GCC-Standard deswegen 
mach das nicht" besser ist es darüber konstruktiv zu diskutieren. So das 
musste mal raus ;-)

Also ich find es absolut OK wenn er sich seine IDE verbiegt :-D er 
erkundet wie es besser gehen kann und lernt und wir lernen mit ihm

Gruß J.

von Julius (Gast)


Lesenswert?

so sorry

http://avr.myluna.de/doku.php

das gemüse meinte ich nicht ;-)

von Oliver (Gast)


Lesenswert?

Julius schrieb:
> Es taucht hier
> immer wieder das Bedürfnis ich nenne es mal "moderneren"
> Sprachkonstrukten als Shift-Opreationen zu benutzen.

Klar kann man sich für Port-IO elegantere Lösungen denken, als das 
Standard-C-Bitgeschubse, aber:

Ich sach mal so: In jeder ernsthaften Anwendung, die über das erste 
Testprogramm "LED-Blinken" hinausgeht, machen die Port-IO-Operationen 
weniger als 0,00x% des gesamten Codes aus. Wer da schon an den 
Bitoperationen scheitert, kriegt den Rest eh nicht hin.

Und die, die den Rest hinkriegen, die störten die paar Zeilen nicht.

Das es mit Arduino, Luna, Bascom, et. al. alternative toolchains mit 
Vor- und Nachteilen gegenüber einem avr-gcc mit avrlibc gibt, ist prima. 
So hat jeder die freie Wahl.

Vorhandene libs der Struturen auf Sourccde-Ebene zu erweitern, ist eine 
geute Sache. IDEs verbiegen ohne sinnvollen Grund zu verbiegen ist 
dagegen keine gute Idee. Spätestens mit dem nächste Update läuft man 
damit voll in die Schxxxe.

Oliver

von Rolf M. (rmagnus)


Lesenswert?

Julius schrieb:
> ich halte die GCC-Standard-Installation nicht unbedingt für den Stein
> der Weisen und das oberste Ende der Entwicklung.

Das bedeutet aber nicht, dass man es deshalb zwanghaft anders machen 
muss. Ich finde ein avr/io.h auch besser als nur io.h. Das ist ähnlich 
wie in C++ mit Namespaces. Man verteilt die Header auf verschiedene 
Verzeichnisse, abhängig davon, für welchen Bereich von Funktionalität 
sie verwendet werden. Und man läuft nicht Gefahr, dass sich jemand ein 
eigenes io.h definiert hat, das dann damit kollidiert.
Das ist etwas, das sehr viele Bibliotheken so machen. Was findest du 
daran schlecht?

> kann man nicht einfach wegbügeln mit "das ist kein GCC-Standard deswegen
> mach das nicht" besser ist es darüber konstruktiv zu diskutieren. So das
> musste mal raus ;-)

Es geht nicht um GCC selbst, sondern eher um die avr-libc. Und ich kann 
umgekehrt auch sagen, nur weil die von dir genannten Projekte es 
irgendwie anders machen, heißt das nicht, dass das der Stein der Weisen 
ist und man bei der Benutzung von avr-libc die avr-libc-Gepflogenheiten 
verwerfen sollte.

> Also ich find es absolut OK wenn er sich seine IDE verbiegt :-D er
> erkundet wie es besser gehen kann und lernt und wir lernen mit ihm

Wie schon gesagt wurde: Was du vorschlägst, ist nicht besser. Es hat 
keinerlei Vorteil, außer dass man 4 Zeichen weniger tippen muss.
Und wenn man etwas "verbiegen" muss, weil man es anders machen will als 
alle anderen, dann ist das zwar nicht immer, aber doch meistens ein 
Zeichen dafür, dass man was falsch macht.

: Bearbeitet durch User
von Peter D. (peda)


Lesenswert?

Rolf M. schrieb:
> Das bedeutet aber nicht ...

Ob Julius nach 6 Jahren noch mitliest?

von Rolf M. (rmagnus)


Lesenswert?

Huch? Warum wurde mir der Thread als einer mit neuen Beiträgen 
angezeigt? Ich bin verwirrt…

von Treadnecrophilist (Gast)


Lesenswert?

Ich verwende, weil es besser lesbar ist, meine util.h in jedem Projekt.
1
#define SETBIT(REG, PIN) ((REG) |= (uint32_t) 1 << (PIN))
2
#define CLEARBIT(REG, PIN) ((REG) &= ~((uint32_t) 1 << (PIN)))
3
#define CHANGEBIT(REG, PIN, WERT) ((WERT) ? SETBIT((REG), (PIN)) : CLEARBIT((REG), (PIN)))
4
#define READBIT(REG, PIN) (((REG) >> (PIN)) & 1)
zum Bleistift:
1
CHANGEBIT(errorvariable, MainPowerError);
Kann man auf Variablen und auch auf Ports verwenden.

o/
Necrophilist ;)

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.