mikrocontroller.net

Forum: Compiler & IDEs Portzugriffe in eine Schleife packen


Autor: Thomas (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Tach,
ich habe eine 7-Segment-Anzeige an einem Atmega8. Nun muss ich die 
einzelnen Segmente der Anzeigen auf verschiedene Ports aufteilen.

Über eine Reihe von defines sage ich jetzt vorher wo die Segmente 
angeschlossen sind:
// Portpins für die einzelnen Segmente
#define SEG_PORT_A  PORTD
#define SEG_DDR_A  DDRD
#define SEG_PIN_A  PD0
#define SEG_PORT_B  PORTD
#define SEG_DDR_B  DDRD
#define SEG_PIN_B  PD1
.
.
.

Eine einzelne Ziffer gebe ich bis jetzt dann so aus:
// Einzelne Ziffer ausgeben
void sev_seg_display_digit(uint8_t digit)
{
  uint8_t pattern;
  pattern = seg_dat[digit];
  
  if (pattern & 0x01)
    SEG_PORT_A |= (1 << SEG_PIN_A);
  else
    SEG_PORT_A &= ~(1 << SEG_PIN_A);
    
  if (pattern & 0x02)
    SEG_PORT_B |= (1 << SEG_PIN_B);
  else
    SEG_PORT_B &= ~(1 << SEG_PIN_B);
.
.
.
Also 10 if-else Abfragen.

Ich würde das ja ganz gerne irgendwie in einer Schleife abarbeiten, aber 
mir ist keine Lösung eingefallen. Wahrscheinlich muss ich dann aber von 
den defines weg oder?
Jemand einen Hinweis?

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das kommt drauf an wie portasbel du das ganze haben willst.

> Nun muss ich die
> einzelnen Segmente der Anzeigen auf verschiedene Ports aufteilen.

Das ist schlecht. Denn das bedeutet, dass du tatsächlich
so gut wie jedes Bit (und damit jedes Segment) einzeln
behandeln musst.

Falls es dir auf Portabilität nicht ankommt, dann fass
wenigstens die Pins die an ein und demselben Port liegen
zusammen und mach jeweils eine eigene Tabelle dafür.
Dann brauchst du nur jeweils die für einen Port zuständige
Tabelle aufsuchen, holst dir mit dem auszugebenden
Digit den dafür notwendigen wert und gibst ihn auf
den Port aus.

Wenn du das Ganze allerdings voll portabel haben willst,
dann bleibt dir nichts anderes übrig, als das was du
bereits gemacht hast.

Autor: Thomas (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Naja, ich brauche die Analog-Komparatoren, und wenn man einen Quarz auch 
braucht ist kein vollständiger Port mehr da.
Ist beim Multiplexen ja auch unschön wenn da so lange im Interrupt 
gearbeitet wird.
Ich dachte nur, dass es irgendeine Möglichkeit gäbe das in eine Schleife 
zu packen (evtl. wenn man die Portdaten in eine Struktur packt, aber das 
wär ja auch Overhead).

Autor: Jörg X. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mit einer schleife ginge es so:
 //...
    uint8_t i;
    for(i=1; i!=0; i<<=1;) {
        if (pattern & i) {
            SETPIN();
        }
        else {
            CLRPIN();
        }
    }
    
Allerdings fehlt da die Möglichkeit, die Bits den Port zuzuordnen :(

Aber du weißt doch, welche Bits in "pattern" zu welchem Segment gehören 
und im
Optimalfall gehören Bits 'auf einer Seite' (Low-, bzw. Highbits) zu 
einem Port:
#define SEG_PORT_A  PORTD
#define SEG_DDR_A  DDRD
// Wenn jeweils ein Nibble zu einem Port gehört
// Pins PD0 bis PD3
#define SEG_MASK_A 0x0F

#define SEG_PORT_B  PORTB
#define SEG_DDR_B  DDRB
// Wenn jeweils ein Nibble zu einem Port gehört
//Pins: PB4-PB7
#define SEG_MASK_B 0xF0
void sev_seg_display_digit(uint8_t digit)
{
    uint8_t pattern;
    pattern = seg_dat[digit];
    // besser/spart RAM (#include <avr/pgmspace.h>, beim AVR-GCC): 
    // pattern = pgm_read_byte(segdat[digit]);
    SEG_PORT_A = (SEG_PORT_A & ~SEG_MASK_A) | (pattern & SEG_MASK_A);
    //           loesche SEG-Bits           setze neue SEG-Bits
    SEG_PORT_B = (SEG_PORT_B & ~SEG_MASK_B) | (pattern & SEG_MASK_B);
    
    /* Falls die Pins nicht exakt auf das High- oder Low-nibble passen:
      z.B. PD2-PD5*/
#define SEG_A_LOW_PIN 2
    SEG_PORT_A = (SEG_PORT_A & ~(SEG_MASK_A<<SEG_A_LOW_PIN)
                            | ((pattern & SEG_MASK_A)<<SEG_A_LOW_PIN);
    /* Das High-Nibble muss ggf. in die andere Richtung geschoben werden*/
}
Die schnellste Möglichkeit wäre jedoch 'pattern' zu vergrößern (z.B. als 
struct),
so dass du für jeden Port gleich das passende Byte ansprechen kannst:
struct pins {uint8_t port1, uint8_t port2, uint8_t port3};
const struct pins segdat[] = {{0x00, 0x02,0x40}, ...};
// um SRAM zu sparen dann: "struct digit PROGMEM segdat[] = "
struct pins pattern;
pattern = segdat[digit];
// in MASKx ist jedes Bit gesetzt, das zu einem segment gehört
PORTA = (PORTA & ~(MASKA) | pattern.port1);
PORTB = (PORTB & ~(MASKB) | pattern.port2);
//etc.

hth. Jörg

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Thomas wrote:
> Ist beim Multiplexen ja auch unschön wenn da so lange im Interrupt
> gearbeitet wird.

Dann bewirkt ne Schleife nur genau das Gegenteil, der Code dauert 
wesentlich länger und wird warscheinlich auch eher länger als kürzer.

Code und Zeit kannst Du aber sparen, indem Du den else-Zweig immer 
ausführst. Der Bittest ist ein Skipbefehl und damit sparst Du 2 RJMP 
Befehle ein. Es stört auch nicht, wenn jede LED kurzzeitig ausgeschaltet 
wird.


Um den Code besser lesbar zu machen, würde ich Dir aber raten, Bitfelder 
zu benutzen. Ein Beispiel findest Du hier:

Beitrag "LCD Treiber Routine 4*40"

Da ist dann auch die kürzere Bitsetz/-lösch Syntax zu sehen.


Peter

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.