Initial code commit
This commit is contained in:
commit
c04af37359
8
code/Makefile
Normal file
8
code/Makefile
Normal file
@ -0,0 +1,8 @@
|
||||
all:
|
||||
make build
|
||||
make program
|
||||
build:
|
||||
avr-gcc main.c -o counter -mmcu=attiny85 -Wall -Wextra
|
||||
|
||||
program:
|
||||
avrdude -p attiny85 -c usbtiny -U flash:w:counter
|
||||
407
code/main.c
Normal file
407
code/main.c
Normal file
@ -0,0 +1,407 @@
|
||||
#define F_CPU 1000000
|
||||
#include <avr/eeprom.h>
|
||||
#include <avr/interrupt.h>
|
||||
#include <avr/io.h>
|
||||
#include <avr/sleep.h>
|
||||
|
||||
#include <util/delay.h>
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define VALUE_MIN -99999
|
||||
#define VALUE_MAX 999999
|
||||
|
||||
#define PIN_BTN_DEC PINB3
|
||||
#define PIN_BTN_INC PINB4
|
||||
|
||||
#define BTN_FLAG_DEC 0x02
|
||||
#define BTN_FLAG_INC 0x01
|
||||
|
||||
#define DISPLAY_SIZE 6
|
||||
|
||||
// Time(ms) to wait before sleep
|
||||
#define DISPLAY_DELAY 1000
|
||||
|
||||
// Time(ms) to assume long button press
|
||||
#define LONG_PRESS 500
|
||||
|
||||
// Event queue macros
|
||||
#define MAX_EVENT_COUNT 64
|
||||
#define PTR_INC(x) ((x) = events + ((((x) - events) + 1) % MAX_EVENT_COUNT))
|
||||
|
||||
uint8_t events[MAX_EVENT_COUNT];
|
||||
uint8_t event_count = 0;
|
||||
uint8_t *event_read = events;
|
||||
uint8_t *event_write = events;
|
||||
|
||||
int32_t counter_value = 0;
|
||||
uint8_t btn_flag = 0;
|
||||
volatile uint32_t ms = 0;
|
||||
uint8_t display_buffer[DISPLAY_SIZE];
|
||||
|
||||
// Shift way (P is DP)
|
||||
// GFAB 1->6
|
||||
// PCDE 6->1
|
||||
// Therefore - EDCPBAFG
|
||||
#define DP 0b00010000
|
||||
uint8_t seg_table[11] =
|
||||
{
|
||||
//EDCPBAFG
|
||||
0b11101110, // 0
|
||||
0b00101000, // 1
|
||||
0b11001101, // 2
|
||||
0b01101101, // 3
|
||||
0b00101011, // 4
|
||||
0b01100111, // 5
|
||||
0b11100111, // 6
|
||||
0b00101100, // 7
|
||||
0b11101111, // 8
|
||||
0b01101111, // 9
|
||||
0b00000001 // -
|
||||
};
|
||||
|
||||
enum event_e
|
||||
{
|
||||
EVENT_NONE,
|
||||
EVENT_DEC_DOWN,
|
||||
EVENT_DEC_UP,
|
||||
EVENT_INC_DOWN,
|
||||
EVENT_INC_UP
|
||||
};
|
||||
|
||||
// ms counter
|
||||
ISR(TIM0_COMPA_vect)
|
||||
{
|
||||
cli();
|
||||
ms += 8;
|
||||
sei();
|
||||
}
|
||||
|
||||
// Button interrupt
|
||||
ISR(PCINT0_vect)
|
||||
{
|
||||
uint8_t new_btn_flag = 0;
|
||||
uint8_t event = EVENT_NONE;
|
||||
|
||||
cli();
|
||||
if (0 == (PINB & PIN_BTN_DEC))
|
||||
{
|
||||
new_btn_flag |= BTN_FLAG_DEC;
|
||||
}
|
||||
|
||||
if (0 == (PINB & PIN_BTN_INC))
|
||||
{
|
||||
new_btn_flag |= BTN_FLAG_INC;
|
||||
}
|
||||
|
||||
if ((new_btn_flag & BTN_FLAG_DEC) != (btn_flag & BTN_FLAG_DEC))
|
||||
{
|
||||
// Press
|
||||
if (new_btn_flag & BTN_FLAG_DEC)
|
||||
{
|
||||
event = EVENT_DEC_DOWN;
|
||||
}
|
||||
// Unpress
|
||||
else
|
||||
{
|
||||
event = EVENT_DEC_UP;
|
||||
}
|
||||
|
||||
// Actually put the event in the queue
|
||||
if (event_count < MAX_EVENT_COUNT)
|
||||
{
|
||||
*event_write = event;
|
||||
++event_count;
|
||||
PTR_INC(event_write);
|
||||
}
|
||||
}
|
||||
|
||||
if ((new_btn_flag & BTN_FLAG_INC) != (btn_flag & BTN_FLAG_INC))
|
||||
{
|
||||
// Press
|
||||
if (new_btn_flag & BTN_FLAG_INC)
|
||||
{
|
||||
event = EVENT_INC_DOWN;
|
||||
}
|
||||
// Unpress
|
||||
else
|
||||
{
|
||||
event = EVENT_INC_UP;
|
||||
}
|
||||
|
||||
// Actually put the event in the queue
|
||||
if (event_count < MAX_EVENT_COUNT)
|
||||
{
|
||||
*event_write = event;
|
||||
++event_count;
|
||||
PTR_INC(event_write);
|
||||
}
|
||||
}
|
||||
|
||||
btn_flag = new_btn_flag;
|
||||
sei();
|
||||
}
|
||||
|
||||
void hard_init()
|
||||
{
|
||||
// Output Store, Data, Clock
|
||||
DDRB = (1 << DDB0) | (1 << DDB1) | (1 << DDB2);
|
||||
|
||||
// Pull-up Buttons
|
||||
PORTB = (1 << PORTB3) | (1 << PORTB4);
|
||||
|
||||
// Sleep mode - Power down
|
||||
MCUCR = (1 << SM1);
|
||||
|
||||
// Disable power to Timer1, Timer0, USI, ADC
|
||||
//PRR = (1 << PRTIM1) | (1 << PRTIM0) | (1 << PRUSI) | (1 << PRADC);
|
||||
PRR = (1 << PRTIM1) | (1 << PRUSI) | (1 << PRADC);
|
||||
|
||||
// Enable button interrupts
|
||||
PCMSK = (1 << PCINT3) | (1 << PCINT4);
|
||||
GIMSK = (1 << PCIE);
|
||||
|
||||
// CTC Mode
|
||||
TCCR0A = (1 << WGM01);
|
||||
|
||||
// 64 Prescaler
|
||||
TCCR0B = (1 << CS01) | (1 << CS00);
|
||||
|
||||
// Interrupt every 8 ms
|
||||
OCR0A = 125;
|
||||
|
||||
// 1 000 000 / 64 = 15625 (Hz)
|
||||
// 15625 / 125 = 125 (Hz)
|
||||
// 1000 / 125 = 8 (ms)
|
||||
|
||||
// Enable Timer interrupt
|
||||
TIMSK = (1 << OCIE0A);
|
||||
|
||||
sei();
|
||||
}
|
||||
|
||||
void display_send_bit(uint8_t bit)
|
||||
{
|
||||
if (0 != bit)
|
||||
{
|
||||
PORTB |= (1 << OUT_DATA);
|
||||
}
|
||||
else
|
||||
{
|
||||
PORTB &= ~(1 << OUT_DATA);
|
||||
}
|
||||
|
||||
_delay_ms(1);
|
||||
PORTB |= (1 << OUT_CLOCK);
|
||||
_delay_ms(1);
|
||||
PORTB &= (1 << OUT_CLOCK);
|
||||
}
|
||||
|
||||
void display_send_buffer()
|
||||
{
|
||||
uint8_t i;
|
||||
uint8_t b;
|
||||
uint8_t custom_buffer[DISPLAY_SIZE];
|
||||
|
||||
for (b = 0; b < DISPLAY_SIZE / 2; ++b)
|
||||
{
|
||||
custom_buffer[b] = (((display_buffer[b * 2] & 0xF0) << 4) | (display_buffer[b * 2 + 1] & 0xF0));
|
||||
}
|
||||
|
||||
for (b = 0; b < DISPLAY_SIZE / 2; ++b)
|
||||
{
|
||||
custom_buffer[b + DISPLAY_SIZE / 2] = (((display_buffer[DISPLAY_SIZE - 1 - b * 2] & 0x0F) << 4) | (display_buffer[DISPLAY_SIZE - 1 - b * 2 - 1] & 0x0F));
|
||||
}
|
||||
|
||||
for (b = 0; b < DISPLAY_SIZE; ++b)
|
||||
{
|
||||
for (i = 0; i < 8; ++i)
|
||||
{
|
||||
display_send_bit(((custom_buffer[b]) >> (7 - i)) & 0x01);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void display_show()
|
||||
{
|
||||
_delay_ms(1);
|
||||
PORTB |= (1 << OUT_STORE);
|
||||
_delay_ms(1);
|
||||
PORTB &= (1 << OUT_STORE);
|
||||
}
|
||||
|
||||
void display_show_value(uint8_t dots)
|
||||
{
|
||||
uint8_t i;
|
||||
uint32_t div_val = 1;
|
||||
uint32_t counter_copy;
|
||||
uint8_t digit;
|
||||
uint8_t txt;
|
||||
|
||||
for (i = 0; i < DISPLAY_SIZE; ++i)
|
||||
{
|
||||
display_buffer[i] = 0;
|
||||
div_val *= 10;
|
||||
}
|
||||
|
||||
div_val /= 10;
|
||||
|
||||
if (counter_value < 0)
|
||||
{
|
||||
counter_copy = -counter_value;
|
||||
display_buffer[0] = seg_table[10];
|
||||
}
|
||||
else
|
||||
{
|
||||
counter_copy = counter_value;
|
||||
}
|
||||
|
||||
txt = 0;
|
||||
for (i = 0; i < DISPLAY_SIZE; ++i)
|
||||
{
|
||||
digit = counter_copy / div_val;
|
||||
if ((0 != txt) || (0 != digit))
|
||||
{
|
||||
txt = 1;
|
||||
display_buffer[i] = seg_table[digit];
|
||||
}
|
||||
counter_copy %= div_val;
|
||||
div_val /= 10;
|
||||
}
|
||||
|
||||
if (0 != dots)
|
||||
{
|
||||
display_buffer[6] |= DP;
|
||||
}
|
||||
|
||||
display_send_buffer();
|
||||
display_show();
|
||||
}
|
||||
|
||||
void mem_load()
|
||||
{
|
||||
int32_t value = 0;
|
||||
uint8_t curr_byte;
|
||||
uint8_t i;
|
||||
|
||||
value = 0;
|
||||
for (i = 0; i < 4; ++i)
|
||||
{
|
||||
curr_byte = eeprom_read_byte((uint8_t *) i);
|
||||
value <<= 8;
|
||||
value |= curr_byte;
|
||||
}
|
||||
counter_value = value;
|
||||
}
|
||||
|
||||
void mem_save()
|
||||
{
|
||||
int32_t value = counter_value;
|
||||
uint8_t curr_byte;
|
||||
uint8_t i;
|
||||
|
||||
for (i = 0; i < 4; ++i)
|
||||
{
|
||||
curr_byte = (value >> (24 - 8 * i)) & 0xFF;
|
||||
eeprom_update_byte((uint8_t *) i, curr_byte);
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
uint32_t ms_sleep = DISPLAY_DELAY;
|
||||
uint32_t dec_ms_long = 0;
|
||||
uint32_t inc_ms_long = 0;
|
||||
uint8_t event;
|
||||
|
||||
hard_init();
|
||||
display_show_value(0);
|
||||
|
||||
while(1)
|
||||
{
|
||||
while (event_count > 0)
|
||||
{
|
||||
// Consume Event
|
||||
cli();
|
||||
event = *event_read;
|
||||
PTR_INC(event_read);
|
||||
--event_count;
|
||||
sei();
|
||||
|
||||
if (event != EVENT_NONE)
|
||||
{
|
||||
ms_sleep = ms + DISPLAY_DELAY;
|
||||
}
|
||||
|
||||
// Process Event
|
||||
switch (event)
|
||||
{
|
||||
case EVENT_DEC_DOWN:
|
||||
dec_ms_long = ms + LONG_PRESS;
|
||||
break;
|
||||
|
||||
case EVENT_DEC_UP:
|
||||
if (0 != dec_ms_long)
|
||||
{
|
||||
if (counter_value > VALUE_MIN)
|
||||
{
|
||||
--counter_value;
|
||||
}
|
||||
dec_ms_long = 0;
|
||||
}
|
||||
display_show_value(0);
|
||||
break;
|
||||
|
||||
case EVENT_INC_DOWN:
|
||||
inc_ms_long = ms + LONG_PRESS;
|
||||
break;
|
||||
|
||||
case EVENT_INC_UP:
|
||||
if (0 != inc_ms_long)
|
||||
{
|
||||
if (counter_value < VALUE_MAX)
|
||||
{
|
||||
++counter_value;
|
||||
}
|
||||
inc_ms_long = 0;
|
||||
}
|
||||
display_show_value(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ((0 != dec_ms_long) && (ms > dec_ms_long))
|
||||
{
|
||||
mem_load();
|
||||
dec_ms_long = 0;
|
||||
display_show_value(1);
|
||||
}
|
||||
|
||||
if ((0 != inc_ms_long) && (ms > inc_ms_long))
|
||||
{
|
||||
mem_save();
|
||||
inc_ms_long = 0;
|
||||
display_show_value(1);
|
||||
}
|
||||
|
||||
if (ms >= ms_sleep)
|
||||
{
|
||||
// Enable sleep
|
||||
MCUCR |= (1 << SE);
|
||||
|
||||
// Go to sleep
|
||||
sleep_cpu();
|
||||
|
||||
cli();
|
||||
ms = 0;
|
||||
sei();
|
||||
|
||||
// Disable sleep
|
||||
MCUCR &= ~(1 << SE);
|
||||
|
||||
ms_sleep = ms + DISPLAY_DELAY;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user