Vladimir Shilov 5 роки тому
коміт
1946c783d5
26 змінених файлів з 3096 додано та 0 видалено
  1. 21 0
      .gitignore
  2. 670 0
      Makefile
  3. 9 0
      ReadMe.txt
  4. 444 0
      SNC.cbp
  5. BIN
      hw/cpu-w104.dip
  6. BIN
      hw/cpu-w95.dip
  7. BIN
      hw/cpu.dch
  8. BIN
      hw/disp-in14x6.dch
  9. BIN
      hw/disp-in14x6.dip
  10. BIN
      hw/disp-in4x6.dch
  11. BIN
      hw/disp-in4x6.dip
  12. BIN
      hw/disp-in82x4.dch
  13. BIN
      hw/disp-in82x4.dip
  14. 12 0
      inc/common.h
  15. 98 0
      inc/ds3231.h
  16. 79 0
      inc/event-system.h
  17. 27 0
      inc/i2c.h
  18. 50 0
      inc/list_event.h
  19. 75 0
      inc/main.h
  20. 67 0
      inc/rtos.h
  21. 141 0
      src/ds3231.c
  22. 209 0
      src/event-system.c
  23. 10 0
      src/fuse.c
  24. 174 0
      src/i2c.c
  25. 824 0
      src/main.c
  26. 186 0
      src/rtos.c

+ 21 - 0
.gitignore

@@ -0,0 +1,21 @@
+*.layout
+.dep
+build
+tmp
+*.rar
+*.zip
+*.7z
+*.DBK
+*.PWI
+*.LST
+*.SDI
+*.hex
+*.eep
+*.elf
+*.bin
+*.srec
+*.o
+*.lst
+*.map
+*.d
+*.depend

+ 670 - 0
Makefile

