matemat/firmware/main.c

141 lines
3.0 KiB
C

#include <stdlib.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include "lcd_routines.h"
#include "uart.h"
#define SAVE PD2
#define SIGNAL PD3
#define FREQ_DOWN PD4
#define FREQ_UP PD5
#define AMP_DOWN PD6
#define AMP_UP PD7
#define KEY_DDR DDRD
#define KEY_PORT PORTD
#define KEY_PIN PIND
#define KEY_ON_DDR DDRB
#define KEY_ON_PORT PORTB
#define KEY_ON_PIN PINB
#define KEY_ON PB0
#define LED_PIN PA7
#define LED_PORT PORTA
#define LED_DDR DDRA
#define led_on() LED_PORT |= _BV(LED_PIN);
#define led_off() LED_PORT &= ~_BV(LED_PIN);
#define led_toggle() LED_PORT ^= _BV(LED_PIN)
#define UART_BAUD_RATE 9600
#define ALL_KEYS (_BV(SAVE) | _BV(SIGNAL) | _BV(FREQ_DOWN) | _BV(FREQ_UP) | _BV(AMP_DOWN) | _BV(AMP_UP) )
#define REPEAT_MASK ALL_KEYS
#define REPEAT_START 50
#define REPEAT_NEXT 20
volatile uint16_t key_state;
volatile uint16_t key_press;
/* prototypes */
void init_io();
uint16_t get_key_press(uint16_t key_mask);
int main(void) {
init_io();
lcd_init();
uart_init(UART_BAUD_SELECT(UART_BAUD_RATE,F_CPU));
lcd_setcursor(0, 0);
unsigned int c;
sei();
for (;;) {
if (uart_available() > 0) {
c = uart_getc();
if (c == '}') {
lcd_clear();
} else if (c == '*') {
lcd_setcursor(0, 2);
} else if (c == '+') {
lcd_setcursor(0, 1);
} else if (c == '\'') {
led_off();
} else if (c == '#') {
led_on();
} else {
lcd_data(c);
}
}
if (get_key_press(_BV(FREQ_DOWN))) {
uart_putc('f');
}
if (get_key_press(_BV(FREQ_UP))) {
uart_putc('F');
}
if (get_key_press(_BV(SIGNAL))) {
uart_putc('s');
}
if (get_key_press(_BV(AMP_UP))) {
uart_putc('A');
}
if (get_key_press(_BV(AMP_DOWN))) {
uart_putc('a');
}
if (get_key_press(_BV(KEY_ON) << 8)) {
uart_putc('o');
}
if (get_key_press(_BV(SAVE))) {
uart_putc('v');
}
}
}
void init_io() {
KEY_DDR &= ~ALL_KEYS; // configure key port for input
KEY_PORT |= ALL_KEYS;
KEY_ON_DDR &= ~_BV(KEY_ON);
KEY_ON_PORT |= _BV(KEY_ON);
LED_DDR |= _BV(LED_PIN);
LED_PORT &= ~_BV(LED_PIN);
TCCR0 = (1 << CS02) | (1 << CS00); // divide by 1024
TCNT0 = (uint8_t) (int16_t) -(F_CPU / 1024 * 10e-3 + 0.5); // preload for 10ms
TIMSK |= 1 << TOIE0; // enable timer interrupt
}
ISR( TIMER0_OVF_vect ) {
static uint16_t ct0, ct1;
uint16_t i;
TCNT0 = (uint8_t) (int16_t) -(F_CPU / 1024 * 10e-3 + 0.5); // preload for 10ms
i = key_state ^ ~(KEY_PIN | (KEY_ON_PIN << 8)); // key changed ?
ct0 = ~(ct0 & i); // reset or count ct0
ct1 = ct0 ^ (ct1 & i); // reset or count ct1
i &= ct0 & ct1; // count until roll over ?
key_state ^= i; // then toggle debounced state
key_press |= key_state & i; // 0->1: key press detect
}
uint16_t get_key_press(uint16_t key_mask) {
cli();
// read and clear atomic !
key_mask &= key_press; // read key(s)
key_press ^= key_mask; // clear key(s)
sei();
return key_mask;
}