Forum: Mikrocontroller und Digitale Elektronik AVR IO Configuration


von Matthias Kölling (Gast)


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

von Hubert G. (hubertg)


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

von Matthias Kölling (Gast)


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

von Hannes J. (Firma: _⌨_) (pnuebergang)


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.

1
// iodef.h
2
3
#include <das übliche Zeug>
4
5
typedef struct {
6
   uint16_t  portAddr;
7
   uint16_t  ddrAddr;
8
   uint8_t   bitMask;
9
   bool      dir;
10
   bool      val;
11
} sigdef;
12
13
14
#define BEGIN_SIGLIST sigdef sigs[] = {  
15
#define END_SIGLIST {0,0,0,0} };
16
17
export sigdef sigs[];
18
19
#define SIGDEF(portid, bit, dir, val)  { _SFR_ADDR(PORT##portid), \
20
                       _SFR_ADDR(DDR##portid), _BV(bit), dir, val},
1
// iodef.c
2
#include <iodef.h>
3
4
void signInit(void) {
5
  sigdef *s = sigs;
6
  while(s->portAddr) {
7
      if(s->val) {
8
          _SFR_MEM8(s->portAddr) |= bitMask;
9
      } else {
10
          _SFR_MEM8(s->portAddr) &= ~bitMask;
11
      } 
12
      if(s->dir) {
13
          _SFR_MEM8(s->ddrAddr) |= bitMask;
14
      } else {
15
          _SFR_MEM8(s->ddrAddr) &= ~bitMask;
16
      } 
17
      s++;
18
  }
19
}
1
// Anwendung
2
#include <iodef.h>
3
4
// "Wunderschöne" Signaldefinitionen
5
#define MeinTollesSignal1  SIGDEF(C, 2, 0, 1)
6
#define MeinTollesSignal2  SIGDEF(D, 0, 1, 1)
7
#define GanzTollesSignal3  SIGDEF(D, 5, 1, 1)
8
9
// Alle schön ins Eimerchen
10
#define BEGIN_SIGLIST
11
  MeinTollesSignal1
12
  MeinTollesSignal2
13
  GanzTollesSignal3
14
#define END_SIGLIST
15
16
17
int main() {
18
   sigInit();   // kotz
19
}

von Andreas B. (bitverdreher)


Lesenswert?

Hi,
ich habe es so gelöst:
in eine hardwaredef.h steht z.B. drin:
1
// Vertical drive
2
// Input
3
#define VERT_ENC_1         PD2
4
#define VERT_ENC_2         PD3
5
#define VERT_PHASE_A       PIND & (1<<PD2)
6
#define VERT_PHASE_B       PIND & (1<<PD3)
7
#define VERT_REF           PC5
8
#define VERT_REF_OUT       (PINC & (1<<VERT_REF))
9
#define VERT_REF_IN        (!(PINC & (1<<VERT_REF)))
10
#define VERT_H_END         PC6
11
// Output
12
#define VERT_DIRECTION     PC3
13
#define VERT_MOVE_DOWN     PORTC |= (1<<VERT_DIRECTION)
14
#define VERT_MOVE_UP       PORTC &= ~(1<<VERT_DIRECTION)
15
#define VERT_STOP          PC2
16
#define VERT_BRAKE_OFF     PORTC &= ~(1<<VERT_STOP)
17
#define VERT_BRAKE_ON      PORTC |= (1<<VERT_STOP)
18
#define VERT_PWM           PD4
19
#define VERT_SPEED         OCR1B
und in der init() stehts dann so:
1
void InitPorts(void) {
2
   // port inputs
3
   DDRA &= ~( (1<<SLID_ENC_1) | (1<<SLID_ENC_2) | (1<<SLID_REF) | (1<<TURN_H_END) );
4
   DDRB &= ~( (1<<PB6) );
5
   DDRC &= ~( (1<<VERT_REF) | (1<<VERT_H_END) | (1<<TURN_REF) | (1<<SDA) | (1<<SCL) );
6
   DDRD &= ~( (1<<VERT_ENC_1) | (1<<VERT_ENC_2) | (1<<TURN_ENC_1) | (1<<TURN_ENC_2));
7
   
8
   // port outputs
9
   DDRA |= (1 << GRIP) | (1 << RESERVE0) | (1 << RESERVE1);
10
   DDRB |= (1 << SLID_3A) | (1 << SLID_4A) | (1 << TURN_1A) |  (1 << TURN_PWM) | (1 << TURN_2A) | (1 << LASER);
11
   DDRC |= (1 << VERT_DIRECTION) | (1 << VERT_STOP);
12
   DDRD |= (1 << VERT_PWM) | (1 << SLID_PWM);
13
   // activate pullup resistors
14
   PORTA |= ((1<<SLID_ENC_1) | (1<<SLID_ENC_2) | (1<<SLID_REF) | (1<<GRIP));
15
   PORTC |= ((1<<SDA) | (1<<SCL));
16
}
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

von let (Gast)


Angehängte Dateien:

Lesenswert?

Habe ich schon einmal geposted, finde den Beitrag aber nicht
mehr. Dort wurde auch noch eine andere (ähnliche) Lösung
vorgestellt.
1
#include <defines.h>
2
3
#define P_LED1    (B, 2)
4
#define P_KEY1    (C, 0)
5
6
int main()
7
{
8
   SET_DDR_OUT(P_LED1);
9
   SET_DDR_IN(P_KEY1);
10
   SETPIN(P_KEY1); // Pull-up ein
11
12
   for (;;) {
13
      if (GETPIN(P_KEY1))
14
         SETPIN(P_LED1);
15
      else
16
         CLRPIN(P_LED1);
17
   }
18
}

von Peter D. (peda)


Lesenswert?

Ich mach das immer ganz einfach mit Macros:
1
#include <io.h>
2
3
struct bits {
4
  uint8_t b0:1;
5
  uint8_t b1:1;
6
  uint8_t b2:1;
7
  uint8_t b3:1;
8
  uint8_t b4:1;
9
  uint8_t b5:1;
10
  uint8_t b6:1;
11
  uint8_t b7:1;
12
} __attribute__((__packed__));
13
14
#define SBIT(port,pin) ((*(volatile struct bits*)&port).b##pin)
15
16
17
18
#define KEY0            SBIT( PORTB, 0 )
19
#define KEY0_IN         SBIT( PINB, 0 )
20
21
#define LED0            SBIT( PORTB, 1 )
22
#define LED0_DDR        SBIT( DDRB, 1 )
23
24
25
int main( void )
26
{
27
  LED0_DDR = 1;         // output
28
  KEY0 = 1;             // pull up on
29
30
  for(;;){
31
32
    if( KEY0_IN == 0 )  // if key pressed (low)
33
      LED0 = 0;         // LED on (low)
34
    else
35
      LED0 = 1;         // LED off (high)
36
  }
37
}


Peter

von Matthias Kölling (Gast)


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

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.