@@ -0,0 +1,670 @@
+# Hey Emacs, this is a -*- makefile -*-
+#----------------------------------------------------------------------------
+# WinAVR Makefile Template written by Eric B. Weddington, Jörg Wunsch, et al.
+#
+# Released to the Public Domain
+#
+# Additional material for this makefile was written by:
+# Peter Fleury
+# Tim Henigan
+# Colin O'Flynn
+# Reiner Patommel
+# Markus Pfaff
+# Sander Pool
+# Frederik Rouleau
+# Carlos Lamas
+#
+#----------------------------------------------------------------------------
+# On command line:
+#
+# make all = Make software.
+#
+# make clean = Clean out built project files.
+#
+# make coff = Convert ELF to AVR COFF.
+#
+# make extcoff = Convert ELF to AVR Extended COFF.
+#
+# make program = Download the hex file to the device, using avrdude.
+#                Please customize the avrdude settings below first!
+#
+# make debug = Start either simulavr or avarice as specified for debugging,
+#              with avr-gdb or avr-insight as the front end for debugging.
+#
+# make filename.s = Just compile filename.c into the assembler code only.
+#
+# make filename.i = Create a preprocessed source file for use in submitting
+#                   bug reports to the GCC project.
+#
+# To rebuild project do "make clean" then "make all".
+#----------------------------------------------------------------------------
+
+
+# MCU name
+MCU = atmega8a
+
+
+# Processor frequency.
+#     This will define a symbol, F_CPU, in all source code files equal to the
+#     processor frequency. You can then use this symbol in your source code to
+#     calculate timings. Do NOT tack on a 'UL' at the end, this will be done
+#     automatically to create a 32-bit value in your source code.
+#     Typical values are:
+#         F_CPU =  1000000
+#         F_CPU =  1843200
+#         F_CPU =  2000000
+#         F_CPU =  3686400
+#         F_CPU =  4000000
+#         F_CPU =  7372800
+#         F_CPU =  8000000
+#         F_CPU = 11059200
+#         F_CPU = 14745600
+#         F_CPU = 16000000
+#         F_CPU = 18432000
+#         F_CPU = 20000000
+F_CPU = 16000000
+
+
+# Output format. (can be srec, ihex, binary)
+FORMAT = ihex
+
+
+# Target file name (without extension).
+TARGET = snc
+
+
+# Application sources directory
+#     To put object files in current directory, use a dot (.), do NOT make
+#     this an empty or blank macro!
+APP_SRC = src
+
+
+# Object files directory
+#     To put object files in current directory, use a dot (.), do NOT make
+#     this an empty or blank macro!
+OBJDIR = build/obj
+
+
+# Binary files directory
+#     To put object files in current directory, use a dot (.), do NOT make
+#     this an empty or blank macro!
+BINDIR = build
+
+
+# Search build/output directory for dependencies
+vpath %.c $(APP_SRC)
+vpath %.o .\$(OBJDIR)
+vpath %.elf .\$(BINDIR)
+vpath %.hex .\$(BINDIR)
+
+# List C source files here. (C dependencies are automatically generated.)
+SRC = $(wildcard $(APP_SRC)/*.c)
+
+# List C++ source files here. (C dependencies are automatically generated.)
+CPPSRC =
+
+
+# List Assembler source files here.
+#     Make them always end in a capital .S.  Files ending in a lowercase .s
+#     will not be considered source files but generated files (assembler
+#     output from the compiler), and will be deleted upon "make clean"!
+#     Even though the DOS/Win* filesystem matches both .s and .S the same,
+#     it will preserve the spelling of the filenames, and gcc itself does
+#     care about how the name is spelled on its command-line.
+ASRC =
+
+
+# Optimization level, can be [0, 1, 2, 3, s].
+#     0 = turn off optimization. s = optimize for size.
+#     (Note: 3 is not always the best optimization level. See avr-libc FAQ.)
+OPT = s
+
+
+# Debugging format.
+#     Native formats for AVR-GCC's -g are dwarf-2 [default] or stabs.
+#     AVR Studio 4.10 requires dwarf-2.
+#     AVR [Extended] COFF format requires stabs, plus an avr-objcopy run.
+DEBUG = dwarf-2
+
+
+# List any extra directories to look for include files here.
+#     Each directory must be seperated by a space.
+#     Use forward slashes for directory separators.
+#     For a directory that has spaces, enclose it in quotes.
+EXTRAINCDIRS = inc
+
+
+# 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 for C sources
+CDEFS = -DF_CPU=$(F_CPU)UL
+
+
+# Place -D or -U options here for ASM sources
+ADEFS = -DF_CPU=$(F_CPU)
+
+
+# Place -D or -U options here for C++ sources
+CPPDEFS = -DF_CPU=$(F_CPU)UL
+#CPPDEFS += -D__STDC_LIMIT_MACROS
+#CPPDEFS += -D__STDC_CONSTANT_MACROS
+
+
+
+#---------------- Compiler Options C ----------------
+#  -g*:          generate debugging information
+#  -O*:          optimization level
+#  -f...:        tuning, see GCC manual and avr-libc documentation
+#  -Wall...:     warning level
+#  -Wa,...:      tell GCC to pass this to the assembler.
+#    -adhlns...: create assembler listing
+CFLAGS = -g$(DEBUG)
+CFLAGS += $(CDEFS)
+CFLAGS += -O$(OPT)
+CFLAGS += -funsigned-char
+CFLAGS += -funsigned-bitfields
+CFLAGS += -fshort-enums
+CFLAGS += -ffunction-sections
+CFLAGS += -fdata-sections
+#CFLAGS += -flto
+CFLAGS += -ffreestanding
+CFLAGS += -mrelax
+#CFLAGS += -fno-ivopts
+#CFLAGS += -fwhole-program
+#CFLAGS += -mcall-prologues
+#CFLAGS += -fno-split-wide-types
+CFLAGS += -W -Wall -Wextra -Wstrict-prototypes -Wundef -Werror
+#CFLAGS += -Wunreachable-code
+#CFLAGS += -Wsign-compare
+CFLAGS += -Wa,-adhlns=$(<:%.c=$(OBJDIR)/%.lst)
+CFLAGS += $(patsubst %,-I%,$(EXTRAINCDIRS))
+CFLAGS += $(CSTANDARD)
+
+
+#---------------- Compiler Options C++ ----------------
+#  -g*:          generate debugging information
+#  -O*:          optimization level
+#  -f...:        tuning, see GCC manual and avr-libc documentation
+#  -Wall...:     warning level
+#  -Wa,...:      tell GCC to pass this to the assembler.
+#    -adhlns...: create assembler listing
+CPPFLAGS = -g$(DEBUG)
+CPPFLAGS += $(CPPDEFS)
+CPPFLAGS += -O$(OPT)
+CPPFLAGS += -funsigned-char
+CPPFLAGS += -funsigned-bitfields
+CPPFLAGS += -fpack-struct
+CPPFLAGS += -fshort-enums
+CPPFLAGS += -fno-exceptions
+CPPFLAGS += -Wall
+CPPFLAGS += -Wundef
+CPPFLAGS += -fno-rtti
+CPPFLAGS += -fno-exceptions
+#CPPFLAGS += -mshort-calls
+#CPPFLAGS += -ffunction-sections
+#CPPFLAGS += -fdata-sections
+#CPPFLAGS += -mcall-prologues
+#CPPFLAGS += -fno-unit-at-a-time
+#CPPFLAGS += --param inline-call-cost=1
+#CPPFLAGS += -fno-split-wide-types
+#CPPFLAGS += -Wstrict-prototypes
+#CPPFLAGS += -Wunreachable-code
+#CPPFLAGS += -Wsign-compare
+#CPPFLAGS += -fvtable-gc
+CPPFLAGS += -Wa,-adhlns=$(<:%.cpp=$(OBJDIR)/%.lst)
+CPPFLAGS += $(patsubst %,-I%,$(EXTRAINCDIRS))
+#CPPFLAGS += $(CSTANDARD)
+
+
+#---------------- Assembler Options ----------------
+#  -Wa,...:   tell GCC to pass this to the assembler.
+#  -adhlns:   create listing
+#  -gstabs:   have the assembler create line number information; note that
+#             for use in COFF files, additional information about filenames
+#             and function names needs to be present in the assembler source
+#             files -- see avr-libc docs [FIXME: not yet described there]
+#  -listing-cont-lines: Sets the maximum number of continuation lines of hex
+#       dump that will be displayed for a given single line of source input.
+ASFLAGS = $(ADEFS) -Wa,-adhlns=$(<:%.S=$(OBJDIR)/%.lst),-gdwarf-2,--listing-cont-lines=100
+#ASFLAGS = $(ADEFS) -Wa,-adhlns=$(<:%.S=$(OBJDIR)/%.lst),-gstabs,--listing-cont-lines=100
+
+
+#---------------- Library Options ----------------
+# 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
+
+# If this is left blank, then it will use the Standard printf version.
+PRINTF_LIB =
+#PRINTF_LIB = $(PRINTF_LIB_MIN)
+#PRINTF_LIB = $(PRINTF_LIB_FLOAT)
+
+
+# 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
+
+# If this is left blank, then it will use the Standard scanf version.
+SCANF_LIB =
+#SCANF_LIB = $(SCANF_LIB_MIN)
+#SCANF_LIB = $(SCANF_LIB_FLOAT)
+
+
+MATH_LIB = -lm
+
+
+# List any extra directories to look for libraries here.
+#     Each directory must be seperated by a space.
+#     Use forward slashes for directory separators.
+#     For a directory that has spaces, enclose it in quotes.
+EXTRALIBDIRS =
+
+
+
+#---------------- External Memory Options ----------------
+
+# 64 KB of external RAM, starting after internal RAM (ATmega128!),
+# used for variables (.data/.bss) and heap (malloc()).
+#EXTMEMOPTS = -Wl,-Tdata=0x801100,--defsym=__heap_end=0x80ffff
+
+# 64 KB of external RAM, starting after internal RAM (ATmega128!),
+# only used for heap (malloc()).
+#EXTMEMOPTS = -Wl,--section-start,.data=0x801100,--defsym=__heap_end=0x80ffff
+
+EXTMEMOPTS =
+
+
+
+#---------------- Linker Options ----------------
+#  -Wl,...:     tell GCC to pass this to linker.
+#    -Map:      create map file
+#    --cref:    add cross reference to  map file
+LDFLAGS = -Wl,-Map=$(BINDIR)/$(TARGET).map,--cref
+#LDFLAGS += -Wl,-static
+LDFLAGS += -Wl,-gc-sections,-flto
+#LDFLAGS += -Wl,-s
+#LDFLAGS += -Wl,-relax
+LDFLAGS += $(EXTMEMOPTS)
+LDFLAGS += $(patsubst %,-L%,$(EXTRALIBDIRS))
+LDFLAGS += $(PRINTF_LIB) $(SCANF_LIB) $(MATH_LIB)
+#LDFLAGS += -T $(TARGET).ld
+
+
+
+#---------------- Programming Options (avrdude) ----------------
+
+# Programming hardware
+# Type: avrdude -c ?
+# to get a full listing.
+#
+AVRDUDE_PROGRAMMER = usbasp
+#AVRDUDE_PROGRAMMER = avr910
+
+# com1 = serial port. Use lpt1 to connect to parallel port.
+#AVRDUDE_PORT = com3    # programmer connected to serial device
+AVRDUDE_PORT = usb
+
+# set com port baudrate
+#AVRDUDE_COM_BAUD = -b 115200
+
+AVRDUDE_WRITE_FLASH = -U flash:w:$(BINDIR)/$(TARGET).hex
+#AVRDUDE_WRITE_EEPROM = -U eeprom:w:$(BINDIR)/$(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
+
+AVRDUDE_MCU = m8
+#AVRDUDE_MCU = $(MCU)
+
+# Increase verbosity level.  Please use this when submitting bug
+# reports about avrdude. See <http://savannah.nongnu.org/projects/avrdude>
+# to submit bug reports.
+#AVRDUDE_VERBOSE = -v -v
+
+AVRDUDE_FLAGS = -p $(AVRDUDE_MCU) -P $(AVRDUDE_PORT) -c $(AVRDUDE_PROGRAMMER)
+AVRDUDE_FLAGS += $(AVRDUDE_COM_BAUD)
+AVRDUDE_FLAGS += $(AVRDUDE_NO_VERIFY)
+AVRDUDE_FLAGS += $(AVRDUDE_VERBOSE)
+AVRDUDE_FLAGS += $(AVRDUDE_ERASE_COUNTER)
+
+
+
+#---------------- Debugging Options ----------------
+
+# For simulavr only - target MCU frequency.
+DEBUG_MFREQ = $(F_CPU)
+
+# Set the DEBUG_UI to either gdb or insight.
+# DEBUG_UI = gdb
+DEBUG_UI = insight
+
+# Set the debugging back-end to either avarice, simulavr.
+#DEBUG_BACKEND = avarice
+DEBUG_BACKEND = simulavr
+
+# GDB Init Filename.
+GDBINIT_FILE = __avr_gdbinit
+
+# When using avarice settings for the JTAG
+JTAG_DEV = /dev/com1
+
+# Debugging port used to communicate between GDB / avarice / simulavr.
+DEBUG_PORT = 4242
+
+# Debugging host used to communicate between GDB / avarice / simulavr, normally
+#     just set to localhost unless doing some sort of crazy debugging when
+#     avarice is running on a different computer.
+DEBUG_HOST = localhost
+
+
+
+#============================================================================
+
+
+# Define programs and commands.
+AVRPATH = C:/mcu/avr-gcc/bin
+SHELL = sh
+CC = $(AVRPATH)/avr-gcc
+OBJCOPY = $(AVRPATH)/avr-objcopy
+OBJDUMP = $(AVRPATH)/avr-objdump
+SIZE = $(AVRPATH)/avr-size
+AR = $(AVRPATH)/avr-ar rcs
+NM = $(AVRPATH)/avr-nm
+AVRDUDE = D:/Program/avrdude/avrdude.exe
+REMOVE = rm -f
+REMOVEDIR = rm -rf
+COPY = cp
+WINSHELL = cmd
+
+
+# Define Messages
+# English
+MSG_ERRORS_NONE = Errors: none
+MSG_BEGIN = -------- begin --------
+MSG_END = --------  end  --------
+MSG_SIZE_BEFORE = Size before:
+MSG_SIZE_AFTER = Size after:
+MSG_COFF = Converting to AVR COFF:
+MSG_EXTENDED_COFF = Converting to AVR Extended COFF:
+MSG_FLASH = Creating load file for Flash:
+MSG_EEPROM = Creating load file for EEPROM:
+MSG_EXTENDED_LISTING = Creating Extended Listing:
+MSG_SYMBOL_TABLE = Creating Symbol Table:
+MSG_LINKING = Linking:
+MSG_COMPILING = Compiling C:
+MSG_COMPILING_CPP = Compiling C++:
+MSG_ASSEMBLING = Assembling:
+MSG_CLEANING = Cleaning project:
+MSG_CREATING_LIBRARY = Creating library:
+
+
+
+
+# Define all object files.
+OBJ = $(SRC:%.c=$(OBJDIR)/%.o) $(CPPSRC:%.cpp=$(OBJDIR)/%.o) $(ASRC:%.S=$(OBJDIR)/%.o)
+
+# Define all listing files.
+LST = $(SRC:%.c=$(OBJDIR)/%.lst) $(CPPSRC:%.cpp=$(OBJDIR)/%.lst) $(ASRC:%.S=$(OBJDIR)/%.lst)
+
+
+# Compiler flags to generate dependency files.
+GENDEPFLAGS = -MMD -MP -MF .dep/$(@F).d
+
+
+# Combine all necessary flags and optional flags.
+# Add target processor to flags.
+ALL_CFLAGS = -mmcu=$(MCU) -I. $(CFLAGS) $(GENDEPFLAGS)
+ALL_CPPFLAGS = -mmcu=$(MCU) -I. -x c++ $(CPPFLAGS) $(GENDEPFLAGS)
+ALL_ASFLAGS = -mmcu=$(MCU) -I. -x assembler-with-cpp $(ASFLAGS)
+
+
+
+
+
+# Default target.
+all: begin gccversion sizebefore build sizeafter end
+
+# Change the build target to build a HEX file or a library.
+build: elf hex eep lss sym
+#build: lib
+
+
+elf: $(BINDIR)/$(TARGET).elf
+hex: $(BINDIR)/$(TARGET).hex
+eep: $(BINDIR)/$(TARGET).eep
+lss: $(BINDIR)/$(TARGET).lss
+sym: $(BINDIR)/$(TARGET).sym
+LIBNAME=$(BINDIR)/lib$(TARGET).a
+lib: $(LIBNAME)
+
+
+
+# Eye candy.
+# AVR Studio 3.x does not check make's exit code but relies on
+# the following magic strings to be generated by the compile job.
+begin:
+	@echo
+	@echo $(MSG_BEGIN)
+
+end:
+	@echo $(MSG_END)
+	@echo
+
+
+# Display size of file.
+HEXSIZE = $(SIZE) --target=$(FORMAT) $(BINDIR)/$(TARGET).hex
+#ELFSIZE = $(SIZE) --mcu=$(MCU) --format=avr $(BINDIR)/$(TARGET).elf
+ELFSIZE = $(SIZE) --target=elf32-avr $(BINDIR)/$(TARGET).elf
+sizebefore:
+	@if test -f $(BINDIR)/$(TARGET).elf; then echo; echo $(MSG_SIZE_BEFORE); $(ELFSIZE); \
+	2>/dev/null; echo; fi
+
+sizeafter:
+	@if test -f $(BINDIR)/$(TARGET).elf; then echo; echo $(MSG_SIZE_AFTER); $(ELFSIZE); \
+	2>/dev/null; echo; fi
+
+
+
+# Display compiler version information.
+gccversion :
+	@$(CC) --version
+
+
+
+# Program the device.
+program: $(BINDIR)/$(TARGET).hex $(BINDIR)/$(TARGET).eep
+	$(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_FLASH) $(AVRDUDE_WRITE_EEPROM)
+
+
+# Generate avr-gdb config/init file which does the following:
+#     define the reset signal, load the target file, connect to target, and set
+#     a breakpoint at main().
+gdb-config:
+	@$(REMOVE) $(GDBINIT_FILE)
+	@echo define reset >> $(GDBINIT_FILE)
+	@echo SIGNAL SIGHUP >> $(GDBINIT_FILE)
+	@echo end >> $(GDBINIT_FILE)
+	@echo file $(BINDIR)/$(TARGET).elf >> $(GDBINIT_FILE)
+	@echo target remote $(DEBUG_HOST):$(DEBUG_PORT)  >> $(GDBINIT_FILE)
+ifeq ($(DEBUG_BACKEND),simulavr)
+	@echo load  >> $(GDBINIT_FILE)
+endif
+	@echo break main >> $(GDBINIT_FILE)
+
+debug: gdb-config $(BINDIR)/$(TARGET).elf
+ifeq ($(DEBUG_BACKEND), avarice)
+	@echo Starting AVaRICE - Press enter when "waiting to connect" message displays.
+	@$(WINSHELL) /c start avarice --jtag $(JTAG_DEV) --erase --program --file \
+	$(BINDIR)/$(TARGET).elf $(DEBUG_HOST):$(DEBUG_PORT)
+	@$(WINSHELL) /c pause
+
+else
+	@$(WINSHELL) /c start simulavr --gdbserver --device $(MCU) --clock-freq \
+	$(DEBUG_MFREQ) --port $(DEBUG_PORT)
+endif
+	@$(WINSHELL) /c start avr-$(DEBUG_UI) --command=$(GDBINIT_FILE)
+
+
+
+
+# Convert ELF to COFF for use in debugging / simulating in AVR Studio or VMLAB.
+COFFCONVERT = $(OBJCOPY) --debugging
+COFFCONVERT += --change-section-address .data-0x800000
+COFFCONVERT += --change-section-address .bss-0x800000
+COFFCONVERT += --change-section-address .noinit-0x800000
+COFFCONVERT += --change-section-address .eeprom-0x810000
+
+
+
+coff: $(BINDIR)/$(TARGET).elf
+#	@echo
+	@echo $(MSG_COFF) $(BINDIR)/$(TARGET).cof
+	@$(COFFCONVERT) -O coff-avr $< $(BINDIR)/$(TARGET).cof
+
+
+extcoff: $(BINDIR)/$(TARGET).elf
+#	@echo
+	@echo $(MSG_EXTENDED_COFF) $(BINDIR)/$(TARGET).cof
+	@$(COFFCONVERT) -O coff-ext-avr $< $(BINDIR)/$(TARGET).cof
+
+
+
+# Create final output files (.hex, .eep) from ELF output file.
+%.hex: %.elf
+#	@echo
+	@echo $(MSG_FLASH) $@
+	@$(OBJCOPY) -O $(FORMAT) -R .eeprom -R .fuse -R .lock -R .signature $< $@
+
+%.eep: %.elf
+#	@echo
+	@echo $(MSG_EEPROM) $@
+	@-$(OBJCOPY) -j .eeprom --set-section-flags=.eeprom="alloc,load" \
+	--change-section-lma .eeprom=0 --no-change-warnings -O $(FORMAT) $< $@ || exit 0
+
+# Create extended listing file from ELF output file.
+%.lss: %.elf
+#	@echo
+	@echo $(MSG_EXTENDED_LISTING) $@
+	@$(OBJDUMP) -h -S -z $< > $@
+
+# Create a symbol table from ELF output file.
+%.sym: %.elf
+#	@echo
+	@echo $(MSG_SYMBOL_TABLE) $@
+	@$(NM) -n $< > $@
+
+
+
+# Create library from object files.
+.SECONDARY : $(BINDIR)/$(TARGET).a
+.PRECIOUS : $(OBJ)
+%.a: $(OBJ)
+#	@echo
+	@echo $(MSG_CREATING_LIBRARY) $@
+	@$(AR) $@ $(OBJ)
+
+
+# Link: create ELF output file from object files.
+.SECONDARY : $(BINDIR)/$(TARGET).elf
+.PRECIOUS : $(OBJ)
+%.elf: $(OBJ)
+#	@echo
+	@echo $(MSG_LINKING) $@
+	@$(CC) $(ALL_CFLAGS) $^ --output $@ $(LDFLAGS)
+
+
+# Compile: create object files from C source files.
+$(OBJDIR)/%.o : %.c
+#	@echo
+	@echo $(MSG_COMPILING) $<
+	@$(CC) -c $(ALL_CFLAGS) $< -o $@
+
+
+# Compile: create object files from C++ source files.
+$(OBJDIR)/%.o : %.cpp
+#	@echo
+	@echo $(MSG_COMPILING_CPP) $<
+	@$(CC) -c $(ALL_CPPFLAGS) $< -o $@
+
+
+# Compile: create assembler files from C source files.
+%.s : %.c
+	@$(CC) -S $(ALL_CFLAGS) $< -o $@
+
+
+# Compile: create assembler files from C++ source files.
+%.s : %.cpp
+	@$(CC) -S $(ALL_CPPFLAGS) $< -o $@
+
+
+# Assemble: create object files from assembler source files.
+$(OBJDIR)/%.o : %.S
+#	@echo
+	@echo $(MSG_ASSEMBLING) $<
+	@$(CC) -c $(ALL_ASFLAGS) $< -o $@
+
+
+# Create preprocessed source for use in sending a bug report.
+%.i : %.c
+	@$(CC) -E -mmcu=$(MCU) -I. $(CFLAGS) $< -o $@
+
+
+# Target: clean project.
+clean: begin clean_list end
+
+clean_list :
+	@echo
+	@echo $(MSG_CLEANING)
+	@$(REMOVE) $(BINDIR)/$(TARGET).hex
+	@$(REMOVE) $(BINDIR)/$(TARGET).eep
+	@$(REMOVE) $(BINDIR)/$(TARGET).cof
+	@$(REMOVE) $(BINDIR)/$(TARGET).elf
+	@$(REMOVE) $(BINDIR)/$(TARGET).map
+	@$(REMOVE) $(BINDIR)/$(TARGET).sym
+	@$(REMOVE) $(BINDIR)/$(TARGET).lss
+	@$(REMOVE) $(SRC:%.c=$(OBJDIR)/%.o)
+	@$(REMOVE) $(SRC:%.c=$(OBJDIR)/%.lst)
+	@$(REMOVE) $(CPPSRC:%.c=$(OBJDIR)/%.o)
+	@$(REMOVE) $(CPPSRC:%.c=$(OBJDIR)/%.lst)
+	@$(REMOVE) $(ASRC:%.S=$(OBJDIR)/%.o)
+	@$(REMOVE) $(ASRC:%.S=$(OBJDIR)/%.lst)
+	@$(REMOVE) $(SRC:.c=.s)
+	@$(REMOVE) $(SRC:.c=.d)
+	@$(REMOVE) $(SRC:.c=.i)
+	@$(REMOVE) $(CPPSRC:.c=.s)
+	@$(REMOVE) $(CPPSRC:.c=.d)
+	@$(REMOVE) $(CPPSRC:.c=.i)
+	@$(REMOVEDIR) .dep
+
+
+# Create object files directory
+$(shell mkdir -p $(OBJDIR)/$(APP_SRC) 2>/dev/null)
+
+# Create bin files directory
+$(shell mkdir -p $(BINDIR) 2>/dev/null)
+
+# Include the dependency files.
+-include $(shell mkdir .dep 2>/dev/null) $(wildcard .dep/*)
+
+
+# Listing of phony targets.
+.PHONY : all begin finish end sizebefore sizeafter gccversion \
+build elf hex eep lss sym coff extcoff \
+clean clean_list program debug gdb-config

+ 9 - 0
ReadMe.txt

@@ -0,0 +1,9 @@
+Simple Nixie Clock / Простые часы на ГРИ
+
+Комплексный проект на разных индикаторах, двуплатной компоновки.
+CPU: ATmega8
+RTC: DS3231
+PWR: MAX771
+Управление катодами: К155ИД1
+
+Начальный исходный код от проекта "My Nixie Clock IN-12".

+ 444 - 0
SNC.cbp

@@ -0,0 +1,444 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
+<CodeBlocks_project_file>
+	<FileVersion major="1" minor="6" />
+	<Project>
+		<Option title="SNC" />
+		<Option makefile_is_custom="1" />
+		<Option pch_mode="2" />
+		<Option compiler="avr-gcc" />
+		<MakeCommands>
+			<Build command="$make -f $makefile" />
+			<CompileFile command="$make -f $makefile $file" />
+			<Clean command="$make -f $makefile clean" />
+			<DistClean command="$make -f $makefile distclean$target" />
+			<AskRebuildNeeded command="$make -q -f $makefile" />
+			<SilentBuild command="$make -f $makefile &gt; $(CMD_NULL)" />
+		</MakeCommands>
+		<Build>
+			<Target title="Debug">
+				<Option output="build/snc.elf" prefix_auto="1" extension_auto="0" />
+				<Option working_dir="" />
+				<Option object_output="build/Debug/" />
+				<Option type="5" />
+				<Option compiler="avr-gcc" />
+				<Compiler>
+					<Add option="-mmcu=atmega8" />
+					<Add option="-Wfatal-errors" />
+					<Add option="-Wextra" />
+					<Add option="-std=c99" />
+					<Add option="-g" />
+					<Add option="-std=gnu99" />
+				</Compiler>
+				<Environment>
+					<Variable name="USE_DHT" value="1" />
+				</Environment>
+			</Target>
+			<Target title="Release">
+				<Option output="build/SNC.elf" prefix_auto="1" extension_auto="0" />
+				<Option working_dir="" />
+				<Option object_output="build/Release/" />
+				<Option type="5" />
+				<Option compiler="avr-gcc" />
+				<Compiler>
+					<Add option="-mmcu=atmega8" />
+					<Add option="-fomit-frame-pointer" />
+					<Add option="-fexpensive-optimizations" />
+					<Add option="-flto" />
+					<Add option="-Os" />
+					<Add option="-Wfatal-errors" />
+				</Compiler>
+				<Linker>
+					<Add option="-flto" />
+					<Add option="-s" />
+				</Linker>
+			</Target>
+			<Environment>
+				<Variable name="MCU" value="atmega8" />
+				<Variable name="USE_DHT" value="1" />
+				<Variable name="USE_UART" value="1" />
+			</Environment>
+		</Build>
+		<Compiler>
+			<Add option="-mmcu=atmega8" />
+			<Add option="-Wall" />
+			<Add option="-DF_CPU=16000000UL" />
+			<Add directory="inc" />
+		</Compiler>
+		<Linker>
+			<Add option="-mmcu=atmega8a" />
+			<Add option="-Wl,-Map=$(TARGET_OUTPUT_DIR)$(TARGET_OUTPUT_BASENAME).map,--cref" />
+		</Linker>
+		<ExtraCommands>
+			<Add after="avr-size --mcu=atmega8 --format=avr $(TARGET_OUTPUT_FILE)" />
+			<Add after='cmd /c &quot;avr-objdump -h -S $(TARGET_OUTPUT_FILE) &gt; $(TARGET_OUTPUT_DIR)$(TARGET_OUTPUT_BASENAME).lss&quot;' />
+			<Add after="avr-objcopy -R .eeprom -R .fuse -R .lock -R .signature -O ihex $(TARGET_OUTPUT_FILE) $(TARGET_OUTPUT_DIR)$(TARGET_OUTPUT_BASENAME).hex" />
+			<Add after="avr-objcopy --no-change-warnings -j .eeprom --change-section-lma .eeprom=0 -O ihex $(TARGET_OUTPUT_FILE) $(TARGET_OUTPUT_DIR)$(TARGET_OUTPUT_BASENAME).eep" />
+			<Add after="avr-objcopy --no-change-warnings -j .lock --change-section-lma .lock=0 -O ihex $(TARGET_OUTPUT_FILE) $(TARGET_OUTPUT_DIR)$(TARGET_OUTPUT_BASENAME).lock" />
+			<Add after="avr-objcopy --no-change-warnings -j .signature --change-section-lma .signature=0 -O ihex $(TARGET_OUTPUT_FILE) $(TARGET_OUTPUT_DIR)$(TARGET_OUTPUT_BASENAME).sig" />
+			<Add after="avr-objcopy --no-change-warnings -j .fuse --change-section-lma .fuse=0 -O ihex $(TARGET_OUTPUT_FILE) $(TARGET_OUTPUT_DIR)$(TARGET_OUTPUT_BASENAME).fuse" />
+			<Add after="srec_cat $(TARGET_OUTPUT_DIR)$(TARGET_OUTPUT_BASENAME).fuse -Intel -crop 0x00 0x01 -offset  0x00 -O $(TARGET_OUTPUT_DIR)$(TARGET_OUTPUT_BASENAME).lfs -Intel" />
+			<Add after="srec_cat $(TARGET_OUTPUT_DIR)$(TARGET_OUTPUT_BASENAME).fuse -Intel -crop 0x01 0x02 -offset -0x01 -O $(TARGET_OUTPUT_DIR)$(TARGET_OUTPUT_BASENAME).hfs -Intel" />
+		</ExtraCommands>
+		<Unit filename=".gitignore" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/alloca.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/assert.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/boot.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/builtins.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/common.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/cpufunc.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/crc16.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/delay.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/eeprom.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/fuse.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/interrupt.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/io.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/io1200.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/io2313.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/io2323.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/io2333.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/io2343.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/io43u32x.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/io43u35x.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/io4414.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/io4433.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/io4434.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/io76c711.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/io8515.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/io8534.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/io8535.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/io86r401.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/io90pwm1.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/io90pwm161.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/io90pwm216.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/io90pwm2b.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/io90pwm316.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/io90pwm3b.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/io90pwm81.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/io90pwmx.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/io90scr100.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/ioa5272.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/ioa5505.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/ioa5702m322.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/ioa5782.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/ioa5790.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/ioa5790n.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/ioa5795.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/ioa5831.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/ioa6285.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/ioa6286.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/ioa6289.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/ioa6612c.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/ioa6613c.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/ioa6614q.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/ioa6616c.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/ioa6617c.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/ioa664251.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/ioat94k.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iocan128.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iocan32.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iocan64.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iocanxx.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iom103.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iom128.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iom1280.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iom1281.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iom1284.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iom1284p.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iom1284rfr2.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iom128a.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iom128rfa1.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iom128rfr2.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iom16.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iom161.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iom162.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iom163.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iom164.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iom164pa.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iom165.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iom165a.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iom165p.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iom165pa.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iom168.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iom168a.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iom168p.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iom168pa.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iom169.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iom169p.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iom169pa.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iom16a.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iom16hva.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iom16hva2.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iom16hvb.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iom16hvbrevb.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iom16m1.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iom16u2.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iom16u4.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iom2560.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iom2561.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iom2564rfr2.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iom256rfr2.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iom3000.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iom32.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iom323.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iom324.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iom324pa.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iom325.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iom3250.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iom3250pa.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iom325pa.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iom328p.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iom329.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iom3290.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iom3290pa.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iom32a.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iom32c1.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iom32hvb.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iom32hvbrevb.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iom32m1.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iom32u2.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iom32u4.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iom32u6.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iom406.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iom48.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iom48a.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iom48p.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iom48pa.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iom48pb.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iom64.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iom640.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iom644.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iom644a.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iom644p.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iom644pa.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iom644rfr2.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iom645.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iom6450.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iom649.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iom6490.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iom649p.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iom64a.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iom64c1.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iom64hve.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iom64hve2.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iom64m1.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iom64rfr2.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iom8.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iom8515.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iom8535.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iom88.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iom88a.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iom88p.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iom88pa.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iom88pb.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iom8a.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iom8hva.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iom8u2.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iomx8.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iomxx0_1.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iomxx4.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iomxxhva.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iotn10.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iotn11.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iotn12.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iotn13.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iotn13a.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iotn15.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iotn1614.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iotn1616.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iotn1617.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iotn1634.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iotn167.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iotn20.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iotn212.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iotn214.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iotn22.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iotn2313.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iotn2313a.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iotn24.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iotn24a.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iotn25.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iotn26.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iotn261.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iotn261a.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iotn28.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iotn3214.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iotn3216.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iotn3217.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iotn4.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iotn40.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iotn412.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iotn414.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iotn416.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iotn417.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iotn4313.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iotn43u.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iotn44.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iotn441.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iotn44a.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iotn45.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iotn461.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iotn461a.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iotn48.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iotn5.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iotn814.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iotn816.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iotn817.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iotn828.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iotn84.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iotn841.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iotn84a.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iotn85.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iotn861.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iotn861a.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iotn87.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iotn88.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iotn9.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iotnx4.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iotnx5.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iotnx61.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iousb1286.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iousb1287.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iousb162.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iousb646.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iousb647.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iousb82.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iousbxx2.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iousbxx6_7.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iox128a1.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iox128a1u.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iox128a3.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iox128a3u.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iox128a4u.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iox128b1.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iox128b3.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iox128c3.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iox128d3.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iox128d4.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iox16a4.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iox16a4u.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iox16c4.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iox16d4.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iox192a3.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iox192a3u.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iox192c3.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iox192d3.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iox256a3.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iox256a3b.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iox256a3bu.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iox256a3u.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iox256c3.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iox256d3.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iox32a4.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iox32a4u.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iox32c3.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iox32c4.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iox32d3.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iox32d4.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iox32e5.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iox384c3.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iox384d3.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iox64a1.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iox64a1u.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iox64a3.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iox64a3u.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iox64a4u.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iox64b1.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iox64b3.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iox64c3.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iox64d3.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iox64d4.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/iox8e5.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/lock.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/parity.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/pgmspace.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/portpins.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/power.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/sfr_defs.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/signal.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/signature.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/sleep.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/version.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/wdt.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/avr/xmega.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/compat/deprecated.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/compat/ina90.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/compat/twi.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/ctype.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/errno.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/fcntl.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/inttypes.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/locale.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/math.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/setjmp.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/signal.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/stdfix-avrlibc.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/stdint.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/stdio.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/stdlib.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/string.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/sys/types.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/time.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/unistd.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/util/atomic.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/util/crc16.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/util/delay.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/util/delay_basic.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/util/eu_dst.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/util/parity.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/util/setbaud.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/util/twi.h" />
+		<Unit filename="C:/MCU/avr-gcc/avr/include/util/usa_dst.h" />
+		<Unit filename="C:/MCU/avr-gcc/lib/gcc/avr/8.0.1/include-fixed/limits.h" />
+		<Unit filename="C:/MCU/avr-gcc/lib/gcc/avr/8.0.1/include-fixed/syslimits.h" />
+		<Unit filename="C:/MCU/avr-gcc/lib/gcc/avr/8.0.1/include/float.h" />
+		<Unit filename="C:/MCU/avr-gcc/lib/gcc/avr/8.0.1/include/gcov.h" />
+		<Unit filename="C:/MCU/avr-gcc/lib/gcc/avr/8.0.1/include/iso646.h" />
+		<Unit filename="C:/MCU/avr-gcc/lib/gcc/avr/8.0.1/include/stdalign.h" />
+		<Unit filename="C:/MCU/avr-gcc/lib/gcc/avr/8.0.1/include/stdarg.h" />
+		<Unit filename="C:/MCU/avr-gcc/lib/gcc/avr/8.0.1/include/stdatomic.h" />
+		<Unit filename="C:/MCU/avr-gcc/lib/gcc/avr/8.0.1/include/stdbool.h" />
+		<Unit filename="C:/MCU/avr-gcc/lib/gcc/avr/8.0.1/include/stddef.h" />
+		<Unit filename="C:/MCU/avr-gcc/lib/gcc/avr/8.0.1/include/stdfix-gcc.h" />
+		<Unit filename="C:/MCU/avr-gcc/lib/gcc/avr/8.0.1/include/stdfix.h" />
+		<Unit filename="C:/MCU/avr-gcc/lib/gcc/avr/8.0.1/include/stdint-gcc.h" />
+		<Unit filename="C:/MCU/avr-gcc/lib/gcc/avr/8.0.1/include/stdint.h" />
+		<Unit filename="C:/MCU/avr-gcc/lib/gcc/avr/8.0.1/include/stdnoreturn.h" />
+		<Unit filename="C:/MCU/avr-gcc/lib/gcc/avr/8.0.1/include/unwind.h" />
+		<Unit filename="C:/MCU/avr-gcc/lib/gcc/avr/8.0.1/include/varargs.h" />
+		<Unit filename="C:/MCU/avr-gcc/lib/gcc/avr/8.0.1/install-tools/gsyslimits.h" />
+		<Unit filename="C:/MCU/avr-gcc/lib/gcc/avr/8.0.1/install-tools/include/limits.h" />
+		<Unit filename="Makefile" />
+		<Unit filename="ReadMe.txt" />
+		<Unit filename="inc/common.h" />
+		<Unit filename="inc/ds3231.h" />
+		<Unit filename="inc/event-system.h" />
+		<Unit filename="inc/i2c.h" />
+		<Unit filename="inc/list_event.h" />
+		<Unit filename="inc/main.h" />
+		<Unit filename="inc/rtos.h" />
+		<Unit filename="src/ds3231.c">
+			<Option compilerVar="CC" />
+		</Unit>
+		<Unit filename="src/event-system.c">
+			<Option compilerVar="CC" />
+		</Unit>
+		<Unit filename="src/fuse.c">
+			<Option compilerVar="CC" />
+		</Unit>
+		<Unit filename="src/i2c.c">
+			<Option compilerVar="CC" />
+		</Unit>
+		<Unit filename="src/main.c">
+			<Option compilerVar="CC" />
+		</Unit>
+		<Unit filename="src/rtos.c">
+			<Option compilerVar="CC" />
+		</Unit>
+		<Extensions>
+			<code_completion />
+			<envvars />
+			<debugger />
+			<lib_finder disable_auto="1" />
+		</Extensions>
+	</Project>
+</CodeBlocks_project_file>

BIN
hw/cpu-w104.dip


BIN
hw/cpu-w95.dip



BIN
hw/disp-in14x6.dch


BIN
hw/disp-in14x6.dip


BIN
hw/disp-in4x6.dch


BIN
hw/disp-in4x6.dip


BIN
hw/disp-in82x4.dch


BIN
hw/disp-in82x4.dip


+ 12 - 0
inc/common.h

@@ -0,0 +1,12 @@
+#pragma once
+#ifndef _COMMON_H
+#define _COMMON_H
+
+/**
+ * Global defines
+ */
+#define USE_BRIGHT_CONTROL
+#define USE_DHT
+//#define USE_UART
+
+#endif /* _COMMON_H */

+ 98 - 0
inc/ds3231.h

@@ -0,0 +1,98 @@
+#pragma once
+#ifndef DS3231_H
+#define DS3231_H
+
+#include <avr/io.h>
+
+/* i2c slave address of the DS3231 chip */
+#define DS3231_I2C_WRADDR  0xD0
+#define DS3231_I2C_RDADDR  0xD1
+
+/* timekeeping registers */
+#define DS3231_TIME_CAL_ADDR        0x00
+#define DS3231_CALENDAR_ADDR        0x03
+#define DS3231_ALARM1_ADDR          0x07
+#define DS3231_ALARM2_ADDR          0x0B
+#define DS3231_CONTROL_ADDR         0x0E
+#define DS3231_STATUS_ADDR          0x0F
+#define DS3231_AGING_OFFSET_ADDR    0x10
+#define DS3231_TEMPERATURE_ADDR     0x11
+
+// control register bits
+#define DS3231_A1IE     0x01
+#define DS3231_A2IE     0x02
+#define DS3231_INTCN    0x04
+#define DS3231_RS1	    0x08
+#define DS3231_RS2	    0x10
+#define DS3231_CONV	    0x20
+#define DS3231_BBSQW	  0x40
+#define DS3231_OSC_OSC	0x80
+
+/* square-wave output frequency */
+#define DS3231_1HZ	    0x00
+#define DS3231_1024HZ	  DS3231_RS1
+#define DS3231_4096HZ	  DS3231_RS2
+#define DS3231_8192HZ	  (DS3231_RS1 | DS3231_RS2)
+
+/* status register bits */
+#define DS3231_A1F      0x01
+#define DS3231_A2F      0x02
+#define DS3231_OSF      0x80
+
+/* RTC Status */
+typedef enum {
+  RTC_OK  = 0x00,
+  RTC_TWI_TimeOut,
+  RTC_TWI_Error
+} rtc_status_t;
+
+/**
+ * @brief   Clock sructure.
+ * @note    structure of ds3231 data.
+ */
+typedef struct {
+  /**
+   * @brief  Seconds
+   */
+  uint8_t Sec;
+  /**
+   * @brief  Minutes
+   */
+  uint8_t Min;
+  /**
+   * @brief  Hours
+   */
+  uint8_t Hr;
+  /**
+   * @brief  Week Day
+   */
+  uint8_t WD;
+  /**
+   * @brief  Day of Month
+   */
+  uint8_t Day;
+  /**
+   * @brief  Month
+   */
+  uint8_t Mon;
+  /**
+   * @brief  Year
+   */
+  uint8_t Year;
+} rtc_t;
+
+void RTC_Init(void);
+
+void RTC_ReadAll(rtc_t * data);
+void RTC_ReadTime(rtc_t * data);
+void RTC_ReadCalendar(rtc_t * data);
+
+void RTC_WriteAll(rtc_t * data);
+void RTC_WriteTime(rtc_t * data);
+void RTC_WriteHHMM(rtc_t * data);
+void RTC_WriteCalendar(rtc_t * data);
+
+uint8_t bcd2bin(uint8_t bcd);
+uint8_t bin2bcd(uint8_t bin);
+
+#endif // DS3231_H

+ 79 - 0
inc/event-system.h

@@ -0,0 +1,79 @@
+/**
+ *
+ *  Author(s)...: Pashgan    http://ChipEnable.Ru
+ *  Target(s)...: любой микроконтроллер mega
+ *  Compiler....: IAR 5.11A
+ *  Description.: Заготовка для событийной системы на таблицах
+ *  Data........: 30.09.12
+ *
+ */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#pragma once
+#ifndef EVENT_SYSTEM_H
+#define EVENT_SYSTEM_H
+
+#include <avr/io.h>
+#include "common.h"
+#include "list_event.h"
+
+/* вместимость буфера очереди событий */
+#define SIZE_BUF 16
+
+void ES_Init(es_state_t init_state);    /* инициализация */
+es_state_t ES_GetState(void);           /* взять код состояния */
+void ES_SetState(es_state_t new_state); /* установить код состояния */
+es_event_t ES_GetEvent(void);           /* взять код события */
+void ES_PlaceEvent(es_event_t event);   /* разместить событие */
+void ES_Dispatch(es_event_t event);     /* вызов диспетчера */
+
+/**
+ * ES function prototypes
+ */
+void dotOnPersistent(void);
+void dotOff(void);
+void showTime(void);
+void showMMSS(void);
+void showWDay(void);
+void showMDay(void);
+void showMonth(void);
+void showYear(void);
+
+#ifdef USE_BRIGHT_CONTROL
+void showBright(void);
+void incBright(void);
+void decBright(void);
+#endif
+
+#ifdef USE_DHT
+void showTemperature(void);
+void showHumidity(void);
+#endif // USE_DHT
+
+void incHH(void);
+void incMM(void);
+void incSS(void);
+void decHH(void);
+void decMM(void);
+void decSS(void);
+
+void incWDay(void);
+void incMDay(void);
+void incMonth(void);
+void incYear(void);
+void decWDay(void);
+void decMDay(void);
+void decMonth(void);
+void decYear(void);
+
+void setTimeShow(void);
+void setTimeBegin(void);
+void setHHBegin(void);
+void setHHInc(void);
+void setHHDec(void);
+void setMMBegin(void);
+void setMMInc(void);
+void setMMDec(void);
+void setTimeEnd(void);
+
+#endif /* EVENT_SYSTEM_H */

+ 27 - 0
inc/i2c.h

@@ -0,0 +1,27 @@
+#ifndef _I2C_H
+#define _I2C_H
+
+#include <avr/io.h>
+
+#define TRUE 1
+#define FALSE 0
+
+typedef enum {
+  TWI_SUCCESS = 0,
+  TWI_TIMEOUT,
+  TWI_ERROR
+} twi_stats_t;
+
+typedef enum {
+  TWI_ACK = 0,
+  TWI_NACK
+} twi_ask_t;
+
+void I2C_Init(void);
+void I2C_Close(void);
+twi_stats_t I2C_Start(void);
+twi_stats_t I2C_Stop(void);
+twi_stats_t I2C_WriteByte(uint8_t data);
+twi_stats_t I2C_ReadByte(uint8_t *data, twi_ask_t ack);
+
+#endif

+ 50 - 0
inc/list_event.h

@@ -0,0 +1,50 @@
+#pragma once
+#ifndef EVENT_LIST_H
+#define EVENT_LIST_H
+
+/* коды событий */
+typedef enum {
+  eventNull = 0x00,
+  evNewSecond,
+  evBTN1Pressed,
+  evBTN2Pressed,
+  evBTN3Pressed,
+  evBTN1Holded,
+  evBTN2Holded,
+  evBTN3Holded,
+  evRefreshCal,
+#ifdef USE_DHT
+  evShTime,
+  evShTemp,
+  evShHum,
+#endif // USE_DHT
+  evDisplayWDT
+} es_event_t;
+
+/* коды состояний */
+typedef enum {
+  stNoChange = 0x00,
+  stShowTime,
+  stShowMMSS,
+  stShowWDay,
+  stShowMDay,
+  stShowMon,
+  stShowYear,
+#ifdef USE_BRIGHT_CONTROL
+  stShowBright,
+#endif // USE_BRIGHT_CONTROL
+#ifdef USE_DHT
+  stShowTemperature,
+  stShowHumidity,
+#endif // USE_DHT
+  stSetHH,
+  stSetMM,
+  /* end */
+  stLastState
+} es_state_t;
+
+#ifndef NULL
+  #define NULL ((void*)0)
+#endif
+
+#endif

+ 75 - 0
inc/main.h

@@ -0,0 +1,75 @@
+#pragma once
+#ifndef _MAIN_H
+#define _MAIN_H
+
+/**
+ * Битовые макросы
+ */
+#define SetBit(x,y)    x |= (1 << (y))
+#define ClrBit(x,y)    x &= ~(1 << (y))
+#define InvBit(x,y)    x ^= (1 << (y))
+#define IsBit(x,y)     (x & (1 << (y)))
+
+#define ResBit(reg,bit)    (reg &= ~_BV(bit))
+/*
+ Автоматически включается avr/sfr_defs.h, который содержит:
+	_BV(bit) === (1<<(bit))
+	bit_is_set(sfr, bit)
+	bit_is_clear(sfr, bit)
+	loop_until_bit_is_set(sfr, bit)
+	loop_until_bit_is_clear(sfr, bit)
+*/
+
+/**
+ * Дефайны
+ */
+/* Port B, puttons, input, pull-up */
+#define DHT_PIN            _BV(PB0)
+#define DHT_PIN_LOW        DDRB |= DHT_PIN
+#define DHT_PIN_INPUT      DDRB &= ~(DHT_PIN)
+
+#define BTN_NUM            3
+#define BUTTON1_PIN        _BV(PB3)
+#define BUTTON2_PIN        _BV(PB4)
+#define BUTTON3_PIN        _BV(PB5)
+#define BUTTON_PINS        (BUTTON1_PIN | BUTTON2_PIN | BUTTON3_PIN)
+#define BUTTON1_STATE      (PINB & BUTTON1_PIN)
+#define BUTTON2_STATE      (PINB & BUTTON2_PIN)
+#define BUTTON3_STATE      (PINB & BUTTON3_PIN)
+#define BUTTONS_STATE      (PINB & BUTTON_PINS)
+#define BUTTON_STATE(pin)  (PINB & pin)
+#define BUTTON_PERIOD      10
+/* in ms */
+#define BTN_SCAN_PERIOD    10
+#define BTN_TIME_PAUSE     20
+/* все временные константы кнопок кратны периоду опроса кнопок - 10 ms. */
+#define BTN_TIME_PRESSED   3
+#define BTN_TIME_HOLDED    50
+#define BTN_TIME_REPEATED  5
+
+/* Port C, Lamp digits, output */
+#define DIGIT_BLANK     0x0F
+#define DIGIT_A0        _BV(PC0)
+#define DIGIT_A1        _BV(PC1)
+#define DIGIT_A2        _BV(PC2)
+#define DIGIT_A3        _BV(PC3)
+#define DIGIT_PINS      (DIGIT_A0 | DIGIT_A1 | DIGIT_A2 | DIGIT_A3)
+
+/* Port D, Lamp anods, Dot, RTC interrupt, UART */
+#define DOT_PIN         _BV(PD2)
+#define ANOD1           _BV(PD4)
+#define ANOD2           _BV(PD5)
+#define ANOD3           _BV(PD6)
+#define ANOD4           _BV(PD7)
+#define ANOD_PINS       (ANOD1 | ANOD2 | ANOD3 | ANOD4)
+
+
+typedef struct {
+  uint8_t     time;
+  es_event_t  pressed;
+  es_event_t  holded;
+  uint8_t     pin;
+} btn_t;
+
+
+#endif

+ 67 - 0
inc/rtos.h

@@ -0,0 +1,67 @@
+/******************************************************************************************
+ * За основу взят планировщик задач с сайта ChipEnable.ru                                 *
+ * http://chipenable.ru/index.php/programming-avr/item/110-planirovschik.html             *
+ *                                                                                        *
+ * Доработал Шибанов Владимир aka KontAr                                                  *
+ * Дата: 26.03.2014                                                                       *
+ *                                                                                        *
+ * Изменения:                                                                             *
+ * - добавлен однократный вызов задачи                                                    *
+ * - добавлено удаление задачи по имени                                                   *
+ * - при повторном добавлении задачи обновляются ее переменные                            *
+ * - добавлен указатель на "хвост" списка                                                 *
+ * - функции РТОС скорректированы с учетом "хвоста"                                       *
+ ******************************************************************************************
+ * shilov, 2015.04.07									  *
+ * совместил с модулем милисекундных задержек на таймере				  *
+ ******************************************************************************************/
+#pragma once
+#ifndef RTOS_H
+#define RTOS_H
+
+#include <avr/io.h>
+
+#define MAX_TASKS      10              // Количество задач
+
+/**
+ * Будем использовать таймер 0, период -- 1 мсек
+ */
+#define TIMER_HZ		    1000
+#define TIMER_PRESCALER 64
+#define	TIMER_CNT		    (0x100 - (F_CPU / TIMER_PRESCALER / TIMER_HZ))
+
+#define TIMER_TCCR		  TCCR0
+#define TIMER_TCNT		  TCNT0
+#define TIMER_TIMSK		  TIMSK
+#define TIMER_CSB		    ((0<<CS02)|(1<<CS01)|(1<<CS00))
+#define TIMER_INT		    (1<<TOIE0)
+#define TIMER_OVF_VECT	TIMER0_OVF_vect
+
+/**
+ * Структура задачи
+ */
+typedef struct task
+{
+   void (*pFunc) (void);  // указатель на функцию
+   uint16_t delay;  // задержка перед первым запуском задачи
+   uint16_t period; // период запуска задачи
+   uint8_t run;     // флаг готовности задачи к запуску
+} task;
+
+/**
+ * Прототипы фукнций
+ */
+void RTOS_Init (void);
+void RTOS_SetTask (void (*taskFunc)(void), uint16_t taskDelay, uint16_t taskPeriod);
+void RTOS_DeleteTask (void (*taskFunc)(void));
+void RTOS_DispatchTask (void);
+void RTOS_Timer (void);
+
+void tdelay_ms(uint16_t msek);
+
+inline void tdelay_us(uint16_t usek) {
+  usek = usek + TCNT1;
+  while (TCNT1 < usek) {};
+}
+
+#endif

+ 141 - 0
src/ds3231.c

@@ -0,0 +1,141 @@
+#include "ds3231.h"
+#include "i2c.h"
+
+/**
+ * @brief Инициализация RTC
+ */
+void RTC_Init(void) {
+  I2C_Start();
+  I2C_WriteByte(DS3231_I2C_WRADDR);
+  I2C_WriteByte(DS3231_CONTROL_ADDR);
+  I2C_WriteByte(DS3231_CONV);
+  I2C_Stop();
+}
+
+/**
+ * @brief Чтение времени и календаря
+ */
+void RTC_ReadAll(rtc_t * data) {
+  I2C_Start();
+  I2C_WriteByte(DS3231_I2C_WRADDR);
+  I2C_WriteByte(DS3231_TIME_CAL_ADDR);
+  I2C_Stop();
+
+  I2C_Start();
+  I2C_WriteByte(DS3231_I2C_RDADDR);
+  I2C_ReadByte(&data->Sec, TWI_ACK);
+  I2C_ReadByte(&data->Min, TWI_ACK);
+  I2C_ReadByte(&data->Hr, TWI_ACK);
+  I2C_ReadByte(&data->WD, TWI_ACK);
+  I2C_ReadByte(&data->Day, TWI_ACK);
+  I2C_ReadByte(&data->Mon, TWI_ACK);
+  I2C_ReadByte(&data->Year, TWI_NACK);
+  I2C_Stop();
+}
+
+/**
+ * @brief Чтение времени
+ */
+void RTC_ReadTime(rtc_t * data) {
+  I2C_Start();
+  I2C_WriteByte(DS3231_I2C_WRADDR);
+  I2C_WriteByte(DS3231_TIME_CAL_ADDR);
+  I2C_Stop();
+
+  I2C_Start();
+  I2C_WriteByte(DS3231_I2C_RDADDR);
+  I2C_ReadByte(&data->Sec, TWI_ACK);
+  I2C_ReadByte(&data->Min, TWI_ACK);
+  I2C_ReadByte(&data->Hr, TWI_NACK);
+  I2C_Stop();
+}
+
+/**
+ * @brief Чтение календаря
+ */
+void RTC_ReadCalendar(rtc_t * data) {
+  I2C_Start();
+  I2C_WriteByte(DS3231_I2C_WRADDR);
+  I2C_WriteByte(DS3231_CALENDAR_ADDR);
+  I2C_Stop();
+
+  I2C_Start();
+  I2C_WriteByte(DS3231_I2C_RDADDR);
+  I2C_ReadByte(&data->WD, TWI_ACK);
+  I2C_ReadByte(&data->Day, TWI_ACK);
+  I2C_ReadByte(&data->Mon, TWI_ACK);
+  I2C_ReadByte(&data->Year, TWI_NACK);
+  I2C_Stop();
+}
+
+/**
+ * @brief Запись времени и календаря
+ */
+void RTC_WriteAll(rtc_t * data) {
+  I2C_Start();
+  I2C_WriteByte(DS3231_I2C_WRADDR);
+  I2C_WriteByte(DS3231_TIME_CAL_ADDR);
+  I2C_WriteByte(data->Sec);
+  I2C_WriteByte(data->Min);
+  I2C_WriteByte(data->Hr);
+  I2C_WriteByte(data->WD);
+  I2C_WriteByte(data->Day);
+  I2C_WriteByte(data->Mon);
+  I2C_WriteByte(data->Year);
+  I2C_Stop();
+}
+
+/**
+ * @brief Запись времени
+ */
+void RTC_WriteTime(rtc_t * data) {
+  I2C_Start();
+  I2C_WriteByte(DS3231_I2C_WRADDR);
+  I2C_WriteByte(DS3231_TIME_CAL_ADDR);
+  I2C_WriteByte(data->Sec);
+  I2C_WriteByte(data->Min);
+  I2C_WriteByte(data->Hr);
+  I2C_Stop();
+}
+
+/**
+ * @brief Запись часов и минут
+ */
+void RTC_WriteHHMM(rtc_t * data) {
+  I2C_Start();
+  I2C_WriteByte(DS3231_I2C_WRADDR);
+  I2C_WriteByte(DS3231_TIME_CAL_ADDR + 1);
+  I2C_WriteByte(data->Min);
+  I2C_WriteByte(data->Hr);
+  I2C_Stop();
+}
+
+/**
+ * @brief Запись календаря
+ */
+void RTC_WriteCalendar(rtc_t * data) {
+  I2C_Start();
+  I2C_WriteByte(DS3231_I2C_WRADDR);
+  I2C_WriteByte(DS3231_CALENDAR_ADDR);
+  I2C_WriteByte(data->WD);
+  I2C_WriteByte(data->Day);
+  I2C_WriteByte(data->Mon);
+  I2C_WriteByte(data->Year);
+  I2C_Stop();
+}
+
+/**
+ * @brief Convert BCD value to Binary
+ */
+uint8_t bcd2bin(uint8_t bcd)
+{
+    return (10 * (bcd >> 4) + (bcd & 0x0f));
+}
+
+/**
+ * @brief Convert Binary value to BCD
+ */
+uint8_t bin2bcd(uint8_t bin)
+{
+    return (((bin / 10 ) << 4) | (bin % 10));
+}

+ 209 - 0
src/event-system.c

@@ -0,0 +1,209 @@
+/**
+ *  Author(s)...: Pashgan    http://ChipEnable.Ru
+ *  Target(s)...: любой микроконтроллер mega
+ *  Compiler....: IAR 5.11A
+ *  Description.: Заготовка для событийной системы на таблицах
+ *  Data........: 30.09.12
+*/
+
+#include "event-system.h"
+#include <avr/pgmspace.h>
+
+/* функция-заглушка */
+static void EmptyFunc(void);
+
+/* кольцевой буфер */
+static volatile es_event_t cycleBuf[SIZE_BUF];
+static volatile uint8_t tailBuf = 0;
+static volatile uint8_t headBuf = 0;
+static volatile uint8_t countBuf = 0;
+
+static volatile es_state_t _State;
+
+typedef struct {
+    es_state_t state;
+    es_event_t event;
+    es_state_t nextState;
+    void (*pStateFunc1)(void);
+    void (*pStateFunc2)(void);
+} table_state_t;
+
+/** таблица состояний */
+const table_state_t stateTable[] PROGMEM = {
+/* STATE    EVENT   NEXT STATE  STATE_FUNC1 STATE_FUNC2 */
+  /* show date, time */
+  {stShowTime, evBTN1Pressed, stShowMMSS, dotOnPersistent, showMMSS},
+  {stShowMMSS, evBTN1Pressed, stShowWDay, showWDay,        dotOff},
+  {stShowWDay, evBTN1Pressed, stShowMDay, showMDay,        dotOff},
+  {stShowMDay, evBTN1Pressed, stShowMon,  showMonth,       dotOff},
+  {stShowMon,  evBTN1Pressed, stShowYear, showYear,        dotOff},
+#ifdef USE_BRIGHT_CONTROL
+  {stShowYear,   evBTN1Pressed, stShowBright, showBright, NULL},
+  {stShowBright, evBTN1Pressed, stShowTime,   showTime,   NULL},
+#else
+  {stShowYear, evBTN1Pressed, stShowTime, showTime, NULL},
+#endif
+#ifdef USE_DHT
+  {stShowTime,        evShTemp,      stShowTemperature,  dotOnPersistent, showTemperature},
+  {stShowTemperature, evShHum,       stShowHumidity,     showHumidity,    NULL},
+  {stShowHumidity,    evShTime,      stShowTime,         showTime,        NULL},
+  {stShowTemperature, evBTN1Pressed, stShowTime,         showTime,        NULL},
+  {stShowHumidity,    evBTN1Pressed, stShowTemperature,  dotOnPersistent, showTemperature},
+#endif // USE_DHT
+  /* display wdt */
+  {stShowWDay,   evDisplayWDT, stShowTime, showTime, NULL},
+  {stShowMDay,   evDisplayWDT, stShowTime, showTime, NULL},
+  {stShowMon,    evDisplayWDT, stShowTime, showTime, NULL},
+  {stShowYear,   evDisplayWDT, stShowTime, showTime, NULL},
+#ifdef USE_BRIGHT_CONTROL
+  {stShowBright, evDisplayWDT, stShowTime, showTime, NULL},
+#endif
+  /* refresh output */
+  {stShowTime, evNewSecond,  stNoChange, showTime,  NULL},
+  {stShowMMSS, evNewSecond,  stNoChange, showMMSS,  NULL},
+  {stShowWDay, evRefreshCal, stNoChange, showWDay,  NULL},
+  {stShowMDay, evRefreshCal, stNoChange, showMDay,  NULL},
+  {stShowMon,  evRefreshCal, stNoChange, showMonth, NULL},
+  {stShowYear, evRefreshCal, stNoChange, showYear,  NULL},
+  /* set time */
+  {stShowTime, evBTN1Holded,  stSetHH,    setTimeBegin, setHHBegin},
+  {stShowMMSS, evBTN1Holded,  stSetHH,    setTimeBegin, setMMBegin},
+  {stSetHH,    evBTN1Pressed, stSetMM,    setMMBegin,   NULL},
+  {stSetMM,    evBTN1Pressed, stSetHH,    setHHBegin,   NULL},
+  {stSetHH,    evNewSecond,   stNoChange, setTimeShow,  NULL},
+  {stSetMM,    evNewSecond,   stNoChange, setTimeShow,  NULL},
+  {stSetHH,    evBTN1Holded,  stShowTime, setTimeEnd,   showTime},
+  {stSetMM,    evBTN1Holded,  stShowTime, setTimeEnd,   showTime},
+  {stSetHH,    evBTN3Pressed, stNoChange, setHHInc,     setTimeShow},
+  {stSetHH,    evBTN2Pressed, stNoChange, setHHDec,     setTimeShow},
+  {stSetMM,    evBTN3Pressed, stNoChange, setMMInc,     setTimeShow},
+  {stSetMM,    evBTN2Pressed, stNoChange, setMMDec,     setTimeShow},
+  /* set calendar */
+  {stShowWDay, evBTN3Pressed, stNoChange, incWDay,  showWDay},
+  {stShowMDay, evBTN3Pressed, stNoChange, incMDay,  showMDay},
+  {stShowMon,  evBTN3Pressed, stNoChange, incMonth, showMonth},
+  {stShowYear, evBTN3Pressed, stNoChange, incYear,  showYear},
+  {stShowWDay, evBTN2Pressed, stNoChange, decWDay,  showWDay},
+  {stShowMDay, evBTN2Pressed, stNoChange, decMDay,  showMDay},
+  {stShowMon,  evBTN2Pressed, stNoChange, decMonth, showMonth},
+  {stShowYear, evBTN2Pressed, stNoChange, decYear,  showYear},
+  #ifdef USE_BRIGHT_CONTROL
+  /* set bright */
+  {stShowBright, evBTN3Pressed, stNoChange, incBright, showBright},
+  {stShowBright, evBTN2Pressed, stNoChange, decBright, showBright},
+  #endif // USE_BRIGHT_CONTROL
+  /* обязательная пустая строка таблицы */
+  {stNoChange, eventNull, stNoChange, EmptyFunc, EmptyFunc}
+};
+
+/**
+  * @brief  Take event.
+  * @param  None
+  * @retval Event
+  */
+es_event_t ES_GetEvent(void)
+{
+  es_event_t event;
+  if (countBuf > 0){
+    event = cycleBuf[headBuf];
+    countBuf--;
+    headBuf = (headBuf + 1) & (SIZE_BUF - 1);
+    return event;
+  }
+  return eventNull;
+}
+
+/**
+  * @brief  Place event.
+  * @param  Event
+  * @retval None
+  */
+void ES_PlaceEvent(es_event_t event)
+{
+  if (countBuf < SIZE_BUF){
+      cycleBuf[tailBuf] = event;
+      tailBuf = (tailBuf + 1) & (SIZE_BUF - 1);
+      countBuf++;
+  /* сигнализация переполнения буфера событий */
+//  } else {
+//      while(1);
+  }
+}
+
+/**
+  * @brief  Initialize event system.
+  * @param  Start Event
+  * @retval None
+  */
+void ES_Init(es_state_t init_state)
+{
+  tailBuf = 0;
+  headBuf = 0;
+  countBuf = 0;
+  _State = init_state;
+}
+
+/**
+  * @brief  Fake function.
+  * @param  None
+  * @retval None
+  */
+static void EmptyFunc(void)
+{
+}
+
+/* макросы для чтения флэш памяти */
+#define prb(data) pgm_read_byte(&(data))
+#define prw(data) pgm_read_word(&(data))
+
+/**
+  * @brief  Dispatcher of event system.
+  * @param  Event
+  * @retval None
+  */
+void ES_Dispatch(es_event_t event)
+{
+    uint8_t i;
+    void (*pStateFunc1)(void);
+    void (*pStateFunc2)(void);
+
+    pStateFunc1 = NULL;
+    pStateFunc2 = NULL;
+
+    /* определяем следующее состояние */
+    for (i=0; prb(stateTable[i].state); i++)
+    {
+        /* если совпадают текущее состояние и поступившее событие */
+        if (prb(stateTable[i].state) == _State && prb(stateTable[i].event) == event)
+        {
+            /* меняем состояние если требуется */
+            if (prb(stateTable[i].nextState) != stNoChange) {
+                _State = prb(stateTable[i].nextState);
+            }
+            /* получаем адреса функций */
+            pStateFunc1 = (void *)prw(stateTable[i].pStateFunc1);
+            pStateFunc2 = (void *)prw(stateTable[i].pStateFunc2);
+            break;
+        }
+    }
+    if (pStateFunc1) pStateFunc1();
+    if (pStateFunc2) pStateFunc2();
+}
+
+/**
+  * @brief  Return current state code.
+  * @param  None
+  * @retval Event
+  */
+es_state_t ES_GetState(void) {
+  return _State;
+}
+
+/**
+  * @brief  Set current state to given code .
+  * @param  Event
+  * @retval None
+  */
+void ES_SetState(es_state_t new_state) {
+  _State = new_state;
+}

+ 10 - 0
src/fuse.c

@@ -0,0 +1,10 @@
+#include <avr/io.h>
+
+/**
+ * avrdude: -U lfuse:w:0x3e:m -U hfuse:w:0xc9:m
+ */
+
+FUSES = {
+    .low = 0x3E,
+    .high = 0xC9
+};

+ 174 - 0
src/i2c.c

@@ -0,0 +1,174 @@
+/****************************************************
+Low Level I2C Data Transreceiveing APIs
+
+PLEASE SEE WWW.EXTREMEELECTRONICS.CO.IN FOR DETAILED
+SCHEMATICS,USER GUIDE AND VIDOES.
+
+COPYRIGHT (C) 2008-2009 EXTREME ELECTRONICS INDIA
+****************************************************/
+
+#include <avr/io.h>
+#include "i2c.h"
+
+/* Private defines */
+// twi_br must be 3
+#define TWI_SPEED       400000UL
+#define TWI_PRESCALER   4
+#define TWI_BR          ((F_CPU / TWI_SPEED) - 16) / (2 * TWI_PRESCALER)
+#define TWPS_1          ((0<<TWPS1) | (0<<TWPS0))
+#define TWPS_4          ((0<<TWPS1) | (1<<TWPS0))
+#define TWPS_16         ((1<<TWPS1) | (0<<TWPS0))
+#define TWPS_64         ((1<<TWPS1) | (1<<TWPS0))
+#define TWI_PS          TWPS_4
+
+#define TWI_WDT_TIMEOUT 10
+
+/* Private variables */
+uint8_t TWI_WDT;
+
+/**
+ * @brief Initialize TWI
+ * @param None
+ * @return None
+ */
+void I2C_Init(void) {
+  //Set up TWI Module
+  TWSR = TWI_PS;
+  TWBR = TWI_BR;
+
+  //Enable the TWI Module
+  TWCR |= 1<<TWEN;
+}
+
+/**
+ * @brief Disable TWI
+ * @param None
+ * @return None
+ */
+void I2C_Close(void)
+{
+  //Disable the module
+  TWCR &= ~(1<<TWEN);
+}
+
+/**
+ * @brief TWI Start condition
+ * @param None
+ * @return Operation status
+ */
+twi_stats_t I2C_Start(void) {
+  //Put Start Condition on Bus
+  TWCR= (1<<TWINT) | (1<<TWEN) | (1<<TWSTA);
+
+  //Poll Till Done
+  TWI_WDT = TWI_WDT_TIMEOUT;
+  while (!(TWCR & (1<<TWINT))) {
+    if (TWI_WDT == 0) {
+      return TWI_TIMEOUT;
+    }
+  }
+
+  if ((TWSR & 0xF8) == 0x08 || (TWSR & 0xF8) == 0x10) {
+    //start condition sent from master
+    //or
+    //repeat start condition sent from master
+    return TWI_SUCCESS;
+  } else {
+    return TWI_ERROR;
+  }
+
+}
+
+/**
+ * @brief TWI Stop condition
+ * @param None
+ * @return Operation status
+ */
+twi_stats_t I2C_Stop(void) {
+  //Put Stop Condition on bus
+  TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO);
+
+  //Wait for STOP to finish
+  // зачем это ждать тут? проверять перед стартом и всё!
+  TWI_WDT = TWI_WDT_TIMEOUT;
+  while (TWCR & (1<<TWSTO)) {
+    if (TWI_WDT == 0) {
+      return TWI_TIMEOUT;
+    }
+  }
+  return TWI_SUCCESS;
+}
+
+/**
+ * @brief TWI Send Byte
+ * @param None
+ * @return Operation status
+ */
+twi_stats_t I2C_WriteByte(uint8_t data) {
+
+  TWDR = data;
+
+  //Initiate Transfer
+  TWCR = (1<<TWEN) | (1<<TWINT);
+
+  //Poll Till Done
+  TWI_WDT = TWI_WDT_TIMEOUT;
+  while (!(TWCR & (1<<TWINT))) {
+    if (TWI_WDT == 0) {
+      return TWI_TIMEOUT;
+    }
+  }
+
+  //Check Status
+  if ((TWSR & 0xF8) == 0x18 || (TWSR & 0xF8) == 0x28 || (TWSR & 0xF8) == 0x40) {
+    //SLA+W Transmitted and ACK received
+    //or
+    //SLA+R Transmitted and ACK received
+    //or
+    //DATA Transmitted and ACK recived
+    return TWI_SUCCESS;
+  } else {
+    return TWI_ERROR;  //Error
+  }
+}
+
+/**
+ * @brief TWI Receive Byte
+ * @param None
+ * @return Operation status
+ */
+twi_stats_t I2C_ReadByte(uint8_t *data, twi_ask_t ack) {
+  //Set up ACK
+  if (ack == TWI_ACK) {
+    //return ACK after reception
+    TWCR |= (1<<TWEA);
+  } else {
+    //return NACK after reception
+    //Signals slave to stop giving more data
+    //usually used for last byte read.
+    TWCR &= ~(1<<TWEA);
+  }
+
+  //Now enable Reception of data by clearing TWINT
+  TWCR |= (1<<TWINT);
+
+  //Wait till done
+  TWI_WDT = TWI_WDT_TIMEOUT;
+  while(!(TWCR & (1<<TWINT))) {
+    if (TWI_WDT == 0) {
+      return TWI_TIMEOUT;
+    }
+  }
+
+  //Check status
+  if ((TWSR & 0xF8) == 0x58 || (TWSR & 0xF8) == 0x50) {
+    //Data received and ACK returned
+    //  or
+    //Data received and NACK returned
+    //Read the data
+    *data = TWDR;
+    return TWI_SUCCESS;
+  } else {
+    return TWI_ERROR;  //Error
+  }
+}

