Cleanup, reorganization
This commit is contained in:
@@ -0,0 +1,437 @@
|
||||
//Imitace casovane bomby, Ondrej Hruska (c) 2010-2012
|
||||
//-------------------------------------------------
|
||||
// Zapojeni:
|
||||
// +------u------+
|
||||
// reset --+ /RST Vcc +-- napajeni +5V
|
||||
// Anoda jednotek --+ PD0 PB7 +-- segment D
|
||||
// Anoda desitek --+ PD1 PB6 +-- sedment E
|
||||
// (nezapojeno) --+ XT2 PB5 +-- segment C
|
||||
// (nezapojeno) --+ XT1 PB4 +-- segment H
|
||||
// drat --+ PD2 PB3 +-- segment G
|
||||
// drat --+ PD3 PB2 +-- segment A
|
||||
// drat --+ PD4 PB1 +-- segment F
|
||||
// drat --+ PD5 PB0 +-- segment B
|
||||
// GND --+ GND PD6 +-- output signal (vybuch)
|
||||
// +-------------+
|
||||
//
|
||||
// Nazvy segmentu na displeji:
|
||||
// ---A---
|
||||
// | |
|
||||
// F B
|
||||
// | |
|
||||
// ---G---
|
||||
// | |
|
||||
// E C
|
||||
// | |
|
||||
// ---D--- H
|
||||
//
|
||||
|
||||
/*
|
||||
|
||||
Ports:
|
||||
|
||||
PORTB - segments
|
||||
|
||||
PD0 anode L
|
||||
PD1 anode H
|
||||
PD2 w0
|
||||
PD3 w1
|
||||
PD4 w2
|
||||
PD5 w3
|
||||
PD6 BOMB
|
||||
PD7 -nc-
|
||||
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#include <avr/io.h>
|
||||
#include <avr/interrupt.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <util/delay_basic.h>
|
||||
#include <avr/eeprom.h>
|
||||
#include <avr/sleep.h>
|
||||
|
||||
void updateDisplayBuffer();
|
||||
void ports_init();
|
||||
void timer_init();
|
||||
void multiplex(uint8_t times);
|
||||
void boom();
|
||||
void halt();
|
||||
void init_animation();
|
||||
|
||||
|
||||
/*FUSES =
|
||||
{
|
||||
.low = 0xE4,
|
||||
.high = 0xDF
|
||||
};*/
|
||||
|
||||
|
||||
/** initial number of intervals */
|
||||
#define INIT_MINS 60
|
||||
|
||||
/** seconds in one interval */
|
||||
#define INIT_MAX 60
|
||||
|
||||
|
||||
/** seconds in one interval */
|
||||
#define RAPID_MAX 8
|
||||
|
||||
/** seconds in one interval */
|
||||
#define RAPID_COUNT 5
|
||||
|
||||
|
||||
|
||||
/* MACROS */
|
||||
|
||||
/** set one hertz interrupt */
|
||||
#define timer_enable() TIMSK=(1<<OCIE1A)
|
||||
|
||||
/** disable timer interrupt */
|
||||
#define timer_disable() TIMSK=0
|
||||
|
||||
|
||||
|
||||
// segments DEChGAFB
|
||||
#define B (1<<0)
|
||||
#define F (1<<1)
|
||||
#define A (1<<2)
|
||||
#define G (1<<3)
|
||||
#define H (1<<4)
|
||||
#define C (1<<5)
|
||||
#define E (1<<6)
|
||||
#define D (1<<7)
|
||||
|
||||
// anodes
|
||||
#define AL 1
|
||||
#define AH 0
|
||||
|
||||
// wires
|
||||
#define W0 2
|
||||
#define W1 3
|
||||
#define W2 4
|
||||
#define W3 5
|
||||
|
||||
//bomb pin
|
||||
#define BM 6
|
||||
|
||||
// pin groups
|
||||
#define WIRES ((1<<W0)|(1<<W1)|(1<<W2)|(1<<W3))
|
||||
#define ANODES ((1<<AL)|(1<<AH))
|
||||
#define BOMB (1<<BM)
|
||||
#define SEGMENTS 0xFF
|
||||
|
||||
|
||||
uint8_t num2seg[10]; // array for num -> 7seg translation
|
||||
|
||||
#define BLANK 0
|
||||
|
||||
|
||||
/* VARIABLES */
|
||||
|
||||
uint8_t EEMEM wireset;
|
||||
|
||||
uint8_t volatile cnt; // time counter (countdown)
|
||||
uint8_t volatile cnt_interval; // current interval counter in seconds
|
||||
uint8_t volatile cnt_interval_max; // length of current interval in seconds
|
||||
|
||||
uint8_t disp_H; // display buffer - ones
|
||||
uint8_t disp_L; // tens
|
||||
|
||||
uint8_t volatile wires;
|
||||
uint8_t volatile last_wires;
|
||||
uint8_t is_one_digit;
|
||||
|
||||
uint8_t wire_shutdown; //absolute mask
|
||||
uint8_t wire_boom;
|
||||
//remaining two are for RAPID COUNTDOWN (30 s)
|
||||
|
||||
|
||||
|
||||
|
||||
/* INTERRUPT VECTORS */
|
||||
|
||||
/** one second interrupt */
|
||||
ISR(TIMER1_COMPA_vect){
|
||||
|
||||
cnt_interval++;
|
||||
|
||||
if(!is_one_digit) disp_H ^= H;
|
||||
disp_L ^= H;
|
||||
|
||||
if(cnt_interval >= cnt_interval_max){
|
||||
cnt_interval=0;
|
||||
cnt--;
|
||||
//to tens and ones
|
||||
updateDisplayBuffer();
|
||||
}
|
||||
|
||||
//time over?
|
||||
if(cnt==0){
|
||||
boom();
|
||||
}
|
||||
}
|
||||
|
||||
/** MAIN */
|
||||
int main()
|
||||
{
|
||||
cnt = INIT_MINS;
|
||||
cnt_interval = 0;
|
||||
cnt_interval_max = INIT_MAX;
|
||||
is_one_digit = 0;
|
||||
disp_H = 0;
|
||||
disp_L = 0;
|
||||
last_wires = WIRES;
|
||||
|
||||
|
||||
num2seg[0] = A|B|C|D|E|F;
|
||||
num2seg[1] = B|C;
|
||||
num2seg[2] = A|B|G|E|D;
|
||||
num2seg[3] = A|B|G|C|D;
|
||||
num2seg[4] = F|G|B|C;
|
||||
num2seg[5] = A|F|G|C|D;
|
||||
num2seg[6] = A|C|D|E|F|G;
|
||||
num2seg[7] = A|B|C;
|
||||
num2seg[8] = A|B|C|D|E|F|G;
|
||||
num2seg[9] = A|B|C|D|F|G;
|
||||
|
||||
timer_disable();
|
||||
timer_init();
|
||||
timer_reset();
|
||||
|
||||
ports_init();
|
||||
init_animation();
|
||||
|
||||
last_wires = ~(PIND & WIRES);
|
||||
|
||||
//wire set
|
||||
//read wireset number
|
||||
uint8_t wireset_r = eeprom_read_byte((uint8_t*)&wireset);
|
||||
//go to next one, reset if >11
|
||||
wireset_r++;
|
||||
if(wireset_r>=12) wireset_r=0;
|
||||
//store new value
|
||||
eeprom_write_byte((uint8_t*)&wireset,wireset_r);
|
||||
|
||||
//select wires for wireset
|
||||
uint8_t ws_boom[12] = {(1<<W1), (1<<W0), (1<<W2), (1<<W0), (1<<W3), (1<<W0), (1<<W1), (1<<W1), (1<<W3), (1<<W2), (1<<W2), (1<<W3)};
|
||||
uint8_t ws_shutdown[12] = {(1<<W0), (1<<W3), (1<<W1), (1<<W2), (1<<W2), (1<<W1), (1<<W3), (1<<W2), (1<<W1), (1<<W0), (1<<W3), (1<<W0)};
|
||||
|
||||
wire_boom = ws_boom[wireset_r];
|
||||
wire_shutdown = ws_shutdown[wireset_r];
|
||||
|
||||
|
||||
updateDisplayBuffer();
|
||||
timer_enable();
|
||||
sei();
|
||||
|
||||
|
||||
uint8_t diff;
|
||||
|
||||
|
||||
while(1){
|
||||
multiplex(50);
|
||||
//check wire
|
||||
wires = ~(PIND & WIRES);
|
||||
diff = wires ^ last_wires;
|
||||
|
||||
//wire changed
|
||||
if(diff != 0){
|
||||
|
||||
//shutdown wire was connected last time
|
||||
if( (last_wires & wire_shutdown) != 0 && (diff & wire_shutdown) != 0){
|
||||
//shutdown wire!
|
||||
halt();
|
||||
exit(0);
|
||||
|
||||
}else if( (last_wires & wire_boom) != 0 && (diff & wire_boom) != 0){
|
||||
//bomb launched!
|
||||
boom();
|
||||
exit(0);
|
||||
|
||||
}else{
|
||||
//rapid
|
||||
if(cnt_interval_max > RAPID_MAX){
|
||||
cnt_interval_max = RAPID_MAX;
|
||||
|
||||
if(cnt>RAPID_COUNT){
|
||||
cnt = RAPID_COUNT;
|
||||
cnt_interval = 0;
|
||||
timer_reset();
|
||||
updateDisplayBuffer();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
last_wires = wires;
|
||||
}
|
||||
|
||||
cli();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/** put corrent segments into display buffer (from cnt) */
|
||||
void updateDisplayBuffer(){
|
||||
div_t foo = div((int)cnt,10);
|
||||
//keep decimal dots
|
||||
disp_H = (disp_L & H) | num2seg[foo.quot];
|
||||
disp_L = (disp_L & H) | num2seg[foo.rem];
|
||||
if(foo.quot == 0){
|
||||
disp_H = 0;
|
||||
is_one_digit = 1;
|
||||
}else{
|
||||
is_one_digit = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** show display, repeat "times" x */
|
||||
void multiplex(uint8_t times){
|
||||
for(; times>0; times--){
|
||||
|
||||
PORTB = ~disp_L; // TENS segments; common anode, needs invert
|
||||
PORTD &= ~ANODES; // reset anodes
|
||||
PORTD |= (1<<AL); // turn TENS anode on
|
||||
_delay_loop_1(255); // wait
|
||||
|
||||
|
||||
PORTB = ~disp_H; // ONES segments; common anode, needs invert
|
||||
PORTD &= ~ANODES; // reset anodes
|
||||
PORTD |= (1<<AH); // turn ONES anode on
|
||||
_delay_loop_1(255); // wait
|
||||
|
||||
}
|
||||
PORTB = ~BLANK; //display off
|
||||
}
|
||||
|
||||
void multiplex_pwm(uint8_t times, uint8_t delay){
|
||||
for(; times>0; times--){
|
||||
|
||||
PORTB = ~disp_L; // TENS segments; common anode, needs invert
|
||||
PORTD &= ~ANODES; // reset anodes
|
||||
PORTD |= (1<<AL); // turn TENS anode on
|
||||
_delay_loop_1(255-delay); // wait
|
||||
|
||||
|
||||
PORTD &= ~(1<<AL);
|
||||
_delay_loop_1(delay);
|
||||
|
||||
|
||||
PORTB = ~disp_H; // ONES segments; common anode, needs invert
|
||||
PORTD &= ~ANODES; // reset anodes
|
||||
PORTD |= (1<<AH); // turn ONES anode on
|
||||
_delay_loop_1(255-delay); // wait
|
||||
|
||||
PORTD &= ~(1<<AH);
|
||||
_delay_loop_1(delay);
|
||||
|
||||
}
|
||||
PORTB = ~BLANK; //display off
|
||||
}
|
||||
|
||||
|
||||
/** the boom */
|
||||
void boom(){
|
||||
|
||||
cli();
|
||||
|
||||
PORTD |= BOMB; //activate bomb
|
||||
PORTD &= ~WIRES; // turn off wire pullups
|
||||
|
||||
disp_H = 0b01010101;
|
||||
disp_L = 0b10101010;
|
||||
|
||||
while(1){
|
||||
disp_H ^= 0xff;
|
||||
disp_L ^= 0xff;
|
||||
|
||||
longmpx();
|
||||
}
|
||||
|
||||
// PORTD |= ANODES; // turn both anodes on
|
||||
// PORTB = 0x00; // all segments on
|
||||
// __asm__("cli");
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
|
||||
/** the boom */
|
||||
void halt(){
|
||||
|
||||
|
||||
|
||||
PORTD &= ~WIRES;
|
||||
|
||||
for(uint8_t volatile pause=0; pause < 0xff; pause++){
|
||||
multiplex_pwm(40,pause);
|
||||
}
|
||||
|
||||
//animation
|
||||
|
||||
PORTD = (1<<AL); // higher part
|
||||
PORTB = ~H; // show one dot
|
||||
|
||||
timer_disable();
|
||||
cli();
|
||||
|
||||
for(;;){}
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/** set up ports */
|
||||
void ports_init(){
|
||||
|
||||
DDRB = SEGMENTS; // segments to output
|
||||
PORTB = SEGMENTS; // turned off (cathodes!)
|
||||
|
||||
DDRD = ANODES|BOMB; // set outputs
|
||||
PORTD = WIRES; // enable wire pullups
|
||||
|
||||
}
|
||||
|
||||
|
||||
/** set timer1 to one hertz */
|
||||
void timer_init(){
|
||||
TCCR1A = 0;
|
||||
TCCR1B=(1<<WGM12)|(1<<CS12);
|
||||
OCR1AH=0b01111010;
|
||||
OCR1AL=0b00010010;
|
||||
}
|
||||
|
||||
/** clear timer */
|
||||
void timer_reset(){
|
||||
TCNT0 = 0;
|
||||
}
|
||||
|
||||
void longmpx(){
|
||||
for(uint8_t i=2; i>0; i--){
|
||||
multiplex(250);
|
||||
}
|
||||
}
|
||||
|
||||
/** animation on startup */
|
||||
void init_animation(){
|
||||
|
||||
disp_H = BLANK;
|
||||
disp_L = BLANK;
|
||||
for(uint8_t i=0; i<10; i++){
|
||||
disp_H ^= 0xff;
|
||||
disp_L ^= 0xff;
|
||||
|
||||
longmpx();
|
||||
}
|
||||
|
||||
disp_H = BLANK;
|
||||
disp_L = BLANK;
|
||||
|
||||
_delay_loop_1(255);
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
PRG = main
|
||||
|
||||
MCU_TARGET = attiny2313
|
||||
OPTIMIZE = 2
|
||||
|
||||
|
||||
LFUSE = 0xE4
|
||||
HFUSE = 0xDF
|
||||
|
||||
|
||||
|
||||
|
||||
DEFS =-std=gnu99 -funsigned-char -funsigned-bitfields -ffunction-sections -fpack-struct -fshort-enums -ffreestanding --combine -fwhole-program -fno-inline-small-functions -fno-split-wide-types -fno-tree-scev-cprop -Wl,--relax,--gc-sections
|
||||
CC = avr-gcc
|
||||
OBJCOPY = avr-objcopy
|
||||
OBJDUMP = avr-objdump
|
||||
|
||||
OBJ = $(PRG).o
|
||||
|
||||
override CFLAGS = -g2 -Wall -O$(OPTIMIZE) -mmcu=$(MCU_TARGET) $(DEFS)
|
||||
|
||||
# program: $(PRG).elf lst hex
|
||||
#
|
||||
|
||||
all: $(PRG).elf lst eeprom
|
||||
|
||||
$(PRG).elf: $(OBJ)
|
||||
$(CC) $(CFLAGS) -o $@ $^ $(LIBS)
|
||||
avr-size -C -d --mcu=$(MCU_TARGET) $(PRG).elf
|
||||
|
||||
lst: $(PRG).lst
|
||||
|
||||
%.lst: %.elf
|
||||
$(OBJDUMP) -h -S $< > $@
|
||||
|
||||
hex: $(PRG).hex lst
|
||||
|
||||
%.hex: %.elf
|
||||
$(OBJCOPY) -j .text -j .data -O ihex $< $@
|
||||
|
||||
|
||||
install: wflash wfuses
|
||||
|
||||
install_ee: weeprom
|
||||
install_fl: wflash
|
||||
install_fu: wfuses
|
||||
|
||||
|
||||
wflash: $(PRG).hex
|
||||
avrdude -P usb -c dragon_isp -p $(MCU_TARGET) -B 16 -U flash:w:$(PRG).hex
|
||||
|
||||
|
||||
wfuses:
|
||||
avrdude -P usb -c dragon_isp -p $(MCU_TARGET) -B 16 -U lfuse:w:$(LFUSE):m -U hfuse:w:$(HFUSE):m
|
||||
|
||||
|
||||
weeprom: ehex
|
||||
avrdude -P usb -c dragon_isp -p $(MCU_TARGET) -B 16 -U lfuse:w:$(LFUSE):m -U eeprom:w:$(PRG)_eeprom.hex
|
||||
|
||||
ee: ehex
|
||||
eeprom: ehex
|
||||
|
||||
ehex: $(PRG)_eeprom.hex
|
||||
|
||||
%_eeprom.hex: %.elf
|
||||
$(OBJCOPY) -j .eeprom --change-section-lma .eeprom=0 -O ihex $< $@
|
||||
|
||||
|
||||
clean:
|
||||
rm -f *.o $(PRG).elf *.hex *.lst *~
|
||||
|
||||
term:
|
||||
avrdude -P usb -c dragon_isp -p $(MCU_TARGET) -B 16 -t
|
||||
|
||||
Reference in New Issue
Block a user