www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik AVR IO Configuration


Autor: Matthias Kölling (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ich suche eine elegante Möglichkeit, die mir eine Zuordnung eines 
Portpins zu einem Signalnamen macht und sich auch bei der 
Initialisierung um die richtige Einstellung der Datenrichtung und 
Pullups kümmert. Hintergrund ist, dass ich bei einer Hardwareumstellung 
wieder einige Schusselfehler drin hatte, die einiges an Zeit und Nerven 
gekostet haben. Meine Idealvorstellung wäre, dass die Signaldefinition 
mit einer Zeile passiert, um Fehler bei der Konfiguration zu minimieren. 
Aus dieser Signaldefinition soll sich alles weitere ableiten lassen. Man 
könnte das mit einer großen Tabelle machen. Allerdings kostet das 
Laufzeit. Besser wäre, der Präprozessor würde aus einer Signaldefinition 
die entsprechenden Makros ableiten. Genau an dieser Stelle zermatere ich 
mir seit Wochen das Hirn und komme nicht weiter. Ich habe mir auch schon 
die Finger wund gegoogelt, allerdings scheint niemand mein Problem zu 
haben.
Wie würdet Ihr das angehen, bzw. welche Lösungen benutzt Ihr in Euren 
Projekten?

Gruß Matthias

Autor: Hubert G. (hubertg)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
So etwas wie hier sollten deine Probleme lösen. 
www.mikrocontroller.net/articles/AVR-GCC-Tutorial#Vordefinierte_Bitnumme 
rn_f.C3.BCr_I.2FO-Register

Autor: Matthias Kölling (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

inwiefern kann es mein Problem lösen?. Ich brauche dann immer noch pro 
Signal eine Definition für den Port, eine für das Bit und eine für das 
Datenrichtungsregister. Mir schwebt so etwas vor:

#define SIGNAL ... (kreiere alle Makros)

Initialisierung:

for(all Signals)
{
  Init DDR;
  Init Pullup;
}

im Code:
Signal = ...
if(Signal)
{
   ...
}

Gruß Matthias

Autor: Hannes Jaeger (pnuebergang)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ein paar Dinge bevor ich eine Lösung skizziere.

Die Idee ist scheiße. Ich habe den Müll nicht mal durch den Compiler 
gejagt. Wer ihn haben will darf ihn selber zum Laufen bringen. Ich werde 
dazu keine Fragen beantworten, ich will davon nichts wissen.

// iodef.h

#include <das übliche Zeug>

typedef struct {
   uint16_t  portAddr;
   uint16_t  ddrAddr;
   uint8_t   bitMask;
   bool      dir;
   bool      val;
} sigdef;


#define BEGIN_SIGLIST sigdef sigs[] = {  
#define END_SIGLIST {0,0,0,0} };

export sigdef sigs[];

#define SIGDEF(portid, bit, dir, val)  { _SFR_ADDR(PORT##portid), \
                       _SFR_ADDR(DDR##portid), _BV(bit), dir, val}, 
// iodef.c
#include <iodef.h>

void signInit(void) {
  sigdef *s = sigs;
  while(s->portAddr) {
      if(s->val) {
          _SFR_MEM8(s->portAddr) |= bitMask;
      } else {
          _SFR_MEM8(s->portAddr) &= ~bitMask;
      } 
      if(s->dir) {
          _SFR_MEM8(s->ddrAddr) |= bitMask;
      } else {
          _SFR_MEM8(s->ddrAddr) &= ~bitMask;
      } 
      s++;
  }
}
// Anwendung
#include <iodef.h>

// "Wunderschöne" Signaldefinitionen
#define MeinTollesSignal1  SIGDEF(C, 2, 0, 1)
#define MeinTollesSignal2  SIGDEF(D, 0, 1, 1)
#define GanzTollesSignal3  SIGDEF(D, 5, 1, 1)

// Alle schön ins Eimerchen
#define BEGIN_SIGLIST
  MeinTollesSignal1
  MeinTollesSignal2
  GanzTollesSignal3
#define END_SIGLIST


int main() {
   sigInit();   // kotz
}

Autor: Andreas B. (bitverdreher)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,
ich habe es so gelöst:
in eine hardwaredef.h steht z.B. drin:
// Vertical drive
// Input
#define VERT_ENC_1         PD2
#define VERT_ENC_2         PD3
#define VERT_PHASE_A       PIND & (1<<PD2)
#define VERT_PHASE_B       PIND & (1<<PD3)
#define VERT_REF           PC5
#define VERT_REF_OUT       (PINC & (1<<VERT_REF))
#define VERT_REF_IN        (!(PINC & (1<<VERT_REF)))
#define VERT_H_END         PC6
// Output
#define VERT_DIRECTION     PC3
#define VERT_MOVE_DOWN     PORTC |= (1<<VERT_DIRECTION)
#define VERT_MOVE_UP       PORTC &= ~(1<<VERT_DIRECTION)
#define VERT_STOP          PC2
#define VERT_BRAKE_OFF     PORTC &= ~(1<<VERT_STOP)
#define VERT_BRAKE_ON      PORTC |= (1<<VERT_STOP)
#define VERT_PWM           PD4
#define VERT_SPEED         OCR1B
und in der init() stehts dann so:
void InitPorts(void) {
   // port inputs
   DDRA &= ~( (1<<SLID_ENC_1) | (1<<SLID_ENC_2) | (1<<SLID_REF) | (1<<TURN_H_END) );
   DDRB &= ~( (1<<PB6) );
   DDRC &= ~( (1<<VERT_REF) | (1<<VERT_H_END) | (1<<TURN_REF) | (1<<SDA) | (1<<SCL) );
   DDRD &= ~( (1<<VERT_ENC_1) | (1<<VERT_ENC_2) | (1<<TURN_ENC_1) | (1<<TURN_ENC_2));
   
   // port outputs
   DDRA |= (1 << GRIP) | (1 << RESERVE0) | (1 << RESERVE1);
   DDRB |= (1 << SLID_3A) | (1 << SLID_4A) | (1 << TURN_1A) |  (1 << TURN_PWM) | (1 << TURN_2A) | (1 << LASER);
   DDRC |= (1 << VERT_DIRECTION) | (1 << VERT_STOP);
   DDRD |= (1 << VERT_PWM) | (1 << SLID_PWM);
   // activate pullup resistors
   PORTA |= ((1<<SLID_ENC_1) | (1<<SLID_ENC_2) | (1<<SLID_REF) | (1<<GRIP));
   PORTC |= ((1<<SDA) | (1<<SCL));
}
man muß dann halt nur aufpassen, daß man Input und Output nicht 
verwechselt (daher in der hardwaredef.h danach sortiert) und die 
Portzuordnung stimmt.
Man könnte das noch nach den Ports aufdröseln, indem man für jeden 
Input/Output noch den Port definiert, aber dann finde ich das etwas 
unübersichtlich.
Für mich ist dies so ein guter Kompromiss.

Gruß
Andy

Autor: let (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Habe ich schon einmal geposted, finde den Beitrag aber nicht
mehr. Dort wurde auch noch eine andere (ähnliche) Lösung
vorgestellt.
#include <defines.h>

#define P_LED1    (B, 2)
#define P_KEY1    (C, 0)

int main()
{
   SET_DDR_OUT(P_LED1);
   SET_DDR_IN(P_KEY1);
   SETPIN(P_KEY1); // Pull-up ein

   for (;;) {
      if (GETPIN(P_KEY1))
         SETPIN(P_LED1);
      else
         CLRPIN(P_LED1);
   }
}

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich mach das immer ganz einfach mit Macros:

#include <io.h>

struct bits {
  uint8_t b0:1;
  uint8_t b1:1;
  uint8_t b2:1;
  uint8_t b3:1;
  uint8_t b4:1;
  uint8_t b5:1;
  uint8_t b6:1;
  uint8_t b7:1;
} __attribute__((__packed__));

#define SBIT(port,pin) ((*(volatile struct bits*)&port).b##pin)



#define KEY0            SBIT( PORTB, 0 )
#define KEY0_IN         SBIT( PINB, 0 )

#define LED0            SBIT( PORTB, 1 )
#define LED0_DDR        SBIT( DDRB, 1 )


int main( void )
{
  LED0_DDR = 1;         // output
  KEY0 = 1;             // pull up on

  for(;;){

    if( KEY0_IN == 0 )  // if key pressed (low)
      LED0 = 0;         // LED on (low)
    else
      LED0 = 1;         // LED off (high)
  }
}



Peter

Autor: Matthias Kölling (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke für die vielen Anregungen. Sie decken sich im Wesentlichen mit 
meinen Überlegungen. Scheinbar braucht man minimum zwei Stellen im Code, 
um zum einen die Makros für den Zugriff und zum Anderen die Init zu 
bewerkstelligen. Diese Stellen müssen immer konsistent sein und da ist 
schnell mal ein Fehler passiert.

@Hannes Jaeger
Letztendlich hast Du auf kompliziertem Weg eine Struktur gebaut. Wenn 
man daraus noch die Makros für den Zugriff ableiten könnte, wäre das der 
Stein der Weisen.

Danke nochmals für die vielen Hinweise

Gruß Matthias

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.