-
-
Notifications
You must be signed in to change notification settings - Fork 34
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #2 from Makuna/rotaryencoderexample
New Rotary Encoder Example
- Loading branch information
Showing
5 changed files
with
293 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
// RotaryEncoder | ||
// This demonstrates the use of the custom Task object feature of Task library | ||
// It will instance one custom RotaryEncoderTask to monitor three pins that a | ||
// rotary encoder is connected to and make call backs when they change state; | ||
// the press button will have debouce and auto repeat support; | ||
// the rotary will tell direction and keep track of "clicks" rotated | ||
// This requires a standard rotary encoder be attached to the defined pins, | ||
// | ||
// Usefull information will be sent to the serial monitor | ||
// | ||
// make sure that you connect your rotary encoder correctly, include gnd and Vcc (+) | ||
|
||
#include <Arduino.h> | ||
|
||
// nothing special about these pins, just make sure they don't collide with | ||
// other active features | ||
#define ClockPin 4 // labeled either as CLK or as A | ||
#define DataPin 5 // labeled either as DT or as B | ||
#define ButtonPin 2 // labeled as SW | ||
|
||
// include libraries | ||
#include <Task.h> | ||
|
||
// include sub files | ||
#include "RotaryEncoderTask.h" // this implements the rotary encoder task | ||
|
||
TaskManager taskManager; | ||
|
||
// foreward delcare functions passed to task constructors now required | ||
void HandleButtonChanged(EncoderButtonState state); | ||
void HandleRotationChanged(int8_t rotationDelta); | ||
|
||
|
||
RotaryEncoderTask RotaryTask(HandleRotationChanged, | ||
HandleButtonChanged, | ||
ClockPin, | ||
DataPin, | ||
ButtonPin); | ||
|
||
void setup() | ||
{ | ||
Serial.begin(57600); | ||
while (!Serial); // wait for serial monitor to connect | ||
|
||
|
||
taskManager.StartTask(&RotaryTask); | ||
|
||
Serial.println("Running..."); | ||
} | ||
|
||
void loop() | ||
{ | ||
taskManager.Loop(); | ||
} | ||
|
||
void HandleButtonChanged(EncoderButtonState state) | ||
{ | ||
if (state == EncoderButtonState_Pressed) | ||
{ | ||
Serial.println("Pressed - "); | ||
} | ||
else if (state == EncoderButtonState_Released) | ||
{ | ||
Serial.println("Released - "); | ||
} | ||
else | ||
{ | ||
Serial.println("Auto-repeat - "); | ||
} | ||
} | ||
|
||
void HandleRotationChanged(int8_t rotationDelta) | ||
{ | ||
if (rotationDelta > 0) | ||
{ | ||
Serial.print("clockwise = "); | ||
} | ||
else | ||
{ | ||
Serial.print("counter-clockwise = "); | ||
} | ||
|
||
Serial.println(RotaryTask.RotationValue()); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,183 @@ | ||
// This assumes the encoder is in a circuit that pulls the pins high in the normal off state | ||
// and when then encoder is rotated the pin is pulled low | ||
// | ||
// you can just copy this whole file into your project and use it | ||
|
||
enum EncoderButtonState | ||
{ | ||
EncoderButtonState_Released = 0b00000000, | ||
EncoderButtonState_Pressed = 0b00000001, | ||
EncoderButtonState_AutoRepeat = 0b00000011, | ||
EncoderButtonState_Tracking = 0b10000001 | ||
}; | ||
|
||
class RotaryEncoderTask : public Task | ||
{ | ||
public: | ||
typedef void(*buttonAction)(EncoderButtonState state); | ||
typedef void(*rotationAction)(int8_t rotationDelta); | ||
|
||
RotaryEncoderTask(rotationAction rotationFunction, | ||
buttonAction buttonFunction, | ||
uint8_t pinClock, // also refered to as A | ||
uint8_t pinData, // also refered to as B | ||
uint8_t pinButton, | ||
int32_t rotationValue = 0) : | ||
Task(MsToTaskTime(5)), // check every five millisecond, 1-10 ms should be ok | ||
_buttonPin(pinButton), | ||
_clockPin(pinClock), | ||
_dataPin(pinData), | ||
_rotationCallback(rotationFunction), | ||
_buttonCallback(buttonFunction), | ||
_buttonState(EncoderButtonState_Released), | ||
_clockState(HIGH), | ||
_rotationValue(rotationValue) | ||
{ | ||
}; | ||
|
||
int32_t RotationValue() | ||
{ | ||
return _rotationValue; | ||
} | ||
|
||
private: | ||
static const uint16_t _debouceMs = 50; // (30-100) are good values | ||
static const uint16_t _repeatDelayMs = 600; // (400 - 1200) are reasonable values | ||
static const uint16_t _repeatRateMs = 50; // (40-1000) are reasonable | ||
|
||
const uint8_t _buttonPin; | ||
const uint8_t _clockPin; | ||
const uint8_t _dataPin; | ||
|
||
const rotationAction _rotationCallback; | ||
const buttonAction _buttonCallback; | ||
|
||
int32_t _rotationValue; | ||
uint16_t _buttonTimer; | ||
|
||
EncoderButtonState _buttonState; | ||
uint8_t _clockState; | ||
|
||
|
||
virtual bool OnStart() | ||
{ | ||
pinMode(_buttonPin, INPUT_PULLUP); | ||
pinMode(_clockPin, INPUT_PULLUP); | ||
pinMode(_dataPin, INPUT_PULLUP); | ||
_buttonState = EncoderButtonState_Released; | ||
_clockState = HIGH; | ||
return true; | ||
} | ||
|
||
virtual void OnUpdate(uint32_t deltaTime) | ||
{ | ||
uint16_t deltaTimeMs = TaskTimeToMs(deltaTime); | ||
|
||
CheckButton(deltaTimeMs); | ||
|
||
// ignore the rotary if button is pressed | ||
if (_buttonState == EncoderButtonState_Released) | ||
{ | ||
CheckRotation(deltaTimeMs); | ||
} | ||
} | ||
|
||
void CheckRotation(uint16_t deltaTimeMs) | ||
{ | ||
uint8_t clockState = digitalRead(_clockPin); | ||
uint8_t dataState = digitalRead(_dataPin); | ||
|
||
// check for any change in the clock pin state | ||
if (clockState != _clockState) | ||
{ | ||
if (clockState == LOW) | ||
{ | ||
// just read clock trigger | ||
if (dataState == LOW) | ||
{ | ||
// clockwise | ||
_rotationValue++; | ||
_rotationCallback(1); | ||
} | ||
else | ||
{ | ||
// counter-clockwise | ||
_rotationValue--; | ||
_rotationCallback(-1); | ||
} | ||
} | ||
|
||
_clockState = clockState; | ||
} | ||
} | ||
|
||
void CheckButton(uint16_t deltaTimeMs) | ||
{ | ||
EncoderButtonState pinState = (digitalRead(_buttonPin) == LOW) ? EncoderButtonState_Pressed : EncoderButtonState_Released; | ||
|
||
if (pinState != (_buttonState & EncoderButtonState_Pressed)) | ||
{ | ||
if (pinState == EncoderButtonState_Pressed) | ||
{ | ||
// just read button down and start timer | ||
_buttonTimer = _debouceMs; | ||
_buttonState = EncoderButtonState_Tracking; | ||
} | ||
else | ||
{ | ||
if ((_buttonState & EncoderButtonState_Tracking) == EncoderButtonState_Pressed) // not tracking | ||
{ | ||
// triggered released | ||
_buttonCallback(EncoderButtonState_Released); | ||
} | ||
_buttonState = EncoderButtonState_Released; | ||
} | ||
} | ||
else | ||
{ | ||
switch (_buttonState) | ||
{ | ||
case EncoderButtonState_Tracking: | ||
if (deltaTimeMs >= _buttonTimer) | ||
{ | ||
// press debounced | ||
_buttonState = EncoderButtonState_Pressed; | ||
_buttonTimer = _repeatDelayMs; | ||
_buttonCallback(EncoderButtonState_Pressed); | ||
} | ||
else | ||
{ | ||
_buttonTimer -= deltaTimeMs; | ||
} | ||
break; | ||
|
||
case EncoderButtonState_Pressed: | ||
if (deltaTimeMs >= _buttonTimer) | ||
{ | ||
// auto repeat started | ||
_buttonState = EncoderButtonState_AutoRepeat; | ||
_buttonTimer = _repeatRateMs; | ||
_buttonCallback(EncoderButtonState_AutoRepeat); | ||
} | ||
else | ||
{ | ||
_buttonTimer -= deltaTimeMs; | ||
} | ||
break; | ||
|
||
case EncoderButtonState_AutoRepeat: | ||
if (deltaTimeMs >= _buttonTimer) | ||
{ | ||
// auto repeat triggered again | ||
_buttonTimer += _repeatRateMs; | ||
_buttonCallback(EncoderButtonState_AutoRepeat); | ||
} | ||
else | ||
{ | ||
_buttonTimer -= deltaTimeMs; | ||
} | ||
break; | ||
} | ||
} | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
{ | ||
"name": "Task by Makuna", | ||
"keywords": "multitasking, task, timer", | ||
"description": "A library that makes creating complex mulitple task projects easy.", | ||
"repository": | ||
{ | ||
"type": "git", | ||
"url": "https://github.com/Makuna/Task.git" | ||
}, | ||
"frameworks": "arduino", | ||
"platforms": "*", | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,9 @@ | ||
name=Task by Makuna | ||
version=1.0 | ||
version=1.1 | ||
author=Michael C. Miller ([email protected]) | ||
maintainer=Michael C. Miller ([email protected]) | ||
sentence=A library that makes creating complex mulitple task projects easy. | ||
paragraph=This implements a Nonpreemptive multitasking library which is effecient in speed and memory, which is good for small Arduino hardware. While multitasking is an advanced topic, our friends at AdaFruit have a great article on it here (https://learn.adafruit.com/multi-tasking-the-arduino-part-1?view=all), Samples include blinking an LED without using delay(), monitoring and reacting to a button press, and cross task messaging. Tested on esp8266. | ||
paragraph=This implements a Nonpreemptive multitasking library which is effecient in speed and memory, which is good for small Arduino hardware. While multitasking is an advanced topic, our friends at AdaFruit have a great article on it here (https://learn.adafruit.com/multi-tasking-the-arduino-part-1?view=all), Samples include blinking an LED without using delay(), monitoring and reacting to a button press, cross task messaging, and rotary encoder. Tested on AVR and esp8266. | ||
category=Timing | ||
url=https://github.com/Makuna/Task | ||
architectures=* |