Effizient coden: dez-to-binär auf 4 verteilte pins ausgeben

Gast #4738218
Lesenswert?

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
#4738227
Lesenswert?

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.
Gast #4738233
Lesenswert?

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
#4738243
Lesenswert?

@ 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);
#4738246
Lesenswert?

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
}
Gast #4738248
Lesenswert?

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.
#4738249
Lesenswert?

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
#4738250
Lesenswert?

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
}
Gast #4738265
Lesenswert?

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?
Gast #4738273
Lesenswert?

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!

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren