Add CesarSound code.

This commit is contained in:
mattbk
2024-01-26 10:26:49 -06:00
parent b2345cf54e
commit 1cda782316
10 changed files with 624 additions and 375 deletions

76
lib/Rotary/README.md Normal file
View File

@ -0,0 +1,76 @@
Rotary Encoder Arduino Library
==============================
Arduino library for reading rotary encoders that output a 2-bit [gray code](http://en.wikipedia.org/wiki/Gray_code).
Rotary r = Rotary(2, 3);
void setup() {
r.begin();
}
void loop() {
result = r.process();
if (result) {
Serial.println(result == DIR_CW ? "Right" : "Left");
}
}
This is a repackaged version of Ben Buxton's excellent [rotary library](http://www.buxtronix.net/2011/10/rotary-encoders-done-properly.html) organized for the Arduino 1.x IDE, keyword highlighting, polling example, Arduino library capitalization conventions.
Features
--------
* Debounce handling with support for high rotation speeds
* Correctly handles direction changes mid-step
* Checks for valid state changes for more robust counting / noise immunity
* Interrupt based or polling in loop()
* Counts full-steps (default) or half-steps
* Supports use with pull-up (default) and pull-down resistors
Installation / Usage
--------------------
1. Download and unzip to Arduino\\libraries\\Rotary. So for example Rotary.h will be in Arduino\\libraries\\Rotary\\Rotary.h.
2. Restart Arduino IDE
3. File -> Examples -> Rotary
Note: Resistor usage is specified through `void begin(bool internalPullup=true, bool flipLogicForPulldown=false)`.
* `r.begin()` enables the Arduino's internal weak pull-ups for the rotary's pins
* `r.begin(false)` disables the Arduino's internal weak pull-ups for the given pins and configures the rotary for use with external _pull-ups_
* `r.begin(false, true)` disables the internal pull-ups and flips the pin logic for use with external _pull-downs_
Background
----------
A typical mechanical rotary encoder emits a two bit gray code on 3 output pins. Every step in the output (often accompanied by a physical 'click') generates a specific sequence of output codes on the pins.
There are 3 pins used for the rotary encoding - one common and two 'bit' pins.
The following is the typical sequence of code on the output when moving from one step to the next:
Position Bit1 Bit2
- - - - - - - - - - -
Step1 0 0
1/4 1 0
1/2 1 1
3/4 0 1
Step2 0 0
From this table, we can see that when moving from one 'click' to the next, there are 4 changes in the output code.
- From an initial 0 - 0, Bit1 goes high, Bit0 stays low.
- Then both bits are high, halfway through the step.
- Then Bit1 goes low, but Bit2 stays high.
- Finally at the end of the step, both bits return to 0.
Detecting the direction is easy - the table simply goes in the other direction (read up instead of down).
To decode this, we use a simple state machine. Every time the output code changes, it follows state, until finally a full steps worth of code is received (in the correct order). At the final 0-0, it returns a value indicating a step in one direction or the other.
It's also possible to use 'half-step' mode. This just emits an event at both the 0-0 and 1-1 positions. This might be useful for some encoders where you want to detect all positions. In Rotary.h, uncomment `#define HALF_STEP` to enable half-step mode.
If an invalid state happens (for example we go from '0-1' straight to '1-0'), the state machine resets to the start until 0-0 and the next valid codes occur.
The biggest advantage of using a state machine over other algorithms is that this has inherent debounce built in. Other algorithms emit spurious output with switch bounce, but this one will simply flip between sub-states until the bounce settles, then continue along the state machine. A side effect of debounce is that fast rotations can cause steps to be skipped. By not requiring debounce, fast rotations can be accurately measured. Another advantage is the ability to properly handle bad state, such as due to EMI, etc. It is also a lot simpler than others - a static state table and less than 10 lines of logic.
License
-------
GNU GPL Version 3

102
lib/Rotary/Rotary.cpp Normal file
View File

@ -0,0 +1,102 @@
/* Rotary encoder handler for arduino.
*
* Copyright 2011 Ben Buxton. Licenced under the GNU GPL Version 3.
* Contact: bb@cactii.net
*
*/
#include "Arduino.h"
#include "Rotary.h"
/*
* The below state table has, for each state (row), the new state
* to set based on the next encoder output. From left to right in,
* the table, the encoder outputs are 00, 01, 10, 11, and the value
* in that position is the new state to set.
*/
#define R_START 0x0
#ifdef HALF_STEP
// Use the half-step state table (emits a code at 00 and 11)
#define R_CCW_BEGIN 0x1
#define R_CW_BEGIN 0x2
#define R_START_M 0x3
#define R_CW_BEGIN_M 0x4
#define R_CCW_BEGIN_M 0x5
const unsigned char ttable[6][4] = {
// R_START (00)
{R_START_M, R_CW_BEGIN, R_CCW_BEGIN, R_START},
// R_CCW_BEGIN
{R_START_M | DIR_CCW, R_START, R_CCW_BEGIN, R_START},
// R_CW_BEGIN
{R_START_M | DIR_CW, R_CW_BEGIN, R_START, R_START},
// R_START_M (11)
{R_START_M, R_CCW_BEGIN_M, R_CW_BEGIN_M, R_START},
// R_CW_BEGIN_M
{R_START_M, R_START_M, R_CW_BEGIN_M, R_START | DIR_CW},
// R_CCW_BEGIN_M
{R_START_M, R_CCW_BEGIN_M, R_START_M, R_START | DIR_CCW},
};
#else
// Use the full-step state table (emits a code at 00 only)
#define R_CW_FINAL 0x1
#define R_CW_BEGIN 0x2
#define R_CW_NEXT 0x3
#define R_CCW_BEGIN 0x4
#define R_CCW_FINAL 0x5
#define R_CCW_NEXT 0x6
const unsigned char ttable[7][4] = {
// R_START
{R_START, R_CW_BEGIN, R_CCW_BEGIN, R_START},
// R_CW_FINAL
{R_CW_NEXT, R_START, R_CW_FINAL, R_START | DIR_CW},
// R_CW_BEGIN
{R_CW_NEXT, R_CW_BEGIN, R_START, R_START},
// R_CW_NEXT
{R_CW_NEXT, R_CW_BEGIN, R_CW_FINAL, R_START},
// R_CCW_BEGIN
{R_CCW_NEXT, R_START, R_CCW_BEGIN, R_START},
// R_CCW_FINAL
{R_CCW_NEXT, R_CCW_FINAL, R_START, R_START | DIR_CCW},
// R_CCW_NEXT
{R_CCW_NEXT, R_CCW_FINAL, R_CCW_BEGIN, R_START},
};
#endif
/*
* Constructor. Each arg is the pin number for each encoder contact.
*/
Rotary::Rotary(char _pin1, char _pin2) {
// Assign variables.
pin1 = _pin1;
pin2 = _pin2;
// Initialise state.
state = R_START;
// Don't invert read pin state by default
inverter = 0;
}
void Rotary::begin(bool internalPullup, bool flipLogicForPulldown) {
if (internalPullup){
// Enable weak pullups
pinMode(pin1,INPUT_PULLUP);
pinMode(pin2,INPUT_PULLUP);
}else{
// Set pins to input.
pinMode(pin1, INPUT);
pinMode(pin2, INPUT);
}
inverter = flipLogicForPulldown ? 1 : 0;
}
unsigned char Rotary::process() {
// Grab state of input pins.
unsigned char pinstate = ((inverter ^ digitalRead(pin2)) << 1) | (inverter ^ digitalRead(pin1));
// Determine new state from the pins and state table.
state = ttable[state & 0xf][pinstate];
// Return emit bits, ie the generated event.
return state & 0x30;
}

38
lib/Rotary/Rotary.h Normal file
View File

@ -0,0 +1,38 @@
/*
* Rotary encoder library for Arduino.
*/
#ifndef Rotary_h
#define Rotary_h
#include "Arduino.h"
// Enable this to emit codes twice per step.
// #define HALF_STEP
// Values returned by 'process'
// No complete step yet.
#define DIR_NONE 0x0
// Clockwise step.
#define DIR_CW 0x10
// Counter-clockwise step.
#define DIR_CCW 0x20
class Rotary
{
public:
Rotary(char, char);
unsigned char process();
void begin(bool internalPullup=true, bool flipLogicForPulldown=false);
inline unsigned char pin_1() const { return pin1; }
inline unsigned char pin_2() const { return pin2; }
private:
unsigned char state;
unsigned char pin1;
unsigned char pin2;
unsigned char inverter;
};
#endif

View File

@ -0,0 +1,37 @@
/*
Rotary Encoder - Interrupt Example
The circuit:
* encoder pin A to Arduino pin 2
* encoder pin B to Arduino pin 3
* encoder ground pin to ground (GND)
*/
#include <Rotary.h>
Rotary r = Rotary(2, 3);
void setup() {
Serial.begin(9600);
r.begin();
PCICR |= (1 << PCIE2);
PCMSK2 |= (1 << PCINT18) | (1 << PCINT19);
sei();
}
void loop() {
}
ISR(PCINT2_vect) {
unsigned char result = r.process();
if (result == DIR_NONE) {
// do nothing
}
else if (result == DIR_CW) {
Serial.println("ClockWise");
}
else if (result == DIR_CCW) {
Serial.println("CounterClockWise");
}
}

View File

@ -0,0 +1,50 @@
/*
Rotary Encoder - Interrupt Example
This is the same as "Interrupt.ino" but works
the Pro Micro from Sparkfun which uses the
Atmega32U4 microcontroller. This controller
does not have the PCIE2 or PCMSK2 registers used in the
Interrupt example. Instead these are moved
to the PCIE0 and PCMSK0 registers instead.
These registers support interrupts on Pro Micro
pins 8, 9, 10 or 11. This example wires the encoder
to pins 8 and 9.
Note that the interrupt vector also changes to
correspond to the PCIE0 interrupt.
The circuit:
* encoder pin A to Arduino pin 8
* encoder pin B to Arduino pin 9
* encoder ground pin to ground (GND)
*/
#include <Rotary.h>
Rotary r = Rotary(8, 9);
void setup() {
Serial.begin(9600);
r.begin();
PCICR |= (1 << PCIE0);
PCMSK0 |= (1 << PCINT4) | (1 << PCINT5);
sei();
}
void loop() {
}
ISR(PCINT0_vect) {
unsigned char result = r.process();
if (result == DIR_NONE) {
// do nothing
}
else if (result == DIR_CW) {
Serial.println("ClockWise");
}
else if (result == DIR_CCW) {
Serial.println("CounterClockWise");
}
}

View File

@ -0,0 +1,25 @@
/*
Rotary Encoder - Polling Example
The circuit:
* encoder pin A to Arduino pin 2
* encoder pin B to Arduino pin 3
* encoder ground pin to ground (GND)
*/
#include <Rotary.h>
Rotary r = Rotary(2, 3);
void setup() {
Serial.begin(9600);
r.begin(true);
}
void loop() {
unsigned char result = r.process();
if (result) {
Serial.println(result == DIR_CW ? "Right" : "Left");
}
}

6
lib/Rotary/keywords.txt Normal file
View File

@ -0,0 +1,6 @@
Rotary KEYWORD1
process KEYWORD2
begin KEYWORD2
DIR_NONE LITERAL1
DIR_CW LITERAL1
DIR_CCW LITERAL1