Zur Vorgeschichte:
Ich muss in den nächsten Tagen eine seit einigen Jahren funktionierende sowie mit wenigen Kenntnissen gebaute Steuerung überarbeiten und dann als nicht mehr zu änderndes Objekt hinterlassen. Was sehr Hardwarenah ist, ist irgendwo zusammengeklaubt...
Aufgebaut wurde das mit einem MEGA.
Unter anderem wurde der gesamte Port K - also die AnalogPins 8 bis 15 - dafür vorgesehen, als ZählerPins zu fungieren. Das geht auch. Nach bisherigen Erkenntnissen auch fehlerfrei.
Die Zustände bleiben lange genug - ich werde die ISR PCINT2_vect nicht mehr ändern.
Aus dem letzten Backup von vor 5 Jahren stelle ich
- das komplett runtergekürzte Stück Code mal vor und
- die Frage, wie das zählen auf den Pins sonst gelöst werden könnte
(Flanke von HIGH nach LOW mit Ausschluss eines prellen)
/*
PinChangeInterrupt, ISR und Ausgabe
zusätzlich 8 Interruptkanäle
an den Analogports A8 bis A15 auf einem MEGA 2650
runtergekürzt aus Heizungssteuerung begrenzt auf die Volumenstromgeber
*/
volatile uint32_t pinscore[8] = {0, 0, 0, 0, 0, 0, 0, 0}; // Vorbelegung Zähler mit 0
volatile bool pinlaststate[8] = {1, 1, 1, 1, 1, 1, 1, 1}; // Vorbelegung für PinStatusAbfrage
long lastmillis = 0;
void setup(void)
{
Serial.begin(115200); // serieller Monitor
Serial.println(F("Start...."));//
pinMode(A8, INPUT_PULLUP); // PIN A8 bis A15 auf dem MEGA
pinMode(A9, INPUT_PULLUP); // als INPUT deklarieren und
pinMode(A10, INPUT_PULLUP); // den internen PULLUP aktivieren
pinMode(A11, INPUT_PULLUP); // PINs stehen auf HIGH
pinMode(A12, INPUT_PULLUP); // ausgewertet wird, wenn PIN auf
pinMode(A13, INPUT_PULLUP); // GND (LOW) geht
pinMode(A14, INPUT_PULLUP); // A8 = PCINT16 / A15 = PCINT23
pinMode(A15, INPUT_PULLUP); // AVR-Pin: 89-82
cli(); // schaltet Interrups ab
PCMSK2 = B11111111; // aktiviert PIN A8 bis A15 / entspricht PORT K
//PCMSK2 |= (1 << PCINT16); // alternativ: aktiviert nur PIN A8
//PCMSK2 |= (1 << PCINT17); // alternativ: aktiviert nur PIN A9
PCICR |= (1 << PCIE1); // aktiviert PinChangeInterrupt (im) ControlRegister
sei(); // schaltet Interrupts wieder ein
}
ISR(PCINT2_vect) // Name ist zwingend festgelegt
{
static uint32_t pinLastMillis[8] = {0, 0, 0, 0, 0, 0, 0, 0};// wird nur hier gebraucht
const uint8_t pindebounce[8] = {0, 0, 0, 0, 0, 0, 0, 0}; // festlegen der Bouncezeit je PIN in ms
// const int pindebounce = 40; // Wenn nur eine Zeit ausreicht
unsigned char portstate = PINK; // PINK ist nicht die Farbe sondern der PINportK
// // kopiert den Zustand in eine Variable
for (uint8_t i = 0; i <= 7; i++) // Auswertung: jeden einzelnen PIN
{
if (pinlaststate[i] != ((portstate << i) & 0x80 )) // Hat sich der PINZustand verändert?
{
if (millis() - pinLastMillis[i] > pindebounce[i]) // Wenn ja: Ist die Bouncezeit abgelaufen?
{
/* if (millis() - pinlastmillis[i] > pindebounce) { */// (Alternative wenn nur eine Bouncetime)
pinlaststate[i] = ((portstate << i) & 0x80 ); // Dann speichere aktuellen Zustand und ...
pinLastMillis[i] = millis(); // ... speichere aktuelle millis und ...
if (0 == pinlaststate[i]) // ... prüfe ob der Zustand jetzt 0 ist
{
pinscore[i]++; // wenn ja, dann zähle für den PIN +1
}
}
}
}
}
void loop(void)
{
static uint32_t lastmillis = 0;
//delay(2000); // delay um zu zeigen, das Interrupt unabhängig von delay()
if (millis() - lastmillis >= 2000) // gibt nur alle xxx ms eine Ausgabe - gezählt wird trotzdem
{
Serial.print(F("Score in loop: ")); // Ausgabe des Inhalts des Zählers, um zu zeigen, das und wie man an die
for (uint8_t i = 5; i <= 7; i++) // Zählerinhalte innerhalb von loop kommt.
{
Serial.print(pinscore[i]);
// pinscore[i] = 0;
Serial.print(";");
}
Serial.println();
lastmillis = millis();
}
}