Implement switches and rotary encoder
This commit is contained in:
parent
f71c65106f
commit
09bc6979e9
@ -1,10 +1,9 @@
|
||||
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
|
||||
CC=avr-gcc
|
||||
TARGET=main
|
||||
_OBJECT_FILES=main.o AVR-SSD1306/Files/SSD1306.c AVR-SSD1306/Files/TWI.c
|
||||
OBJECT_FILES=main.o oled-display/font.o oled-display/i2c.o oled-display/lcd.o
|
||||
OBJECT_FILES=main.o input.o systick.o oled-display/font.o oled-display/i2c.o oled-display/lcd.o
|
||||
|
||||
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,22 +1,37 @@
|
||||
#include <avr/io.h>
|
||||
#include <avr/interrupt.h>
|
||||
#include <avr/pgmspace.h>
|
||||
#include <avr/delay.h>
|
||||
#include <util/delay.h>
|
||||
#include "oled-display/lcd.h"
|
||||
#include "input.h"
|
||||
#include "systick.h"
|
||||
|
||||
#define PORT_SPI(t) t##B
|
||||
#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 x = 0;
|
||||
static uint8_t y = DISPLAY_HEIGHT / 8 - 1;
|
||||
uint8_t spi_cs;
|
||||
|
||||
|
||||
spi_cs = !(PORT_SPI(PIN) & PIN_SPI_CS);
|
||||
|
||||
|
||||
if (spi_cs) {
|
||||
if (SPSR & (1 << SPIF)) {
|
||||
//SPDR = get_rotary_delta();
|
||||
SPDR = get_switch_event();
|
||||
//SPDR = dbg;
|
||||
lcd_set_buffer(x, y, SPDR);
|
||||
if (y == 0) {
|
||||
y = DISPLAY_HEIGHT / 8 - 1;
|
||||
@ -37,10 +52,12 @@ void spi_proc()
|
||||
x = 0;
|
||||
y = DISPLAY_HEIGHT / 8 - 1;
|
||||
}
|
||||
|
||||
return spi_cs;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
void lcd_startup()
|
||||
{
|
||||
lcd_init(LCD_DISP_ON);
|
||||
lcd_gotoxy(0, 0);
|
||||
lcd_puts_p(PSTR("== Internet Radio =="));
|
||||
@ -50,13 +67,24 @@ int main()
|
||||
lcd_gotoxy(0, 3);
|
||||
lcd_puts_p(PSTR("Please wait..."));
|
||||
lcd_display();
|
||||
|
||||
SPCR = (1 << SPE);
|
||||
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
cli();
|
||||
|
||||
lcd_startup();
|
||||
spi_init();
|
||||
systick_init();
|
||||
input_init();
|
||||
|
||||
_delay_ms(10);
|
||||
|
||||
|
||||
while (1) {
|
||||
spi_proc();
|
||||
if (!spi_proc()) {
|
||||
timer_proc();
|
||||
input_proc();
|
||||
}
|
||||
}
|
||||
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