Setup (Arduino Pro Mini ATmega328p 16MHz, 5V, kein Pin verbunden):
Bei einem Aufruf aus der setup()
funktioniert das:
pinMode(11, INPUT_PULLUP);
bool identifiesAsFast = digitalRead(11); // always true
Dies nicht:
const uint8_t identificationPinBitNumber = PB3; // pin 11
const byte identificationPinBit = bit(identificationPinBitNumber);
DDRB &= ~identificationPinBit;
PORTB |= identificationPinBit;
bool identifiesAsFast = PINB & identificationPinBit; // occasionally false
Pin 11 ist nicht angeschlossen, aber - wie man oben sieht - habe ich ihn hochgezogen. Ich würde also erwarten, dass es immer einen Wert von 1 hat.
Was übersehe ich bei der direkten Port-Manipulation?
Ich bekomme das Verhalten mit vier verschiedenen Arduino Pro Minis. Alle sind originale Pro Minis, entworfen von Sparkfun, hergestellt in den USA und gekauft von Digi-Key. Eine davon habe ich frisch aus der Originaltüte gezogen. Möglicherweise muss ich den FTDI-Adapter ungefähr dreißig Mal entfernen und wieder einsetzen, aber schließlich kann ich das Problem reproduzieren.
Das Hinzufügen einer Verzögerung von 100 ms zwischen dem Hochziehen von Pin 11 und dem Lesen scheint das Problem zu lösen. Ich verstehe jedoch nicht, warum diese Verzögerung notwendig sein sollte.
PB3
für Pin 11 ist korrekt, wie ich verifiziert habe, indem ich eine LED angeschlossen und zum Blinken gebracht habe. Siehe auch das Pin-Mapping-Diagramm, das an anderer Stelle im Internet zu finden ist:
Vollständiger Code:
// Felix E. Klee <felix.klee@inka.de>
const uint8_t ledPinBitNumber = PB5; // pin 13
const byte ledPinBit = bit(ledPinBitNumber);
const uint8_t identificationPinBitNumber = PB3; // pin 11
const byte identificationPinBit = bit(identificationPinBitNumber);
unsigned long delayDuration; // ms
void turnLedOn() {
PORTB |= ledPinBit;
}
void turnLedOff() {
PORTB &= ~ledPinBit;
}
void setDelayDuration() {
#if 0
pinMode(11, INPUT_PULLUP);
bool identifiesAsFast = digitalRead(11); // always true
#else
// Input pullup:
DDRB &= ~identificationPinBit;
PORTB |= identificationPinBit;
bool identifiesAsFast = PINB & identificationPinBit; // occasionally false
#endif
delayDuration = identifiesAsFast ? 300 : 3000;
}
void setup() {
DDRB |= ledPinBit; // Set up LED pin for output
setDelayDuration();
}
void loop() {
turnLedOn();
delay(delayDuration);
turnLedOff();
delay(delayDuration);
}
So seltsam das auch klingen mag, Ihr Code ist zu schnell .
Der Stift (und der Teil des Steckbretts, an den er angeschlossen ist) hat eine gewisse Kapazität. Es dauert einige Zeit, bis der resistive Pullup im AVR den Pin hochzieht.
Das Arduino pinMode()
und digitalRead()
die Funktionen sind langsam genug, dass der Pullup seine Arbeit erledigt hat, wenn sie zum Lesen des Pins kommen. Ihr Code greift direkt auf Register zu, was erheblich schneller ist – daher ist es möglich, dass der Pin beim Lesen immer noch niedrig ist.
Die benötigte Verzögerung ist jedoch ziemlich gering. 50 Mikrosekunden (nicht Millisekunden!) sollten ausreichen.
Du machst es falsch!
Ein Arduino-Port besteht aus 8 Pins, zum Beispiel PB0, PB2, PB3, ..., PB7.
Wenn Sie ein Register oder ein Bit oder einige Bits manipulieren möchten, müssen Sie möglicherweise wie folgt vorgehen:
PORTB |= (1 << PB5) // Set a bit
PORTB &= ~(1 << PB5) // Clear a bit
PORTB &= ~(1 << PB5) // Clear a bit
Ich kann nicht bearbeiten, da es sich um eine einzelne Zeichenänderung handelt.bit
(in Arduino.h definiert ) und Konstanten ersetzen, sehen wir, dass das PORTB |= identificationPinBit
gleich ist PORTB |= 1ul << PB3
. Das Problem liegt woanders.define
wird irgendwo in der Arduino-internen Maschine verwendet, was ich über bit()
die Funktion finde, kann sich darauf beziehen .
feklee
feklee