Skip to content

Instantly share code, notes, and snippets.

@carlcrott
Created November 2, 2012 04:27
Show Gist options
  • Save carlcrott/3998720 to your computer and use it in GitHub Desktop.
Save carlcrott/3998720 to your computer and use it in GitHub Desktop.
// OSH orbital shaker: www.black-glass.com
// TYVM Mayhew Labs: www.mayhewlabs.com/products/rotary-encoder-led-ring
// TYVM Mike McCauley: www.open.com.au/mikem/arduino/AccelStepper/
#include <AccelStepper.h>
// ####### Encoder Variables #######
//These are the pins that will talk to the shift register through SPI
#define SDI 11 //Data
#define CLK 12 //Clock
#define LE 13 //Latch
//These are the rotary encoder pins A, B, and switch
#define ENC_A 8
#define ENC_B 9
#define ENC_SW 10
#define ENC_PORT PINB //The port that the rotary encoder is on (see http://www.arduino.cc/en/Reference/PortManipulation)
// Global variables
int scaledCounter = 0; //The LED output is based on a scaled veryson of the rotary encoder counter
int sequenceNumber = 0; //The output sequence for the LEDs
int incomingByte = 0; //Serial input to select LED output sequence
int switch_spool = 0; //Counts the loops where switch is in LOW state ... used to power off machine
int power_state = 1; // Stores current power state
// 16 LEDs on the ring.... each line has 16 bits with the 1 being on and 0 being off ... for that LED
unsigned int sequence[1][16] = {{
0b1000000000000000, // This has a single LED turned on
0b1000000000000001, // This has the fist and last LEDs on and the rest off.
0b1000000000000011,
0b1000000000000111,
0b1000000000001111,
0b1000000000011111,
0b1000000000111111,
0b1000000001111111,
0b1000000011111111,
0b1000000111111111,
0b1000001111111111,
0b1000011111111111,
0b1000111111111111,
0b1001111111111111,
0b1011111111111111,
0b1111111111111111 // This is all LEDs turned on
}};
// ####### Stepper Driver Variables #######
AccelStepper myStepper( 1, 6, 7 ); // initialize AccelStepper in step/dir mode on pins 8 and 9
const int RUN_PIN = 5; // On - Off switch
const int FREQ_PIN = 4; // High - Low frequency pin ( 2hz or 3hz )
const int ON_PIN = 3; // On - Off switch
int targetFreq = 0;
int previousFreq = 0;
int buttonState = 0; // variable for storing the RUN_PIN status
// counts the number of cycles for reading inputs
// starts at 10000 so all inputs are read on first cycle
int run_cycle_count = 100000;
void setup() {
// ####### Encoder Setup #######
//Set SPI pins to output
pinMode(SDI, OUTPUT);
pinMode(CLK, OUTPUT);
pinMode(LE, OUTPUT);
//Set encoder pins to input, turn internal pull-ups on
pinMode(ENC_A, INPUT);
digitalWrite(ENC_A, HIGH);
pinMode(ENC_B, INPUT);
digitalWrite(ENC_B, HIGH);
pinMode(ENC_SW, INPUT);
digitalWrite(ENC_SW, HIGH);
// ####### Stepper Driver Setup #######
// initialize input pins
pinMode( RUN_PIN, INPUT );
pinMode( FREQ_PIN, INPUT );
pinMode( ON_PIN, OUTPUT );
myStepper.setAcceleration( 200.0 );
// ####### General Setup #######
Serial.begin(115200);
}
void loop()
{
//Local Variables
static uint8_t counter = 0; //this variable will be changed by encoder input
int8_t tmpdata;
if ( digitalRead( ENC_SW ) == LOW ){
// spool 100 times to ensure we're not getting a false positive
if ( switch_spool >= 100 ){
if ( power_state == 1 ){
Serial.print(" POWERING OFF ");
// So tell the user to hold the button till they hear it spooling down
slow_to_zero();
power_state = 0;
}
if ( power_state == 0 ){
Serial.print(" POWERING UP ");
power_state = 1;
}
}
switch_spool++;
} else {
switch_spool = 0;
}
//Call read_encoder() function
tmpdata = read_encoder();
//if the encoder has moved
if(tmpdata) {
// Set the new counter value of the encoder
// Scale by factor of 4 so that each physical encoder click... lights or extinguishes a LED
// Explanation:
// Each encoder-click changes the "counter" value by about 4
// multiply that by 4 and you've got 16
// 256 ( the total number of possible values from 0 - 255 )
// 256 / 16 = 16 therefore each click is scaled to be exactly 1 LED
// And therefore each click accounts for 1/16th the total value of the int8_t of scaledCounter
counter += tmpdata * 4;
//Scale the counter value for referencing the LED sequence
//***NOTE: Change the map() function to suit the limits of your rotary encoder application.
// The first two numbers are the lower, upper limit of the rotary encoder, the
// second two numbers 0 and 15 are limits of LED sequence arrays. This is done
// so that the LEDs can use a different scaling than the encoder value.
scaledCounter = map(counter, 0, 255, 0, 16);
//scaledCounter = ( counter / 255) * 16;
//Print out the counter value
//Serial.print("scaled value: ");
//Serial.println(counter, DEC);
//Send the LED output to the shift register
digitalWrite(LE,LOW);
shiftOut(SDI,CLK,MSBFIRST,(sequence[sequenceNumber][scaledCounter] >> 8)); //High byte first
shiftOut(SDI,CLK,MSBFIRST,sequence[sequenceNumber][scaledCounter]); //Low byte second
digitalWrite(LE,HIGH);
}
}
// Returns change in encoder state (-1,0,1)
// www.circuitsathome.com/mcu/reading-rotary-encoder-on-arduino
int8_t read_encoder() {
int8_t enc_states[] = {0,-1,1,0,1,0,0,-1,-1,0,0,1,0,1,-1,0};
static uint8_t old_AB = 0;
/**/
old_AB <<= 2; //remember previous state
old_AB |= ( ENC_PORT & 0x03 ); //add current state
return ( enc_states[( old_AB & 0x0f )]);
}
void toggled() {
//toggle_switch = !toggle_switch;
//Serial.println( toggle_switch );
}
void slow_to_zero() {
if ( myStepper.speed() > 0 )
myStepper.moveTo( myStepper.currentPosition() + 1000 );
// Blocks while it slows to zero
while ( myStepper.speed() > 0 )
myStepper.run();
Serial.println("stopped");
digitalWrite( ON_PIN, LOW );
delay( 1000 );
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment