This commit is contained in:
2026-05-10 16:35:21 -06:00
parent c473d4906e
commit 9dad0f9390
6 changed files with 182 additions and 179 deletions
+2 -1
View File
@@ -1,2 +1,3 @@
[*.c] [*.c]
indent_style = tab indent_style = space
indent_size = 2
+2 -2
View File
@@ -2,6 +2,6 @@
#include "i2c.h" #include "i2c.h"
int as1115_send_command(uint8_t cmd, uint8_t data) { int as1115_send_command(uint8_t cmd, uint8_t data) {
uint8_t packet[] = {cmd, data}; uint8_t packet[] = {cmd, data};
return i2c_write(0x00, packet, sizeof packet); return i2c_write(0x00, packet, sizeof packet);
} }
+1 -1
View File
@@ -5,7 +5,7 @@
#define OSCILLATOR_CALIBRATION 0x76 #define OSCILLATOR_CALIBRATION 0x76
#define MAIN_TIME 30*1000L #define MAIN_TIME 30 * 1000L
// #define TIME_INCREMENT 30*1000L // #define TIME_INCREMENT 30*1000L
#define INCREMENT_MODE MODE_FISCHER #define INCREMENT_MODE MODE_FISCHER
#define RESET_DELAY 3000 #define RESET_DELAY 3000
+46 -46
View File
@@ -1,78 +1,78 @@
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include <avr/io.h>
#include <avr/interrupt.h> #include <avr/interrupt.h>
#include <avr/io.h>
#include "i2c.h" #include "i2c.h"
void i2c_init() { void i2c_init() {
DDRA |= _BV(SDA_BIT) | _BV(SCL_BIT); // Set SDA and SCL to output DDRA |= _BV(SDA_BIT) | _BV(SCL_BIT); // Set SDA and SCL to output
PORTA |= _BV(SDA_BIT) | _BV(SCL_BIT); // Write HIGH to SDA and SCL PORTA |= _BV(SDA_BIT) | _BV(SCL_BIT); // Write HIGH to SDA and SCL
} }
#define HIGH 1 #define HIGH 1
#define LOW 0 #define LOW 0
void port_a_put(uint8_t pin, bool value) { void port_a_put(uint8_t pin, bool value) {
if(value) { if (value) {
PORTA |= _BV(pin); PORTA |= _BV(pin);
DDRA &= ~_BV(pin); DDRA &= ~_BV(pin);
} else { } else {
PORTA &= ~_BV(pin); PORTA &= ~_BV(pin);
DDRA |= _BV(pin); DDRA |= _BV(pin);
} }
} }
int i2c_write_byte(uint8_t byte) { int i2c_write_byte(uint8_t byte) {
for (int i = 7; i >= 0; i--) { for (int i = 7; i >= 0; i--) {
port_a_put(SDA_BIT, (byte & 0x80) != 0); port_a_put(SDA_BIT, (byte & 0x80) != 0);
byte <<= 1; byte <<= 1;
// pulse clock // pulse clock
port_a_put(SCL_BIT, HIGH); port_a_put(SCL_BIT, HIGH);
port_a_put(SCL_BIT, LOW); port_a_put(SCL_BIT, LOW);
} }
port_a_put(SDA_BIT, HIGH); port_a_put(SDA_BIT, HIGH);
// check ACK // check ACK
port_a_put(SCL_BIT, HIGH); port_a_put(SCL_BIT, HIGH);
int ack = PINA & _BV(SDA_BIT); int ack = PINA & _BV(SDA_BIT);
port_a_put(SCL_BIT, LOW); port_a_put(SCL_BIT, LOW);
return ack; return ack;
} }
int i2c_write(uint8_t addr, const uint8_t* data, uint8_t len) { int i2c_write(uint8_t addr, const uint8_t *data, uint8_t len) {
// START condition // START condition
port_a_put(SDA_BIT, LOW); port_a_put(SDA_BIT, LOW);
port_a_put(SCL_BIT, LOW); port_a_put(SCL_BIT, LOW);
// write address // write address
int ack = i2c_write_byte(addr); int ack = i2c_write_byte(addr);
if (ack) { if (ack) {
port_a_put(SDA_BIT, HIGH); port_a_put(SDA_BIT, HIGH);
port_a_put(SCL_BIT, HIGH); port_a_put(SCL_BIT, HIGH);
return 1; return 1;
} }
for (int i = 0; i < len; i++) { for (int i = 0; i < len; i++) {
int ack = i2c_write_byte(data[i]); int ack = i2c_write_byte(data[i]);
if (ack) { if (ack) {
port_a_put(SDA_BIT, HIGH); port_a_put(SDA_BIT, HIGH);
port_a_put(SCL_BIT, HIGH); port_a_put(SCL_BIT, HIGH);
return 1; return 1;
} }
} }
// STOP condition // STOP condition
port_a_put(SCL_BIT, HIGH); port_a_put(SCL_BIT, HIGH);
port_a_put(SDA_BIT, HIGH); port_a_put(SDA_BIT, HIGH);
return 0; return 0;
} }
+1 -1
View File
@@ -1,4 +1,4 @@
#include <stdint.h> #include <stdint.h>
void i2c_init(); void i2c_init();
int i2c_write(uint8_t addr, const uint8_t* data, uint8_t len); int i2c_write(uint8_t addr, const uint8_t *data, uint8_t len);
+130 -128
View File
@@ -1,11 +1,11 @@
#include <avr/interrupt.h>
#include <avr/io.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include <string.h> #include <string.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include "config.h"
#include "as1115.h" #include "as1115.h"
#include "config.h"
#include "i2c.h" #include "i2c.h"
#if MAIN_TIME > 5999000 #if MAIN_TIME > 5999000
@@ -17,11 +17,7 @@
volatile uint32_t ms_since_boot = 0; volatile uint32_t ms_since_boot = 0;
typedef enum { typedef enum { STOPPED, PLAYER_A, PLAYER_B } state_type;
STOPPED,
PLAYER_A,
PLAYER_B
} state_type;
volatile state_type state = STOPPED; volatile state_type state = STOPPED;
@@ -31,162 +27,168 @@ volatile uint32_t move_started_at = MAIN_TIME;
volatile uint32_t finished_at = 0; volatile uint32_t finished_at = 0;
ISR(TIM1_COMPA_vect) ISR(TIM1_COMPA_vect) {
{ ms_since_boot++;
ms_since_boot++;
if(state == PLAYER_A) { if (state == PLAYER_A) {
player_a_timer--; player_a_timer--;
if(player_a_timer == 0) { state = STOPPED; finished_at = ms_since_boot; } if (player_a_timer == 0) {
} else if(state == PLAYER_B) { state = STOPPED;
player_b_timer--; finished_at = ms_since_boot;
if(player_b_timer == 0) { state = STOPPED; finished_at = ms_since_boot; } }
} } else if (state == PLAYER_B) {
player_b_timer--;
if (player_b_timer == 0) {
state = STOPPED;
finished_at = ms_since_boot;
}
}
} }
void setupio(void) { void setupio(void) {
// Set port A to inputs // Set port A to inputs
DDRA = 0x00; DDRA = 0x00;
PORTA |= _BV(PORTA0) | _BV(PORTA1); // pull-up PORTA |= _BV(PORTA0) | _BV(PORTA1); // pull-up
// Set port B to output // Set port B to output
DDRB = 0xFF; DDRB = 0xFF;
} }
void setup_clock(void) { void setup_clock(void) {
OSCCAL = OSCILLATOR_CALIBRATION; OSCCAL = OSCILLATOR_CALIBRATION;
TCCR1B = 0x09; TCCR1B = 0x09;
OCR1A = 1000; OCR1A = 1000;
TIMSK1 = 0x02; TIMSK1 = 0x02;
} }
bool button_pressed(uint8_t pin) { bool button_pressed(uint8_t pin) { return (PINA & (1 << pin)) == 0; }
return (PINA & (1 << pin)) == 0;
}
#define DISPLAY_LEFT 0 #define DISPLAY_LEFT 0
#define DISPLAY_RIGHT 1 #define DISPLAY_RIGHT 1
void render_timer(unsigned long ms, uint8_t display) { void render_timer(unsigned long ms, uint8_t display) {
uint8_t digits[4] = {0xFF, 0xFF, 0xFF, 0xFF}; uint8_t digits[4] = {0xFF, 0xFF, 0xFF, 0xFF};
if (ms == 0) { if (ms == 0) {
memset(&digits, 0x0A, 4); // show all dashes memset(&digits, 0x0A, 4); // show all dashes
goto render; goto render;
} }
if (ms >= 60000) { if (ms >= 60000) {
uint8_t sec = ms / 1000 % 60; uint8_t sec = ms / 1000 % 60;
uint8_t min = ms / 1000 / 60; uint8_t min = ms / 1000 / 60;
digits[3] = sec % 10; digits[3] = sec % 10;
digits[2] = sec / 10; digits[2] = sec / 10;
if (min != 0) { if (min != 0) {
digits[1] = min % 10; digits[1] = min % 10;
if (min >= 10) { if (min >= 10) {
digits[0] = min / 10; digits[0] = min / 10;
} }
} }
} else { } else {
uint8_t cs = ms / 10 % 100; uint8_t cs = ms / 10 % 100;
uint8_t sec = ms / 1000; uint8_t sec = ms / 1000;
digits[3] = cs % 10; digits[3] = cs % 10;
digits[2] = cs / 10; digits[2] = cs / 10;
if (sec != 0) { if (sec != 0) {
digits[1] = sec % 10; digits[1] = sec % 10;
if (sec >= 10) { if (sec >= 10) {
digits[0] = sec / 10; digits[0] = sec / 10;
} }
} }
} }
render: render:
switch(display) { switch (display) {
case DISPLAY_LEFT: case DISPLAY_LEFT:
as1115_send_command(0x01, digits[0]); as1115_send_command(0x01, digits[0]);
as1115_send_command(0x02, digits[1]); as1115_send_command(0x02, digits[1]);
as1115_send_command(0x03, digits[2]); as1115_send_command(0x03, digits[2]);
as1115_send_command(0x04, digits[3]); as1115_send_command(0x04, digits[3]);
break; break;
case DISPLAY_RIGHT: case DISPLAY_RIGHT:
as1115_send_command(0x05, digits[0]); as1115_send_command(0x05, digits[0]);
as1115_send_command(0x06, digits[1]); as1115_send_command(0x06, digits[1]);
as1115_send_command(0x07, digits[2]); as1115_send_command(0x07, digits[2]);
as1115_send_command(0x08, digits[3]); as1115_send_command(0x08, digits[3]);
break; break;
} }
} }
uint32_t get_increment(uint32_t player_timer) { uint32_t get_increment(uint32_t player_timer) {
if (state == STOPPED) { if (state == STOPPED) {
return 0; return 0;
} }
#ifdef TIME_INCREMENT #ifdef TIME_INCREMENT
#if INCREMENT_MODE == MODE_FISCHER #if INCREMENT_MODE == MODE_FISCHER
return TIME_INCREMENT; return TIME_INCREMENT;
#elif INCREMENT_MODE == MODE_BRONSTEIN #elif INCREMENT_MODE == MODE_BRONSTEIN
uint32_t difference = move_started_at - player_timer; uint32_t difference = move_started_at - player_timer;
if(difference < TIME_INCREMENT) { if (difference < TIME_INCREMENT) {
return difference; return difference;
} else { } else {
return TIME_INCREMENT; return TIME_INCREMENT;
} }
#endif #endif
#else #else
return 0; return 0;
#endif #endif
} }
void reset() { void reset() {
cli(); cli();
state = STOPPED; state = STOPPED;
player_a_timer = MAIN_TIME; player_a_timer = MAIN_TIME;
player_b_timer = MAIN_TIME; player_b_timer = MAIN_TIME;
move_started_at = MAIN_TIME; move_started_at = MAIN_TIME;
finished_at = 0; finished_at = 0;
sei(); sei();
render_timer(player_a_timer, DISPLAY_LEFT); render_timer(player_a_timer, DISPLAY_LEFT);
render_timer(player_b_timer, DISPLAY_RIGHT); render_timer(player_b_timer, DISPLAY_RIGHT);
} }
int main() { int main() {
cli(); cli();
setupio(); setupio();
i2c_init(); i2c_init();
setup_clock(); setup_clock();
sei(); sei();
render_timer(MAIN_TIME, DISPLAY_LEFT); render_timer(MAIN_TIME, DISPLAY_LEFT);
render_timer(MAIN_TIME, DISPLAY_RIGHT); render_timer(MAIN_TIME, DISPLAY_RIGHT);
as1115_send_command(DECODE_MODE_REG, 0xFF); // decode as1115_send_command(DECODE_MODE_REG, 0xFF); // decode
as1115_send_command(SCAN_LIMIT_REG, 0x07); // enable all digits as1115_send_command(SCAN_LIMIT_REG, 0x07); // enable all digits
as1115_send_command(GLOBAL_INTENSITY_REG, 0x06); // set brightness as1115_send_command(GLOBAL_INTENSITY_REG, 0x06); // set brightness
as1115_send_command(SHUTDOWN_REG, 0x01); // turn on as1115_send_command(SHUTDOWN_REG, 0x01); // turn on
while(true) { while (true) {
render_timer(player_a_timer, DISPLAY_LEFT); render_timer(player_a_timer, DISPLAY_LEFT);
render_timer(player_b_timer, DISPLAY_RIGHT); render_timer(player_b_timer, DISPLAY_RIGHT);
cli(); cli();
if(button_pressed(PLAYER_A_BUTTON) && state != PLAYER_B && player_b_timer != 0 && player_a_timer != 0) { if (button_pressed(PLAYER_A_BUTTON) && state != PLAYER_B &&
player_a_timer += get_increment(player_a_timer); player_b_timer != 0 && player_a_timer != 0) {
state = PLAYER_B; player_a_timer += get_increment(player_a_timer);
move_started_at = player_b_timer; state = PLAYER_B;
} move_started_at = player_b_timer;
}
if(button_pressed(PLAYER_B_BUTTON) && state != PLAYER_A && player_b_timer != 0 && player_a_timer != 0) { if (button_pressed(PLAYER_B_BUTTON) && state != PLAYER_A &&
player_b_timer += get_increment(player_b_timer); player_b_timer != 0 && player_a_timer != 0) {
state = PLAYER_A; player_b_timer += get_increment(player_b_timer);
move_started_at = player_a_timer; state = PLAYER_A;
} move_started_at = player_a_timer;
sei(); }
sei();
if (state == STOPPED && (player_a_timer == 0 || player_b_timer == 0) && (ms_since_boot > finished_at + RESET_DELAY)) { if (state == STOPPED && (player_a_timer == 0 || player_b_timer == 0) &&
reset(); (ms_since_boot > finished_at + RESET_DELAY)) {
} reset();
} }
}
} }