make it work
This commit is contained in:
@@ -0,0 +1,2 @@
|
|||||||
|
CompileFlags:
|
||||||
|
Add: ["-I/opt/avr8-gnu-toolchain-darwin_x86_64/avr/include", "-D__AVR_ATtiny84A__"]
|
||||||
@@ -1 +1,2 @@
|
|||||||
a.*
|
a.*
|
||||||
|
build/
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
all: a.bin
|
all: a.out
|
||||||
|
|
||||||
a.out: main.c
|
a.out: src/*.c src/*.h
|
||||||
avr-gcc -g -Os -mmcu=attiny84a $< -o $@
|
avr-gcc -Wall -g -Os -mmcu=attiny84a src/*.c -o $@
|
||||||
|
|
||||||
a.bin: a.out
|
a.bin: a.out
|
||||||
avr-objcopy -O binary $< $@
|
avr-objcopy -O binary $< $@
|
||||||
|
|
||||||
deploy: a.bin
|
deploy: a.out
|
||||||
avrdude -p t84a -c stk500v1 -P/dev/tty.usbmodemflip_Rab3gao3 -U flash:w:$<:r
|
avrdude -p t84a -c stk500v1 -P/dev/tty.usbmodemflip_Rab3gao3 -U flash:w:$<:e
|
||||||
|
|||||||
@@ -1,6 +0,0 @@
|
|||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
#define OSCILLATOR_CALIBRATION 0x76
|
|
||||||
// #define STARTING_TIME_MS (uint32_t)6*60*1000 // 6 min
|
|
||||||
#define STARTING_TIME_MS (uint32_t)5*1000 // 5 sec
|
|
||||||
|
|
||||||
@@ -1,77 +0,0 @@
|
|||||||
#include <stdbool.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <avr/io.h>
|
|
||||||
#include <avr/interrupt.h>
|
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
#define PLAYER_A_BUTTON 0
|
|
||||||
#define PLAYER_B_BUTTON 1
|
|
||||||
|
|
||||||
uint32_t ms_since_boot = 0;
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
STOPPED,
|
|
||||||
PLAYER_A,
|
|
||||||
PLAYER_B
|
|
||||||
} state_type;
|
|
||||||
|
|
||||||
state_type state = STOPPED;
|
|
||||||
|
|
||||||
uint32_t player_a_timer = STARTING_TIME_MS;
|
|
||||||
uint32_t player_b_timer = STARTING_TIME_MS;
|
|
||||||
|
|
||||||
ISR(TIM1_COMPA_vect)
|
|
||||||
{
|
|
||||||
ms_since_boot++;
|
|
||||||
|
|
||||||
if(state == PLAYER_A) {
|
|
||||||
player_a_timer--;
|
|
||||||
if(player_a_timer == 0) { state = STOPPED; }
|
|
||||||
} else if(state == PLAYER_B) {
|
|
||||||
player_b_timer--;
|
|
||||||
if(player_b_timer == 0) { state = STOPPED; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void setupio(void) {
|
|
||||||
// Set port A to inputs
|
|
||||||
DDRA = 0x00;
|
|
||||||
PORTA |= _BV(PORTA0) | _BV(PORTA1); // pull-up
|
|
||||||
|
|
||||||
// Set port B to output
|
|
||||||
DDRB = 0xFF;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setup_clock(void) {
|
|
||||||
OSCCAL = OSCILLATOR_CALIBRATION;
|
|
||||||
|
|
||||||
TCCR1B = 0x09;
|
|
||||||
OCR1A = 1000;
|
|
||||||
TIMSK1 = 0x02;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool button_pressed(uint8_t pin) {
|
|
||||||
return (PINA & (1 << pin)) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int main() {
|
|
||||||
setupio();
|
|
||||||
setup_clock();
|
|
||||||
sei();
|
|
||||||
|
|
||||||
while(true) {
|
|
||||||
cli();
|
|
||||||
if(button_pressed(PLAYER_A_BUTTON) && player_b_timer != 0) {
|
|
||||||
state = PLAYER_B;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(button_pressed(PLAYER_B_BUTTON) && player_a_timer != 0) {
|
|
||||||
state = PLAYER_A;
|
|
||||||
}
|
|
||||||
|
|
||||||
PORTB = 1 << state;
|
|
||||||
sei();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
#include "as1115.h"
|
||||||
|
#include "i2c.h"
|
||||||
|
|
||||||
|
int as1115_send_command(uint8_t cmd, uint8_t data) {
|
||||||
|
uint8_t packet[] = {cmd, data};
|
||||||
|
return i2c_write(0x00, packet, sizeof packet);
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#define DIGIT_0_REG 0x01
|
||||||
|
#define DIGIT_1_REG 0x02
|
||||||
|
#define DIGIT_2_REG 0x03
|
||||||
|
#define DIGIT_3_REG 0x04
|
||||||
|
#define DIGIT_4_REG 0x05
|
||||||
|
#define DIGIT_5_REG 0x06
|
||||||
|
#define DIGIT_6_REG 0x07
|
||||||
|
#define DIGIT_7_REG 0x08
|
||||||
|
#define DECODE_MODE_REG 0x09
|
||||||
|
#define GLOBAL_INTENSITY_REG 0x0A
|
||||||
|
#define SCAN_LIMIT_REG 0x0B
|
||||||
|
#define SHUTDOWN_REG 0x0C
|
||||||
|
#define SELF_ADDRESSING_REG 0x0D
|
||||||
|
#define FEATURE_REG 0x0E
|
||||||
|
#define DISPLAY_TEST_MODE_REG 0x0F
|
||||||
|
#define DIG_0_1_INTENSITY_REG 0x10
|
||||||
|
#define DIG_2_3_INTENSITY_REG 0x11
|
||||||
|
#define DIG_4_5_INTENSITY_REG 0x12
|
||||||
|
#define DIG_6_7_INTENSITY_REG 0x13
|
||||||
|
|
||||||
|
int as1115_send_command(uint8_t cmd, uint8_t data);
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#define OSCILLATOR_CALIBRATION 0x76
|
||||||
|
#define STARTING_TIME_MS (uint32_t)10*60*1000 // 10 min
|
||||||
|
// #define STARTING_TIME_MS (uint32_t)5*1000 // 5 sec
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <avr/io.h>
|
||||||
|
#include <avr/interrupt.h>
|
||||||
|
|
||||||
|
#include "i2c.h"
|
||||||
|
|
||||||
|
void i2c_init() {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
#define HIGH 1
|
||||||
|
#define LOW 0
|
||||||
|
|
||||||
|
void port_a_put(uint8_t pin, bool value) {
|
||||||
|
if(value) {
|
||||||
|
PORTA |= _BV(pin);
|
||||||
|
DDRA &= ~_BV(pin);
|
||||||
|
} else {
|
||||||
|
PORTA &= ~_BV(pin);
|
||||||
|
DDRA |= _BV(pin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int i2c_write_byte(uint8_t byte) {
|
||||||
|
for (int i = 7; i >= 0; i--) {
|
||||||
|
port_a_put(SDA_BIT, (byte & 0x80) != 0);
|
||||||
|
byte <<= 1;
|
||||||
|
|
||||||
|
// pulse clock
|
||||||
|
port_a_put(SCL_BIT, HIGH);
|
||||||
|
port_a_put(SCL_BIT, LOW);
|
||||||
|
}
|
||||||
|
|
||||||
|
port_a_put(SDA_BIT, HIGH);
|
||||||
|
|
||||||
|
// check ACK
|
||||||
|
|
||||||
|
port_a_put(SCL_BIT, HIGH);
|
||||||
|
|
||||||
|
int ack = PINA & _BV(SDA_BIT);
|
||||||
|
|
||||||
|
port_a_put(SCL_BIT, LOW);
|
||||||
|
|
||||||
|
return ack;
|
||||||
|
}
|
||||||
|
|
||||||
|
int i2c_write(uint8_t addr, const uint8_t* data, uint8_t len) {
|
||||||
|
// START condition
|
||||||
|
port_a_put(SDA_BIT, LOW);
|
||||||
|
|
||||||
|
port_a_put(SCL_BIT, LOW);
|
||||||
|
|
||||||
|
// write address
|
||||||
|
int ack = i2c_write_byte(addr);
|
||||||
|
if (ack) {
|
||||||
|
port_a_put(SDA_BIT, HIGH);
|
||||||
|
port_a_put(SCL_BIT, HIGH);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < len; i++) {
|
||||||
|
int ack = i2c_write_byte(data[i]);
|
||||||
|
if (ack) {
|
||||||
|
port_a_put(SDA_BIT, HIGH);
|
||||||
|
port_a_put(SCL_BIT, HIGH);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// STOP condition
|
||||||
|
port_a_put(SCL_BIT, HIGH);
|
||||||
|
port_a_put(SDA_BIT, HIGH);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
void i2c_init();
|
||||||
|
int i2c_write(uint8_t addr, const uint8_t* data, uint8_t len);
|
||||||
+130
@@ -0,0 +1,130 @@
|
|||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <avr/io.h>
|
||||||
|
#include <avr/interrupt.h>
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#include "as1115.h"
|
||||||
|
#include "i2c.h"
|
||||||
|
|
||||||
|
#define PLAYER_A_BUTTON 0
|
||||||
|
#define PLAYER_B_BUTTON 1
|
||||||
|
|
||||||
|
volatile uint32_t ms_since_boot = 0;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
STOPPED,
|
||||||
|
PLAYER_A,
|
||||||
|
PLAYER_B
|
||||||
|
} state_type;
|
||||||
|
|
||||||
|
volatile state_type state = STOPPED;
|
||||||
|
|
||||||
|
volatile uint32_t player_a_timer = STARTING_TIME_MS;
|
||||||
|
volatile uint32_t player_b_timer = STARTING_TIME_MS;
|
||||||
|
|
||||||
|
ISR(TIM1_COMPA_vect)
|
||||||
|
{
|
||||||
|
ms_since_boot++;
|
||||||
|
|
||||||
|
if(state == PLAYER_A) {
|
||||||
|
player_a_timer--;
|
||||||
|
if(player_a_timer == 0) { state = STOPPED; }
|
||||||
|
} else if(state == PLAYER_B) {
|
||||||
|
player_b_timer--;
|
||||||
|
if(player_b_timer == 0) { state = STOPPED; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setupio(void) {
|
||||||
|
// Set port A to inputs
|
||||||
|
DDRA = 0x00;
|
||||||
|
PORTA |= _BV(PORTA0) | _BV(PORTA1); // pull-up
|
||||||
|
|
||||||
|
// Set port B to output
|
||||||
|
DDRB = 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup_clock(void) {
|
||||||
|
OSCCAL = OSCILLATOR_CALIBRATION;
|
||||||
|
|
||||||
|
TCCR1B = 0x09;
|
||||||
|
OCR1A = 1000;
|
||||||
|
TIMSK1 = 0x02;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool button_pressed(uint8_t pin) {
|
||||||
|
return (PINA & (1 << pin)) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define DISPLAY_LEFT 0
|
||||||
|
#define DISPLAY_RIGHT 1
|
||||||
|
|
||||||
|
void render_timer(unsigned long ms, uint8_t display) {
|
||||||
|
uint8_t digits[4] = {0xFF, 0xFF, 0xFF, 0xFF};
|
||||||
|
|
||||||
|
if (ms == 0) {
|
||||||
|
memset(&digits, 0x0A, 4); // show all dashes
|
||||||
|
goto render;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t sec = (ms + (1000 - 1)) / 1000 % 60;
|
||||||
|
uint8_t min = (ms + (1000 - 1)) / 1000 / 60;
|
||||||
|
|
||||||
|
digits[3] = sec % 10;
|
||||||
|
digits[2] = sec / 10;
|
||||||
|
|
||||||
|
if (min != 0) {
|
||||||
|
digits[1] = min % 10;
|
||||||
|
if (min >= 10) {
|
||||||
|
digits[0] = min / 10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
render:
|
||||||
|
switch(display) {
|
||||||
|
case DISPLAY_LEFT:
|
||||||
|
as1115_send_command(0x01, digits[0]);
|
||||||
|
as1115_send_command(0x02, digits[1]);
|
||||||
|
as1115_send_command(0x03, digits[2]);
|
||||||
|
as1115_send_command(0x04, digits[3]);
|
||||||
|
break;
|
||||||
|
case DISPLAY_RIGHT:
|
||||||
|
as1115_send_command(0x05, digits[0]);
|
||||||
|
as1115_send_command(0x06, digits[1]);
|
||||||
|
as1115_send_command(0x07, digits[2]);
|
||||||
|
as1115_send_command(0x08, digits[3]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
cli();
|
||||||
|
setupio();
|
||||||
|
i2c_init();
|
||||||
|
setup_clock();
|
||||||
|
sei();
|
||||||
|
|
||||||
|
render_timer(STARTING_TIME_MS, DISPLAY_LEFT);
|
||||||
|
render_timer(STARTING_TIME_MS, DISPLAY_RIGHT);
|
||||||
|
|
||||||
|
as1115_send_command(SHUTDOWN_REG, 0x01); // turn on
|
||||||
|
as1115_send_command(DECODE_MODE_REG, 0xFF); // decode
|
||||||
|
as1115_send_command(SCAN_LIMIT_REG, 0x07); // enable all digits
|
||||||
|
|
||||||
|
while(true) {
|
||||||
|
render_timer(player_a_timer, DISPLAY_LEFT);
|
||||||
|
render_timer(player_b_timer, DISPLAY_RIGHT);
|
||||||
|
|
||||||
|
cli();
|
||||||
|
if(button_pressed(PLAYER_A_BUTTON) && player_b_timer != 0 && player_a_timer != 0) {
|
||||||
|
state = PLAYER_B;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(button_pressed(PLAYER_B_BUTTON) && player_b_timer != 0 && player_a_timer != 0) {
|
||||||
|
state = PLAYER_A;
|
||||||
|
}
|
||||||
|
sei();
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user