commit a1e5c1b312b1a5f041dc0fff76ff9d68509df921 Author: Marek Baczynski Date: Wed Jul 28 19:50:48 2021 +0200 Initial commit with code that mostly works. diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1b7f858 --- /dev/null +++ b/.gitignore @@ -0,0 +1,55 @@ +# Ignore any backup files. +*~ +*.bak + +# Ignore kate swap files +*.kate-swp + +# Ignore any build directories +_bld + +# Prerequisites +*.d + +# Compiled Object files +*.slo +*.lo +*.o +*.obj + +# Precompiled Headers +*.gch +*.pch + +# Compiled Dynamic libraries +*.so +*.dylib +*.dll + +# Fortran module files +*.mod +*.smod + +# Compiled Static libraries +*.lai +*.la +*.a +*.lib + +# Executables +*.exe +*.out +*.app + +# Junk files +*.tar +*.gz +*.xz +*.bz2 +*_bld +avrdude* +avr-libc* +binutils* +gcc* +gdb* +simulavr* \ No newline at end of file diff --git a/Bomb robot parameters.txt b/Bomb robot parameters.txt new file mode 100644 index 0000000..50bba68 --- /dev/null +++ b/Bomb robot parameters.txt @@ -0,0 +1,5 @@ +Bomb robot parameters: + +Cutting range: + LOWEST: 82mm + §HIGHEST: 115mm \ No newline at end of file diff --git a/main.c b/main.c new file mode 100755 index 0000000..87b95c6 --- /dev/null +++ b/main.c @@ -0,0 +1,379 @@ +#include +#include +#include +#include + +#define DEBOUNCE_COUNT 100 +#define BOMB_COUNTDOWN_TIME 65 + +unsigned char displaydata[8] = {' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '}, adress; +uint8_t debounce[8] = {0,0,0,0,0,0,0,0}; //input debounce +uint8_t debounced = 0; + + + +void display_time(int time); +void display_clear(void); + +void display_update(void); +void display_send_one(uint8_t address, unsigned char data); +void shift_send(unsigned char data); + +void mp3_play(uint8_t mp3file); +void timer_start(void); +void timer_speed_up(void); +void timer_pause(void); + +void motor_step_forward(void); +void motor_step_back(void); + +uint8_t radio_signal(void); + +enum{ + BOMB_DISARMED, + BOMB_ARMED, + BOMB_DEFUSED, + BOMB_EXPLODED +} bombState; + +//functions for updating the bomb in a given state +void bomb_logic_disarmed(void); +void bomb_logic_armed(void); // <-- this will be unique for each bomb +void bomb_logic_defused(void); +void bomb_logic_exploded(void); + +//functions for ENTERING a state +void bomb_logic_disarm(void); +void bomb_logic_arm(void); +void bomb_logic_defuse(void); +void bomb_logic_explode(void); + +//return_data_type function(input_data_type input_variable_local_name) +//void display_send_one(unsigned char data); +//PORTD |= 1<<0; //(set D.0) Shifts a one zero steps left +//PORTD &= ~(1<<0); //(reset D.0) Creates a byte consisting of ones, shifts a zero 0 steps left + +void display_send_one(uint8_t address, unsigned char data) //Send the character 'data' to the display position defined in 'adress' +{ + address = 7-address; + PORTD &= 0b10000000; //Clear all data pins + PORTA &= 0b11111100; //Clear address + PORTA |= (address & 0b00000011); //set address + PORTD |= (data & 0b01111111); //Set the 7 bit ASCII output for one character + _delay_us(5); + if (address & 0b0000100) + { + PORTA &= 0b11111011; //Clock the write pin + _delay_us(5); + PORTA |= 0b00000100; + } + else + { + PORTA &= 0b11110111; //Clock the write pin + _delay_us(5); + PORTA |= 0b00001000; + } + _delay_us(5); +} + +void display_update(void) //Send the array displaydata to the display, setting the adress variable to the correct value for each char. +{ + for (unsigned char i = 0; i < 8; i++) + { + display_send_one(i, displaydata[i]); + } +} + + +void mp3_play(uint8_t mp3file) +{ + mp3file &= 0b00000111; + DDRB |= mp3file; + _delay_ms(40); + DDRB &=0b11111000; +} + + +void display_clear(void){ + displaydata[0] = ' '; displaydata[1] = ' '; displaydata[2] = ' '; displaydata[3] = ' '; + displaydata[4] = ' '; displaydata[5] = ' '; displaydata[6] = ' '; displaydata[7] = ' '; + display_update(); +} + +void display_time(int time) //displays the 'time' given in seconds as MM:SS on the LCD +{ + uint8_t current_digit = 0; + + //static part of display + displaydata[0] = ' '; + displaydata[4] = ':'; + displaydata[7] = ' '; + + //limit to 60:00 + if(time > 3600){ + time = 3600; + } + + //'-' sign for negative time? + if(time < 0){ + time *= -1; + displaydata[1] = '-'; + }else{ + displaydata[1] = ' '; + } + + //rest of the time + current_digit = 0; + while(time>=600){ //tens of minutes + current_digit += 1; + time -= 600; + } + displaydata[2] = current_digit + '0'; + + current_digit = 0; + while(time>=60){ //minutes + current_digit += 1; + time -= 60; + } + displaydata[3] = current_digit + '0'; + + current_digit = 0; + while(time>=10){ //tens of seconds + current_digit += 1; + time -= 10; + } + displaydata[5] = current_digit + '0'; + + + displaydata[6] = time + '0'; + + display_update(); +} + +void timer_start(void){ + //Set up Timer1 + TCCR1B |= (1 << CS10) | (1 << CS12) | (1 << WGM12); //prescaler 1024 + TCNT1 = 0; //zero out timer + //TIMSK1 |= (1 << OCIE1A); //enable output compare A + OCR1A = 4040; //output compare A will trigger at approx 1Hz. Callibrated at 5V + TIMSK1 |= (1 << OCIE1A); +} + +void timer_speed_up(void){ + TCNT1 = 1700; //set a timer a safe distance away from the trigger point. + OCR1A = 2020; //output compare A will triger at approx 2Hz. Callibrated at 5V +} + +void timer_pause(void){ + TCCR1B = 0; //stop timer +} + + +void motor_step_forward(void){ + PORTD &= 0xF0; //PRE-enable zero + PORTB &= 0b01111111; //enable motor drive + PORTD &= 0xF0; _delay_us(50); PORTD |= 0b00000001; _delay_us(2000); + PORTD &= 0xF0; _delay_us(50); PORTD |= 0b00000100; _delay_us(2000); + PORTD &= 0xF0; _delay_us(50); PORTD |= 0b00000010; _delay_us(2000); + PORTD &= 0xF0; _delay_us(50); PORTD |= 0b00001000; _delay_us(2000); + PORTB |= 0b10000000; //disable motor drive +} + +void motor_step_back(void){ + PORTD &= 0xF0; //PRE-enable zero + PORTB &= 0b01111111; //enable motor drive + PORTD &= 0xF0; _delay_us(50); PORTD |= 0b00001000; _delay_us(2000); + PORTD &= 0xF0; _delay_us(50); PORTD |= 0b00000010; _delay_us(2000); + PORTD &= 0xF0; _delay_us(50); PORTD |= 0b00000100; _delay_us(2000); + PORTD &= 0xF0; _delay_us(50); PORTD |= 0b00000001; _delay_us(2000); + PORTB |= 0b10000000; //disable motor drive +} + + +uint8_t radio_signal(void){ + return (PINB & 0b01000000); +} + +//BOMB LOGIC +int16_t countdown = 65; +uint8_t armed = 0; + +int main(void) +{ + DDRA = 0b00001111; + DDRB = 0b10000000; + DDRC = 0b10111111; + DDRD = 0b11111111; +/* +D0-D6 data +D7 CU +A0-A1 adress +A2 /Write0 +A3 /Write1 + +D0-D3 doubles as motor drive pins + +C0-C5 inputs, C7 input/button +B0, B1, B2 MP3 playback triggers +B3 spare MP3 trigger +B4-B5 NMOS outputs +B6 Radio remote input +B7 enable motor drive +*/ + PORTA |= 0b00000110; + PORTB = 0b10000000; + PORTC = 0b10111111; + PORTD = 0; + _delay_us(500); + PORTA &= 0b11111011; //Clock the write pin + _delay_us(500); + PORTA |= 0b00000100; + _delay_us(500); + PORTA &= 0b11110111; //Clock the write pin + _delay_us(500); + PORTA |= 0b00001000; + _delay_us(500); + PORTD |= 0b10000000; + + timer_start(); + display_clear(); + + sei(); //interrupts enable! + + while(1) + { + if(radio_signal()){ + if(bombState == BOMB_DISARMED){bomb_logic_arm();} + }else{ + if(bombState != BOMB_DISARMED){bomb_logic_disarm();} + } + + //input debouncing + for(int i=0; i<8; i++){ + if(PINC & 1< 0){ + debounce[i]-=1; + } + } + if(debounce[i] == DEBOUNCE_COUNT){ + debounced |= 1<> i & 0x01){ + displaydata[i] += 32; + } + } + display_update(); +} + +void bomb_logic_arm(void){ + bombState = BOMB_ARMED; + countdown = BOMB_COUNTDOWN_TIME; + display_time(countdown); + mp3_play(1); + timer_start(); +} + +void bomb_logic_armed(void){ + if(countdown == 0){ + bomb_logic_explode(); + } + + if(debounced & 0b10000000){ + bomb_logic_defuse(); + } + + if(debounced & 0b00100000){ + bomb_logic_explode(); + } +} + + +void bomb_logic_defuse(void){ + bombState = BOMB_DEFUSED; + timer_pause(); + displaydata[1] = '['; + displaydata[7] = ']'; + display_update(); +} + +void bomb_logic_defused(void){ + //not much to do here +} + +void bomb_logic_explode(void){ + bombState = BOMB_EXPLODED; + timer_pause(); + mp3_play(2); + displaydata[0] = ' '; displaydata[1] = ' '; displaydata[2] = 'B'; displaydata[3] = 'O'; + displaydata[4] = 'O'; displaydata[5] = 'M'; displaydata[6] = ' '; displaydata[7] = ' '; + display_update(); +} + +void bomb_logic_exploded(void){ + //BOOM animation. + //Because of rand(), this takes a LOT of FLASH MEMORY + //Remove if in need of more PROGRAM space + for(int i=2; i<6; i++){ + if(rand() > 0x3FFF){ + displaydata[i] |= 0b00100000; + }else{ + displaydata[i] &= 0b11011111; + } + } + display_update(); + _delay_ms(100); + //not much to do here + //maybe blink an LED or something +} + +uint8_t half_second = 0; +ISR(TIMER1_COMPA_vect){ + half_second ^= 0x01; //will be true every other half-second + if(half_second){ + if(countdown>0){countdown -= 1;} + display_time(countdown); + if(countdown < 10){mp3_play(1);} + }else{ + display_send_one(4, ' '); + } +} diff --git a/makefile b/makefile new file mode 100755 index 0000000..77e7b75 --- /dev/null +++ b/makefile @@ -0,0 +1,224 @@ +# Hey Emacs, this is a -*- makefile -*- + +# AVR-GCC Makefile template, derived from the WinAVR template (which +# is public domain), believed to be neutral to any flavor of "make" +# (GNU make, BSD make, SysV make) + + +MCU = attiny88 +FORMAT = ihex +TARGET = main +SRC = $(TARGET).c +ASRC = +OPT = 3 + +# Name of this Makefile (used for "make depend"). +MAKEFILE = Makefile + +# Debugging format. +# Native formats for AVR-GCC's -g are stabs [default], or dwarf-2. +# AVR (extended) COFF requires stabs, plus an avr-objcopy run. +DEBUG = stabs + +# Compiler flag to set the C Standard level. +# c89 - "ANSI" C +# gnu89 - c89 plus GCC extensions +# c99 - ISO C99 standard (not yet fully implemented) +# gnu99 - c99 plus GCC extensions +CSTANDARD = -std=gnu99 + +# Place -D or -U options here +CDEFS = -DF_CPU=8000000 + +# Place -I options here +CINCS = + + +CDEBUG = -g$(DEBUG) +CWARN = -Wall -Wstrict-prototypes +CTUNING = -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums +# CEXTRA = -Wa,-adhlns=$(<:.c=.lst) +CFLAGS = $(CDEBUG) $(CDEFS) $(CINCS) -O$(OPT) $(CWARN) $(CSTANDARD) $(CEXTRA) + + +#ASFLAGS = -Wa,-adhlns=$(<:.S=.lst),-gstabs + + +#Additional libraries. + +# Minimalistic printf version +PRINTF_LIB_MIN = -Wl,-u,vfprintf -lprintf_min + +# Floating point printf version (requires MATH_LIB = -lm below) +PRINTF_LIB_FLOAT = -Wl,-u,vfprintf -lprintf_flt + +PRINTF_LIB = + +# Minimalistic scanf version +SCANF_LIB_MIN = -Wl,-u,vfscanf -lscanf_min + +# Floating point + %[ scanf version (requires MATH_LIB = -lm below) +SCANF_LIB_FLOAT = -Wl,-u,vfscanf -lscanf_flt + +SCANF_LIB = + +MATH_LIB = -lm + +# External memory options + +# 64 KB of external RAM, starting after internal RAM (ATmega128!), +# used for variables (.data/.bss) and heap (malloc()). +# EXTMEMOPTS = -Wl,--section-start,.data=0x801100,--defsym=__heap_end=0x80ffff + +# 64 KB of external RAM, starting after internal RAM (ATmega128!), +# only used for heap (malloc()). +# EXTMEMOPTS = -Wl,--defsym=__heap_start=0x801100,--defsym=__heap_end=0x80ffff + +EXTMEMOPTS = + +# LDMAP = $(LDFLAGS) -Wl,-Map=$(TARGET).map,--cref +LDFLAGS = $(EXTMEMOPTS) $(LDMAP) $(PRINTF_LIB) $(SCANF_LIB) $(MATH_LIB) + + +# Programming support using avrdude. Settings and variables. + +AVRDUDE_PROGRAMMER = usbasp +# AVRDUDE_PORT = /dev/term/a + +AVRDUDE_WRITE_FLASH = -U flash:w:$(TARGET).hex -U lfuse:w:0xEE:m +# AVRDUDE_WRITE_EEPROM = -U eeprom:w:$(TARGET).eep + + +# Uncomment the following if you want avrdude's erase cycle counter. +# Note that this counter needs to be initialized first using -Yn, +# see avrdude manual. +# AVRDUDE_ERASE_COUNTER = -y + +# Uncomment the following if you do /not/ wish a verification to be +# performed after programming the device. +# AVRDUDE_NO_VERIFY = -V + +# Increase verbosity level. Please use this when submitting bug +# reports about avrdude. See +# to submit bug reports. +# AVRDUDE_VERBOSE = -v -v + +AVRDUDE_BASIC = -p $(MCU) -c $(AVRDUDE_PROGRAMMER) -B 10 +# -P $(AVRDUDE_PORT) +AVRDUDE_FLAGS = $(AVRDUDE_BASIC) $(AVRDUDE_NO_VERIFY) $(AVRDUDE_VERBOSE) $(AVRDUDE_ERASE_COUNTER) + + +CC = avr-gcc +OBJCOPY = avr-objcopy +OBJDUMP = avr-objdump +SIZE = avr-size +NM = avr-nm +AVRDUDE = avrdude +REMOVE = rm -f +MV = mv -f + +# Define all object files. +OBJ = $(SRC:.c=.o) $(ASRC:.S=.o) + +# Define all listing files. +LST = $(ASRC:.S=.lst) $(SRC:.c=.lst) + +# Combine all necessary flags and optional flags. +# Add target processor to flags. +ALL_CFLAGS = -mmcu=$(MCU) -I. $(CFLAGS) +ALL_ASFLAGS = -mmcu=$(MCU) -I. -x assembler-with-cpp $(ASFLAGS) + + +# Default target. +all: build + +build: elf hex eep + +elf: $(TARGET).elf +hex: $(TARGET).hex +eep: $(TARGET).eep +lss: $(TARGET).lss +sym: $(TARGET).sym + + +# Program the device. +program: $(TARGET).hex $(TARGET).eep + $(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_FLASH) $(AVRDUDE_WRITE_EEPROM) + + + + +# Convert ELF to COFF for use in debugging / simulating in AVR Studio or VMLAB. +COFFCONVERT=$(OBJCOPY) --debugging \ +--change-section-address .data-0x800000 \ +--change-section-address .bss-0x800000 \ +--change-section-address .noinit-0x800000 \ +--change-section-address .eeprom-0x810000 + + +coff: $(TARGET).elf + $(COFFCONVERT) -O coff-avr $(TARGET).elf $(TARGET).cof + + +extcoff: $(TARGET).elf + $(COFFCONVERT) -O coff-ext-avr $(TARGET).elf $(TARGET).cof + + +.SUFFIXES: .elf .hex .eep .lss .sym + +.elf.hex: + $(OBJCOPY) -O $(FORMAT) -R .eeprom $< $@ + +.elf.eep: + -$(OBJCOPY) -j .eeprom --set-section-flags=.eeprom="alloc,load" \ + --change-section-lma .eeprom=0 -O $(FORMAT) $< $@ + +# Create extended listing file from ELF output file. +.elf.lss: + $(OBJDUMP) -h -S $< > $@ + +# Create a symbol table from ELF output file. +.elf.sym: + $(NM) -n $< > $@ + + + +# Link: create ELF output file from object files. +$(TARGET).elf: $(OBJ) + $(CC) $(ALL_CFLAGS) $(OBJ) --output $@ $(LDFLAGS) + + +# Compile: create object files from C source files. +.c.o: + $(CC) -c $(ALL_CFLAGS) $< -o $@ + + +# Compile: create assembler files from C source files. +.c.s: + $(CC) -S $(ALL_CFLAGS) $< -o $@ + + +# Assemble: create object files from assembler source files. +.S.o: + $(CC) -c $(ALL_ASFLAGS) $< -o $@ + + + +# Target: clean project. +clean: + $(REMOVE) $(TARGET).hex $(TARGET).eep $(TARGET).cof $(TARGET).elf \ + $(TARGET).map $(TARGET).sym $(TARGET).lss \ + $(OBJ) $(LST) $(SRC:.c=.s) $(SRC:.c=.d) + +depend: + if grep '^# DO NOT DELETE' $(MAKEFILE) >/dev/null; \ + then \ + sed -e '/^# DO NOT DELETE/,$$d' $(MAKEFILE) > \ + $(MAKEFILE).$$$$ && \ + $(MV) $(MAKEFILE).$$$$ $(MAKEFILE); \ + fi + echo '# DO NOT DELETE THIS LINE -- make depend depends on it.' \ + >> $(MAKEFILE); \ + $(CC) -M -mmcu=$(MCU) $(CDEFS) $(CINCS) $(SRC) $(ASRC) >> $(MAKEFILE) + +.PHONY: all build elf hex eep lss sym program coff extcoff clean depend