Implement switches and rotary encoder
This commit is contained in:
parent
f71c65106f
commit
09bc6979e9
@ -1,10 +1,9 @@
|
|||||||
MCU=atmega88
|
MCU=atmega88
|
||||||
CFLAGS=-g -Wall -mcall-prologues -mmcu=$(MCU) -Os -DF_CPU=8000000 -IAVR-SSD1306/Files/
|
CFLAGS=-g -Wall -Wno-multichar -Wno-overflow -mcall-prologues -mmcu=$(MCU) -O2 -DF_CPU=8000000 -IAVR-SSD1306/Files/
|
||||||
LDFLAGS=-Wl,-gc-sections -Wl,-relax
|
LDFLAGS=-Wl,-gc-sections -Wl,-relax
|
||||||
CC=avr-gcc
|
CC=avr-gcc
|
||||||
TARGET=main
|
TARGET=main
|
||||||
_OBJECT_FILES=main.o AVR-SSD1306/Files/SSD1306.c AVR-SSD1306/Files/TWI.c
|
OBJECT_FILES=main.o input.o systick.o oled-display/font.o oled-display/i2c.o oled-display/lcd.o
|
||||||
OBJECT_FILES=main.o oled-display/font.o oled-display/i2c.o oled-display/lcd.o
|
|
||||||
|
|
||||||
all: $(TARGET).hex
|
all: $(TARGET).hex
|
||||||
|
|
||||||
|
98
firmware/input.c
Normal file
98
firmware/input.c
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
#include <avr/io.h>
|
||||||
|
#include <util/delay.h>
|
||||||
|
#include <avr/interrupt.h>
|
||||||
|
#include "input.h"
|
||||||
|
#include "systick.h"
|
||||||
|
|
||||||
|
static volatile int8_t rotary_delta = 0;
|
||||||
|
static volatile uint8_t sw_event = 0;
|
||||||
|
|
||||||
|
void input_init()
|
||||||
|
{
|
||||||
|
PORT_ROTARY(DDR) &= ~(PIN_ROTARY_A | PIN_ROTARY_B); // Configure as input
|
||||||
|
PORT_ROTARY(PORT) &= ~(PIN_ROTARY_A | PIN_ROTARY_B); // Set pullups
|
||||||
|
|
||||||
|
PORT_KEYPAD(DDR) &= ~(PIN_KEYPAD_MASK); // Key inputs
|
||||||
|
PORT_KEYPAD(PORT) |= PIN_KEYPAD_MASK; // Key pullups
|
||||||
|
}
|
||||||
|
|
||||||
|
int8_t get_rotary_delta()
|
||||||
|
{
|
||||||
|
int8_t temp = rotary_delta;
|
||||||
|
//rotary_delta = 0;
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void input_proc_rotary()
|
||||||
|
{
|
||||||
|
static int8_t last_a;
|
||||||
|
int8_t a;
|
||||||
|
int8_t b;
|
||||||
|
int8_t p;
|
||||||
|
|
||||||
|
p = PORT_ROTARY(PIN);
|
||||||
|
a = (p & PIN_ROTARY_A);
|
||||||
|
b = (p & PIN_ROTARY_B);
|
||||||
|
a = !a;
|
||||||
|
b = !b;
|
||||||
|
|
||||||
|
if (a == 1 && last_a == 0) {
|
||||||
|
_delay_ms(1); // TODO
|
||||||
|
rotary_delta += !!(a ^ b);
|
||||||
|
}
|
||||||
|
if (a == 0 && last_a == 1) {
|
||||||
|
_delay_ms(1); // TODO
|
||||||
|
rotary_delta -= !(a ^ b);
|
||||||
|
}
|
||||||
|
|
||||||
|
last_a = a;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Pressing two keys at the same time can lead to unfortunate behavior.
|
||||||
|
void input_proc_switches()
|
||||||
|
{
|
||||||
|
uint8_t sw;
|
||||||
|
uint8_t ev;
|
||||||
|
uint8_t i;
|
||||||
|
static uint8_t sw_last = 0xFF;
|
||||||
|
uint8_t delta;
|
||||||
|
|
||||||
|
sw = PORT_KEYPAD(PIN) & PIN_KEYPAD_MASK;
|
||||||
|
ev = sw ^ sw_last;
|
||||||
|
|
||||||
|
if (ev) {
|
||||||
|
if (timer_expired(TIMID_SW_DEBOUNCE)) { // If we read a value, wait for the debounce time before we process any other state
|
||||||
|
for (i=0; i < 8; ++i) {
|
||||||
|
if (ev & (1 << i)) {
|
||||||
|
if (sw & (1 << i)) { // Key release
|
||||||
|
if (timer_expired(TIMID_SW_LONGPRESS))
|
||||||
|
i |= (1 << 7) | (1 << 6);
|
||||||
|
else
|
||||||
|
i |= (1 << 7);
|
||||||
|
sw_event = i;
|
||||||
|
} else { // Key push
|
||||||
|
sw_event = 0; // To be honest, I don't have a f*cking clue why I need this...
|
||||||
|
timer_set(TIMID_SW_LONGPRESS, MS_TO_TICKS(1000));
|
||||||
|
}
|
||||||
|
timer_set(TIMID_SW_DEBOUNCE, MS_TO_TICKS(250));
|
||||||
|
break; // We can only process one event at a time anyway, so let's quit it here
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sw_last = sw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t get_switch_event()
|
||||||
|
{
|
||||||
|
uint8_t temp = sw_event;
|
||||||
|
sw_event = 0;
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Need to call timer_proc() before calling this function!
|
||||||
|
void input_proc()
|
||||||
|
{
|
||||||
|
input_proc_rotary();
|
||||||
|
input_proc_switches();
|
||||||
|
}
|
19
firmware/input.h
Normal file
19
firmware/input.h
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
#ifndef INPUT_H
|
||||||
|
#define INPUT_H
|
||||||
|
|
||||||
|
#define PORT_KEYPAD(t) t##D // Keys connected to: 0,1,2(INT0->POWER),5,6,7
|
||||||
|
#define PIN_KEYPAD_MASK 0b11100111
|
||||||
|
#define PORT_KEYAUX(t) t##B
|
||||||
|
#define PIN_ROTARY_PUSH (1 << 0)
|
||||||
|
|
||||||
|
#define PORT_ROTARY(t) t##D
|
||||||
|
#define PIN_ROTARY_A (1 << 3) // INT1
|
||||||
|
#define PIN_ROTARY_B (1 << 4)
|
||||||
|
|
||||||
|
void input_init();
|
||||||
|
void input_proc();
|
||||||
|
int8_t get_rotary_delta();
|
||||||
|
uint8_t get_switch_event();
|
||||||
|
extern uint8_t ctime;
|
||||||
|
|
||||||
|
#endif // INPUT_H
|
@ -1,12 +1,24 @@
|
|||||||
#include <avr/io.h>
|
#include <avr/io.h>
|
||||||
|
#include <avr/interrupt.h>
|
||||||
#include <avr/pgmspace.h>
|
#include <avr/pgmspace.h>
|
||||||
#include <avr/delay.h>
|
#include <util/delay.h>
|
||||||
#include "oled-display/lcd.h"
|
#include "oled-display/lcd.h"
|
||||||
|
#include "input.h"
|
||||||
|
#include "systick.h"
|
||||||
|
|
||||||
#define PORT_SPI(t) t##B
|
#define PORT_SPI(t) t##B
|
||||||
#define PIN_SPI_CS (1 << 2)
|
#define PIN_SPI_CS (1 << 2)
|
||||||
|
|
||||||
void spi_proc()
|
int dbg = 0;
|
||||||
|
|
||||||
|
void spi_init()
|
||||||
|
{
|
||||||
|
SPCR = (1 << SPE);
|
||||||
|
SPSR = (1 << SPI2X);
|
||||||
|
DDRB |= (1 << 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t spi_proc()
|
||||||
{
|
{
|
||||||
static uint8_t new_data = 0;
|
static uint8_t new_data = 0;
|
||||||
static uint8_t x = 0;
|
static uint8_t x = 0;
|
||||||
@ -17,6 +29,9 @@ void spi_proc()
|
|||||||
|
|
||||||
if (spi_cs) {
|
if (spi_cs) {
|
||||||
if (SPSR & (1 << SPIF)) {
|
if (SPSR & (1 << SPIF)) {
|
||||||
|
//SPDR = get_rotary_delta();
|
||||||
|
SPDR = get_switch_event();
|
||||||
|
//SPDR = dbg;
|
||||||
lcd_set_buffer(x, y, SPDR);
|
lcd_set_buffer(x, y, SPDR);
|
||||||
if (y == 0) {
|
if (y == 0) {
|
||||||
y = DISPLAY_HEIGHT / 8 - 1;
|
y = DISPLAY_HEIGHT / 8 - 1;
|
||||||
@ -37,9 +52,11 @@ void spi_proc()
|
|||||||
x = 0;
|
x = 0;
|
||||||
y = DISPLAY_HEIGHT / 8 - 1;
|
y = DISPLAY_HEIGHT / 8 - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return spi_cs;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main()
|
void lcd_startup()
|
||||||
{
|
{
|
||||||
lcd_init(LCD_DISP_ON);
|
lcd_init(LCD_DISP_ON);
|
||||||
lcd_gotoxy(0, 0);
|
lcd_gotoxy(0, 0);
|
||||||
@ -50,13 +67,24 @@ int main()
|
|||||||
lcd_gotoxy(0, 3);
|
lcd_gotoxy(0, 3);
|
||||||
lcd_puts_p(PSTR("Please wait..."));
|
lcd_puts_p(PSTR("Please wait..."));
|
||||||
lcd_display();
|
lcd_display();
|
||||||
|
}
|
||||||
|
|
||||||
SPCR = (1 << SPE);
|
int main()
|
||||||
|
{
|
||||||
|
cli();
|
||||||
|
|
||||||
|
lcd_startup();
|
||||||
|
spi_init();
|
||||||
|
systick_init();
|
||||||
|
input_init();
|
||||||
|
|
||||||
_delay_ms(10);
|
_delay_ms(10);
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
spi_proc();
|
if (!spi_proc()) {
|
||||||
|
timer_proc();
|
||||||
|
input_proc();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
66
firmware/systick.c
Normal file
66
firmware/systick.c
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
#include <avr/io.h>
|
||||||
|
#include "systick.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
uint8_t ctime;
|
||||||
|
|
||||||
|
static uint8_t tims[NTIM];
|
||||||
|
|
||||||
|
void systick_init()
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
TCCR1A = 0;
|
||||||
|
TCCR1B = (1 << CS10) | (1 << CS12); // f_tim = f_clk / 256 -> TCNT1H counts with 8ms / tick
|
||||||
|
TCCR1C = 0;
|
||||||
|
OCR1A = 0x7FFF;
|
||||||
|
|
||||||
|
for (i=0; i < NTIM; ++i) {
|
||||||
|
tims[i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void timer_proc()
|
||||||
|
{
|
||||||
|
uint8_t now;
|
||||||
|
uint8_t delta;
|
||||||
|
uint8_t i;
|
||||||
|
|
||||||
|
now = TCNT1L;
|
||||||
|
now = TCNT1H;
|
||||||
|
|
||||||
|
if (now == ctime)
|
||||||
|
return;
|
||||||
|
delta = now - ctime;
|
||||||
|
if (delta > 127)
|
||||||
|
delta -= 128;
|
||||||
|
|
||||||
|
for (i=0; i < NTIM; ++i) {
|
||||||
|
if (tims[i] > delta) {
|
||||||
|
tims[i] -= delta;
|
||||||
|
} else {
|
||||||
|
tims[i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ctime = now;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t timer_expired(uint8_t tim_id)
|
||||||
|
{
|
||||||
|
return !tims[tim_id];
|
||||||
|
}
|
||||||
|
|
||||||
|
void timer_set(uint8_t tim_id, uint8_t ticks)
|
||||||
|
{
|
||||||
|
tims[tim_id] = ticks;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t block_for(uint8_t tim_id, uint8_t ticks)
|
||||||
|
{
|
||||||
|
if (timer_expired(tim_id)) {
|
||||||
|
timer_set(tim_id, ticks);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
19
firmware/systick.h
Normal file
19
firmware/systick.h
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
#ifndef SYSTICK_H
|
||||||
|
#define SYSTICK_H
|
||||||
|
#include <avr/io.h>
|
||||||
|
|
||||||
|
#define TIMID_SW_DEBOUNCE 0
|
||||||
|
#define TIMID_SW_LONGPRESS 1
|
||||||
|
#define NTIM 2
|
||||||
|
|
||||||
|
#define MS_TO_TICKS(ms) (((ms/1000 * F_CPU/1024) / 256))
|
||||||
|
|
||||||
|
#define SYSTICK_VAL TCNT1H
|
||||||
|
|
||||||
|
void timer_proc();
|
||||||
|
void systick_init();
|
||||||
|
uint8_t timer_expired(uint8_t tim_id);
|
||||||
|
void timer_set(uint8_t tim_id, uint8_t ticks);
|
||||||
|
uint8_t block_for(uint8_t tim_id, uint8_t ticks);
|
||||||
|
|
||||||
|
#endif // SYSTICK_H
|
Loading…
Reference in New Issue
Block a user