Hi
Da ich gerade mit einem Drehencoder spiele, wollte ich Euch auch Was zum Spielen anbieten.
Der Sketch läuft bei mir auf einem Nano, sollte somit auch auf einem Uno funktionieren, bei einem Mega müsste man die Register für die ISR-Routinen wohl anpassen.
//Beispiel und Auflistung der verschiedenen Vectoren
//Quelle:https://thewanderingengineer.com/2014/08/11/arduino-pin-change-interrupts/
//
//Zuordnung Arduino-Pins zu PCINT-Nummer nach
// -Link entfernt-, siehe Post #2
//
//Aufblasen des Code durch boolean-Merker und einer Anzeige, welchen Status wir haben
//bei Änderungen durch Drehencoder
//alle 2 Sekunden nach der letzten Ausgabe *111 0 92 0 -> ABC Status Wert Anzahl
//A,B die Phasen des Drehencoder, pro Raste 11 01 00 10
//C Button, gedrückt 0, zählt auch Status um 1 hoch
//Status, das aktuelle 'Programm' - Quasi-PWM 0, oder Zahl Blinken 1
//Wert die vorzublinkende Zahl oder die Offzeit beim Quasi-PWM
//Anzahl Summe der aufgerufenen ISR
//ISR(PCINT0_vect){} // Port B, PCINT0 - PCINT7 (D8,D9,D10,D11,D12,D13,--,--) (XTAL1 & XTAL2)
//ISR(PCINT1_vect){} // Port C, PCINT8 - PCINT14 (D14,D15,D16,D17,D18,D19,--,-- (Reset, nicht vorhanden)
//ISR(PCINT2_vect){} // Port D, PCINT16 - PCINT23 (D0,D1,D2,D3,D4,D5,D6,D7) (D0 & D1 RX/TX SERIAL-USB-Anschluss)
#include <avr/interrupt.h>
volatile uint16_t value = 92; //wird hoch/runter gezählt durch Encoder
volatile uint16_t value2 = 0; //wird nur hoch gezählt in jeder ISR
volatile boolean a = 1, b = 1, c = 1, aold = 1, bold = 1, cold = 1, newset = 0, newc = 0; //Merker für die Phasen, den Button und, ob eine ISR ausgelöst hat
uint16_t status = 0; //wird durch Drücken des Button geändert
//um eine Zahl ausblinken zu lassen
const int ledPin = LED_BUILTIN;// the number of the LED pin
// Nicht ändern, da die Pin-Nummern mit den Bitmasken überein stimmen müssen
//Phase b und Button sind an PCINT1, Phase a an PCINT0
const byte pinPhaseA=17;
const byte pinPhaseB=8;
const byte pinButton=9;
void setup()
{
cli();
PCICR |= 0b00000011; // Enables Ports B and C Pin Change Interrupts
PCMSK0 |= 0b00000011; // PCINT0 = D8 -> PCINT0, D9 -> PCINT1
PCMSK1 |= 0b00001000; // PCINT11 = D17/A3 -> PCINT1
pinMode(pinPhaseA, INPUT_PULLUP);
pinMode(pinPhaseB, INPUT_PULLUP);
pinMode(pinButton, INPUT_PULLUP);
sei();
Serial.begin(9600);
}
void loop()
{
static unsigned long oldmillis = millis();
if (millis() - oldmillis >= 2000) {
oldmillis += 2000;
Serial.print("*");
printer();
newset = 0;
}
if (newset == 1) {
oldmillis = millis();
newset = 0;
printer();
}
if (newc == 1) {
newc = 0;
status++;
}
switch (status) {
case 0: //Lampe blitzen lassen, ONtime 10ms, OFFtime value
blitzout(10, value);
break;
case 1: //LED die Zahl vorblinken lassen, value in Impulsen ausgeben
impulseout();
break;
case 2: status = 0; //zurück setzen
}
}
void printer(void) {
Serial.print(a);
Serial.print(b);
Serial.print(c);
Serial.print(" ");
Serial.print(status);
Serial.print(" ");
Serial.print(value);
Serial.print(" ");
Serial.println(value2);
}
ISR(PCINT0_vect)
{
b = digitalRead(pinPhaseB);
c = digitalRead(pinButton);
if (b != bold) {
if (a == b) {
value++;
} else {
value--;
}
bold = b;
}
if (c != cold) {
if (c == 0) {
newc = 1;
}
cold = c; //hier wird nur C angepasst, kann im Programm dann normal ausgelesen werden
}
value2++;
newset = 1;
}
ISR(PCINT1_vect)
{
a = digitalRead(pinPhaseA);
if (aold != a) {
if (a == b) {
value--;
} else {
value++;
}
aold = a;
}
value2++;
newset = 1;
}
/*
Funktion gibt den Wert der Variable 'value' 10-stellig in Blinkimpulsen aus (32bit = 10stellig)
Vor dem Ziffernblinken wird der Ausgang 'ledPin' auf LOW gesetzt
Vor und Nach dem Ziffernblinken wird eine 'wartezeit' ... gewartet :) - in ms
Führende Nullen werden ignoriert
1-9 Blinkimpulse mit gleich langer Pause, Länge 'waitkurz' ms
0 Blinkimpuls mit 3-facher Länge
Zwischen den Ziffern Pause in 3-facher Länge
*/
void impulseout(void) {
const uint16_t waitkurz = 400; //ms, Die ein Impuls hell bleibt (x3 für Null, x3 für Pause zwischen Ziffern)
const uint16_t wartezeit = 1000; //ms vor und nach dem Ziffernblinken
static byte ziffer[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; //Merker für die Ziffernzeichen
static byte blinkstatus = 0; //State der Blink-Maschine
static unsigned long blinkvalue2, millisstart; //Berechnung, Merker für Startzeit
uint32_t zehnerpotenz = 1000000000; //Berechnung, Start-Zehnerpotenz
static byte i, i2; //Merker für die aktuelle Ziffer bzw. den darzustellenden Wert
switch (blinkstatus) {
case 0:
blinkvalue2 = value; //Den aktuellen Zahlenwert übernehmen
i = 10; //und in das Ziffern-Array packen
while (i > 0) { //Die Zahl in Einzelziffern aufteilen, pow versagte mit 999999 für 10^5
i--;
ziffer[i] = blinkvalue2 / zehnerpotenz;
Serial.print(ziffer[i]);
Serial.print(" ");
blinkvalue2 -= ziffer[i] * zehnerpotenz;
zehnerpotenz /= 10;
}
Serial.println();
blinkstatus++; //Weiter mit Status 1
millisstart = millis(); //merken, wann wir aufgerufen wurden wegen der Start-Pause
digitalWrite(ledPin, LOW); //Pin für Anzeige AUS schalten
break;
case 1:
if (millis() - millisstart >= wartezeit) { //Anfangs-Wartezeit, damit die LED vor dem Blinken AUS war
//ziffer[7]...ziffer[0] = Anzahl der Blinkimpulse
//die erste Ziffer (oder die Null beim Einer) erfassen
i = 10; //mit 100000er anfangen //erste Ziffer auslesen, führende Nullen ignorieren, Einer-Null ausgeben
do {
i--;
i2 = ziffer[i];
} while (i2 == 0 && i != 0);
blinkstatus++; //Weiter mit der HIGH-Phase für diese Ziffer
}
break;
case 2:
digitalWrite(ledPin, HIGH); //LES für Ziffer AN
millisstart = millis(); //merken, wann die HIGH-Phase gestartet hat
blinkstatus++; //und zur Abschaltung
break;
case 3:
if (millis() - millisstart >= waitkurz * (i2 == 0 ? 3 : 1)) { //bei einer Null länger bis zum LOW warten
digitalWrite(ledPin, LOW);
millisstart = millis(); //merken, wann wir die LED abgeschaltet haben
blinkstatus++; //weiter um neue Ziffer auszulesen oder die Aktuelle fertig zu blinken
}
break;
case 4:
if (millis() - millisstart >= waitkurz * (i2 <= 1 ? 3 : 1)) { //nach dem 1er oder 0er Blink-Impuls Pause zwischen den Ziffern
if (i2 > 1) {
i2--; //Ziffer noch nicht fertig, weiteren Blinkzyklus einleiten
blinkstatus -= 2; //2 hoch zu 'LED AN'
} else {
if (i > 0) { //wenn noch Ziffern auszugeben sind, dann die Nächste auslesen
i--;
i2 = ziffer[i]; //die neue Ziffer auslesen
blinkstatus -= 2; //weiter mit 'LED AN'
} else {
blinkstatus++; //sonst weiter mit End-Pause
}
}
}
break;
case 5:
if (millis() - millisstart >= wartezeit) { //Wartezeit nach dem Ziffernblinken
blinkstatus++; //verlassen wir die Blinkerei
}
break;
default:
status++; //diesen Modus wieder verlassen, zur 'normalen' Blinkerei wechseln
blinkstatus = 0; //für den nächsten Start vorbereiten
}
}
// Siehe #4
//Wenn keine 2er Potenzen als Summe von ontime und offtime benutzt werden, spielt
//die Funktion nach 49 Tagen verrückt - Überlauf von millis() und somit ein Sprung in der 'Zeitlinie'
//4294967295ms = 49 Tage, 17 Stunden, 2 Minuten, 47 Sekunden und 275 Millisekunden.
void blitzout(uint16_t ontime, uint16_t offtime) {
//Wielle Quasi-PWM: http://forum.arduino.cc/index.php?topic=530097.msg3621399#msg3621399
digitalWrite(ledPin, (millis() % ((uint32_t)ontime + offtime) < ontime)); //(millis()%ontime+offtime)<ontime}
}
eBay, Drehencoder ALPS, Beispiel-Link
MfG
Edit
Link im Quellcode entfernt
Anmerkung zu millis() in #4 im Code eingebracht