Initial code commit

This commit is contained in:
nedko 2023-03-06 21:12:55 +02:00
commit c04af37359
2 changed files with 415 additions and 0 deletions

8
code/Makefile Normal file
View 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
View 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;
}