Hallo liebe Community, meine Frage ist im Grunde sehr einfach mit einer switch-case loop lösbar, ich würde es aber gerne eleganter implementieren, weil das sicher geht: Ich habe auf meinem µC (SAM4S) ein paralleles 4Bit Interface eingerichtet: 4 Pins, nicht auf dem selben port, also z.B: PA7, PA8, PC1, PC2 sollen möglichst einfach den eingegebenen (hexa-)dezimalen funktionswert 0-15 bzw F abbilden. Lägen die jetzt alle auf dem selben Port wäre das ja 1 zu 1 durch die Bitmaske machbar. Nun frage ich mich aber, wie ich das (ähnlich unkompliziert) hinbekomme ohne für jede Zahl einen case schreiben zu müssen...? Das selbe gilt dann auch fürs lesen an anderer Stelle (wenn ein Slave die selben pins als Eingänge nutzt). Fällt da jemandem auf die Schnelle ein Tip ein? Beste Grüße
Peter schrieb: > ohne für jede Zahl einen case schreiben zu müssen...? Wenn es nur vier Bits sind, weise sie einfach einzeln den Pins zu.
Peter schrieb: > ich würde es aber gerne eleganter implementieren Definiere Eleganz!? Für den einen ist eine Sprung-LookUp Tabelle elegant für den anderen dagegen "Obfuscated Code".
Port auslesen, verUNDen mit den Pins, zusammenpacken. In etwa so.
1 | uint8_t my_bits; |
2 | |
3 | my_bits = (PORT_A & (PA7 | PA8)) | (PORT_C & (PC0 | PC1)); |
solange die Bits der Port unterschiedlich sind, kannst das so machen. Sonst musst halt gucken das du die Pins irgendwie noch verschiebst.
Nico W. schrieb: > Port auslesen, verUNDen mit den Pins, zusammenpacken. In etwa so. >
1 | > uint8_t my_bits; |
2 | > |
3 | > my_bits = (PORT_A & (PA7 | PA8)) | (PORT_C & (PC0 | PC1)); |
4 | > |
> > solange die Bits der Port unterschiedlich sind, kannst das so machen. > Sonst musst halt gucken das du die Pins irgendwie noch verschiebst. Das sieht so elegant aus wie ein Elefant beim Klöppeln. https://de.wikipedia.org/wiki/Kl%C3%B6ppeln
@ Peter (Gast)
>Fällt da jemandem auf die Schnelle ein Tip ein?
Mit einer Tabelle
1 | #define PORTMASK1 0x45
|
2 | #define PORTMASK2 0x1A
|
3 | |
4 | int hex2port[16] = {0xABCD, ...} |
5 | int a; |
6 | |
7 | Port1 = (Port1 & ~PORTMASK1) | hex2port[a]>>8; |
8 | Port2 = (Port2 & ~PORTMASK2) | (hex2port[a] & 0xFF); |
Peter schrieb: > meine Frage ist im Grunde sehr einfach mit einer switch-case loop > lösbar Wie das denn? Hier mal der Code aus meiner lcd.c:
1 | static void lcd_nibble( uint8_t d ) |
2 | {
|
3 | LCD_D4 = 0; if( d & 1<<4 ) LCD_D4 = 1; |
4 | LCD_D5 = 0; if( d & 1<<5 ) LCD_D5 = 1; |
5 | LCD_D6 = 0; if( d & 1<<6 ) LCD_D6 = 1; |
6 | LCD_D7 = 0; if( d & 1<<7 ) LCD_D7 = 1; |
7 | |
8 | LCD_E0 = 1; |
9 | _delay_us( 1 ); // 1us |
10 | LCD_E0 = 0; |
11 | }
|
Es ging ums ausgeben? das geht beim Cortex auch ganz schön über Bitband
1 | //---------------------------------------------------------------------------
|
2 | //---------------------------------------------------------------------------
|
3 | constexpr volatile uint32_t* BITBAND_ALIAS_ADDRESS(volatile void *addr, uint32_t bit) |
4 | {
|
5 | volatile uint32_t* result = |
6 | (
|
7 | (volatile uint32_t*) |
8 | (
|
9 | (((uint32_t)(addr) & 0xF0000000) + 0x02000000) |
10 | + ((((uint32_t)(addr) & 0x000FFFFF)*32) + ((uint32_t)(bit)*4)) |
11 | )
|
12 | );
|
13 | return result; |
14 | }
|
15 | //---------------------------------------------------------------------------
|
16 | //---------------------------------------------------------------------------
|
17 | class COutputPin |
18 | {
|
19 | public:
|
20 | COutputPin (ioport_pin_t pin) |
21 | :
|
22 | _pin(pin), |
23 | _bb_set(BITBAND_ALIAS_ADDRESS(&arch_ioport_pin_to_base(pin)->PIO_ODSR, pin & 0x1f)), |
24 | _bb_pdsr(BITBAND_ALIAS_ADDRESS(&arch_ioport_pin_to_base(pin)->PIO_PDSR, pin & 0x1f)) |
25 | {
|
26 | }
|
27 | void Set(bool lvl) const |
28 | {
|
29 | *_bb_set = lvl ? 1 : 0; |
30 | }
|
31 | void Toggle () const |
32 | {
|
33 | *_bb_set = (*_bb_set) ^ 1; |
34 | }
|
35 | const COutputPin & operator = (const bool level) const |
36 | {
|
37 | Set (level); |
38 | return(*this); |
39 | }
|
40 | private:
|
41 | const ioport_pin_t _pin; |
42 | volatile uint32_t * const _bb_set; |
43 | volatile uint32_t * const _bb_pdsr; |
44 | };
|
nun kann man
1 | void PutValue (uint8_t v) |
2 | {
|
3 | const COutputPin OUT1(PA7); |
4 | const COutputPin OUT2(PA8); |
5 | const COutputPin OUT3(PC1); |
6 | const COutputPin OUT4(PC2); |
7 | |
8 | OUT1 = (v >> 0) &1; |
9 | OUT2 = (v >> 1) &1; |
10 | OUT3 = (v >> 2) &1; |
11 | OUT4 = (v >> 3) &1; |
12 | }
|
Die Werte Elegant und lesbar ausgeben.
Hallo zusammen, wenn die Bits zusammen liegen, was sie sollten damit es effizient ist, reicht lesen, verodern und schreiben... Am Beispiel von Port B, Bits 4-7, val ist der dezimale Wert:
1 | uint8_t val = 14; |
2 | uint8_t tmp_bits = PINB; |
3 | |
4 | tmp_bits |= (val << 4); |
5 | |
6 | PORTB = tmp_bits; |
Wenn in dem Beispiel die Bits 0-3 gesetzt werden müssten, dann wird das Shiften weggelassen. Viele Grüße! Sven
Oder mit 4 einfachen if(), das hat den Vorteil, daß man die Zuordnung zu den Bits in der obigen Tabelle nicht selber ausrechnen muss.
1 | void set_ports(a) { |
2 | if (a & (1<<0)) port1 |= (1<<4); else port1 &= ~(1<<4); |
3 | if (a & (1<<1)) port2 |= (1<<3); else port2 &= ~(1<<3); |
4 | if (a & (1<<2)) port3 |= (1<<7); else port3 &= ~(1<<7); |
5 | if (a & (1<<3)) port4 |= (1<<5); else port4 &= ~(1<<5); |
6 | }
|
Habe die Port-Maske vergessen:
1 | uint8_t port_mask = 0xf0; // Bits 4-7 maskieren |
2 | |
3 | tmp_bits |= (val << 4) & port_mask; |
4 | PORTB = tmp_bits; |
Viele Grüße! Sven
lieber Sven, der TE hat doch aber explizit nach verteilten Port Pins gefragt
Wow, danke für das viele feedback! Da ich den ASF verwende (inkl. set_pin_level funktion) habe ich jetzt daraus das hier gemacht:
1 | void ch_cntrl_set(device_status* devstat, uint8_t active_channel){ |
2 | |
3 | devstat->active_channel = active_channel; |
4 | |
5 | ioport_set_pin_level(CH_CTRL0_GPIO_M, (active_channel & (1<<0))); |
6 | ioport_set_pin_level(CH_CTRL1_GPIO_M, (active_channel & (1<<1))); |
7 | ioport_set_pin_level(CH_CTRL2_GPIO_M, (active_channel & (1<<2))); |
8 | ioport_set_pin_level(CH_CTRL3_GPIO_M, (active_channel & (1<<3))); |
9 | }
|
Wobei die Prüfbedingung aus dem if-Vorschlag von Falk den boolschen Wert für das Pinlevel vorgibt. Gedanken?
funktioniert auch gut, gerade getestet. Wie Effizient das jetzt ist kann ich nicht abschätzen, weil ich nicht weiß was der AVR Studio Compiler aus den ASF IOPORT Funktionen macht, aber momentan bin ich glücklich. Danke für eure Hilfe!
Effizient ist die Bitband Geschiche, die ich oben gepostet habe. Vor allem, wenn man die Compiler - Optimierung aussschaltet.
DerDan schrieb: > der TE hat doch aber explizit nach verteilten Port Pins gefragt Hab' ich erst im Nachhinein gesehen...sorry! Viele Grüße! Sven
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.