parent
f928a4ff8c
commit
033273b9d1
@ -0,0 +1,5 @@ |
||||
**Files in this folder are experimental, work-in-progress projects.** |
||||
|
||||
Do not expect them to work. |
||||
|
||||
For finished stuff, look into the /projects folder. |
@ -0,0 +1,147 @@ |
||||
## === CPU settings ===
|
||||
# CPU type
|
||||
MCU = atmega328p
|
||||
# CPU frequency
|
||||
F_CPU = 16000000
|
||||
# Fuses
|
||||
LFUSE = 0xFF
|
||||
HFUSE = 0xDE
|
||||
EFUSE = 0x05
|
||||
|
||||
|
||||
## === Source files ===
|
||||
# Main C file
|
||||
MAIN = main.c
|
||||
# Extra C files in this folder
|
||||
LOCAL_SOURCE =
|
||||
|
||||
# Library directory (with C files)
|
||||
EXTRA_SOURCE_DIR = lib/
|
||||
|
||||
|
||||
# C files in the library directory
|
||||
EXTRA_SOURCE_FILES = uart.c iopins.c stream.c adc.c dht11.c sonar.c onewire.c
|
||||
#Files that need config file:
|
||||
# EXTRA_SOURCE_FILES += lcd.c
|
||||
# EXTRA_SOURCE_FILES += color.c wsrgb.c
|
||||
# EXTRA_SOURCE_FILES += debouce.c
|
||||
|
||||
|
||||
## === Programmer ===
|
||||
PROGRAMMER_TYPE = arduino
|
||||
PROGRAMMER_ARGS = -b 57600 -P /dev/ttyUSB0
|
||||
|
||||
|
||||
## === C flags ===
|
||||
|
||||
CFLAGS = -std=gnu99 -mmcu=$(MCU) -DF_CPU=$(F_CPU)UL -I. -I$(EXTRA_SOURCE_DIR)
|
||||
CFLAGS += -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums
|
||||
CFLAGS += -Wall -Wno-main -Wno-strict-prototypes -Wno-comment
|
||||
CFLAGS += -g2 -Wextra -Wfatal-errors -Wno-unused-but-set-variable
|
||||
CFLAGS += -ffunction-sections -fdata-sections -Wl,--gc-sections -Wl,--relax
|
||||
# CFLAGS += -lm ## Math
|
||||
# CFLAGS += -Wl,-u,vfprintf -lprintf_flt -lm ## for floating-point printf
|
||||
# CFLAGS += -Wl,-u,vfprintf -lprintf_min ## for smaller printf
|
||||
CFLAGS_BUILD = $(CFLAGS) -Os
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
## Defined programs / locations
|
||||
CC = avr-gcc
|
||||
OBJCOPY = avr-objcopy
|
||||
OBJDUMP = avr-objdump
|
||||
AVRSIZE = avr-size
|
||||
AVRDUDE = avrdude
|
||||
|
||||
## === File lists ===
|
||||
TARGET = $(strip $(basename $(MAIN)))
|
||||
SRC1 = $(TARGET).c
|
||||
SRC = $(SRC1)
|
||||
EXTRA_SOURCE = $(addprefix $(EXTRA_SOURCE_DIR), $(EXTRA_SOURCE_FILES))
|
||||
SRC += $(EXTRA_SOURCE)
|
||||
SRC += $(LOCAL_SOURCE)
|
||||
|
||||
HEADERS = $(SRC:.c=.h)
|
||||
OBJ = $(SRC:.c=.o)
|
||||
|
||||
|
||||
## === File generation ===
|
||||
all: $(TARGET).hex size |
||||
pre: $(TARGET).pre |
||||
|
||||
%.hex: %.elf |
||||
$(OBJCOPY) -R .eeprom -O ihex $< $@
|
||||
|
||||
%.elf: $(SRC) |
||||
$(CC) $(CFLAGS_BUILD) $(SRC) --output $@
|
||||
|
||||
%.pre: $(SRC1) |
||||
$(CC) $(CFLAGS) -E $(SRC1) --output $@
|
||||
|
||||
%.eeprom: %.elf |
||||
$(OBJCOPY) -j .eeprom --change-section-lma .eeprom=0 -O ihex $< $@
|
||||
|
||||
%.lst: %.elf |
||||
$(OBJDUMP) -S $< > $@
|
||||
|
||||
# Show debug info
|
||||
debug: |
||||
@echo
|
||||
@echo "Source files:" $(SRC)
|
||||
@echo "MCU, F_CPU, BAUD:" $(MCU), $(F_CPU), $(BAUD)
|
||||
@echo
|
||||
|
||||
|
||||
# Disassemble the ELF
|
||||
disassemble: $(TARGET).lst |
||||
dis: disassemble |
||||
lst: disassemble |
||||
|
||||
# Make eeprom file
|
||||
eeprom: $(TARGET).eeprom |
||||
|
||||
# Show how big the resulting program is
|
||||
size: $(TARGET).elf |
||||
$(AVRSIZE) -C --mcu=$(MCU) $(TARGET).elf
|
||||
|
||||
# Clean all produced trash
|
||||
clean: |
||||
rm -f $(TARGET).elf $(TARGET).hex $(TARGET).obj \
|
||||
$(TARGET).o $(TARGET).d $(TARGET).eep $(TARGET).lst \
|
||||
$(TARGET).lss $(TARGET).sym $(TARGET).map $(TARGET)~ \
|
||||
$(TARGET).eeprom
|
||||
|
||||
# Clean all trash
|
||||
purge: |
||||
rm -f *.elf *.hex *.obj *.o *.d *.eep *.lst *.lss *.sym *.map *~
|
||||
|
||||
|
||||
## === avrdude ===
|
||||
|
||||
flash: $(TARGET).hex |
||||
$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -U flash:w:$<
|
||||
|
||||
flashe: $(TARGET).eeprom |
||||
$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -U eeprom:w:$<
|
||||
|
||||
shell: |
||||
$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -nt
|
||||
|
||||
fser: all flash ser |
||||
|
||||
ser: |
||||
gtkterm -p /dev/ttyUSB0
|
||||
|
||||
# === fuses ===
|
||||
|
||||
FUSE_STRING = -U lfuse:w:$(LFUSE):m -U hfuse:w:$(HFUSE):m -U efuse:w:$(EFUSE):m
|
||||
|
||||
fuses: |
||||
$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) \
|
||||
$(PROGRAMMER_ARGS) $(FUSE_STRING)
|
||||
show_fuses: |
||||
$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -nv
|
||||
|
||||
set_default_fuses: FUSE_STRING = -U lfuse:w:$(LFUSE):m -U hfuse:w:$(HFUSE):m -U efuse:w:$(EFUSE):m |
||||
set_default_fuses: fuses |
@ -0,0 +1 @@ |
||||
/home/ondra/git/avr-lib/lib |
@ -0,0 +1,35 @@ |
||||
#include <avr/io.h> |
||||
#include <avr/pgmspace.h> |
||||
#include <avr/interrupt.h> |
||||
#include <util/delay.h> |
||||
#include <stdint.h> |
||||
#include <stdbool.h> |
||||
|
||||
#include "lib/iopins.h" |
||||
#include "lib/uart.h" |
||||
#include "lib/stream.h" |
||||
#include "lib/dht11.h" |
||||
|
||||
void main() |
||||
{ |
||||
uart_init(9600); |
||||
uart_puts_P(PSTR("*** DHT11 test ***\r\n")); |
||||
|
||||
while(1) |
||||
{ |
||||
dht11_result_t result; |
||||
|
||||
if (dht11_read(2, &result)) { |
||||
// Temperature
|
||||
put_i8(uart, result.temp); |
||||
uart_puts_P(PSTR(" °C, ")); |
||||
// Humidity
|
||||
put_i8(uart, result.rh); |
||||
uart_puts_P(PSTR(" %r.H\r\n")); |
||||
} else { |
||||
uart_puts_P(PSTR("Read error!\r\n")); |
||||
} |
||||
|
||||
_delay_ms(500); |
||||
} |
||||
} |
@ -0,0 +1,137 @@ |
||||
## === CPU settings ===
|
||||
# CPU type
|
||||
MCU = atmega328p
|
||||
# CPU frequency
|
||||
F_CPU = 16000000
|
||||
# Fuses
|
||||
LFUSE = 0xFF
|
||||
HFUSE = 0xDE
|
||||
EFUSE = 0x05
|
||||
|
||||
|
||||
## === Source files ===
|
||||
# Main C file
|
||||
MAIN = main.c
|
||||
# Extra C files in this folder
|
||||
LOCAL_SOURCE =
|
||||
|
||||
# Library directory (with C files)
|
||||
EXTRA_SOURCE_DIR = lib/
|
||||
# C files in the library directory
|
||||
EXTRA_SOURCE_FILES = uart.c uart_ansi.c iopins.c
|
||||
|
||||
|
||||
## === Programmer ===
|
||||
PROGRAMMER_TYPE = arduino
|
||||
PROGRAMMER_ARGS = -b 57600 -P /dev/ttyUSB0
|
||||
|
||||
|
||||
## === C flags ===
|
||||
|
||||
CFLAGS = -std=gnu99 -mmcu=$(MCU) -DF_CPU=$(F_CPU)UL -I. -I$(EXTRA_SOURCE_DIR)
|
||||
CFLAGS += -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums
|
||||
CFLAGS += -Wall -Wno-main -Wno-strict-prototypes -Wno-comment
|
||||
CFLAGS += -g2 -Wextra -Wfatal-errors -Wno-unused-but-set-variable
|
||||
CFLAGS += -ffunction-sections -fdata-sections -Wl,--gc-sections -Wl,--relax
|
||||
# CFLAGS += -lm ## Math
|
||||
# CFLAGS += -Wl,-u,vfprintf -lprintf_flt -lm ## for floating-point printf
|
||||
# CFLAGS += -Wl,-u,vfprintf -lprintf_min ## for smaller printf
|
||||
CFLAGS_BUILD = $(CFLAGS) -Os
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
## Defined programs / locations
|
||||
CC = avr-gcc
|
||||
OBJCOPY = avr-objcopy
|
||||
OBJDUMP = avr-objdump
|
||||
AVRSIZE = avr-size
|
||||
AVRDUDE = avrdude
|
||||
|
||||
## === File lists ===
|
||||
TARGET = $(strip $(basename $(MAIN)))
|
||||
SRC1 = $(TARGET).c
|
||||
SRC = $(SRC1)
|
||||
EXTRA_SOURCE = $(addprefix $(EXTRA_SOURCE_DIR), $(EXTRA_SOURCE_FILES))
|
||||
SRC += $(EXTRA_SOURCE)
|
||||
SRC += $(LOCAL_SOURCE)
|
||||
|
||||
HEADERS = $(SRC:.c=.h)
|
||||
OBJ = $(SRC:.c=.o)
|
||||
|
||||
|
||||
## === File generation ===
|
||||
all: $(TARGET).hex size |
||||
pre: $(TARGET).pre |
||||
|
||||
%.hex: %.elf |
||||
$(OBJCOPY) -R .eeprom -O ihex $< $@
|
||||
|
||||
%.elf: $(SRC) |
||||
$(CC) $(CFLAGS_BUILD) $(SRC) --output $@
|
||||
|
||||
%.pre: $(SRC1) |
||||
$(CC) $(CFLAGS) -E $(SRC1) --output $@
|
||||
|
||||
%.eeprom: %.elf |
||||
$(OBJCOPY) -j .eeprom --change-section-lma .eeprom=0 -O ihex $< $@
|
||||
|
||||
%.lst: %.elf |
||||
$(OBJDUMP) -S $< > $@
|
||||
|
||||
# Show debug info
|
||||
debug: |
||||
@echo
|
||||
@echo "Source files:" $(SRC)
|
||||
@echo "MCU, F_CPU, BAUD:" $(MCU), $(F_CPU), $(BAUD)
|
||||
@echo
|
||||
|
||||
|
||||
# Disassemble the ELF
|
||||
disassemble: $(TARGET).lst |
||||
dis: disassemble |
||||
lst: disassemble |
||||
|
||||
# Make eeprom file
|
||||
eeprom: $(TARGET).eeprom |
||||
|
||||
# Show how big the resulting program is
|
||||
size: $(TARGET).elf |
||||
$(AVRSIZE) -C --mcu=$(MCU) $(TARGET).elf
|
||||
|
||||
# Clean all produced trash
|
||||
clean: |
||||
rm -f $(TARGET).elf $(TARGET).hex $(TARGET).obj \
|
||||
$(TARGET).o $(TARGET).d $(TARGET).eep $(TARGET).lst \
|
||||
$(TARGET).lss $(TARGET).sym $(TARGET).map $(TARGET)~ \
|
||||
$(TARGET).eeprom
|
||||
|
||||
# Clean all trash
|
||||
purge: |
||||
rm -f *.elf *.hex *.obj *.o *.d *.eep *.lst *.lss *.sym *.map *~
|
||||
|
||||
|
||||
## === avrdude ===
|
||||
|
||||
flash: $(TARGET).hex |
||||
$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -U flash:w:$<
|
||||
|
||||
flashe: $(TARGET).eeprom |
||||
$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -U eeprom:w:$<
|
||||
|
||||
shell: |
||||
$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -nt
|
||||
|
||||
|
||||
# === fuses ===
|
||||
|
||||
FUSE_STRING = -U lfuse:w:$(LFUSE):m -U hfuse:w:$(HFUSE):m -U efuse:w:$(EFUSE):m
|
||||
|
||||
fuses: |
||||
$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) \
|
||||
$(PROGRAMMER_ARGS) $(FUSE_STRING)
|
||||
show_fuses: |
||||
$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -nv
|
||||
|
||||
set_default_fuses: FUSE_STRING = -U lfuse:w:$(LFUSE):m -U hfuse:w:$(HFUSE):m -U efuse:w:$(EFUSE):m |
||||
set_default_fuses: fuses |
Binary file not shown.
@ -0,0 +1,276 @@ |
||||
#include <avr/io.h> |
||||
#include <stdbool.h> |
||||
#include <stdint.h> |
||||
|
||||
#include "calc.h" |
||||
#include "iopins.h" |
||||
|
||||
|
||||
void set_dir_n(const uint8_t pin, const uint8_t d) |
||||
{ |
||||
switch(pin) { |
||||
case 0: set_dir(0, d); return; |
||||
case 1: set_dir(1, d); return; |
||||
case 2: set_dir(2, d); return; |
||||
case 3: set_dir(3, d); return; |
||||
case 4: set_dir(4, d); return; |
||||
case 5: set_dir(5, d); return; |
||||
case 6: set_dir(6, d); return; |
||||
case 7: set_dir(7, d); return; |
||||
case 8: set_dir(8, d); return; |
||||
case 9: set_dir(9, d); return; |
||||
case 10: set_dir(10, d); return; |
||||
case 11: set_dir(11, d); return; |
||||
case 12: set_dir(12, d); return; |
||||
case 13: set_dir(13, d); return; |
||||
case 14: set_dir(14, d); return; |
||||
case 15: set_dir(15, d); return; |
||||
case 16: set_dir(16, d); return; |
||||
case 17: set_dir(17, d); return; |
||||
case 18: set_dir(18, d); return; |
||||
case 19: set_dir(19, d); return; |
||||
case 20: set_dir(20, d); return; |
||||
case 21: set_dir(21, d); return; |
||||
} |
||||
} |
||||
|
||||
void as_input_n(const uint8_t pin) |
||||
{ |
||||
switch(pin) { |
||||
case 0: as_input(0); return; |
||||
case 1: as_input(1); return; |
||||
case 2: as_input(2); return; |
||||
case 3: as_input(3); return; |
||||
case 4: as_input(4); return; |
||||
case 5: as_input(5); return; |
||||
case 6: as_input(6); return; |
||||
case 7: as_input(7); return; |
||||
case 8: as_input(8); return; |
||||
case 9: as_input(9); return; |
||||
case 10: as_input(10); return; |
||||
case 11: as_input(11); return; |
||||
case 12: as_input(12); return; |
||||
case 13: as_input(13); return; |
||||
case 14: as_input(14); return; |
||||
case 15: as_input(15); return; |
||||
case 16: as_input(16); return; |
||||
case 17: as_input(17); return; |
||||
case 18: as_input(18); return; |
||||
case 19: as_input(19); return; |
||||
case 20: as_input(20); return; |
||||
case 21: as_input(21); return; |
||||
} |
||||
} |
||||
|
||||
|
||||
void as_input_pu_n(const uint8_t pin) |
||||
{ |
||||
switch(pin) { |
||||
case 0: as_input_pu(0); return; |
||||
case 1: as_input_pu(1); return; |
||||
case 2: as_input_pu(2); return; |
||||
case 3: as_input_pu(3); return; |
||||
case 4: as_input_pu(4); return; |
||||
case 5: as_input_pu(5); return; |
||||
case 6: as_input_pu(6); return; |
||||
case 7: as_input_pu(7); return; |
||||
case 8: as_input_pu(8); return; |
||||
case 9: as_input_pu(9); return; |
||||
case 10: as_input_pu(10); return; |
||||
case 11: as_input_pu(11); return; |
||||
case 12: as_input_pu(12); return; |
||||
case 13: as_input_pu(13); return; |
||||
case 14: as_input_pu(14); return; |
||||
case 15: as_input_pu(15); return; |
||||
case 16: as_input_pu(16); return; |
||||
case 17: as_input_pu(17); return; |
||||
case 18: as_input_pu(18); return; |
||||
case 19: as_input_pu(19); return; |
||||
case 20: as_input_pu(20); return; |
||||
case 21: as_input_pu(21); return; |
||||
} |
||||
} |
||||
|
||||
|
||||
void as_output_n(const uint8_t pin) |
||||
{ |
||||
switch(pin) { |
||||
case 0: as_output(0); return; |
||||
case 1: as_output(1); return; |
||||
case 2: as_output(2); return; |
||||
case 3: as_output(3); return; |
||||
case 4: as_output(4); return; |
||||
case 5: as_output(5); return; |
||||
case 6: as_output(6); return; |
||||
case 7: as_output(7); return; |
||||
case 8: as_output(8); return; |
||||
case 9: as_output(9); return; |
||||
case 10: as_output(10); return; |
||||
case 11: as_output(11); return; |
||||
case 12: as_output(12); return; |
||||
case 13: as_output(13); return; |
||||
case 14: as_output(14); return; |
||||
case 15: as_output(15); return; |
||||
case 16: as_output(16); return; |
||||
case 17: as_output(17); return; |
||||
case 18: as_output(18); return; |
||||
case 19: as_output(19); return; |
||||
case 20: as_output(20); return; |
||||
case 21: as_output(21); return; |
||||
} |
||||
} |
||||
|
||||
void set_pin_n(const uint8_t pin, const uint8_t v) |
||||
{ |
||||
switch(pin) { |
||||
case 0: set_pin(0, v); return; |
||||
case 1: set_pin(1, v); return; |
||||
case 2: set_pin(2, v); return; |
||||
case 3: set_pin(3, v); return; |
||||
case 4: set_pin(4, v); return; |
||||
case 5: set_pin(5, v); return; |
||||
case 6: set_pin(6, v); return; |
||||
case 7: set_pin(7, v); return; |
||||
case 8: set_pin(8, v); return; |
||||
case 9: set_pin(9, v); return; |
||||
case 10: set_pin(10, v); return; |
||||
case 11: set_pin(11, v); return; |
||||
case 12: set_pin(12, v); return; |
||||
case 13: set_pin(13, v); return; |
||||
case 14: set_pin(14, v); return; |
||||
case 15: set_pin(15, v); return; |
||||
case 16: set_pin(16, v); return; |
||||
case 17: set_pin(17, v); return; |
||||
case 18: set_pin(18, v); return; |
||||
case 19: set_pin(19, v); return; |
||||
case 20: set_pin(20, v); return; |
||||
case 21: set_pin(21, v); return; |
||||
} |
||||
} |
||||
|
||||
void set_low_n(const uint8_t pin) |
||||
{ |
||||
switch(pin) { |
||||
case 0: set_low(0); return; |
||||
case 1: set_low(1); return; |
||||
case 2: set_low(2); return; |
||||
case 3: set_low(3); return; |
||||
case 4: set_low(4); return; |
||||
case 5: set_low(5); return; |
||||
case 6: set_low(6); return; |
||||
case 7: set_low(7); return; |
||||
case 8: set_low(8); return; |
||||
case 9: set_low(9); return; |
||||
case 10: set_low(10); return; |
||||
case 11: set_low(11); return; |
||||
case 12: set_low(12); return; |
||||
case 13: set_low(13); return; |
||||
case 14: set_low(14); return; |
||||
case 15: set_low(15); return; |
||||
case 16: set_low(16); return; |
||||
case 17: set_low(17); return; |
||||
case 18: set_low(18); return; |
||||
case 19: set_low(19); return; |
||||
case 20: set_low(20); return; |
||||
case 21: set_low(21); return; |
||||
} |
||||
} |
||||
|
||||
void set_high_n(const uint8_t pin) |
||||
{ |
||||
switch(pin) { |
||||
case 0: set_high(0); return; |
||||
case 1: set_high(1); return; |
||||
case 2: set_high(2); return; |
||||
case 3: set_high(3); return; |
||||
case 4: set_high(4); return; |
||||
case 5: set_high(5); return; |
||||
case 6: set_high(6); return; |
||||
case 7: set_high(7); return; |
||||
case 8: set_high(8); return; |
||||
case 9: set_high(9); return; |
||||
case 10: set_high(10); return; |
||||
case 11: set_high(11); return; |
||||
case 12: set_high(12); return; |
||||
case 13: set_high(13); return; |
||||
case 14: set_high(14); return; |
||||
case 15: set_high(15); return; |
||||
case 16: set_high(16); return; |
||||
case 17: set_high(17); return; |
||||
case 18: set_high(18); return; |
||||
case 19: set_high(19); return; |
||||
case 20: set_high(20); return; |
||||
case 21: set_high(21); return; |
||||
} |
||||
} |
||||
|
||||
|
||||
void toggle_pin_n(const uint8_t pin) |
||||
{ |
||||
switch(pin) { |
||||
case 0: toggle_pin(0); return; |
||||
case 1: toggle_pin(1); return; |
||||
case 2: toggle_pin(2); return; |
||||
case 3: toggle_pin(3); return; |
||||
case 4: toggle_pin(4); return; |
||||
case 5: toggle_pin(5); return; |
||||
case 6: toggle_pin(6); return; |
||||
case 7: toggle_pin(7); return; |
||||
case 8: toggle_pin(8); return; |
||||
case 9: toggle_pin(9); return; |
||||
case 10: toggle_pin(10); return; |
||||
case 11: toggle_pin(11); return; |
||||
case 12: toggle_pin(12); return; |
||||
case 13: toggle_pin(13); return; |
||||
case 14: toggle_pin(14); return; |
||||
case 15: toggle_pin(15); return; |
||||
case 16: toggle_pin(16); return; |
||||
case 17: toggle_pin(17); return; |
||||
case 18: toggle_pin(18); return; |
||||
case 19: toggle_pin(19); return; |
||||
case 20: toggle_pin(20); return; |
||||
case 21: toggle_pin(21); return; |
||||
} |
||||
} |
||||
|
||||
|
||||
bool get_pin_n(const uint8_t pin) |
||||
{ |
||||
switch(pin) { |
||||
case 0: return get_pin(0); |
||||
case 1: return get_pin(1); |
||||
case 2: return get_pin(2); |
||||
case 3: return get_pin(3); |
||||
case 4: return get_pin(4); |
||||
case 5: return get_pin(5); |
||||
case 6: return get_pin(6); |
||||
case 7: return get_pin(7); |
||||
case 8: return get_pin(8); |
||||
case 9: return get_pin(9); |
||||
case 10: return get_pin(10); |
||||
case 11: return get_pin(11); |
||||
case 12: return get_pin(12); |
||||
case 13: return get_pin(13); |
||||
case 14: return get_pin(14); |
||||
case 15: return get_pin(15); |
||||
case 16: return get_pin(16); |
||||
case 17: return get_pin(17); |
||||
case 18: return get_pin(18); |
||||
case 19: return get_pin(19); |
||||
case 20: return get_pin(20); |
||||
case 21: return get_pin(21); |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
|
||||
bool is_low_n(const uint8_t pin) |
||||
{ |
||||
return !get_pin_n(pin); |
||||
} |
||||
|
||||
|
||||
bool is_high_n(const uint8_t pin) |
||||
{ |
||||
return get_pin_n(pin); |
||||
} |
@ -0,0 +1,190 @@ |
||||
#pragma once |
||||
|
||||
#include <avr/io.h> |
||||
#include <stdbool.h> |
||||
#include <stdint.h> |
||||
|
||||
#include "calc.h" |
||||
|
||||
/** Pin numbering reference */ |
||||
#define D0 0 |
||||
#define D1 1 |
||||
#define D2 2 |
||||
#define D3 3 |
||||
#define D4 4 |
||||
#define D5 5 |
||||
#define D6 6 |
||||
#define D7 7 |
||||
#define D8 8 |
||||
#define D9 9 |
||||
#define D10 10 |
||||
#define D11 11 |
||||
#define D12 12 |
||||
#define D13 13 |
||||
#define D14 14 |
||||
#define D15 15 |
||||
#define D16 16 |
||||
#define D17 17 |
||||
#define D18 18 |
||||
#define D19 19 |
||||
#define D20 20 |
||||
#define D21 21 |
||||
#define A0 14 |
||||
#define A1 15 |
||||
#define A2 16 |
||||
#define A3 17 |
||||
#define A4 18 |
||||
#define A5 19 |
||||
#define A6 20 |
||||
#define A7 21 |
||||
|
||||
|
||||
/** Set pin direction */ |
||||
#define set_dir(pin, d) set_bit(_DDR_##pin, _PN_##pin, d) |
||||
void set_dir_n(const uint8_t pin, const uint8_t d); |
||||
|
||||
|
||||
/** Configure pin as input */ |
||||
#define as_input(pin) cbi(_DDR_##pin, _PN_##pin) |
||||
void as_input_n(const uint8_t pin); |
||||
|
||||
|
||||
/** Configure pin as input, with pull-up enabled */ |
||||
#define as_input_pu(pin) { as_input(pin); set_high(pin); } |
||||
void as_input_pu_n(const uint8_t pin); |
||||
|
||||
|
||||
/** Configure pin as output */ |
||||
#define as_output(pin) sbi(_DDR_##pin, _PN_##pin) |
||||
void as_output_n(const uint8_t pin); |
||||
|
||||
|
||||
/** Write value to a pin */ |
||||
#define set_pin(pin, v) set_bit(_PORT_##pin, _PN_##pin, v) |
||||
void set_pin_n(const uint8_t pin, const uint8_t v); |
||||
|
||||
|
||||
/** Write 0 to a pin */ |
||||
#define set_low(pin) cbi(_PORT_##pin, _PN_##pin) |
||||
void set_low_n(const uint8_t pin); |
||||
|
||||
|
||||
/** Write 1 to a pin */ |
||||
#define set_high(pin) sbi(_PORT_##pin, _PN_##pin) |
||||
void set_high_n(const uint8_t pin); |
||||
|
||||
|
||||
/** Toggle a pin state */ |
||||
#define toggle_pin(pin) sbi(_PIN_##pin, _PN_##pin) |
||||
void toggle_pin_n(const uint8_t pin); |
||||
|
||||
|
||||
/** Read a pin value */ |
||||
#define get_pin(pin) get_bit(_PIN_##pin, _PN_##pin) |
||||
bool get_pin_n(const uint8_t pin); |
||||
|
||||
|
||||
/** CHeck if pin is low */ |
||||
#define is_low(pin) (get_pin(pin) == 0) |
||||
bool is_low_n(const uint8_t pin); |
||||
|
||||
|
||||
/** CHeck if pin is high */ |
||||
#define is_high(pin) (get_pin(pin) != 0) |
||||
bool is_high_n(const uint8_t pin); |
||||
|
||||
|
||||
|
||||
// Helper macros
|
||||
|
||||
#define _PORT_0 PORTD |
||||
#define _PORT_1 PORTD |
||||
#define _PORT_2 PORTD |
||||
#define _PORT_3 PORTD |
||||
#define _PORT_4 PORTD |
||||
#define _PORT_5 PORTD |
||||
#define _PORT_6 PORTD |
||||
#define _PORT_7 PORTD |
||||
#define _PORT_8 PORTB |
||||
#define _PORT_9 PORTB |
||||
#define _PORT_10 PORTB |
||||
#define _PORT_11 PORTB |
||||
#define _PORT_12 PORTB |
||||
#define _PORT_13 PORTB |
||||
#define _PORT_14 PORTC |
||||
#define _PORT_15 PORTC |
||||
#define _PORT_16 PORTC |
||||
#define _PORT_17 PORTC |
||||
#define _PORT_18 PORTC |
||||
#define _PORT_19 PORTC |
||||
#define _PORT_20 PORTC |
||||
#define _PORT_21 PORTC |
||||
|
||||
#define _PIN_0 PIND |
||||
#define _PIN_1 PIND |
||||
#define _PIN_2 PIND |
||||
#define _PIN_3 PIND |
||||
#define _PIN_4 PIND |
||||
#define _PIN_5 PIND |
||||
#define _PIN_6 PIND |
||||
#define _PIN_7 PIND |
||||
#define _PIN_8 PINB |
||||
#define _PIN_9 PINB |
||||
#define _PIN_10 PINB |
||||
#define _PIN_11 PINB |
||||
#define _PIN_12 PINB |
||||
#define _PIN_13 PINB |
||||
#define _PIN_14 PINC |
||||
#define _PIN_15 PINC |
||||
#define _PIN_16 PINC |
||||
#define _PIN_17 PINC |
||||
#define _PIN_18 PINC |
||||
#define _PIN_19 PINC |
||||
#define _PIN_20 PINC |
||||
#define _PIN_21 PINC |
||||
|
||||
#define _DDR_0 DDRD |
||||
#define _DDR_1 DDRD |
||||
#define _DDR_2 DDRD |
||||
#define _DDR_3 DDRD |
||||
#define _DDR_4 DDRD |
||||
#define _DDR_5 DDRD |
||||
#define _DDR_6 DDRD |
||||
#define _DDR_7 DDRD |
||||
#define _DDR_8 DDRB |
||||
#define _DDR_9 DDRB |
||||
#define _DDR_10 DDRB |
||||
#define _DDR_11 DDRB |
||||
#define _DDR_12 DDRB |
||||
#define _DDR_13 DDRB |
||||
#define _DDR_14 DDRC |
||||
#define _DDR_15 DDRC |
||||
#define _DDR_16 DDRC |
||||
#define _DDR_17 DDRC |
||||
#define _DDR_18 DDRC |
||||
#define _DDR_19 DDRC |
||||
#define _DDR_20 DDRC |
||||
#define _DDR_21 DDRC |
||||
|
||||
#define _PN_0 0 |
||||
#define _PN_1 1 |
||||
#define _PN_2 2 |
||||
#define _PN_3 3 |
||||
#define _PN_4 4 |
||||
#define _PN_5 5 |
||||
#define _PN_6 6 |
||||
#define _PN_7 7 |
||||
#define _PN_8 0 |
||||
#define _PN_9 1 |
||||
#define _PN_10 2 |
||||
#define _PN_11 3 |
||||
#define _PN_12 4 |
||||
#define _PN_13 5 |
||||
#define _PN_14 0 |
||||
#define _PN_15 1 |
||||
#define _PN_16 2 |
||||
#define _PN_17 3 |
||||
#define _PN_18 4 |
||||
#define _PN_19 5 |
||||
#define _PN_20 6 |
||||
#define _PN_21 7 |
@ -0,0 +1 @@ |
||||
/home/ondra/git/avr-lib/lib |
@ -0,0 +1,27 @@ |
||||
#include <avr/io.h> |
||||
#include <avr/pgmspace.h> |
||||
#include <avr/interrupt.h> |
||||
#include <util/delay.h> |
||||
#include <stdint.h> |
||||
#include <stdbool.h> |
||||
|
||||
#include "lib/iopins.h" |
||||
|
||||
void main() |
||||
{ |
||||
for (int i = 2; i <= 5; i++) { |
||||
as_output_n(i); |
||||
} |
||||
|
||||
as_input_pu(12); |
||||
|
||||
while(1) { |
||||
for (int i = 2; i <= 5; i++) { |
||||
if (is_low(12)) { |
||||
set_high_n(i); |
||||
_delay_ms(100); |
||||
set_low_n(i); |
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,167 @@ |
||||
|
||||
MCU = atmega328p
|
||||
|
||||
F_CPU = 16000000
|
||||
|
||||
LFUSE = 0xFF
|
||||
HFUSE = 0xDE
|
||||
EFUSE = 0x05
|
||||
|
||||
MAIN = main.c
|
||||
|
||||
## If you've split your program into multiple files,
|
||||
## include the additional .c source (in same directory) here
|
||||
## (and include the .h files in your foo.c)
|
||||
LOCAL_SOURCE =
|
||||
|
||||
## Here you can link to one more directory (and multiple .c files)
|
||||
# EXTRA_SOURCE_DIR = ../AVR-Programming-Library/
|
||||
EXTRA_SOURCE_DIR = lib/
|
||||
EXTRA_SOURCE_FILES = debounce.c lcd.c adc.c
|
||||
|
||||
EXTRA_CFLAGS =
|
||||
|
||||
##########------------------------------------------------------##########
|
||||
########## Programmer Defaults ##########
|
||||
########## Set up once, then forget about it ##########
|
||||
########## (Can override. See bottom of file.) ##########
|
||||
##########------------------------------------------------------##########
|
||||
#19200
|
||||
PROGRAMMER_TYPE = arduino
|
||||
PROGRAMMER_ARGS = -b 57600 -P /dev/ttyUSB0
|
||||
|
||||
|
||||
##########------------------------------------------------------##########
|
||||
########## Makefile Magic! ##########
|
||||
########## Summary: ##########
|
||||
########## We want a .hex file ##########
|
||||
########## Compile source files into .elf ##########
|
||||
########## Convert .elf file into .hex ##########
|
||||
########## You shouldn't need to edit below. ##########
|
||||
##########------------------------------------------------------##########
|
||||
|
||||
## Defined programs / locations
|
||||
CC = avr-gcc
|
||||
OBJCOPY = avr-objcopy
|
||||
OBJDUMP = avr-objdump
|
||||
AVRSIZE = avr-size
|
||||
AVRDUDE = avrdude
|
||||
|
||||
## Compilation options, type man avr-gcc if you're curious.
|
||||
CFLAGS = -std=gnu99 -mmcu=$(MCU) -DF_CPU=$(F_CPU)UL -I. -I$(EXTRA_SOURCE_DIR)
|
||||
CFLAGS += -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums
|
||||
CFLAGS += -Wall -Wno-main -Wno-strict-prototypes -Wno-comment
|
||||
CFLAGS += -g2 -Wextra -Wfatal-errors
|
||||
CFLAGS += -ffunction-sections -fdata-sections -Wl,--gc-sections -Wl,--relax
|
||||
CFLAGS += $(EXTRA_CFLAGS)
|
||||
|
||||
CFLAGS_BUILD = $(CFLAGS) -Os
|
||||
|
||||
# CFLAGS += -lm
|
||||
## CFLAGS += -Wl,-u,vfprintf -lprintf_flt -lm ## for floating-point printf
|
||||
## CFLAGS += -Wl,-u,vfprintf -lprintf_min ## for smaller printf
|
||||
|
||||
## Lump target and extra source files together
|
||||
TARGET = $(strip $(basename $(MAIN)))
|
||||
SRC1 = $(TARGET).c
|
||||
SRC = $(SRC1)
|
||||
EXTRA_SOURCE = $(addprefix $(EXTRA_SOURCE_DIR), $(EXTRA_SOURCE_FILES))
|
||||
SRC += $(EXTRA_SOURCE)
|
||||
SRC += $(LOCAL_SOURCE)
|
||||
|
||||
## List of all header files
|
||||
HEADERS = $(SRC:.c=.h)
|
||||
|
||||
## For every .c file, compile an .o object file
|
||||
OBJ = $(SRC:.c=.o)
|
||||
|
||||
## Generic Makefile targets. (Only .hex file is necessary)
|
||||
all: $(TARGET).hex size |
||||
pre: $(TARGET).pre |
||||
|
||||
%.hex: %.elf |
||||
$(OBJCOPY) -R .eeprom -O ihex $< $@
|
||||
|
||||
%.elf: $(SRC) |
||||
$(CC) $(CFLAGS_BUILD) $(SRC) --output $@
|
||||
|
||||
%.pre: $(SRC1) |
||||
$(CC) $(CFLAGS) -E $(SRC1) --output $@
|
||||
|
||||
%.eeprom: %.elf |
||||
$(OBJCOPY) -j .eeprom --change-section-lma .eeprom=0 -O ihex $< $@
|
||||
|
||||
debug: |
||||
@echo
|
||||
@echo "Source files:" $(SRC)
|
||||
@echo "MCU, F_CPU, BAUD:" $(MCU), $(F_CPU), $(BAUD)
|
||||
@echo
|
||||
|
||||
# Optionally create listing file from .elf
|
||||
# This creates approximate assembly-language equivalent of your code.
|
||||
# Useful for debugging time-sensitive bits,
|
||||
# or making sure the compiler does what you want.
|
||||
disassemble: $(TARGET).lst |
||||
|
||||
dis: disassemble |
||||
lst: disassemble |
||||
|
||||
eeprom: $(TARGET).eeprom |
||||
|
||||
%.lst: %.elf |
||||
$(OBJDUMP) -S $< > $@
|
||||
|
||||
# Optionally show how big the resulting program is
|
||||
size: $(TARGET).elf |
||||
$(AVRSIZE) -C --mcu=$(MCU) $(TARGET).elf
|
||||
|
||||
clean: |
||||
rm -f $(TARGET).elf $(TARGET).hex $(TARGET).obj \
|
||||
$(TARGET).o $(TARGET).d $(TARGET).eep $(TARGET).lst \
|
||||
$(TARGET).lss $(TARGET).sym $(TARGET).map $(TARGET)~ \
|
||||
$(TARGET).eeprom
|
||||
|
||||
squeaky_clean: |
||||
rm -f *.elf *.hex *.obj *.o *.d *.eep *.lst *.lss *.sym *.map *~
|
||||
|
||||
|
||||
##########------------------------------------------------------##########
|
||||
########## Programmer-specific details ##########
|
||||
########## Flashing code to AVR using avrdude ##########
|
||||
##########------------------------------------------------------##########
|
||||
|
||||
flash: $(TARGET).hex |
||||
$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -U flash:w:$<
|
||||
|
||||
flash_eeprom: $(TARGET).eeprom |
||||
$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -U eeprom:w:$<
|
||||
|
||||
terminal: |
||||
$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -nt
|
||||
|
||||
|
||||
flash_arduino: PROGRAMMER_TYPE = arduino |
||||
flash_arduino: PROGRAMMER_ARGS = |
||||
flash_arduino: flash |
||||
|
||||
flash_dragon_isp: PROGRAMMER_TYPE = dragon_isp |
||||
flash_dragon_isp: PROGRAMMER_ARGS = |
||||
flash_dragon_isp: flash |
||||
|
||||
|
||||
##########------------------------------------------------------##########
|
||||
########## Fuse settings and suitable defaults ##########
|
||||
##########------------------------------------------------------##########
|
||||
|
||||
## Generic
|
||||
FUSE_STRING = -U lfuse:w:$(LFUSE):m -U hfuse:w:$(HFUSE):m -U efuse:w:$(EFUSE):m
|
||||
|
||||
fuses: |
||||
$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) \
|
||||
$(PROGRAMMER_ARGS) $(FUSE_STRING)
|
||||
show_fuses: |
||||
$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -nv
|
||||
|
||||
## Called with no extra definitions, sets to defaults
|
||||
set_default_fuses: FUSE_STRING = -U lfuse:w:$(LFUSE):m -U hfuse:w:$(HFUSE):m -U efuse:w:$(EFUSE):m |
||||
set_default_fuses: fuses |
@ -0,0 +1,10 @@ |
||||
Snake for HD44780 |
||||
================= |
||||
|
||||
This is a Snake game (known from old Nokia phones) played on a character display with HD44780. |
||||
|
||||
Program tested on Arduino Pro Mini (flashed with avrdude using the Makefile). |
||||
|
||||
**Connections** are `#define`d in `main.c`, board size and snake speed can also be adjusted. No external parts except the display and buttons required. |
||||
|
||||
Best works with a gamepad, but any buttons will work. |
@ -0,0 +1,5 @@ |
||||
#pragma once |
||||
|
||||
// Config file for debouncer
|
||||
#define DEBO_CHANNELS 6 |
||||
#define DEBO_TICKS 1 |
@ -0,0 +1,13 @@ |
||||
#pragma once |
||||
|
||||
// Config file for LCD.
|
||||
|
||||
#include "lib/arduino_pins.h" |
||||
|
||||
#define LCD_RS D2 |
||||
#define LCD_RW D3 |
||||
#define LCD_E D4 |
||||
#define LCD_D4 D5 |
||||
#define LCD_D5 D6 |
||||
#define LCD_D6 D7 |
||||
#define LCD_D7 D8 |
@ -0,0 +1 @@ |
||||
/home/ondra/git/avr-lib/lib |
@ -0,0 +1,429 @@ |
||||
#include <avr/io.h> |
||||
#include <avr/interrupt.h> |
||||
#include <avr/pgmspace.h> |
||||
#include <util/delay.h> |
||||
#include <stdbool.h> |
||||
#include <stdint.h> |
||||
#include <stdlib.h> |
||||
|
||||
#include "lib/meta.h" |
||||
#include "lib/arduino_pins.h" |
||||
#include "lib/calc.h" |
||||
#include "lib/adc.h" |
||||
#include "lib/lcd.h" |
||||
#include "lib/debounce.h" |
||||
|
||||
// Buttons (to ground)
|
||||
#define BTN_LEFT A0 |
||||
#define BTN_RIGHT A1 |
||||
#define BTN_UP A2 |
||||
#define BTN_DOWN A3 |
||||
#define BTN_PAUSE A4 |
||||
#define BTN_RESTART A5 |
||||
|
||||
// Debouncer channels for buttons
|
||||
// (Must be added in this order to debouncer)
|
||||
#define D_LEFT 0 |
||||
#define D_RIGHT 1 |
||||
#define D_UP 2 |
||||
#define D_DOWN 3 |
||||
#define D_PAUSE 4 |
||||
#define D_RESTART 5 |
||||
|
||||
// Board size (!!! rows = 2x number of display lines, max 2*4 = 8 !!!)
|
||||
#define ROWS 8 |
||||
#define COLS 20 |
||||
|
||||
// Delay between snake steps, in 10 ms
|
||||
#define STEP_DELAY 24 |
||||
|
||||
// proto
|
||||
void update(); |
||||
void init_cgram(); |
||||
void init_gameboard(); |
||||
|
||||
void init() |
||||
{ |
||||
// Randomize RNG
|
||||
adc_init(); |
||||
srand(adc_read_word(3)); |
||||
|
||||
// Init LCD
|
||||
lcd_init(); |
||||
init_cgram(); // load default glyphs
|
||||
|
||||
// Init game board.
|
||||
init_gameboard(); |
||||
|
||||
// gamepad buttons
|
||||
as_input_pu(BTN_LEFT); |
||||
as_input_pu(BTN_RIGHT); |
||||
as_input_pu(BTN_UP); |
||||
as_input_pu(BTN_DOWN); |
||||
as_input_pu(BTN_PAUSE); |
||||
as_input_pu(BTN_RESTART); |
||||
|
||||
// add buttons to debouncer
|
||||
debo_add_rev(BTN_LEFT); |
||||
debo_add_rev(BTN_RIGHT); |
||||
debo_add_rev(BTN_UP); |
||||
debo_add_rev(BTN_DOWN); |
||||
debo_add_rev(BTN_PAUSE); |
||||
debo_add_rev(BTN_RESTART); |
||||
|
||||
// setup timer
|
||||
TCCR0A = _BV(WGM01); // CTC
|
||||
TCCR0B = _BV(CS02) | _BV(CS00); // prescaler 1024
|
||||
OCR0A = 156; // interrupt every 10 ms
|
||||
sbi(TIMSK0, OCIE0A); |
||||
sei(); |
||||
} |
||||
|
||||
|
||||
/** timer 0 interrupt vector */ |
||||
ISR(TIMER0_COMPA_vect) |
||||
{ |
||||
debo_tick(); // poll debouncer
|
||||
update(); // update and display
|
||||
} |
||||
|
||||
|
||||
|
||||
// sub-glyphs
|
||||
#define _HEAD_ 15, 21, 21, 30 |
||||
#define _BODY_ 15, 31, 31, 30 |
||||
#define _FOOD_ 10, 21, 17, 14 |
||||
//14, 17, 17, 14
|
||||
#define _NONE_ 0, 0, 0, 0 |
||||
|
||||
// complete glyphs for loading into memory
|
||||
|
||||
// Only one food & one head glyph have to be loaded at a time.
|
||||
|
||||
// Body - Body
|
||||
const uint8_t SYMBOL_BB[] PROGMEM = {_BODY_, _BODY_}; |
||||
|
||||
// Body - None
|
||||
const uint8_t SYMBOL_BX[] PROGMEM = {_BODY_, _NONE_}; |
||||
const uint8_t SYMBOL_XB[] PROGMEM = {_NONE_, _BODY_}; |
||||
|
||||
// Head - None
|
||||
const uint8_t SYMBOL_HX[] PROGMEM = {_HEAD_, _NONE_}; |
||||
const uint8_t SYMBOL_XH[] PROGMEM = {_NONE_, _HEAD_}; |
||||
|
||||
// Body - Head
|
||||
const uint8_t SYMBOL_BH[] PROGMEM = {_BODY_, _HEAD_}; |
||||
const uint8_t SYMBOL_HB[] PROGMEM = {_HEAD_, _BODY_}; |
||||
|
||||
// Head - Food
|
||||
const uint8_t SYMBOL_HF[] PROGMEM = {_HEAD_, _FOOD_}; |
||||
const uint8_t SYMBOL_FH[] PROGMEM = {_FOOD_, _HEAD_}; |
||||
|
||||
// Food - None
|
||||
const uint8_t SYMBOL_FX[] PROGMEM = {_FOOD_, _NONE_}; |
||||
const uint8_t SYMBOL_XF[] PROGMEM = {_NONE_, _FOOD_}; |
||||
|
||||
// Body - Food
|
||||
const uint8_t SYMBOL_BF[] PROGMEM = {_BODY_, _FOOD_}; |
||||
const uint8_t SYMBOL_FB[] PROGMEM = {_FOOD_, _BODY_}; |
||||
|
||||
|
||||
// board block (snake, food...)
|
||||
typedef enum { |
||||
bEMPTY = 0x00, |
||||
bHEAD = 0x01, |
||||
bFOOD = 0x02, |
||||
bBODY_LEFT = 0x80, |
||||
bBODY_RIGHT = 0x81, |
||||
bBODY_UP = 0x82, |
||||
bBODY_DOWN = 0x83, |
||||
} block_t; |
||||
|
||||
// Snake direction
|
||||
typedef enum { |
||||
dLEFT = 0x00, |
||||
dRIGHT = 0x01, |
||||
dUP = 0x02, |
||||
dDOWN = 0x03, |
||||
} dir_t; |
||||
|
||||
// Coordinate on board
|
||||
typedef struct { |
||||
int8_t x; |
||||
int8_t y; |
||||
} coord_t; |
||||
|
||||
#define is_body(blk) (((blk) & 0x80) != 0) |
||||
#define mk_body_dir(dir) (0x80 + (dir)) |
||||
|
||||
// compare two coords
|
||||
#define coord_eq(a, b) (((a).x == (b).x) && ((a).y == (b).y)) |
||||
|
||||
|
||||
bool crashed; |
||||
uint8_t snake_len; |
||||
|
||||
// y, x indexing
|
||||
block_t board[ROWS][COLS]; |
||||
|
||||
coord_t head_pos; |
||||
coord_t tail_pos; |
||||
dir_t head_dir; |
||||
|
||||
const uint8_t CODE_BB = 0; |
||||
const uint8_t CODE_BX = 1; |
||||
const uint8_t CODE_XB = 2; |
||||
const uint8_t CODE_H = 3; // glyph with head, dynamic
|
||||
const uint8_t CODE_F = 4; // glyph with food, dynamic
|
||||
const uint8_t CODE_XX = 32; // space
|
||||
|
||||
|
||||
// Set a block in board
|
||||
#define set_block_xy(x, y, block) do { board[y][x] = (block); } while(0) |
||||
#define get_block_xy(x, y) board[y][x] |
||||
#define get_block(pos) get_block_xy((pos).x, (pos).y) |
||||
#define set_block(pos, block) set_block_xy((pos).x, (pos).y, (block)) |
||||
|
||||
|
||||
void init_cgram() |
||||
{ |
||||
// those will be always the same
|
||||
lcd_glyph_P(CODE_BB, SYMBOL_BB); |
||||
lcd_glyph_P(CODE_BX, SYMBOL_BX); |
||||
lcd_glyph_P(CODE_XB, SYMBOL_XB); |
||||
lcd_glyph_P(5, SYMBOL_XF); |
||||
} |
||||
|
||||
|
||||
void place_food() |
||||
{ |
||||
while(1) { |
||||
const uint8_t xx = rand() % COLS; |
||||
const uint8_t yy = rand() % ROWS; |
||||
|
||||
if (get_block_xy(xx, yy) == bEMPTY) { |
||||
set_block_xy(xx, yy, bFOOD); |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
|
||||
|
||||
void init_gameboard() |
||||
{ |
||||
//erase the board
|
||||
for (uint8_t x = 0; x < COLS; x++) { |
||||
for (uint8_t y = 0; y < ROWS; y++) { |
||||
set_block_xy(x, y, bEMPTY); |
||||
} |
||||
} |
||||
|
||||
lcd_clear(); |
||||
|
||||
tail_pos = (coord_t) {.x = 0, .y = 0}; |
||||
|
||||
set_block_xy(0, 0, bBODY_RIGHT); |
||||
set_block_xy(1, 0, bBODY_RIGHT); |
||||
set_block_xy(2, 0, bBODY_RIGHT); |
||||
set_block_xy(3, 0, bHEAD); |
||||
|
||||
head_pos = (coord_t) {.x = 3, .y = 0}; |
||||
|
||||
snake_len = 4; // includes head
|
||||
|
||||
head_dir = dRIGHT; |
||||
crashed = false; |
||||
|
||||
place_food(); |
||||
} |
||||
|
||||
|
||||
uint8_t presc = 0; |
||||
|
||||
bool restart_held; |
||||
bool pause_held; |
||||
bool paused; |
||||
void update() |
||||
{ |
||||
if (debo_get_pin(D_RESTART)) { |
||||
|
||||
if (!restart_held) { |
||||
// restart
|
||||
init_gameboard(); |
||||
presc = 0; |
||||
restart_held = true; |
||||
} |
||||
|
||||
} else { |
||||
restart_held = false; |
||||
} |
||||
|
||||
if (debo_get_pin(D_PAUSE)) { |
||||
|
||||
if (!pause_held) { |
||||
paused ^= true; |
||||
pause_held = true; |
||||
} |
||||
|
||||
} else { |
||||
pause_held = false; |
||||
} |
||||
|
||||
if(!crashed && !paused) { |
||||
|
||||
// resolve movement direction
|
||||
if (debo_get_pin(D_LEFT)) |
||||
head_dir = dLEFT; |
||||
else if (debo_get_pin(D_RIGHT)) |
||||
head_dir = dRIGHT; |
||||
else if (debo_get_pin(D_UP)) |
||||
head_dir = dUP; |
||||
else if (debo_get_pin(D_DOWN)) |
||||
head_dir = dDOWN; |
||||
|
||||
// time's up for a move
|
||||
if (presc++ == STEP_DELAY) { |
||||
presc = 0; |
||||
|
||||
// move snake
|
||||
const coord_t oldpos = head_pos; |
||||
|
||||
switch (head_dir) { |
||||
case dLEFT: head_pos.x--; break; |
||||
case dRIGHT: head_pos.x++; break; |
||||
case dUP: head_pos.y--; break; |
||||
case dDOWN: head_pos.y++; break; |
||||
} |
||||
|
||||
bool do_move = false; |
||||
bool do_grow = false; |
||||
|
||||
if (head_pos.x < 0 || head_pos.x >= COLS || head_pos.y < 0 || head_pos.y >= ROWS) { |
||||
// ouch, a wall!
|
||||
crashed = true; |
||||
} else { |
||||
// check if tile occupied or not
|
||||
if (coord_eq(head_pos, tail_pos)) { |
||||
// head moved in previous tail, that's OK.
|
||||
do_move = true; |
||||
} else { |
||||
// moved to other tile than tail
|
||||
switch (get_block(head_pos)) { |
||||
|
||||
case bFOOD: |
||||
do_grow = true; // fall through
|
||||
case bEMPTY: |
||||
do_move = true; |
||||
break; |
||||
|
||||
default: // includes all BODY_xxx
|
||||
crashed = true; // snake crashed into some block
|
||||
} |
||||
} |
||||
} |
||||
|
||||
if (do_move) { |
||||
// Move tail
|
||||
if (do_grow) { |
||||
// let tail as is
|
||||
snake_len++; // grow the counter
|
||||
} else { |
||||
// tail dir
|
||||
dir_t td = get_block(tail_pos) & 0xF; |
||||
|
||||
// clean tail
|
||||
set_block(tail_pos, bEMPTY); |
||||
|
||||
// move tail based on old direction of tail block
|
||||
switch (td) { |
||||
case dLEFT: tail_pos.x--; break; |
||||
case dRIGHT: tail_pos.x++; break; |
||||
case dUP: tail_pos.y--; break; |
||||
case dDOWN: tail_pos.y++; break; |
||||
} |
||||
} |
||||
|
||||
// Move head
|
||||
set_block(head_pos, bHEAD); // place head in new pos
|
||||
set_block(oldpos, mk_body_dir(head_dir)); // directional body in old head pos
|
||||
|
||||
if (do_grow) { |
||||
// food eaten, place new
|
||||
place_food(); |
||||
} |
||||
} |
||||
} |
||||
} // end !crashed
|
||||
|
||||
|
||||
// Render the board
|
||||
for (uint8_t r = 0; r < ROWS / 2; r++) { |
||||
lcd_xy(0, r); |
||||
for (uint8_t c = 0; c < COLS; c++) { |
||||
const block_t t1 = get_block_xy(c, r * 2); |
||||
const block_t t2 = get_block_xy(c, (r * 2) + 1); |
||||
|
||||
uint8_t code = '!'; // ! marks fail
|
||||
|
||||
if ((t1 == bEMPTY) && (t2 == bEMPTY)) { |
||||
code = CODE_XX; |
||||
if (crashed) code = '*'; |
||||
} else if (is_body(t1) && is_body(t2)) |
||||
code = CODE_BB; |
||||
else if (is_body(t1) && (t2 == bEMPTY)) |
||||
code = CODE_BX; |
||||
else if (t1 == bEMPTY && is_body(t2)) |
||||
code = CODE_XB; |
||||
else if ((t1 == bFOOD) || (t2 == bFOOD)) { |
||||
// one is food
|
||||
|
||||
code = CODE_F; |
||||
|
||||
if (t1 == bFOOD) { |
||||
if (t2 == bEMPTY) |
||||
lcd_glyph_P(code, SYMBOL_FX); |
||||
else if (t2 == bHEAD) |
||||
lcd_glyph_P(code, SYMBOL_FH); |
||||
else if (is_body(t2)) |
||||