Forum: Projekte & Code Vorstellung EasyIO.h


von Björn W. (papayawhip)


Lesenswert?

Hallo zusammen,

ich habe eine kleine Datei auf GitHub geworfen, die möglicherweise bei 
kleinen und schnellen Projekten helfen kann.

Da ich auch von Verbesserungen profitieren kann, nehme ich Anregungen 
und Korrekturen gerne entgegen.


Im Prinzip habe ich mir nur eine Header Datei gebaut, mit der ich extrem 
schnell und einfach auf Port und Pin Register zugreifen kann und ich 
deren Belegung per definements ändern kann.

Gruß Björn


https://github.com/BjWe/avr-minitools
https://github.com/BjWe/avr-minitools/blob/master/EasyIO.h


Beispiel:

global.h

...
#define SWITCH1  B,3  // (Für PORTB 3)
...

main.c

...
SETPIN(SWITCH1);   // Als PIN definieren
SETON(SWITCH1);    // Pullups an

if(ISNSET(SWITCH1)){
  ...
}
...

von SE (Gast)


Lesenswert?

Schöne kleine Makro-Sammlung.

Gefällt mir gut, werde das mal im nächsten Projekt mit einbauen.
Danke fürs teilen.

von Andy Y. (merlin129)


Lesenswert?

Es ist zwar nicht immer gut zusätzliche Abstraktionsschichten 
einzubauen, aber das gefällt mir wirklich gut. Herzlichen Dank für's 
veröffentlichen.

von Sven (Gast)


Lesenswert?

Gefällt mir sehr gut! Danke!

lg Sven

von Mw E. (Firma: fritzler-avr.de) (fritzler)


Lesenswert?

@Andreas Pantle
Was ist an defines jetzt eine zusätzliche Abstraktionsschicht?
Das wird einfach vom Precompiler als C Code eingesetzt als hätt mans 
selber an die entsprechende Stelle getippt.

von Nils S. (kruemeltee) Benutzerseite


Lesenswert?

Naja, wie abstrahiert wird tut nichts zur Sache (Funktionen, #defines).

Ein SetPin(PORTB, 0) ist einfacher  als PORTD |= (1<<PB0). Aber ob das 
schon als "abstrahiert" oder nur umbenannt gilt, ist die Frage.

Einfach wie bei Arduino. Alle freien Pins in einen "virtuellen Port" 
packen, drei Funktionen drumherum und keiner muss mehr denken.

von Andy Y. (merlin129)


Lesenswert?

Hmm - nochmals zum klarstellen: Ich finde den Code Klasse und spiele 
auch damit herum.
Wie auch immer, für mich ist es eben so, auch über Defines und gerade da 
weil es u.U. nicht immer klar ist was da nun passiert. Übersichtlicher 
ist es für mich wenn ich den Code vor mir habe und nicht derjenige der 
nachher übersetzt wird.

von Nils S. (kruemeltee) Benutzerseite


Lesenswert?

Nils S. schrieb:
> Einfach wie bei Arduino. Alle freien Pins in einen "virtuellen Port"
> packen, drei Funktionen drumherum und keiner muss mehr denken.

Hmm, das liest sich sehr abwertend. Ich zielte damit auf viel zu 
aufgeblasene Abstraktion im Allgemeinen ab und nicht auf irgend Etwas 
hier.

von Björn W. (papayawhip)


Lesenswert?

Nils S. schrieb:
> Hmm, das liest sich sehr abwertend. Ich zielte damit auf viel zu
> aufgeblasene Abstraktion im Allgemeinen ab und nicht auf irgend Etwas
> hier.

Hätte ich jetzt auch nicht so aufgefasst :)

Bei Arduino kann ich es ebenfalls nachvollziehen. Wenn alle I/O's 
nochmal durch eine extra Lib gepeitscht wird, dauert es eben ein paar 
Takte mehr.

Wenn der Compiler sauber arbeitet, müsste meine Makro-Sammlung direkt 
optimiert werden können, dass z.B. aus 2xSETON (auf dem gleichen Port) 
nur eine Anweisung wird.

Gruß Björn

von N. G. (newgeneration) Benutzerseite


Lesenswert?

Björn W. schrieb:
> Wenn der Compiler sauber arbeitet, müsste meine Makro-Sammlung direkt
> optimiert werden können, dass z.B. aus 2xSETON (auf dem gleichen Port)
> nur eine Anweisung wird.

Darf er nicht, weil die Register volatile sind.

Dein
1
#define SETON(ex)      DPORT_(ex) |= (1<<DBIT_(ex));
2
3
SETON(A,4)
4
SETON(A,5)
löst ja letzten Endes auf zu
1
PORTA |= (1 << 4);
2
PORTA |= (1 << 4);

und das ist (je nach AVR ne andere Addresse)
1
*((volatile uint8_t*)(0xAA + 0x20)) |= (1 << 4);
2
*((volatile uint8_t*)(0xAA + 0x20)) |= (1 << 5);
Tja, da ist ja das volatile.
Also muss der Compiler 2 mal schreiben, was dann entweder zu zwei sbi's 
führt oder zu 2x lds-ori-sts