+ 824 - 0
src/main.c

@@ -0,0 +1,824 @@
+/**
+ * My Nixie Clock IN-12
+ * Vladimir N. Shilov <shilow@ukr.net>
+ * 2019.01.18
+ */
+/* Compiler libs */
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <avr/io.h>
+#include <avr/interrupt.h>
+#include <avr/sleep.h>
+#include <avr/eeprom.h>
+#include <avr/pgmspace.h>
+
+/* Project libs */
+#include "i2c.h"
+#include "ds3231.h"
+#include "rtos.h"
+#include "event-system.h"
+#include "common.h"
+#include "main.h"
+
+/* Defines */
+/* Timer2 settings */
+#define TIMER2_HZ         400
+#define TIMER2_PRESCALER  1024
+#define TIMER2_CS         (1<<CS22 | 1<<CS21 | 1<<CS20)
+#define TIMER2_CNT        (0x100 - (F_CPU / TIMER2_PRESCALER / TIMER2_HZ))
+
+/* Display timeout, sec */
+#define DISP_WDT_TIME   10
+
+#ifdef USE_UART
+/* USART */
+#define BAUD            19200UL
+#define BAUD_PRESCALE   (uint8_t)((F_CPU / BAUD / 16UL) - 1)
+#define CHAR_NEWLINE    '\n'
+#define CHAR_RETURN     '\r'
+#define RETURN_NEWLINE  "\r\n"
+#endif // USE_UART
+
+#ifdef USE_BRIGHT_CONTROL
+/* Lamp brightness */
+#define BRIGHT_IDX_MAX    4
+#define FULL_BRIGHT_ON    0x06
+#define FULL_BRIGHT_OFF   0x22
+static const uint8_t PROGMEM brightConv[BRIGHT_IDX_MAX+1] = {
+  218, 225, 230, 240, 255
+};
+#endif // USE_BRIGHT_CONTROL
+
+#ifdef USE_DHT
+// timeout in timer tiks, step 4 mks
+#define DHT_TIMEOUT       1500
+#define DHT_TOUT1         55
+static struct {
+  uint8_t Humidity;
+  uint16_t Temperature;
+} dhtData;
+#endif // USE_DHT
+
+
+/* Variables */
+static volatile uint8_t Digit[4] = {1, 2, 3, 4};
+static rtc_t RTC, setRTC;
+static volatile struct {
+  uint8_t RTC_Int:  1;
+  uint8_t saveCal:  1;
+  uint8_t blinkC:   1;
+  uint8_t blink0:   1;
+  uint8_t blink1:   1;
+  uint8_t blink2:   1;
+  uint8_t blink3:   1;
+  uint8_t saveEEP:  1;
+} Flag;
+static btn_t Button[BTN_NUM] = {
+  {0, evBTN1Pressed, evBTN1Holded, BUTTON1_PIN},
+  {0, evBTN2Pressed, evBTN2Pressed, BUTTON2_PIN},
+  {0, evBTN3Pressed, evBTN3Pressed, BUTTON3_PIN}
+};
+static volatile uint8_t DISP_WDT = 0;
+static EEMEM uint8_t EEP_BrightIdx;
+static uint8_t brightIdx;
+static EEMEM uint8_t EEP_SummerTime;
+
+/* Function prototypes */
+static void Board_Init(void);
+static void dotOn(void);
+static void btnProcess(void);
+static void valIncrease(uint8_t * val, uint8_t max);
+static void valDecrease(uint8_t * val, uint8_t max);
+static void blink(void);
+static void setSummerWinterTime(void);
+#ifdef USE_DHT
+static void dhtStart(void);
+static void dhtProcess(void);
+static void dhtEnd(void);
+static void dhtTimeout(void);
+static void dhtNoAck(void);
+#endif // USE_DHT
+#ifdef USE_UART
+void usart_putc (char send);
+void usart_puts (const char *send);
+#endif // USE_UART
+
+void main(void) {
+  /**
+   * Локальные переменные
+   */
+  uint8_t event = 0;
+  Flag.RTC_Int = 0;
+  Flag.saveCal = 0;
+  Flag.blink0 = 0;
+  Flag.blink1 = 0;
+  Flag.blink2 = 0;
+  Flag.blink3 = 0;
+  Flag.blinkC = 0;
+  Flag.saveEEP = 0;
+
+#ifdef USE_BRIGHT_CONTROL
+  brightIdx = eeprom_read_byte(&EEP_BrightIdx);
+  if (brightIdx > BRIGHT_IDX_MAX) {
+    brightIdx = BRIGHT_IDX_MAX;
+  }
+#endif // USE_BRIGHT_CONTROL
+
+  /**
+   * Инициализация, настройка...
+   */
+  Board_Init();
+
+  /* Initialize Scheduler */
+  RTOS_Init();
+
+  /* Initialize I2C Bus and RTC */
+  I2C_Init();
+  RTC_Init();
+  RTC_ReadAll(&RTC);
+
+  /* Initialize Event State Machine */
+  ES_Init(stShowTime);
+
+  showTime();
+
+  RTOS_SetTask(btnProcess, 3, BTN_SCAN_PERIOD);
+#ifdef USE_DHT
+  RTOS_SetTask(dhtStart, 2000, 15000);
+#endif // USE_DHT
+
+  /** main loop */
+  do {
+    /* new second interrupt from RTC */
+    if (Flag.RTC_Int != 0) {
+      Flag.RTC_Int = 0;
+      ES_PlaceEvent(evNewSecond);
+
+      RTC_ReadTime(&RTC);
+      if (RTC.Sec == 0 && RTC.Min == 0) {
+        // begin of new hour
+        if (RTC.Hr == 0) {
+          RTC_ReadCalendar(&RTC);
+          ES_PlaceEvent(evRefreshCal);
+        }
+#ifdef USE_BRIGHT_CONTROL
+        if (RTC.Hr >= FULL_BRIGHT_ON && RTC.Hr < FULL_BRIGHT_OFF) {
+          OCR2 = pgm_read_byte(&brightConv[BRIGHT_IDX_MAX]);
+        } else {
+          OCR2 = pgm_read_byte(&brightConv[brightIdx]);
+        }
+#endif // USE_BRIGHT_CONTROL
+
+        setSummerWinterTime();
+      } // begin new hour
+
+      if (DISP_WDT != 0) {
+        DISP_WDT --;
+        if (DISP_WDT == 0) {
+          ES_PlaceEvent(evDisplayWDT);
+
+          if (Flag.saveCal != 0) {
+            Flag.saveCal = 0;
+            RTC_WriteCalendar(&RTC);
+          }
+
+          if (Flag.saveEEP != 0) {
+            Flag.saveEEP = 0;
+            eeprom_update_byte(&EEP_BrightIdx, brightIdx);
+          }
+        }
+      }
+#ifdef USE_DHT
+      switch(RTC.Sec) {
+      case 0x20:
+      case 0x50:
+        ES_PlaceEvent(evShTemp);
+        break;
+
+      case 0x22:
+      case 0x52:
+        ES_PlaceEvent(evShHum);
+        break;
+
+      case 0x24:
+      case 0x54:
+        ES_PlaceEvent(evShTime);
+        break;
+      }
+#endif // USE_DHT
+    } // End of New Second
+
+    event = ES_GetEvent();
+    if (event) {
+      ES_Dispatch(event);
+    }
+
+    // крутим диспетчер
+    RTOS_DispatchTask();
+
+    // делать нечего -- спим, ждём прерывание
+    set_sleep_mode(SLEEP_MODE_IDLE);
+    sleep_mode();
+
+  } while(1);
+}
+
+/**
+ *  П о д п р о г р а м м ы
+ */
+
+/**
+ * @brief Initializy perephireal
+ */
+static void Board_Init(void) {
+  /* power off Analog Comparator */
+  ACSR = ACD;
+
+  /* GPIO */
+  PORTB = BUTTON_PINS; // enable pull-up
+  DDRC = DIGIT_PINS; // as output
+  DDRD = (DOT_PIN | ANOD_PINS); // as output
+
+#ifdef USE_DHT
+  /* Timer1, IC negative edge, CTC mode, 64 prescaler, 4 mks one tick */
+  TCCR1B = ((0<<ICES1) | (1<<CS11) | (1<<CS10));
+#endif // USE_DHT
+
+  /* Timer2 - refresh Nixie values */
+  TCCR2 = TIMER2_CS;
+  TCNT2 = TIMER2_CNT;
+  TIMSK = _BV(TOIE2);
+
+#ifdef USE_BRIGHT_CONTROL
+  OCR2 = pgm_read_byte(&brightConv[BRIGHT_IDX_MAX]);
+  TIMSK |= _BV(OCIE2);
+#endif // USE_BRIGHT_CONTROL
+
+  /* Interrupt from RTC */
+  MCUCR = _BV(ISC11); // falling edge
+  GICR = _BV(INT1);
+
+#ifdef USE_UART
+  /* USART */
+  // Turn on USART hardware (no RX, TX)
+  UCSRB |= (0 << RXEN) | (1 << TXEN);
+  // 8 bit char sizes
+  UCSRC |= (1 << UCSZ0) | (1 << UCSZ1);
+  // Set baud rate
+  UBRRH = (BAUD_PRESCALE >> 8);
+  UBRRL = BAUD_PRESCALE;
+#endif // USE_UART
+
+  /* Enable Interrupts */
+  sei();
+}
+
+/**
+ * @brief Correct current time for Sun or Winter
+ */
+static void setSummerWinterTime(void) {
+  uint8_t sunTime = eeprom_read_byte(&EEP_SummerTime);
+
+  /* Переход на летнее время */
+  if ((RTC.Mon == 3) && (RTC.WD == 7) && (RTC.Hr == 3) && (sunTime != 0)) {
+    if ((RTC.Day + 7) > 31) {
+      RTC.Hr = 4;
+      RTC_WriteHHMM(&RTC);
+      sunTime = 0;
+    }
+  }
+
+  /* Переход на зимнее время */
+  if ((RTC.Mon == 10) && (RTC.WD == 7) && (RTC.Hr == 4) && (sunTime == 0)) {
+    if ((RTC.Day + 7) > 31) {
+      RTC.Hr = 3;
+      RTC_WriteHHMM(&RTC);
+      sunTime = 1;
+    }
+  }
+
+  eeprom_update_byte(&EEP_SummerTime, sunTime);
+}
+
+static void dotOn(void) {
+  PORTD |= DOT_PIN;
+}
+
+void dotOff(void) {
+  PORTD &= ~(DOT_PIN);
+}
+
+void dotOnPersistent(void) {
+  RTOS_DeleteTask(dotOff);
+  PORTD |= DOT_PIN;
+}
+
+#ifdef USE_DHT
+static void dhtStart(void) {
+  RTOS_SetTask(dhtProcess, 2, 0);
+  DHT_PIN_LOW;
+}
+
+static void dhtProcess(void) {
+  uint8_t cnt1, cnt2, buf;
+  uint16_t tcnt_old, hmdt, tmprtr;
+
+  DHT_PIN_INPUT;
+  TCNT1 = 0;
+
+  // ждём первого "0"
+  while(bit_is_set(PINB, PB0) && TCNT1<DHT_TOUT1);
+  if (TCNT1 >= DHT_TOUT1) {
+    RTOS_SetTask(dhtNoAck, 0, 0);
+    return;
+  }
+  // white for end of preamble
+  while(bit_is_clear(PINB, PB0));
+  while(bit_is_set(PINB, PB0) && TCNT1<DHT_TIMEOUT);
+  if (TCNT1 >= DHT_TIMEOUT) {
+    RTOS_SetTask(dhtTimeout, 0, 0);
+  }
+  hmdt = 0; tmprtr = 0;
+  for (cnt1=0; cnt1<32; cnt1+=8) { // 0 8 16 24 32
+    buf = 0;
+    for (cnt2=0; cnt2<8; cnt2++) {
+      buf <<= 1;
+      // "0", начало периода
+      while(bit_is_clear(PINB, PB0)); // ждём начало импульса
+      tcnt_old = TCNT1; // начало импульса
+      while(bit_is_set(PINB, PB0) && TCNT1<DHT_TIMEOUT); // ждём конец импульса
+      if ((TCNT1 - tcnt_old) > 10) {
+        buf |= 1;
+      }
+    }
+    switch (cnt1) {
+    case 0:
+      hmdt = buf << 8;
+      break;
+    case 8:
+      hmdt |= buf;
+      break;
+    case 16:
+      tmprtr = buf << 8;
+      break;
+    case 24:
+      tmprtr |= buf;
+      break;
+    }
+  }
+  if (TCNT1 >= DHT_TIMEOUT) {
+    RTOS_SetTask(dhtTimeout, 0, 0);
+    return;
+  }
+
+  dhtData.Humidity = (uint8_t)((hmdt + 5) / 10);
+  dhtData.Temperature = tmprtr;
+
+  RTOS_SetTask(dhtEnd, 0, 0);
+}
+
+static void dhtEnd(void) {
+#ifdef USE_UART
+  char buffer[6];
+
+  usart_puts("Humidity: ");
+  itoa(dhtData.Humidity, buffer, 10);
+  usart_puts(buffer);
+  usart_puts(" %\t\t");
+
+  usart_puts("Temperature: ");
+  itoa(dhtData.Temperature/10, buffer, 10);
+  usart_puts(buffer);
+  usart_putc('.');
+  itoa(dhtData.Temperature%10, buffer, 10);
+  usart_puts(buffer);
+  usart_puts("oC\r\n");
+#endif // USE_UART
+}
+
+static void dhtNoAck(void) {
+#ifdef USE_UART
+  usart_puts("DHT22 no ACK occurred.\r\n");
+#endif // USE_UART
+}
+
+static void dhtTimeout(void) {
+#ifdef USE_UART
+  usart_puts("DHT22 Timeout occurred.\r\n");
+#endif // USE_UART
+}
+
+void showTemperature(void) {
+  uint8_t a = dhtData.Temperature / 10;
+  uint8_t b = dhtData.Temperature % 10;
+  Digit[0] = a / 10;
+  Digit[1] = a % 10;
+  Digit[2] = b;
+  Digit[3] = DIGIT_BLANK;
+}
+
+void showHumidity(void) {
+  Digit[0] = DIGIT_BLANK;
+  Digit[1] = DIGIT_BLANK;
+  Digit[2] = dhtData.Humidity / 10;
+  Digit[3] = dhtData.Humidity % 10;}
+#endif // USE_DHT
+
+/**
+  * @brief  Обработка кнопок.
+  * @param  : None
+  * @retval : None
+  */
+static void btnProcess(void) {
+  uint8_t i;
+  for (i=0; i<BTN_NUM; i++) {
+    if (Button[i].pin != 0) {
+      // button pressed
+      if (BUTTON_STATE(Button[i].pin) == 0) {
+        Button[i].time ++;
+        if (Button[i].time >= BTN_TIME_HOLDED) {
+          Button[i].time -= BTN_TIME_REPEATED;
+          if (Button[i].holded == Button[i].pressed) {
+            // if pressed and holded - same function, then button pressed auto repeat
+            ES_PlaceEvent(Button[i].pressed);
+          }
+        }
+      } else {
+        // button released
+        if (Button[i].time >= (BTN_TIME_HOLDED - BTN_TIME_REPEATED)) {
+          ES_PlaceEvent(Button[i].holded); // process long press
+        } else if (Button[i].time >= BTN_TIME_PRESSED) {
+          ES_PlaceEvent(Button[i].pressed); // process short press
+        }
+        Button[i].time = 0;
+        RTOS_SetTask(btnProcess, BTN_TIME_PAUSE, BTN_SCAN_PERIOD);
+      }
+    } /* end (pin == 0) */
+  } /* end FOR */
+}
+
+void showTime(void) {
+  dotOn();
+  RTOS_SetTask(dotOff, 500, 0);
+
+  if (RTC.Hr > 0x09) {
+    Digit[0] = RTC.Hr >> 4;
+  } else {
+    Digit[0] = DIGIT_BLANK;
+  }
+  Digit[1] = RTC.Hr & 0x0F;
+  Digit[2] = RTC.Min >> 4;
+  Digit[3] = RTC.Min & 0x0F;
+}
+
+void showMMSS(void) {
+  Digit[0] = RTC.Min >> 4;
+  Digit[1] = RTC.Min & 0x0F;
+  Digit[2] = RTC.Sec >> 4;
+  Digit[3] = RTC.Sec & 0x0F;
+}
+
+void showWDay(void) {
+  DISP_WDT = DISP_WDT_TIME;
+  Digit[0] = DIGIT_BLANK;
+  Digit[1] = DIGIT_BLANK;
+  Digit[2] = RTC.WD & 0x0F;
+  Digit[3] = DIGIT_BLANK;
+}
+
+void showMDay(void) {
+  DISP_WDT = DISP_WDT_TIME;
+  Digit[0] = RTC.Day >> 4;
+  Digit[1] = RTC.Day & 0x0F;
+  Digit[2] = DIGIT_BLANK;
+  Digit[3] = DIGIT_BLANK;
+}
+
+void showMonth(void) {
+  DISP_WDT = DISP_WDT_TIME;
+  Digit[0] = DIGIT_BLANK;
+  Digit[1] = DIGIT_BLANK;
+  Digit[2] = RTC.Mon >> 4;
+  Digit[3] = RTC.Mon & 0x0F;
+}
+
+void showYear(void) {
+  DISP_WDT = DISP_WDT_TIME;
+  Digit[0] = 0x02;
+  Digit[1] = 0x00;
+  Digit[2] = RTC.Year >> 4;
+  Digit[3] = RTC.Year & 0x0F;
+}
+
+void incWDay(void) {
+  if (RTC.WD < 7) {
+    RTC.WD ++;
+  } else {
+    RTC.WD = 1;
+  }
+  Flag.saveCal = 1;
+}
+
+void decWDay(void) {
+  if (RTC.WD > 1) {
+    RTC.WD --;
+  } else {
+    RTC.WD = 7;
+  }
+  Flag.saveCal = 1;
+}
+
+void incMDay(void) {
+  valIncrease(&RTC.Day, 31);
+  Flag.saveCal = 1;
+}
+
+void decMDay(void) {
+  valDecrease(&RTC.Day, 31);
+  Flag.saveCal = 1;
+}
+
+void incMonth(void) {
+  valIncrease(&RTC.Mon, 12);
+  if (RTC.Mon == 0) {
+    RTC.Mon = 1;
+  }
+  Flag.saveCal = 1;
+}
+
+void decMonth(void) {
+  valDecrease(&RTC.Mon, 12);
+  if (RTC.Mon == 0) {
+    RTC.Mon = 0x12;
+  }
+  Flag.saveCal = 1;
+}
+
+void incYear(void) {
+  valIncrease(&RTC.Year, 99);
+  Flag.saveCal = 1;
+}
+
+void decYear(void) {
+  valDecrease(&RTC.Year, 99);
+  Flag.saveCal = 1;
+}
+
+#ifdef USE_BRIGHT_CONTROL
+void showBright(void) {
+  DISP_WDT = DISP_WDT_TIME;
+  Digit[0] = DIGIT_BLANK;
+  Digit[1] = DIGIT_BLANK;
+  Digit[2] = brightIdx;
+  Digit[3] = DIGIT_BLANK;
+}
+
+void incBright(void) {
+  if (brightIdx < BRIGHT_IDX_MAX) {
+    brightIdx ++;
+    OCR2 = pgm_read_byte(&brightConv[brightIdx]);
+    Flag.saveEEP = 1;
+  }
+}
+
+void decBright(void) {
+  if (brightIdx > 0 ) {
+    brightIdx --;
+    OCR2 = pgm_read_byte(&brightConv[brightIdx]);
+    Flag.saveEEP = 1;
+  }
+}
+#endif // USE_BRIGHT_CONTROL
+
+static void blink(void) {
+  static uint8_t s = 0;
+  switch (s) {
+  case 0:
+    Flag.blinkC = 0;
+    RTOS_SetTask(blink, 750, 0);
+    s = 1;
+    break;
+
+  case 1:
+    Flag.blinkC = 1;
+    RTOS_SetTask(blink, 250, 0);
+    s = 0;
+    break;
+
+  default:
+    s = 0;
+  }
+}
+
+void setTimeShow(void) {
+  dotOn();
+  RTOS_SetTask(dotOff, 500, 0);
+
+  Digit[0] = setRTC.Hr >> 4;
+  Digit[1] = setRTC.Hr & 0x0F;
+  Digit[2] = setRTC.Min >> 4;
+  Digit[3] = setRTC.Min & 0x0F;
+}
+
+void setTimeBegin(void) {
+  RTC_ReadTime(&setRTC);
+  RTOS_SetTask(btnProcess, 500, BTN_SCAN_PERIOD);
+}
+
+void setHHBegin(void) {
+  Flag.blink0 = 1;
+  Flag.blink1 = 1;
+  Flag.blink2 = 0;
+  Flag.blink3 = 0;
+  RTOS_SetTask(blink, 0, 0);
+  setTimeShow();
+}
+
+void setHHInc(void) {
+  valIncrease(&setRTC.Hr, 23);
+}
+
+void setHHDec(void) {
+  valDecrease(&setRTC.Hr, 23);
+}
+
+void setMMBegin(void) {
+  Flag.blink0 = 0;
+  Flag.blink1 = 0;
+  Flag.blink2 = 1;
+  Flag.blink3 = 1;
+  RTOS_SetTask(blink, 0, 0);
+  setTimeShow();
+}
+
+void setMMInc(void) {
+  valIncrease(&setRTC.Min, 59);
+}
+
+void setMMDec(void) {
+  valDecrease(&setRTC.Min, 59);
+}
+
+void setTimeEnd(void) {
+  RTOS_SetTask(btnProcess, 500, BTN_SCAN_PERIOD);
+
+  setRTC.Sec = 0;
+  RTC_WriteTime(&setRTC);
+
+  RTOS_DeleteTask(blink);
+  Flag.blink0 = 0;
+  Flag.blink1 = 0;
+  Flag.blink2 = 0;
+  Flag.blink3 = 0;
+  Flag.blinkC = 0;
+
+  RTC_ReadTime(&RTC);
+}
+
+/**
+  * @brief  Increase BCD value.
+  * @param  : val, max
+  * @retval : None
+  */
+static void valIncrease(uint8_t * val, uint8_t max) {
+  uint8_t bin = 10 * (*val >> 4) + (*val & 0x0f);
+  if (bin < max) {
+    bin ++;
+  } else {
+    bin = 0;
+  }
+  *val = ((bin / 10 ) << 4) | (bin % 10);
+}
+
+/**
+  * @brief  Decrease BCD value.
+  * @param  : value, max
+  * @retval : None
+  */
+static void valDecrease(uint8_t * val, uint8_t max) {
+  uint8_t bin = 10 * (*val >> 4) + (*val & 0x0f);
+  if (bin > 0) {
+    bin --;
+  } else {
+    bin = max;
+  }
+  *val = ((bin / 10 ) << 4) | (bin % 10);
+}
+
+#ifdef USE_UART
+void usart_putc (char send) {
+    // Do nothing for a bit if there is already
+    // data waiting in the hardware to be sent
+    while ((UCSRA & (1 << UDRE)) == 0) {};
+    UDR = send;
+}
+
+void usart_puts (const char *send) {
+    // Cycle through each character individually
+    while (*send) {
+        usart_putc(*send++);
+    }
+}
+#endif // USE_UART
+
+/**
+ *  П р е р ы в а н и я
+ */
+
+/**
+ * @brief RTC one seconds interrupt
+ */
+ISR (INT1_vect) {
+  Flag.RTC_Int = 1;
+}
+
+/**
+ * @brief Refresh Nixie output
+ * @note  Digit[] must be in range 0x00 - 0x0F
+ */
+#pragma GCC optimize ("O3")
+ISR(TIMER2_OVF_vect) {
+  static uint8_t idx = 0;
+
+  // reload timer
+  TCNT2 = TIMER2_CNT;
+
+  // read current register value and clean bits
+  uint8_t pd = PORTD & ~ANOD_PINS;
+  uint8_t pc = PORTC & ~DIGIT_PINS;
+
+#ifndef USE_BRIGHT_CONTROL
+  // power off lamps
+  PORTD = pd;
+  PORTC = pc;
+#endif
+
+  switch (idx) {
+  case 0:
+    // output lamp value
+    PORTC = pc | Digit[0];
+    // power on lamp
+    if (Digit[0] != DIGIT_BLANK) {
+      if (Flag.blink0 == 0 || Flag.blinkC == 0) {
+        PORTD = pd | ANOD1;
+      }
+    }
+    idx = 1;
+    break;
+
+  case 1:
+    PORTC = pc | Digit[1];
+    if (Digit[1] != DIGIT_BLANK) {
+      if (Flag.blink1 == 0 || Flag.blinkC == 0) {
+        PORTD = pd | ANOD2;
+      }
+    }
+    idx = 2;
+    break;
+
+  case 2:
+    PORTC = pc | Digit[2];
+    if (Digit[2] != DIGIT_BLANK) {
+      if (Flag.blink2 == 0 || Flag.blinkC == 0) {
+        PORTD = pd | ANOD3;
+      }
+    }
+    idx = 3;
+    break;
+
+  case 3:
+    PORTC = pc | Digit[3];
+    if (Digit[3] != DIGIT_BLANK) {
+      if (Flag.blink3 == 0 || Flag.blinkC == 0) {
+        PORTD = pd | ANOD4;
+      }
+    }
+    idx = 0;
+    break;
+
+  default:
+    idx = 0;
+    break;
+  }
+}
+
+#ifdef USE_BRIGHT_CONTROL
+/**
+ * @brief Power Off Nixie output
+ * @note  For Brightnes dimming
+ */
+#pragma GCC optimize ("O3")
+ISR(TIMER2_COMP_vect) {
+  // power off lamps
+  PORTD &= ~ANOD_PINS;
+  PORTC &= ~DIGIT_PINS;
+}
+#endif // USE_BRIGHT_CONTROL
+
+/**
+ * @brief заглушка для неиспользуемых прерываний
+ */
+ISR(__vector_default,ISR_NAKED) {
+  reti();
+}

