Generische Portzuweisungen
Schreibt man einen Treiber für eine Mikrocontrollerapplikation (z. B. für ein USB-Device oder LCD-Display), so will man diesen meist in späteren Projekten wiederverwenden wollen. Deshalb werden insbesondere Port- und Pinzuweisungen an einer zentralen Stelle definiert. Da hierfür bei AVR/Atmel-Prozessoren gleich drei Register (Richtung, Eingang, Ausgang bzw. DDR, PORT, PIN) nötig sind, muss man hierfür auch drei “später anzupassende” Zeilen vorsehen:
#define USB_OUT PORTD #define USB_IN PIND #define USB_DDR DDRD
Dank reverse-Engineering eines anderen Problems bin ich heute auf folgende (meines Erachtens geniale) Codestelle gestoßen, wie dieses Problem möglichst generisch und kurz gelöst wird:
// 1. concatenation-macro: #define CONCAT(a, b) a ## b
// 2. generic macros for PORT, PIN and DDR (AVR/Atmel): #define OUTPORT(name) CONCAT(PORT, name) #define INPORT(name) CONCAT(PIN, name) #define DDRPORT(name) CONCAT(DDR, name)
// 3. spezific macros for USB-module: #define USB_OUT OUTPORT(USB_CFG_IOPORTNAME) #define USB_IN INPORT(USB_CFG_IOPORTNAME) #define USB_DDR DDRPORT(USB_CFG_IOPORTNAME)
Somit ist statt obigem Dreizeiler nur noch folgendes nötig:
#define USB_CFG_IOPORTNAME B
Auf den ersten Blick sieht dies jetzt viel komplexer als obere Variante aus. Um aber in einem späteren Projekt einen anderen Port zu verwenden, ist nur eine statt drei Zeilen anzupassen – somit besteht auch nicht die Gefahr, eine dieser Zeilen zu “vergessen”.
Außerdem sind Block #1 und #2 wiederverwendbar, Beispiel:
#define LCD_PORTNAME B #define LCD_PORT OUTPORT (LCD_PORTNAME) #define LCD_DDR DDRPORT (LCD_PORTNAME)
18. Juli 2010 | von Markus
Kategorie:
Letzte Kommentare