Forum: Mikrocontroller und Digitale Elektronik Effizient coden: dez-to-binär auf 4 verteilte pins ausgeben


von Peter (Gast)


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

von Huh (Gast)


Lesenswert?

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.

von Ordner (Gast)


Lesenswert?

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".

von Nico W. (nico_w)


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.

von Torffriese (Gast)


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

von Falk B. (falk)


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);

von Peter D. (peda)


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
}

von DerDan (Gast)


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.

von Sven L. (svenl)


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

von Falk B. (falk)


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
}

von Sven L. (svenl)


Lesenswert?

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

von DerDan (Gast)


Lesenswert?

lieber Sven,

der TE hat doch aber explizit nach verteilten Port Pins gefragt

von Peter (Gast)


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?

von DerDan (Gast)


Lesenswert?

Das sieht gut aus

von Peter (Gast)


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!

von DerDan (Gast)


Lesenswert?

Effizient ist die Bitband Geschiche, die ich oben gepostet habe.
Vor allem, wenn man die Compiler - Optimierung aussschaltet.

von SvenL (Gast)


Lesenswert?

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
Noch kein Account? Hier anmelden.