+ 186 - 0
src/rtos.c

@@ -0,0 +1,186 @@
+#include <avr/sleep.h>
+#include <avr/interrupt.h>
+#include "rtos.h"
+
+static volatile uint8_t saveRegister;
+#define  ENABLE_INTERRUPT sei()
+#define DISABLE_INTERRUPT saveRegister = SREG; cli()
+#define RESTORE_INTERRUPT SREG = saveRegister
+//использовать RESTORE только после DISABLE
+
+/*
+ * Переменные модуля
+ */
+static volatile task TaskArray[MAX_TASKS]; // очередь задач
+static volatile uint8_t arrayTail;         // "хвост" очереди
+
+// внешние переменные
+extern uint8_t TWI_WDT;
+
+// счётчик задержки
+static volatile uint16_t TDelay;
+
+/*
+ * Инициализация РТОС и t_delay, время тика - 1 мс
+ */
+inline void RTOS_Init(void) {
+  // настраиваем основной таймер
+  TIMER_TCCR = TIMER_CSB;
+  TIMER_TCNT = TIMER_CNT;
+  TIMER_TIMSK |= TIMER_INT;
+
+  // "хвост" в 0
+  arrayTail = 0;
+}
+
+/*
+ * Добавление задачи в список
+ */
+void RTOS_SetTask (void (*taskFunc)(void), uint16_t taskDelay, uint16_t taskPeriod) {
+   uint8_t i;
+
+   if (!taskFunc) {
+    return;
+   }
+
+   // поиск задачи в текущем списке
+   for(i = 0; i < arrayTail; i++) {
+      // если нашли, то обновляем переменные
+      if (TaskArray[i].pFunc == taskFunc) {
+         DISABLE_INTERRUPT;
+
+         TaskArray[i].delay  = taskDelay;
+         TaskArray[i].period = taskPeriod;
+         TaskArray[i].run    = 0;
+
+         RESTORE_INTERRUPT;
+         // обновив, выходим
+         return;
+      }
+   }
+
+   // если такой задачи в списке нет
+   if (arrayTail < MAX_TASKS) {
+      // и есть место, то добавляем
+      DISABLE_INTERRUPT;
+
+      TaskArray[arrayTail].pFunc  = taskFunc;
+      TaskArray[arrayTail].delay  = taskDelay;
+      TaskArray[arrayTail].period = taskPeriod;
+      TaskArray[arrayTail].run    = 0;
+
+      // увеличиваем "хвост"
+      arrayTail++;
+      RESTORE_INTERRUPT;
+   } else {
+     while(1);
+   }
+}
+
+/*
+ * Удаление задачи из списка
+ */
+inline void RTOS_DeleteTask (void (*taskFunc)(void)) {
+   uint8_t i;
+
+   // проходим по списку задач
+   for (i=0; i<arrayTail; i++) {
+      // если задача в списке найдена
+      if (TaskArray[i].pFunc == taskFunc) {
+         DISABLE_INTERRUPT;
+         // переносим последнюю задачу
+         if (i != (arrayTail - 1)) {
+            // на место удаляемой
+            TaskArray[i] = TaskArray[arrayTail - 1];
+         }
+         // уменьшаем указатель "хвоста"
+         arrayTail--;
+         RESTORE_INTERRUPT;
+         return;
+      }
+   }
+}
+
+/*
+ * Диспетчер РТОС, вызывается в main
+ */
+void RTOS_DispatchTask(void) {
+   uint8_t i;
+   void (*function) (void);
+   // проходим по списку задач
+   for (i=0; i<arrayTail; i++) {
+      // если флаг на выполнение взведен,
+      if (TaskArray[i].run != 0) {
+        // запоминаем задачу, т.к. во время выполнения может измениться индекс
+        function = TaskArray[i].pFunc;
+        if (TaskArray[i].period == 0) {
+          // если период равен 0, удаляем задачу из списка,
+          RTOS_DeleteTask(TaskArray[i].pFunc);
+        } else {
+          // иначе снимаем флаг запуска
+          TaskArray[i].run = 0;
+          // если задача не изменила задержку
+          if (!TaskArray[i].delay) {
+            // задаем ее
+            TaskArray[i].delay = TaskArray[i].period-1;
+            // задача для себя может сделать паузу
+          }
+        }
+        // выполняем задачу
+        (*function)();
+      }
+   }
+}
+
+/*
+ * Delay, msek
+ * также, что-бы зря не терять время -- крутим диспетчер
+ */
+void tdelay_ms(uint16_t msek) {
+
+  TDelay = msek;
+
+  do {
+    if (TDelay > 1) {
+      RTOS_DispatchTask();
+    }
+    // делать нехрен -- спим, ждём прерывание
+    set_sleep_mode(SLEEP_MODE_IDLE);
+    sleep_mode();
+  } while (TDelay != 0);
+
+}
+
+/******************************************************************************************
+ * Таймерная служба РТОС и tdelay (прерывание аппаратного таймера)
+ */
+#pragma GCC optimize ("O3")
+ISR(TIMER_OVF_VECT) {
+
+  // перезарядим таймер
+  TIMER_TCNT = TIMER_CNT;
+
+  /* RTOS_Timer */
+  uint8_t i;
+  // проходим по списку задач
+  for (i=0; i<arrayTail; i++) {
+    // если время до выполнения истекло
+    if (TaskArray[i].delay == 0) {
+      // взводим флаг запуска,
+      TaskArray[i].run = 1;
+    } else {
+      // иначе уменьшаем время
+      TaskArray[i].delay--;
+    }
+  }
+
+  /* TDelay_Timer -- уменьшим счётчик */
+  if (TDelay != 0) {
+    TDelay --;
+  }
+
+  if (TWI_WDT != 0) {
+    TWI_WDT --;
+  }
+
+}