Aber daran hat deine Makro-Sammlung nicht die geringste Schuld, das wäre 
ohne sie exakt genau so. Ich finde sie jetzt auch nicht schlecht, aber 
ich zweifle den Nutzen in einem größeren Projekt an. Weil spätestens 
dort spielen die GPIOs ja nicht mehr eine so große Rolle und sollten 
sowieso von einer/mehreren Funktionen mit aussagekräftigen Namen 
gekapselt werden.

Nebenbei:
ich finde es persönlich schlecht, wenn an einem Makro ein Semikolon 
hinten dran steht, das kann zu sehr komischem verhalten führen, z.B. bei 
if-Abfragen.
Deswegen würde ich auch diese Einzeiler umklammern mit do{...}while(0) .
Dann setzt nämlich der Nutzer später das Semikolon

von SE (Gast)


Lesenswert?

N. G. schrieb:
> Nebenbei:
> ich finde es persönlich schlecht, wenn an einem Makro ein Semikolon
> hinten dran steht, das kann zu sehr komischem verhalten führen, z.B. bei
> if-Abfragen.

Oh ja. Ist mir beim überfliegen nicht aufgefallen.
Das mag ich auch nicht. :-)

Bei großen Projekten sollte man Makros nur gezielt einsetzen.
Sonst kann es unübersichtlich werden und jemand anders, oder bei 
Hobbyfricklern eher wahrscheinlich, man selber nach paar Monaten steigt 
nicht mehr durch.

von Carl D. (jcw2)


Lesenswert?

Noch kleiner Hinweis:
TOGGLE funktioniert natürlich nicht auf den schon etwas betagteren AVRs, 
die aber häufig auch von Anfängern benutzt werden (Z.B. ATmega8/16/32). 
Ob die dann verstehen warum nicht, oder einfach das Zeug in die Ecke 
werfen?

von Boris O. (bohnsorg) Benutzerseite


Lesenswert?

Mw E. schrieb:
> Was ist an defines jetzt eine zusätzliche Abstraktionsschicht?

Wenn ich PORTB meine und B schreibe, dann ist das eine Form von 
Abstraktion. Mir erschließt sich der Nutzen nicht. Je nach Schreibweise 
der Bit-Manipulationen und Compiler-Laune werden das sehr 
unterschiedliche Maschineninstruktionen. Das Makro verschleiert das u.U. 
und es macht inline-Assembler o.ä. nicht überflüssig. 
Software-Entwicklung damit einfacher zu machen ist eine Illusion. Der 
Begriff dahinter heißt leaky abstraction.

von Anfänger (Gast)


Lesenswert?

Carl D. schrieb:
> Noch kleiner Hinweis: TOGGLE funktioniert natürlich nicht auf den
> schon etwas betagteren AVRs, die aber häufig auch von Anfängern benutzt
> werden (Z.B. ATmega8/16/32). Ob die dann verstehen warum nicht, oder
> einfach das Zeug in die Ecke werfen?

Könntest du erklären warum das TOGGLE Makro bei älteren AVRs nicht 
funktioniert?

von Carl D. (jcw2)


Lesenswert?

Ganz einfach: weil die Hardware es nicht kann.
Toggle per Write auf PIN-Register wurde erst später eingeführt.
Arduino-Benutzer haben da Glück, wer aber lieber einen Mega8 auf sein 
Steckbrett packt, der muß nicht nur mit Kondensatoren an der Versorgung 
kämpfen, was manchmal schwer scheint, sondern hat dann auch noch eine 
Library, die ihm Rätsel auf gibt.

von Anfänger (Gast)


Lesenswert?

Ach ja,
da war was. Ich hatte da jetzt irgendeine Feinheit in den Makros und dem 
jeweiligen Prozessor-Befehlssatz vermutet.

von egberto (Gast)


Lesenswert?

Aber das PIN Write wird im Macro des TE gar nicht benutzt!

#define TOGGLE(ex)     DPORT_(ex) ^= (1<<DBIT_(ex));


Somit ist der Hinweis von Carl Drexler gegenstandslos - trotzdem gut von 
ihm, daran zu denken.

Grüße,

egberto

von gascht (Gast)


Lesenswert?

Was macht eigentlich die Doppelraute ##?

Die taucht in meiner C Referenz gar nicht auf. Hab ich so noch nie 
gesehen. Hat da jemand vielleicht einen weiterführenden Link wie:

https://de.wikibooks.org/wiki/C-Programmierung:_Ausdr%C3%BCcke_und_Operatore

von egberto (Gast)


Lesenswert?

Ich hab das mal für dich gegoogled ;-)

http://www.cprogramming.com/tutorial/cpreprocessor.html

Unter advanced, pasting tokens......

Grüße,

egberto

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.