www.mikrocontroller.net

Forum: Mikrocontroller und Elektronik AVR IO Configuration

Autor: Matthias Kölling (Gast)
Datum: 17.05.2008 11:43

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: 17.05.2008 16:26

So etwas wie hier sollten deine Probleme lösen.
www.mikrocontroller.net/articles/AVR-GCC-Tutorial#Vordefinierte_Bitnummern_f.C3.BCr_I.2FO-Register
Autor: Matthias Kölling (Gast)
Datum: 17.05.2008 17:20

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: 17.05.2008 18:44

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: 17.05.2008 19:02

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: 17.05.2008 19:29
Dateianhang: defines.h (1,4 KB, 19 Downloads) | formatierter Code

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: 17.05.2008 20:06

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: 18.05.2008 13:10

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 Email-Adresse ist freiwillig. Wenn Sie automatisch per Email über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Suchfunktion und Betreffsuche benutzen - vielleicht gibt es schon einen ähnlichen Beitrag
  • Aussagekräftigen Betreff wählen
  • Im Betreff angeben um welchen Controllertyp es geht (AVR, PIC, ...)
  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang
  • JPEG-Dateien (.jpg) nur für Fotos und Scans verwenden
  • Schaltpläne, Screenshots usw. als PNG oder GIF anhängen

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [pre]vorformatierter Text (z.B. Code in anderen Sprachen)[/pre]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel






webmaster@mikrocontroller.netImpressumWerbung auf Mikrocontroller.net