mikrocontroller.net

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


Autor: Peter (Gast)
Datum:

Bewertung
-2 lesenswert
nicht 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

Autor: Huh (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Ordner (Gast)
Datum:

Bewertung
1 lesenswert
nicht 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".

Autor: Nico W. (nico_w)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Port auslesen, verUNDen mit den Pins, zusammenpacken. In etwa so.
uint8_t my_bits;

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.

Autor: Torffriese (Gast)
Datum:

Bewertung
-2 lesenswert
nicht lesenswert
Nico W. schrieb:
> Port auslesen, verUNDen mit den Pins, zusammenpacken. In etwa so.
>
> uint8_t my_bits;
> 
> 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.

Das sieht so elegant aus wie ein Elefant beim Klöppeln.

https://de.wikipedia.org/wiki/Kl%C3%B6ppeln

Autor: Falk B. (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ Peter (Gast)

>Fällt da jemandem auf die Schnelle ein Tip ein?

Mit einer Tabelle
#define PORTMASK1 0x45
#define PORTMASK2 0x1A

int hex2port[16] = {0xABCD, ...}
int a;

Port1 = (Port1 & ~PORTMASK1) | hex2port[a]>>8;
Port2 = (Port2 & ~PORTMASK2) | (hex2port[a] & 0xFF);


Autor: Peter D. (peda)
Datum:

Bewertung
0 lesenswert
nicht 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:
static void lcd_nibble( uint8_t d )
{
  LCD_D4 = 0; if( d & 1<<4 ) LCD_D4 = 1;
  LCD_D5 = 0; if( d & 1<<5 ) LCD_D5 = 1;
  LCD_D6 = 0; if( d & 1<<6 ) LCD_D6 = 1;
  LCD_D7 = 0; if( d & 1<<7 ) LCD_D7 = 1;

  LCD_E0 = 1;
  _delay_us( 1 );      // 1us
  LCD_E0 = 0;
}

Autor: DerDan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Es ging ums ausgeben?

das geht beim Cortex auch ganz schön über Bitband
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
constexpr volatile uint32_t* BITBAND_ALIAS_ADDRESS(volatile void *addr, uint32_t bit)
{
   volatile uint32_t* result =
   (
      (volatile uint32_t*)
      (
         (((uint32_t)(addr)  & 0xF0000000) + 0x02000000)
       + ((((uint32_t)(addr) & 0x000FFFFF)*32) + ((uint32_t)(bit)*4))
      )
   );
   return result;
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
class COutputPin
{
   public:
      COutputPin (ioport_pin_t pin)
            :
            _pin(pin),
            _bb_set(BITBAND_ALIAS_ADDRESS(&arch_ioport_pin_to_base(pin)->PIO_ODSR, pin & 0x1f)),
            _bb_pdsr(BITBAND_ALIAS_ADDRESS(&arch_ioport_pin_to_base(pin)->PIO_PDSR, pin & 0x1f))
      {
      }
      void Set(bool lvl) const
      {
         *_bb_set = lvl ? 1 : 0;
      }
      void Toggle () const
      {
         *_bb_set = (*_bb_set) ^ 1;
      }
      const COutputPin & operator = (const bool level) const
      {
         Set (level);
         return(*this);
      }
   private:
      const ioport_pin_t _pin;
      volatile uint32_t * const _bb_set;
      volatile uint32_t * const _bb_pdsr;
};

nun kann man


void PutValue (uint8_t v)
{
  const COutputPin OUT1(PA7);
  const COutputPin OUT2(PA8);
  const COutputPin OUT3(PC1);
  const COutputPin OUT4(PC2);

  OUT1 = (v >> 0) &1;
  OUT2 = (v >> 1) &1;
  OUT3 = (v >> 2) &1;
  OUT4 = (v >> 3) &1;
}

Die Werte Elegant und lesbar ausgeben.

Autor: Sven L. (svenl)
Datum:

Bewertung
-1 lesenswert
nicht 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:
uint8_t val = 14;
uint8_t tmp_bits = PINB;

tmp_bits |= (val << 4);

PORTB = tmp_bits;

Wenn in dem Beispiel die Bits 0-3 gesetzt werden müssten, dann wird das 
Shiften weggelassen.

Viele Grüße!

Sven

Autor: Falk B. (falk)
Datum:

Bewertung
0 lesenswert
nicht 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.
void set_ports(a) {
  if (a & (1<<0)) port1 |= (1<<4); else port1 &= ~(1<<4);
  if (a & (1<<1)) port2 |= (1<<3); else port2 &= ~(1<<3);
  if (a & (1<<2)) port3 |= (1<<7); else port3 &= ~(1<<7);
  if (a & (1<<3)) port4 |= (1<<5); else port4 &= ~(1<<5);
}

Autor: Sven L. (svenl)
Datum:

Bewertung
-1 lesenswert
nicht lesenswert
Habe die Port-Maske vergessen:
uint8_t port_mask = 0xf0; // Bits 4-7 maskieren

tmp_bits |= (val << 4) & port_mask;
PORTB = tmp_bits;

Viele Grüße!

Sven

Autor: DerDan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
lieber Sven,

der TE hat doch aber explizit nach verteilten Port Pins gefragt

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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:
void ch_cntrl_set(device_status* devstat, uint8_t active_channel){
  
  devstat->active_channel = active_channel;
    
  ioport_set_pin_level(CH_CTRL0_GPIO_M, (active_channel & (1<<0)));
  ioport_set_pin_level(CH_CTRL1_GPIO_M, (active_channel & (1<<1)));
  ioport_set_pin_level(CH_CTRL2_GPIO_M, (active_channel & (1<<2)));
  ioport_set_pin_level(CH_CTRL3_GPIO_M, (active_channel & (1<<3)));
}

Wobei die Prüfbedingung aus dem if-Vorschlag von Falk den boolschen Wert 
für das Pinlevel vorgibt.

Gedanken?

Autor: DerDan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das sieht gut aus

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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!

Autor: DerDan (Gast)
Datum:

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

Autor: SvenL (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.