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
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
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
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 } |
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
Datum: 17.05.2008 19:29
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); } } |
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
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