Compare commits

...

7 Commits

11 changed files with 207 additions and 54 deletions

View File

@ -2,19 +2,12 @@
#include "constants.h"
#include <Arduino.h>
void buzzOff() {
noTone(BUZZER_PIN);
pinMode(BUZZER_PIN, INPUT);
}
void helloBuzz() {
tone(BUZZER_PIN, 500, 100);
delay(100);
tone(BUZZER_PIN, 1000, 100);
delay(100);
tone(BUZZER_PIN, 4000, 100);
delay(100);
buzzOff();
}
void happyBuzz() {
@ -22,23 +15,18 @@ void happyBuzz() {
delay(75);
tone(BUZZER_PIN, 2000, 100);
delay(100);
buzzOff();
}
void sadBuzz() {
tone(BUZZER_PIN, 330, 250);
delay(300);
tone(BUZZER_PIN, 311, 250);
delay(250);
buzzOff();
}
void beep() {
tone(BUZZER_PIN, 1000, 50);
delay(50);
buzzOff();
}
void tick() {
tone(BUZZER_PIN, 200, 5);
tone(BUZZER_PIN, 200, 10);
}

View File

@ -4,5 +4,4 @@ void helloBuzz();
void happyBuzz();
void sadBuzz();
void beep();
void buzzOff();
void tick();

View File

@ -24,3 +24,12 @@
// --- Keyboard config
#define KBD_I2C_ADDR 0x21
// Used by keyboard and encoder switch
#define DEBOUNCE_MS 10
// --- Z axis motor
#define STEPPER_ENABLE 8
#define STEPPER_DIR 9
#define STEPPER_STEP 10

View File

@ -13,8 +13,6 @@ When rotated clockwise, CLK changes before DT; when rotated counter-clockwise, D
*/
#define SW_DEBOUNCE_MS 10
bool previousClk = false;
bool previousDt = false;
@ -40,8 +38,8 @@ SwitchEvent handleSwitch() {
}
// debounce
unsigned long now = millis();
if (now - lastChangeAt < SW_DEBOUNCE_MS) {
auto now = millis();
if (now - lastChangeAt < DEBOUNCE_MS) {
return SWITCH_NONE;
}
@ -53,6 +51,8 @@ SwitchEvent handleSwitch() {
return isPressed ? SWITCH_PRESSED : SWITCH_RELEASED;
}
unsigned long lastEncoderChangeAt = 0;
EncoderEvent handleEncoder() {
bool clk = digitalRead(CLK_PIN);
bool dt = digitalRead(DT_PIN);
@ -62,7 +62,11 @@ EncoderEvent handleEncoder() {
return ENCODER_NONE;
}
// TODO: Do we need to debounce encoder?
// debounce
auto now = millis();
if (now - lastEncoderChangeAt < DEBOUNCE_MS) {
return SWITCH_NONE;
}
// clockwise pattern:
// clk: 1001 1001
@ -78,6 +82,7 @@ EncoderEvent handleEncoder() {
// save state
previousClk = clk;
previousDt = dt;
lastEncoderChangeAt = now;
// return event
return event;

View File

@ -3,6 +3,8 @@
#include "constants.h"
#include "debug.h"
#include "buzzer.h"
#include "keyboard.h"
PCF8574 kbd(KBD_I2C_ADDR, &Wire);
@ -15,15 +17,10 @@ row/col 0 1 2 3
1 4 5 6 B
2 7 8 9 C
3 * 0 # D
Keys, in order:
123A 456B 789C *0#D
*/
typedef uint8_t Key;
const char *allKeys = "123A456B789C*0#D";
#define KEY_NONE 255
const uint8_t digits[16] =
{ 1, 2, 3, KEY_NONE,
4, 5, 6, KEY_NONE,
@ -43,30 +40,35 @@ bool setupKeyboard() {
return true;
}
Key previousKey = KEY_NONE;
unsigned long lastPressedAt = 0;
Key getPressedKey();
uint8_t getPressedDigit(Key key);
Key handleKeyboard() {
auto key = getPressedKey();
// only handle change
if (key == previousKey) {
return KEY_NONE;
}
// debounce
auto now = millis();
if (now - lastPressedAt < DEBOUNCE_MS) {
return KEY_NONE;
}
// save state
previousKey = key;
lastPressedAt = now;
// return event
return key;
}
#define KBD_COL_MASK 0b11110000
#define KBD_ROW_MASK 0b00001111
void demoKeyboard() {
auto key = getPressedKey();
if (key != KEY_NONE) {
Serial.print("Key pressed: ");
Serial.print(allKeys[key]);
auto digit = getPressedDigit(key);
if (digit != KEY_NONE) {
Serial.print(", digit: ");
Serial.print(digit);
} else {
Serial.print(" (Not a digit)");
}
Serial.println();
}
}
/**
* Returns pressed key or KEY_NONE if no key is pressed
*
@ -89,27 +91,40 @@ Key getPressedKey() {
else if (colState & 0b0100) colPressed = 1;
else if (colState & 0b0010) colPressed = 2;
else if (colState & 0b0001) colPressed = 3;
else fatal();
else {
Serial.print("Invalid kbd column state: ");
Serial.println(cols, BIN);
sadBuzz();
return KEY_NONE;
}
// check pressed row
// last 4 bits are rows, low when pressed
kbd.write8(KBD_ROW_MASK);
uint8_t rowState = ~kbd.read8();
uint8_t rows = kbd.read8();
if (rows == KBD_ROW_MASK) {
// between col and row read, a key could be released
return KEY_NONE;
}
uint8_t rowState = ~rows;
uint8_t rowPressed = 0;
if (rowState & 0b1000) rowPressed = 0;
else if (rowState & 0b0100) rowPressed = 1;
else if (rowState & 0b0010) rowPressed = 2;
else if (rowState & 0b0001) rowPressed = 3;
else fatal();
else {
Serial.print("Invalid kbd row state: ");
Serial.println(rowState, BIN);
sadBuzz();
return KEY_NONE;
}
// return key
return (rowPressed * 4) + colPressed;
}
/**
* Returns pressed digit or KEY_NONE if the key is not a digit
*/
uint8_t getPressedDigit(Key key) {
if (key == KEY_NONE) return KEY_NONE;
return digits[key];

View File

@ -1,4 +1,32 @@
#pragma once
/*
Keys, in order:
123A 456B 789C *0#D
*/
typedef uint8_t Key;
#define KEY_NONE 255
#define KEY_A 3
#define KEY_B 7
#define KEY_C 11
#define KEY_D 15
#define KEY_ASTERISK 12
#define KEY_HASH 14
extern const char *allKeys;
bool setupKeyboard();
void demoKeyboard();
/**
* Returns pressed key once upon its release
* or KEY_NONE if no key is pressed
*
* NOTE: Only one key can be pressed at a time;
* if multiple keys are pressed, the behavior is undefined
*/
Key handleKeyboard();
/**
* Returns pressed digit or KEY_NONE if the key is not a digit
*/
uint8_t getPressedDigit(Key key);

View File

@ -7,10 +7,14 @@
#include "keyboard.h"
#include "encoder.h"
#include "debug.h"
#include "timer.h"
#include "stepper.h"
void setup() {
setupDebug();
setupEncoder();
setupTimer();
setupStepper();
Wire.begin();
@ -22,11 +26,39 @@ void setup() {
}
void loop() {
// tick();
// debugScanI2C();
// demoScreen();
// demoKeyboard();
// demoStepper();
demoTimer();
auto key = handleKeyboard();
if (key != KEY_NONE) {
Serial.print("Key pressed: ");
Serial.print(allKeys[key]);
auto digit = getPressedDigit(key);
if (digit != KEY_NONE) {
Serial.print(", digit: ");
Serial.print(digit);
} else {
Serial.print(" (Not a digit)");
}
Serial.println();
if (key == KEY_A) {
happyBuzz();
} else if (key == KEY_B) {
sadBuzz();
} else if (key == KEY_C) {
beep();
} else if (key == KEY_D) {
tick();
} else {
tick();
}
}
if (auto event = handleSwitch()) {
tick();

25
firmware/src/stepper.cpp Normal file
View File

@ -0,0 +1,25 @@
#include <Arduino.h>
#include "constants.h"
void setupStepper() {
pinMode(STEPPER_ENABLE, OUTPUT);
pinMode(STEPPER_DIR, OUTPUT);
pinMode(STEPPER_STEP, OUTPUT);
// low = enabled
digitalWrite(STEPPER_ENABLE, LOW);
}
bool stepperDir = HIGH;
void demoStepper() {
Serial.println("Demoing stepper motor - rotating 200 steps");
stepperDir = !stepperDir;
digitalWrite(STEPPER_DIR, stepperDir);
for (int i = 0; i < 200; i++) {
digitalWrite(STEPPER_STEP, HIGH);
delay(2);
digitalWrite(STEPPER_STEP, LOW);
delay(7);
}
}

4
firmware/src/stepper.h Normal file
View File

@ -0,0 +1,4 @@
#pragma once
void setupStepper();
void demoStepper();

46
firmware/src/timer.cpp Normal file
View File

@ -0,0 +1,46 @@
#include <Arduino.h>
#define DEMO_TRIGGER_MS 1500
void setupTimer() {
// Set up Timer 0 to trigger interrupt every 1ms
// Timer 0 is already used and configured by Arduino for millis()
// however it uses TOIE0 (overflow interrupt), so we'll use OCIE0A:
// When this bit is written to one, and the I-flag in the Status Register is set
// (interrupts globally enabled), the Timer/Counter0 Output Compare A Match interrupt is enabled
// The corresponding Interrupt Vector is executed when the OCF0A Flag, located in TIFR0, is set.
OCR0A = 0xAF; // any number is OK, it will trigger at some point during the counter
TIMSK0 |= _BV(OCIE0A);
}
// incremented every DEMO_TRIGGER_MS by interrupt,
// read and decremented by main loop
volatile uint8_t timerEvents = 0;
void demoTimer() {
bool shouldTrigger = false;
noInterrupts();
if (timerEvents > 0) {
timerEvents--;
shouldTrigger = true;
}
interrupts();
if (shouldTrigger) {
Serial.println("Timer tick!");
}
}
volatile uint16_t timerMillis = 0;
// triggers every 1ms
ISR(TIMER0_COMPA_vect) {
timerMillis++;
if (timerMillis >= DEMO_TRIGGER_MS) {
timerMillis -= DEMO_TRIGGER_MS;
timerEvents++;
}
// TODO: Add motor encoder reading, calculate required carriage offset, control stepper
}

2
firmware/src/timer.h Normal file
View File

@ -0,0 +1,2 @@
void setupTimer();
void demoTimer();