// clock module concept
// aka "Not Pockets"
#include <LiquidCrystal.h>
#include "not_pockets.h"
LiquidCrystal lcd(12, 11, 10, 9, 8, 7); // might want to redo these to avoid PWM pins?
// Master clock declarations
#define CHANNEL1_OUT 5 // might update later
unsigned int master_clock = 0; // I'm thinking we make this a long int to make clock division simpler
// it will rollover at 65536 beats, which should be several hours even at the fastest rate
// remember to reset the clock to 0 on restart
unsigned int bpm = 60;
bool prev_clk = 0;
// Rotary encoder declarations
#define ENCODER_CLK 2
#define ENCODER_DT 3
#define ENCODER_SW 4
bool encLastClk = 1;
bool encNewClk;
bool encDtVal;
ISR(TIMER1_COMPA_vect){
master_clock += bpm;
}
void setup() {
cli();
TCCR1A = 0; // zero this out, not sure what the default is, but it wasn't working as expected
TCCR1B = 0;
// set timer 1 register to zero, I don't know if this is strictly necessary
TCNT1 = 0;
// freq (Hz) = bpm / 60
// number of increments per beat = increment rate / freq
// increment value = 65536 / number of increments (for 16 bit uint)
// so the increment value = 65536 * bpm / (increment rate * 60)
// with an increment rate of 65536/60, increment value = bpm, which corresponds to 1092.26Hz
// 2MHz / 1092.26 Hz = 1831
// Set Compare Match to 1831 - 1
OCR1A = 1830;
// Set CTC mode and /8 prescale
TCCR1B |= (1<<WGM12);
TCCR1B |= (1<<CS11);
// Output Compare Match A Interrupt Enable
TIMSK1 |= (1 << OCIE1A);
sei();
Serial.begin(115200);
pinMode(LED_BUILTIN,OUTPUT);
pinMode(CHANNEL1_OUT,OUTPUT);
lcd.createChar(0, zero_dark);
lcd.createChar(1, one_dark);
lcd.createChar(2, two_dark);
lcd.begin(16, 2);
lcd.write(byte(0));
lcd.write(byte(1));
lcd.write(byte(2));
}
void loop() {
if (prev_clk ^ master_clock>>15){
prev_clk ^= 1;
digitalWrite(LED_BUILTIN,master_clock>>15);
// Serial.print(millis());
// Serial.print(" : ");
// Serial.println(master_clock);
}
// read push button (move to interupt?)
// encNewSw = digitalRead(ENCODER_SW);
// if (encLastSw ^ encNewSw){ // this might need debouncing under real circumstances
// if(encNewSw){
// lcd.clear();
// lcd.print("Press!"); // have this print on release
// button_time
// }
// encLastSw = encNewSw;
// }
// How to handle long press?
switch(checkButton()){
case 0:
// do nothing
break;
case 1:
lcd.clear();
lcd.print("POLICE");
break;
case 2:
lcd.clear();
lcd.print("Release");
break;
case 3:
lcd.clear();
lcd.print("Long Press");
break;
case 4:
lcd.clear();
lcd.print("LRel");
break;
}
// read encoder rotation (move to interupt)
// we don't want to harcode the bpm changes here, maybe have interupt do a function call?
// I messed something up because it is ocasssionally skipping two or going the wrong direction
encNewClk = digitalRead(ENCODER_CLK);
if (encNewClk ^ encLastClk) {
encLastClk = encNewClk; // move this to end?
if (!encNewClk){
lcd.clear();
lcd.setCursor(4,0);
encDtVal = digitalRead(ENCODER_DT);
if (encDtVal){
lcd.print("clockwise");
if (bpm<200){
bpm++;
}
} else { // if (!encDtVal)
lcd.print("anticlck");
if (bpm > 30){
bpm--;
}
}
lcd.setCursor(0,0);
lcd.print(bpm);
}
}
}
bool encLastSw = 1; // default (unengaged) state is high
bool encNewSw = 1;
unsigned int downTime;
unsigned int upTime;
unsigned int DEBOUNCE_TIME = 50;
unsigned int LONG_PRESS = 1000;
unsigned char buttonEvent;
bool longPressLatch = false;
bool upLatch = true;
bool downLatch = false;
// this is still printing down/low on startup - why?
// maybe for now ignore the long press and debounce and just focus on the main menu level
// could always add another button....
int checkButton(){ // I don't know if the simulation is wonky or if it is my code
buttonEvent = 0; // Catch all for non-events
encNewSw = digitalRead(ENCODER_SW);
if (encLastSw & !encNewSw){ // was 1 (up), now 0 (down)
Serial.println("down");
downTime = millis(); // start downTime timer
}
if (!encLastSw & encNewSw){ // was 0 (down), now 1 (up)
Serial.println("up");
upTime = millis(); // start downTime timer
}
if (!encLastSw & !downLatch & (millis()-downTime> DEBOUNCE_TIME)){
buttonEvent = 1;
downLatch = true;
upLatch = false;
}
if (encLastSw & !upLatch & (millis()-downTime> DEBOUNCE_TIME)){
buttonEvent = 2;
upLatch = true;
downLatch = false;
if (longPressLatch){
buttonEvent = 4;
}
longPressLatch = false;
}
if (downLatch & !longPressLatch & (millis()-downTime > LONG_PRESS)){
buttonEvent = 3;
longPressLatch = true;
}
if (encNewSw ^ encLastSw){
digitalWrite(CHANNEL1_OUT,encNewSw); // serial would also be good
Serial.println(encNewSw?"high":"low");
encLastSw = encNewSw;
}
return buttonEvent;
}