PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Pins zu virtuellem Port in C zusammenfassen



AlKI
31.01.2008, 20:38
Ich nutze WinAVR mit GCC und möchte verschiedene Pins (aus verschiedenen Ports) zu einem virtuellen neuen Port zusammenfassen.

In BASCOM geht ja sowas (PORTX), aber in C hab ich leider noch nix gefunden.

Mit sehr umständlichen Unterfunktionen würde das wohl auch gehen, aber das kostet zu viel Rechenzeit und Speicherplatz.

Kennt ihr da nen Trick?

Ceos
31.01.2008, 22:24
die register sind mit den defines von PORTA - PORTX ja schon vorgegeben im AVR-Studio, du müsstest theoretisch nur
PORTA |= BV(PA1); zum setzen und
PORTA &= ~BV(PA1); zum löschen verwenden
aber von dieser punktartigen notation musst du leider abweichen
ich find aber folgende code-schnipsel ganz sinnvoll ^^

#define SETBIT(x,n) ((x) |= (1L << (n)))
#define CLEARBIT(x,n) ((x) &= ~(1L << (n)))
#define GETBIT(x,n) ((x) & (1L << (n))) // gibt ne 0 oder einen wert > 0

...
SETBIT(PORTA,1);
CLEARBIT(PORTA,1);

if (GETBIT(PORTA,1) == 0) DoSth();
else if (GETBIT(PORTA,1) > 0) DoSthOther();
...

wkrug
01.02.2008, 05:54
Ich denke mal es geht dabei um Eingänge.

Ich lege dazu eine Variable an, in die ich die gewünschten Ports mit logischen verknüpfungen und Verschiebeoperationen reinschiebe.




// Pin C 0...3 Low Byte, Pin D 0...3 High Byte
volatile unsined char uc_input;
uc_input = (PIND&0b00000111); // High Wert einlesen und maskieren
uc_input = (uc_imput<<3); // High Wert an den richtigen Platz schieben
uc_input = uc_input|(PINC&0b00000111); // Low Wert einlesen und maskieren

Das sollte der C-Compiler mit ein paar Assembler Befehlen umsetzen können.

AlKI
01.02.2008, 13:07
ich glaube, ich habe wohl ein bischen zuwenig angegeben.

Ich wollte damit einen virtuellen Port aus vielen verschiedenen Pins zusammenstellen und als Ausgang, wenn möglich aber auch als Eingang nutzen.

Ich glaube, dass das suf etwas wie den codeschnipsel von dir, wkrug, herauslaufen wird.

beim Schreiben kann ich das auch mit 8 verschiedenen Bitpositionen machen, ich muss mir davor nur die passenden Masken 'zusammenstellen'.
und eben jeh nach dem Bitpositionen setzen oder löschen. Hab ich da richtig gedacht?


und damit auch bekannt ist, wozu ich das nutzen will: ich will auch in C LCDs komplett unabhängig anschließen (wenn ich zum Beispiel vom einen Port ADCs , vom nächsten UART nutzen und die ISP-Anschlüsse trotzdem freihalten will)

robocat
01.02.2008, 13:34
wenn du die fleury lcd lib verwendest, kann man die ports/pins frei wählen. bei grafik-lcds bräuchtest du eine andere lib, aber vielleicht kann man sich das schema der wählbaren PINs bei fleury "abgucken".

gruesse

AlKI
01.02.2008, 14:52
Fleury hat es wohl mit dem " BV(... " gemacht.
Was bedeutet das eigentlich???
ist ja sonst ganz normales Bitsetzen oder löschen...

(ich weiß leider nicht, wie ich danach suchen sollte, die Sufus hier und im Wiki sagen nix)

robocat
01.02.2008, 15:17
aus "WinAVR-20070525/doc/avr-libc/avr-libc-user-manual/FAQ.html#faq_use_bv":

What is all this _BV() stuff about?
When performing low-level output work, which is a very central point in microcontroller programming, it is quite common that a particular bit needs to be set or cleared in some IO register. While the device documentation provides mnemonic names for the various bits in the IO registers, and the AVR device-specific IO definitions reflect these names in definitions for numerical constants, a way is needed to convert a bit number (usually within a byte register) into a byte value that can be assigned directly to the register. However, sometimes the direct bit numbers are needed as well (e. g. in an SBI() instruction), so the definitions cannot usefully be made as byte values in the first place.

So in order to access a particular bit number as a byte value, use the _BV() macro. Of course, the implementation of this macro is just the usual bit shift (which is done by the compiler anyway, thus doesn't impose any run-time penalty), so the following applies:

_BV(3) => 1 << 3 => 0x08

However, using the macro often makes the program better readable.

"BV" stands for "bit value", in case someone might ask you. :-)

Example: clock timer 2 with full IO clock (CS2x = 0b001), toggle OC2 output on compare match (COM2x = 0b01), and clear timer on compare match (CTC2 = 1). Make OC2 (PD7) an output.

TCCR2 = _BV(COM20)|_BV(CTC2)|_BV(CS20);
DDRD = _BV(PD7);

kurzgesagt macht BV also aus einer pin-nr (0-7, PD7 = 7 zB) einen bytewert (byte-value 0-255), also aus 0,1,2,3,4..7 wird 1,2,4,8..128, also alles kein hexenwerk.

übrigens wusste ich das selbst nicht so genau, und habe die FAQ grade erst entdeckt. lohnt sich sicher, da mal reinzugucken.

gruesse

EDIT: hier findet man die faq online: http://www.nongnu.org/avr-libc/
EDIT2: und ja, ich programmiere schon länger und bins inzwischen gewohnt, include-verzeichnisse nach hinweisen zu durchwühlen ;)

EDIT3:

Jeder Mensch lebt wie ein Uhrwerk, ...
... die meisten ticken nicht ganz richtig O:) ;)
(keinesfalls persönlich gemeint, ist mir nur grade so eingefallen)

AlKI
01.02.2008, 15:32
Danke!

dann raff ich jetzt auch, wie der das gemacht hat:
...
/* output high nibble first */
LCD_DATA3_PORT &= ~_BV(LCD_DATA3_PIN);
LCD_DATA2_PORT &= ~_BV(LCD_DATA2_PIN);
LCD_DATA1_PORT &= ~_BV(LCD_DATA1_PIN);
LCD_DATA0_PORT &= ~_BV(LCD_DATA0_PIN);
if(data & 0x80) LCD_DATA3_PORT |= _BV(LCD_DATA3_PIN);
if(data & 0x40) LCD_DATA2_PORT |= _BV(LCD_DATA2_PIN);
if(data & 0x20) LCD_DATA1_PORT |= _BV(LCD_DATA1_PIN);
if(data & 0x10) LCD_DATA0_PORT |= _BV(LCD_DATA0_PIN);
halt geguckt, ob das bit in der Variable gesetzt ist ( logische &-Verknüpfung) und dann den dementsprechenden Pin vom Portxyz gesetzt oder nicht.
ok, sowas hatte ich schon im Kopf, mir ist die lib bloß etwas zu kompliziert 8-[ will mir was einfacheres schreiben, und gleichzeitig nen haufen lernen.