From 2b91c6fadba20d6269e51dac8505735ba2bb1084 Mon Sep 17 00:00:00 2001 From: Paul Goeser Date: Sun, 5 Dec 2010 22:47:40 +0100 Subject: [PATCH] copied initial files for firmware from other projects --- firmware/Makefile | 9 + firmware/avrbuild/Makefile.avrbuild | 74 +++++ firmware/avrbuild/countregs.py | 18 ++ firmware/avrbuild/functionsize.py | 50 +++ firmware/avrbuild/menu_autogen.py | 43 +++ firmware/avrbuild/update_header.py | 113 +++++++ firmware/display.c | 264 +++++++++++++++ firmware/display.h | 35 ++ firmware/lcd/COPYING | 341 ++++++++++++++++++++ firmware/lcd/lcd.c | 314 ++++++++++++++++++ firmware/lcd/lcd.h | 189 +++++++++++ firmware/main.c | 484 ++++++++++++++++++++++++++++ firmware/main.h | 91 ++++++ 13 files changed, 2025 insertions(+) create mode 100644 firmware/Makefile create mode 100644 firmware/avrbuild/Makefile.avrbuild create mode 100755 firmware/avrbuild/countregs.py create mode 100755 firmware/avrbuild/functionsize.py create mode 100755 firmware/avrbuild/menu_autogen.py create mode 100755 firmware/avrbuild/update_header.py create mode 100644 firmware/display.c create mode 100644 firmware/display.h create mode 100644 firmware/lcd/COPYING create mode 100644 firmware/lcd/lcd.c create mode 100644 firmware/lcd/lcd.h create mode 100644 firmware/main.c create mode 100644 firmware/main.h diff --git a/firmware/Makefile b/firmware/Makefile new file mode 100644 index 0000000..9ad1ef9 --- /dev/null +++ b/firmware/Makefile @@ -0,0 +1,9 @@ +DEFINES += -DF_CPU=8e6 +CFLAGS += -save-temps + +OBJECTS = main.o + + + +include avrbuild/Makefile.avrbuild + diff --git a/firmware/avrbuild/Makefile.avrbuild b/firmware/avrbuild/Makefile.avrbuild new file mode 100644 index 0000000..79b3d8e --- /dev/null +++ b/firmware/avrbuild/Makefile.avrbuild @@ -0,0 +1,74 @@ +#DEFINES += +CFLAGS += -Wall -Os -I. -mmcu=atmega8 + +# further optimization: +# this removes dead code and does global linker optimization +#CFLAGS += -ffunction-sections -Wl,--gc-sections -Wl,--relax +#CFLAGS += --param inline-call-cost=2 + +COMPILE = avr-gcc $(CFLAGS) $(DEFINES) + +# symbolic targets: +all: firmware.hex + +.c.o: + $(COMPILE) -c $< -o $@ + +.S.o: + $(COMPILE) -x assembler-with-cpp -c $< -o $@ +# "-x assembler-with-cpp" should not be necessary since this is the default +# file type for the .S (with capital S) extension. However, upper case +# characters are not always preserved on Windows. To ensure WinAVR +# compatibility define the file type manually. + +.c.s: + $(COMPILE) -S $< -o $@ + +flash: all + avrdude -c usbasp -p m8 -U flash:w:firmware.hex + +fuses: + avrdude -c usbasp -p m8 -U lfuse:w:0xe4:m -U hfuse:w:0xd9:m # internal 8Mhz oscillator + + +## what are the source dependencies +%.d: %.c + @set -e; rm -f $@; \ + $(COMPILE) -MM $< | sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' > $@; +# line 1: exits if anything goes wrong +# line 2a: gcc -MM outputs dependencies +# line 2b: insert the %.d into dependency list + +#main.c: version.h + + +version.h: .svn/entries + export LANG=POSIX; (svn info 2>/dev/null || echo "Revision: unknown") | awk '/^Revision:/ {print "#define SVNVERSION \"" $$2 "\""};' >version.h + + +clean: + rm -f *.o *.hex *.obj *.i *.s *.d */*.i */*.s */*.o */*.d version.h + +# file targets: +firmware.bin: $(OBJECTS) + $(COMPILE) -o firmware.bin $(OBJECTS) + +firmware.hex: firmware.bin + rm -f firmware.hex firmware.eep.hex + avr-objcopy -j .text -j .data -O ihex firmware.bin firmware.hex + avr-size firmware.bin +# ./checksize firmware.bin 8192 960 +# do the checksize script as our last action to allow successful compilation +# on Windows with WinAVR where the Unix commands will fail. + +disasm: firmware.bin + avr-objdump -d firmware.bin >disasm + +functionsize: disasm + python avrbuild/functionsize.py + +countregs: disasm + python avrbuild/countregs.py + +# for depends: +-include $(OBJECTS:.o=.d) diff --git a/firmware/avrbuild/countregs.py b/firmware/avrbuild/countregs.py new file mode 100755 index 0000000..5c50b63 --- /dev/null +++ b/firmware/avrbuild/countregs.py @@ -0,0 +1,18 @@ +#!/usr/bin/python +import re +import os + +fd = os.popen("avr-objdump -d firmware.bin") +regcount = [0]*32 +s="foo" +while s: + s=fd.readline() + m=re.findall(r"[ \n\t,;]r(\d\d?)[ \n\t,;]",s) + if m: + for i in m: + regcount[int(i)] += 1; + +for i in range(16): + print "r%2d: %4d"%(i,regcount[i]), + print "\tr%2d: %4d"%(i+16,regcount[i+16]) + diff --git a/firmware/avrbuild/functionsize.py b/firmware/avrbuild/functionsize.py new file mode 100755 index 0000000..97e6baf --- /dev/null +++ b/firmware/avrbuild/functionsize.py @@ -0,0 +1,50 @@ +#!/usr/bin/python +import re +import os + + +def main(): + fd = os.popen("avr-objdump -d firmware.bin") + oldaddr=0 + lastfnname="" + namespacedict = {} + s="foo" + while s: + s=fd.readline() + m=re.match("([0-9a-f]+) <(\w+)>:",s) + if m: + addr,fname=m.groups() + addr=int(addr,16) + size=addr-oldaddr + oldaddr=addr + # print size,"\t",lastfnname + namespace=get_namespace(lastfnname) + try: + namespacedict[namespace].append((lastfnname, size)) + except: + namespacedict[namespace] = [(lastfnname, size)] + lastfnname = fname + + print "individual sizes:" + for k,v in namespacedict.items(): + for a,b in sorted(v): + print "%4i %s"%(b,a) + print "namespace sizes:" + for k,v in namespacedict.items(): + totalsize = sum( [ i[1] for i in v ] ) + print "%4i %s*"%(totalsize,k) + +def get_namespace(name): + matchlist = [ + r"(^__)", + r"(^\w+?_)", + r"(\w[a-z0-9])[A-Z]"] + for i in matchlist: + m = re.match(i, name) + if m: + return m.groups()[0] + return "" + + +if __name__=="__main__": + main() diff --git a/firmware/avrbuild/menu_autogen.py b/firmware/avrbuild/menu_autogen.py new file mode 100755 index 0000000..e3362b8 --- /dev/null +++ b/firmware/avrbuild/menu_autogen.py @@ -0,0 +1,43 @@ +#!/usr/bin/python + +import re + +print "Auto-generating menu_autogen.h..." + +items=set([]) + +fd=file("menu.c") +for line in fd: + m = re.search(r"menu_item_(\w+)\s*\(",line) + if m: + items.add( m.groups()[0]) + +fd.close() + +items=list(items) # create clear ordering + +fd=file("menu_autogen.h","wb") + +fd.write("\n"); +for i in range(len(items)): + fd.write("extern int8_t menu_item_%s();\n" % items[i]) + +fd.write("\ntypedef int8_t (*item_handler_t)();\n\n") + +fd.write("item_handler_t menu_item_handlers[] = {\n") +fd.write("\t\tNULL") + +for i in range(len(items)): + fd.write(",\n\t\t*menu_item_%s" % items[i]) + +fd.write("\n};\n\n") + +for i in range(len(items)): + fd.write("#define MENU_ITEM_%s \t%s\n" % (items[i].upper(), i+1)) + +fd.write("\n") +fd.write("#define MENU_MAX_ITEM %s\n\n"%len(items)) + + + + diff --git a/firmware/avrbuild/update_header.py b/firmware/avrbuild/update_header.py new file mode 100755 index 0000000..5b17d3b --- /dev/null +++ b/firmware/avrbuild/update_header.py @@ -0,0 +1,113 @@ +#!/usr/bin/python + +import re +from sys import argv + +startline = "/* autogenerated by update_header.py. Please check and uncomment.\n" +changedline = "// changed declarations:\n" +newline = "// new declarations:\n" +endline = "*/ // update_header.py end\n" + +def parse_c(data): + l=0 + while l!=len(data): + l=len(data) + data=re.sub(r"(?ms)\{[^{}]*\}",";",data) + data = re.sub(r"(?ms)/\*.*?\*/","",data) + data = re.sub(r"(?m)^#.*$","",data) + data = data.split(";") + data = map(lambda x:x.strip(), data) + data = filter(None, data) # kill empty lines + data = map(lambda x:re.sub(r"\s*=.*$","",x), data) + return data + + +def make_symtable(data): + symbols={} + for i in data: + symname=get_symname(i) + symbols[symname] = i + return symbols + +def get_symname(line): + try: + r = re.search(r"(\w+)($|\(|\[)",line).groups()[0] + return r + except: + raise 'Could not extract symbol from "%s".'%repr(line) + +def update_header(filebase): + data = file(filebase+".c").read() + data = parse_c(data) + header = file(filebase+".h").read() + header = parse_c(header) + headersyms = make_symtable(header) + + changed=[] + new=[] + for i in data: + symname = get_symname(i) + if symname not in headersyms: + new.append(i) + continue + headerline = headersyms[symname] + headerline = re.sub(r"extern\s+","",headerline) + if headerline != i: + changed.append(i) + + print changed + print new + + if (not changed) and (not new): + return # nothing to do + + fd=file(filebase+".h") + header = fd.readlines() + fd.close() + if startline in header: + try: + print "foo" + start=header.index(startline) + stop=header.index(endline) + print start, stop + header = header[:start] + header[stop+1:] + fd = file(filebase+".h","wb") + fd.write("".join(header)) + fd.close() + except: + print "Error killing old entry" + fd = file(filebase+".h","ab") + + fd.write("\n\n\n") + fd.write(startline) + if changed: + fd.write("\n") + fd.write(changedline) + for i in changed: + fd.write("extern "+i+";\n") + if new: + fd.write("\n") + fd.write(newline) + for i in new: + fd.write("extern "+i+";\n") + fd.write("\n") + fd.write(endline) + fd.write("\n\n\n") + fd.close() + + + + + + + + + +def main(): + for i in argv[1:]: + i=re.sub(".[ch]$","",i) + update_header(i) + + +if __name__=="__main__": + main() diff --git a/firmware/display.c b/firmware/display.c new file mode 100644 index 0000000..f9ca2f1 --- /dev/null +++ b/firmware/display.c @@ -0,0 +1,264 @@ +#include +#include "display.h" +#include "debug.h" + + +char display_content[40]; // is zeroed by being in .bss +uint8_t display_currpos; + + +/* char layout is "line-addr" | "data" */ +const prog_uint8_t lcd_halfbar_char[] = {0x1c, /* 11100 */ + 0x1c, /* 11100 */ + 0x1c, /* 11100 */ + 0x1c, /* 11100 */ + 0x1c, /* 11100 */ + 0x1c, /* 11100 */ + 0x1c, /* 11100 */ + 0x00}; /* 00000 */ /* cursor line */ + +const prog_uint8_t lcd_bar_char[] = {0x1f, /* 11111 */ + 0x1f, /* 11111 */ + 0x1f, /* 11111 */ + 0x1f, /* 11111 */ + 0x1f, /* 11111 */ + 0x1f, /* 11111 */ + 0x1f, /* 11111 */ + 0x00}; /* 00000 */ /* cursor line */ + +const prog_uint8_t lcd_degree_char[] = {0x12, /* 10010 */ + 0x05, /* 00101 */ + 0x04, /* 00100 */ + 0x05, /* 00101 */ + 0x02, /* 00010 */ + 0x00, /* 00000 */ + 0x00, /* 00000 */ + 0x00}; /* 00000 */ /* cursor line */ + + + + +void lcd_defchar(uint8_t contr, uint8_t addr, const prog_uint8_t * chargraph) { + int i=0; + + lcd_command(contr, _BV(LCD_CGRAM) | addr*8); + + for (i=0; i<=7; i++) { + lcd_data(contr, pgm_read_byte(chargraph+i) & 0x1F); /* only the lower 5 bits */ + } + lcd_command(contr, _BV(LCD_DDRAM)); +} + + +void display_puts(const char * printstr) { + + while (*printstr){ + if (*printstr == '\n') { + display_put_eol(); + } else { + display_putc(*printstr); + } + printstr++; + } +} + +void display_puts_P(const prog_char * printstr) { + + while(pgm_read_byte(printstr)) { + if (pgm_read_byte(printstr) == '\n') { + display_put_eol(); + } else { + display_putc(pgm_read_byte(printstr)); + } + printstr++; + } +} + +void display_put_eol() { + /* fill until end of display line */ + + uint8_t j = 0; + + if (display_currpos <= 16) { + /* first line */ + for (j = display_currpos; j < 16; j++) { + display_putc(' '); + } + } else if (display_currpos <= 32) { + /* second line */ + for (j = display_currpos; j < 32; j++) { + display_putc(' '); + } + } +} + +void display_putc(char printchar) { + uint8_t lcdaddr; + if (display_currpos >= 32) { + return; + } + if (printchar != display_content[display_currpos]) { + display_content[display_currpos] = printchar; + lcdaddr = display_currpos; + if (display_currpos >= 16) { + lcdaddr = LCD_LINE2_ADDR - 16 + display_currpos; + } + lcd_command(1,_BV(LCD_DDRAM) | lcdaddr); + lcd_data(1,printchar); + } + display_currpos++; +} + + +void display_fillblank() { + while (display_currpos < 32){ + display_putc(' '); + } +} + +void display_gotoyx(uint8_t y, uint8_t x) { + /* first line is line 0 */ + + if (y > 1) { + /* caller error, we only have two lines! set to first line */ + y = 0; + } + if (x > 15) { + /* caller error, we only have 16 chars! set to first char */ + x = 0; + } + + display_currpos = y * 16 + x; +} + + +extern void display_update() { + uint8_t i=0; + + lcd_command(1, _BV(LCD_DDRAM)); + for (i = 0; i <= 15; i++) { + lcd_data(1,display_content[i]); + } + + lcd_command(1, _BV(LCD_DDRAM) | LCD_LINE2_ADDR); + for (i = 16; i <= 32; i++) { + lcd_data(1,display_content[i]); + } +} + + +extern void display_force_redraw() { + display_update(); +} + + + + +int16_t intexp10(int8_t a){ + int8_t i; + int16_t ret=1; + for(i=0; i=0; i--){ + if(i==1) { + fillzero = 1; + } + c = getdigit(&temperature, intexp10(i)*16, &fillzero); // hundred-digit + display_putc(c); + if(i==1) { + display_putc('.'); + } + } + + +} + +void display_putint(int16_t number){ + int8_t fillzero=0, i; + char c; + + for(i=2; i>=0; i--){ + if(i==1) { + fillzero = 1; + } + c = getdigit(&number, intexp10(i), &fillzero); // hundred-digit + display_putc(c); + } + + +} + +char getdigit(int16_t *input, int16_t div, int8_t *fillzero){ + char digit; + if(*input < 0){ + *input = - *input; /* to convert from (binary) 2s-complement + to (ascii) sign and magnitude */ + debug_int(PSTR("getdigit"),*input); + debug_int(PSTR("getdigit2"),div); + return '-'; + } else { + digit = *input / div; + *input -= digit * div; + } + digit += '0'; //converts to ascii + if(digit == '0' && ! *fillzero){ + digit = ' '; + } else { + *fillzero = 1; + } + return digit; +} + + + +void display_puthex(uint8_t outbyte) { + uint8_t lownibble, highnibble; + + lownibble = outbyte & 0x0F; + highnibble = (outbyte & 0xF0) >> 4; + + if (highnibble >= 10) { + display_putc(0x41 - 10 + highnibble); + } else { + display_putc(0x30 + highnibble); + } + if (lownibble >= 10) { + display_putc(0x41 - 10 + lownibble); + } else { + display_putc(0x30 + lownibble); + } +} + +void display_bar(int8_t value, int8_t min, int8_t max) { + /* paint contrast bar */ + uint16_t tmp_var = 0; + + max -= min; + value -= min; + + tmp_var = value * 32; + tmp_var = tmp_var / max; + + while (tmp_var >= 2) { + display_putc(LCD_CHAR_BAR); + tmp_var -= 2; + } + if (tmp_var >=1) { + display_putc(LCD_CHAR_HALFBAR); + tmp_var -= 1; + } +} + + + diff --git a/firmware/display.h b/firmware/display.h new file mode 100644 index 0000000..e0cb553 --- /dev/null +++ b/firmware/display.h @@ -0,0 +1,35 @@ +#include + +#include "lcd/lcd.h" + + +#define LCD_CHAR_HALFBAR 0x01 +#define LCD_CHAR_BAR 0x02 +#define LCD_CHAR_DEGREE 0x03 +#define LCD_CHAR_BLANK 0x20 + +extern const prog_uint8_t lcd_halfbar_char[]; +extern const prog_uint8_t lcd_bar_char[]; +extern const prog_uint8_t lcd_degree_char[]; + + + +extern void lcd_defchar(uint8_t contr, uint8_t addr, const prog_uint8_t * chargraph); + + +extern void display_put_eol(); +extern void display_puts(const char * printstr); +extern void display_puts_P(const prog_char * printstr); +extern void display_putc(char printchar); +extern void display_fillblank(); +extern void display_gotoyx(uint8_t y, uint8_t x); +extern void display_update(); +extern void display_force_redraw(); + +extern int16_t intexp10(int8_t a); +extern void display_temperature(int16_t temperature); +extern char getdigit(int16_t *input, int16_t div, int8_t *fillzero); + +extern void display_puthex(uint8_t outbyte); +extern void display_bar(int8_t value, int8_t min, int8_t max); +extern void display_putint(int16_t number); diff --git a/firmware/lcd/COPYING b/firmware/lcd/COPYING new file mode 100644 index 0000000..a52b16e --- /dev/null +++ b/firmware/lcd/COPYING @@ -0,0 +1,341 @@ + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/firmware/lcd/lcd.c b/firmware/lcd/lcd.c new file mode 100644 index 0000000..a7c69c2 --- /dev/null +++ b/firmware/lcd/lcd.c @@ -0,0 +1,314 @@ +/**************************************************************************** + Title : HD44780U LCD library / stripped down version for lcd@usb + Author: Peter Fleury http://jump.to/fleury + lcd@usb modifications by Till Harbaum + File: $Id: lcd.c,v 1.2 2007/01/14 12:12:27 harbaum Exp $ + Software: AVR-GCC 3.3 + Target: any AVR device, memory mapped mode only for AT90S4414/8515/Mega + + DESCRIPTION + Basic routines for interfacing a HD44780U-based text lcd display + + Originally based on Volker Oth's lcd library, + changed lcd_init(), added additional constants for lcd_command(), + added 4-bit I/O mode, improved and optimized code. + + Memory mapped mode compatible with Kanda STK200, but supports also + generation of R/W signal through A8 address line. + + Major changes for LCD2USB: Removed many functions not needed in + LCD2USB. Added support for a second controller. + + USAGE + See the C include lcd.h file for a description of each function + +*****************************************************************************/ +#include +#include +#include +#include + +#include "lcd.h" + +/* +** constants/macros +*/ +#define DDR(x) (*(&x - 1)) /* address of data direction register of port x */ +#define PIN(x) (*(&x - 2)) /* address of input register of port x */ + +#define lcd_e_delay() __asm__ __volatile__( "rjmp 1f\n 1:" ); +#define lcd_e0_high() LCD_E_PORT |= _BV(LCD_E0_PIN); +#define lcd_e0_low() LCD_E_PORT &= ~_BV(LCD_E0_PIN); +#define lcd_e1_high() LCD_E_PORT |= _BV(LCD_E1_PIN); +#define lcd_e1_low() LCD_E_PORT &= ~_BV(LCD_E1_PIN); +#define lcd_rw_high() LCD_RW_PORT |= _BV(LCD_RW_PIN) +#define lcd_rw_low() LCD_RW_PORT &= ~_BV(LCD_RW_PIN) +#define lcd_rs_high() LCD_RS_PORT |= _BV(LCD_RS_PIN) +#define lcd_rs_low() LCD_RS_PORT &= ~_BV(LCD_RS_PIN) + +/* we don't really know anything about the display attached, */ +/* so assume that it's a display with two lines */ +#define LCD_FUNCTION_DEFAULT LCD_FUNCTION_4BIT_2LINES + +/* +** function prototypes +*/ +static void lcd_e_toggle(uint8_t ctrl); + +/* +** local functions +*/ + + +/************************************************************************* + delay loop for small accurate delays: 16-bit counter, 4 cycles/loop +*************************************************************************/ +static inline void _delayFourCycles(unsigned int __count) +{ + if ( __count == 0 ) + __asm__ __volatile__( "rjmp 1f\n 1:" ); // 2 cycles + else + __asm__ __volatile__ ( + "1: sbiw %0,1" "\n\t" + "brne 1b" // 4 cycles/loop + : "=w" (__count) + : "0" (__count) + ); +} + + +/************************************************************************* +delay for a minimum of microseconds +the number of loops is calculated at compile-time from MCU clock frequency +*************************************************************************/ +#define delay(us) _delayFourCycles( ( ( 1*(XTAL/4000) )*us)/1000 ) + + +/* toggle Enable Pin to initiate write */ +static void lcd_e_toggle(uint8_t ctrl) +{ + if(ctrl & LCD_CTRL_0) lcd_e0_high(); + if(ctrl & LCD_CTRL_1) lcd_e1_high(); + + lcd_e_delay(); + + if(ctrl & LCD_CTRL_0) lcd_e0_low(); + if(ctrl & LCD_CTRL_1) lcd_e1_low(); +} + + +/************************************************************************* +Low-level function to write byte to LCD controller +Input: data byte to write to LCD + rs 1: write data + 0: write instruction +Returns: none +*************************************************************************/ +static void lcd_write(uint8_t ctrl, uint8_t data, uint8_t rs) +{ + unsigned char dataBits ; + + + if (rs) lcd_rs_high(); /* write data (RS=1, RW=0) */ + else lcd_rs_low(); /* write instruction (RS=0, RW=0) */ + lcd_rw_low(); + + /* configure data pins as output */ + DDR(LCD_DATA_PORT) |= 0x0F; + + /* output high nibble first */ + dataBits = LCD_DATA_PORT & 0xF0; + LCD_DATA_PORT = dataBits |((data>>4)&0x0F); + lcd_e_toggle(ctrl); + + /* output low nibble */ + LCD_DATA_PORT = dataBits | (data&0x0F); + lcd_e_toggle(ctrl); + + /* all data pins high (inactive) */ + LCD_DATA_PORT = dataBits | 0x0F; +} + +/************************************************************************* +Low-level function to read byte from LCD controller +Input: rs 1: read data + 0: read busy flag / address counter +Returns: byte read from LCD controller +*************************************************************************/ +static uint8_t lcd_read(uint8_t ctrl, uint8_t rs) +{ + uint8_t data; + + if (rs) lcd_rs_high(); /* RS=1: read data */ + else lcd_rs_low(); /* RS=0: read busy flag */ + lcd_rw_high(); /* RW=1 read mode */ + + DDR(LCD_DATA_PORT) &= 0xF0; /* configure data pins as input */ + LCD_DATA_PORT |= 0x0F; /* enable pullups to get a busy */ + /* on unconnected display */ + + if(ctrl & LCD_CTRL_0) lcd_e0_high(); + if(ctrl & LCD_CTRL_1) lcd_e1_high(); + lcd_e_delay(); + data = (PIN(LCD_DATA_PORT) & 0x0F)<<4; /* read high nibble first */ + if(ctrl & LCD_CTRL_0) lcd_e0_low(); + if(ctrl & LCD_CTRL_1) lcd_e1_low(); + + lcd_e_delay(); /* Enable 500ns low */ + + if(ctrl & LCD_CTRL_0) lcd_e0_high(); + if(ctrl & LCD_CTRL_1) lcd_e1_high(); + lcd_e_delay(); + data |= (PIN(LCD_DATA_PORT)&0x0f); /* read low nibble */ + if(ctrl & LCD_CTRL_0) lcd_e0_low(); + if(ctrl & LCD_CTRL_1) lcd_e1_low(); + + return data; +} + + +/************************************************************************* +loops while lcd is busy, returns address counter +*************************************************************************/ +static void lcd_waitbusy(uint8_t ctrl) +{ +#if 1 + uint8_t busy; + + do { + busy = 0; + + /* check all controllers separately */ + if(ctrl & LCD_CTRL_0) + if((lcd_read(LCD_CTRL_0, 0)) & (1<>4); + lcd_e_toggle(ctrl); + delay(4992); /* delay, busy flag can't be checked here */ + + /* repeat last command */ + lcd_e_toggle(ctrl); + delay(64); /* delay, busy flag can't be checked here */ + + /* repeat last command a third time */ + lcd_e_toggle(ctrl); + delay(64); /* delay, busy flag can't be checked here */ + + /* now configure for 4bit mode */ + LCD_DATA_PORT &= ~(_BV(LCD_FUNCTION_8BIT) >> 4); + lcd_e_toggle(ctrl); + delay(64); /* some displays need this additional delay */ + + /* from now the LCD only accepts 4 bit I/O, we can use lcd_command() */ + + /* try to find out of there's a controller and return 0 if not */ + + /* display must not be busy anymore */ + if((lcd_read(ctrl, 0)) & (1< http://jump.to/fleury + File: $Id: lcd.h,v 1.1.1.1 2007/01/14 11:37:56 harbaum Exp $ + Software: AVR-GCC 3.3 + Hardware: any AVR device, memory mapped mode only for AT90S4414/8515/Mega +***************************************************************************/ + +/** + @defgroup pfleury_lcd LCD library + @code #include @endcode + + @brief Basic routines for interfacing a HD44780U-based text LCD display + + Originally based on Volker Oth's LCD library, + changed lcd_init(), added additional constants for lcd_command(), + added 4-bit I/O mode, improved and optimized code. + + Memory mapped mode compatible with Kanda STK200, but supports also + generation of R/W signal through A8 address line. + + @author Peter Fleury pfleury@gmx.ch http://jump.to/fleury + + @see The chapter Interfacing a HD44780 Based LCD to an AVR + on my home page. + +*/ + +/*@{*/ + +#if (__GNUC__ * 100 + __GNUC_MINOR__) < 303 +#error "This library requires AVR-GCC 3.3 or later, update to newer AVR-GCC compiler !" +#endif + +#include +#include + +/** + * @name Definitions for MCU Clock Frequency + * Adapt the MCU clock frequency in Hz to your target. + */ +//#define XTAL 12000000 /**< clock frequency in Hz, used to calculate delay timer */ + +/** + * @name Definitions for 4-bit IO mode + * Change LCD_PORT if you want to use a different port for the LCD pins. + * + * The four LCD data lines and the three control lines RS, RW, E can be on the + * same port or on different ports. + * Change LCD_RS_PORT, LCD_RW_PORT, LCD_E_PORT if you want the control lines on + * different ports. + * + * Normally the four data lines should be mapped to bit 0..3 on one port, but it + * is possible to connect these data lines in different order or even on different + * ports by adapting the LCD_DATAx_PORT and LCD_DATAx_PIN definitions. + * + */ +#define LCD_DATA_PORT PORTD /**< port for the LCD lines */ +#define LCD_RS_PORT PORTD /**< port for RS line */ +#define LCD_RS_PIN 4 /**< pin for RS line */ +#define LCD_RW_PORT PORTD /**< port for RW line */ +#define LCD_RW_PIN 5 /**< pin for RW line */ +#define LCD_E_PORT PORTD /**< port for Enable line */ +#define LCD_E0_PIN 6 /**< pin for Enable line 0 */ +#define LCD_E1_PIN 6 /**< pin for Enable line 1 */ + +#define LCD_CTRL_0 (1<<0) +#define LCD_CTRL_1 (1<<1) + +/** + * @name Definitions for LCD command instructions + * The constants define the various LCD controller instructions which can be passed to the + * function lcd_command(), see HD44780 data sheet for a complete description. + */ + +/* instruction register bit positions, see HD44780U data sheet */ +#define LCD_CLR 0 /* DB0: clear display */ +#define LCD_HOME 1 /* DB1: return to home position */ +#define LCD_ENTRY_MODE 2 /* DB2: set entry mode */ +#define LCD_ENTRY_INC 1 /* DB1: 1=increment, 0=decrement */ +#define LCD_ENTRY_SHIFT 0 /* DB2: 1=display shift on */ +#define LCD_ON 3 /* DB3: turn lcd/cursor on */ +#define LCD_ON_DISPLAY 2 /* DB2: turn display on */ +#define LCD_ON_CURSOR 1 /* DB1: turn cursor on */ +#define LCD_ON_BLINK 0 /* DB0: blinking cursor ? */ +#define LCD_MOVE 4 /* DB4: move cursor/display */ +#define LCD_MOVE_DISP 3 /* DB3: move display (0-> cursor) ? */ +#define LCD_MOVE_RIGHT 2 /* DB2: move right (0-> left) ? */ +#define LCD_FUNCTION 5 /* DB5: function set */ +#define LCD_FUNCTION_8BIT 4 /* DB4: set 8BIT mode (0->4BIT mode) */ +#define LCD_FUNCTION_2LINES 3 /* DB3: two lines (0->one line) */ +#define LCD_FUNCTION_10DOTS 2 /* DB2: 5x10 font (0->5x7 font) */ +#define LCD_CGRAM 6 /* DB6: set CG RAM address */ +#define LCD_DDRAM 7 /* DB7: set DD RAM address */ +#define LCD_BUSY 7 /* DB7: LCD is busy */ + +/* set entry mode: display shift on/off, dec/inc cursor move direction */ +#define LCD_ENTRY_DEC 0x04 /* display shift off, dec cursor move dir */ +#define LCD_ENTRY_DEC_SHIFT 0x05 /* display shift on, dec cursor move dir */ +#define LCD_ENTRY_INC_ 0x06 /* display shift off, inc cursor move dir */ +#define LCD_ENTRY_INC_SHIFT 0x07 /* display shift on, inc cursor move dir */ + +/* display on/off, cursor on/off, blinking char at cursor position */ +#define LCD_DISP_OFF 0x08 /* display off */ +#define LCD_DISP_ON 0x0C /* display on, cursor off */ +#define LCD_DISP_ON_BLINK 0x0D /* display on, cursor off, blink char */ +#define LCD_DISP_ON_CURSOR 0x0E /* display on, cursor on */ +#define LCD_DISP_ON_CURSOR_BLINK 0x0F /* display on, cursor on, blink char */ + +/* move cursor/shift display */ +#define LCD_MOVE_CURSOR_LEFT 0x10 /* move cursor left (decrement) */ +#define LCD_MOVE_CURSOR_RIGHT 0x14 /* move cursor right (increment) */ +#define LCD_MOVE_DISP_LEFT 0x18 /* shift display left */ +#define LCD_MOVE_DISP_RIGHT 0x1C /* shift display right */ + +/* function set: set interface data length and number of display lines */ +#define LCD_FUNCTION_4BIT_1LINE 0x20 /* 4-bit interface, single line, 5x7 dots */ +#define LCD_FUNCTION_4BIT_2LINES 0x28 /* 4-bit interface, dual line, 5x7 dots */ +#define LCD_FUNCTION_8BIT_1LINE 0x30 /* 8-bit interface, single line, 5x7 dots */ +#define LCD_FUNCTION_8BIT_2LINES 0x38 /* 8-bit interface, dual line, 5x7 dots */ + + +#define LCD_MODE_DEFAULT ((1< +#include +#include +#include +#include + +#include +#include + +#include "version.h" + +#include "main.h" +#include "display.h" +#include "1wire/1wire.h" +#include "sensors.h" +#include "menu.h" +#include "delay.h" +#include "debug.h" + +uint32_t ledval[4], ledacc[4]; + /* 0: led1 colour + * 1: led1 brightness + * 2: led2 + * 3: led3 + */ + +uint8_t run_mainloop; //set to 1 if mainloop needs running +uint8_t run_1wireloop; //set to 1 if 1wire loop needs running + +uint8_t buttlold, buttrold, butttold; +uint8_t butttbounce; + + +uint8_t buttonevent; +int8_t buttoninc; + +uint8_t EEMEM display_stored_brightness; +uint8_t EEMEM display_stored_contrast; +uint8_t EEMEM flowtemp_stored; +uint8_t EEMEM flowtemp_stored_range; +uint8_t EEMEM flowtemp_stored_alarm; + +uint8_t flowtemp; +uint8_t flowtemp_range; +uint8_t flowtemp_alarm; + +uint8_t volatile timer1_acc; + + +void hardinit(){ + /* initializes the hardware */ + // DDRB: XXXXX111 + DDRB = 0xff; + // DDRC: -X000111 + DDRC = 0x07; + // DDRD: 1XXXXXXX; + DDRD = 0x80; + + // no pullups; all digital outputs can take care of themselves + PORTB = 0x00; + PORTC = 0x00; + PORTD = 0x00; + + /* our event driver gets called with 10kHz frequency + * (to allow for proper LED PWM) + * Thats 100us or 800 cycles. + * Priority is: 1wire-bit first, then buttons, then LED-PWMs, then LCD, then the rest of 1wire. + * Sending a 1wire-bit takes about 70us. + */ + TCCR0 = 0x02; // prescaler: clk/8 + TCNT0 = 0xff-100; // 100 cycles of 1us each + TIMSK |= 0x01; // enable interrupt + + /* hardware pwm for brightness/contrast: + */ + + TCCR1A = _BV(COM1A1) | _BV(COM1A0) | _BV(COM1B1) | _BV(WGM10); + TCCR1B = _BV(WGM12) | _BV(CS11); // clk/8 prescaler, 4kHz PWM-freq. + TIMSK &=( (~_BV(3)) & (~_BV(4)) & (~_BV(5))); //disable all timer1-interrupts + TIMSK |= _BV(2); // but enable overflow + + OCR1A = 0xff-15; // contrast + OCR1B = 200; // brightness + + // init LCD: + lcd_init(1); + lcd_clrscr(1); + + // 1wire needs no own init, bus search is done in softinit + + sei(); +} + + + +void softinit(){ + + lcd_defchar(1, LCD_CHAR_HALFBAR, lcd_halfbar_char); + lcd_defchar(1, LCD_CHAR_BAR, lcd_bar_char); + lcd_defchar(1, LCD_CHAR_DEGREE, lcd_degree_char); + + sensors_search(); + + menu_init(); + + set_display_brightness(load_display_brightness()); + set_display_contrast(load_display_contrast()); + set_flowtemp(load_flowtemp()); + set_flowtemp_range(load_flowtemp_range()); + set_flowtemp_alarm(load_flowtemp_alarm()); + + sei(); +} + + +void mainloop(){ + // called with about 80Hz + static uint8_t ctr_subsec; // counts to 79, wraps around every second + static uint8_t ctr_sec; // counts to 255, use with modulo for rare events + + int16_t vorlaufdiff; + uint16_t ledbrightness; + + + menu_display(); + + + + ctr_subsec++; + if(ctr_subsec >= 80){ + ctr_subsec = 0; + ctr_sec++; + + // starting here: stuff that happens every second (or rarer) + sensors_startconv(); + if(ctr_sec % 32 == 0){ + sensors_search(); // overrides sensors_startconv + } + + } + + /* warning for flow too hot */ + /* "inverted" blink-code compared to duo-led */ + if (sensoravg[sensor_which[0]]/256 >= flowtemp_alarm) { + if (ctr_subsec < 40) { + ledval[3] = 0; + } else { + ledval[3] = 65535; + } + } + + + + /* do colour/brightness for duo-led*/ + if (sensoravg[sensor_which[0]]/256 > flowtemp) { + ledval[0] = 0; // red + } else { + ledval[0] = 65535; // green + } + + vorlaufdiff = sensoravg[sensor_which[0]]/256 - (int16_t)flowtemp; + vorlaufdiff = vorlaufdiff > 0 ? vorlaufdiff : -vorlaufdiff; + + if (vorlaufdiff <= flowtemp_range / 4) { + // flowtemp OK + ledbrightness = 0; + } else { // flowtemp out of range + if (vorlaufdiff < flowtemp_range) { + // inside range, scale brightness linearly with difference + ledbrightness = (4 * vorlaufdiff - flowtemp_range) * 256 / 3 / flowtemp_range; + } else { + // outside margin, blink as a warning + if (ctr_subsec < 40) { + ledbrightness = 255; + } else { + ledbrightness = 0; + } + } + } + + ledval[1] = ledbrightness * ledbrightness; +} + + +void main(){ + hardinit(); + softinit(); + + + for(;;){ + if(run_1wireloop){ + run_1wireloop=0; + sensors_1wirebitloop(); + } + if(run_mainloop){ + run_mainloop=0; + mainloop(); + } + } + + +} + +void buttonpoll(){ // runs with 1.2kHz + uint8_t l,r,t,flanks,dir; + l=BUTTPIN & _BV(BUTTLPIN); + r=BUTTPIN & _BV(BUTTRPIN); + t=BUTTPIN & _BV(BUTTTPIN); + + // debounce code + if (t != butttold && !butttbounce ) { + butttold = t; + butttbounce = BUTT_BOUNCE; + if (t == 0) { // active low + buttonevent |= BUTTEV_PUSH; + } + } + + flanks=0; + dir=0; + if (l != buttlold) { + flanks += 1; + } + if (r != buttrold) { + flanks += 1; + dir = 1; + } + if (flanks == 1){ // we need to have exactly one flank, 0 flanks are no + // change, and 2 flanks are too fast (error) + if (l) { + dir ^= 1; + } + if (r) { + dir ^= 1; + } + if ((r && l) || (!r && !l)) { + buttoninc += dir ? -1 : 1; + } + } + + buttlold = l; + buttrold = r; + + + if(butttbounce){ + butttbounce -= 1; + } + +} + + + + + + +void ledsoftpwm(){ + // LED softpwm: + uint8_t i; + for(i=1; i<4; ++i){ + ledacc[i] += ledval[i]; + if(ledacc[i]>0xffff){ + ledacc[i] -= 0xffff; + if(i==1){ + ledacc[0] += ledval[0]; + if(ledacc[0]>0xffff){ + ledacc[0] -= 0xffff; + LED1PORT |= _BV(LED1APIN); + LED1PORT &= ~_BV(LED1BPIN); + } else { + LED1PORT |= _BV(LED1BPIN); + LED1PORT &= ~_BV(LED1APIN); + } + } + if(i==2){ + LED2PORT &= ~_BV(LED2PIN); + } + if(i==3){ + LED3PORT &= ~_BV(LED3PIN); + } + } else { + if(i==1){ + LED1PORT &= ~(_BV(LED1BPIN) | _BV(LED1APIN)); + } + if(i==2){ + LED2PORT |= _BV(LED2PIN); + } + if(i==3){ + LED3PORT |= _BV(LED3PIN); + } + } + } +} + + + + +void set_display_brightness(uint8_t display_brightness) { + // set "runtime-brightness", will be lost at poweroff! + if (display_brightness < 1 || display_brightness > 16) { + // erratic values + display_brightness = 10; + } + OCR1B = (display_brightness * display_brightness) - 1; +} +void store_display_brightness(uint8_t new_brightness) { + // store brightness-value to eeprom for next boot + if (new_brightness < 1 || new_brightness > 16) { + // erratic values, abort + return; + } + uint8_t cur_brightness = eeprom_read_byte(&display_stored_brightness); + if (new_brightness != cur_brightness) { + // value hast changed, save to eeprom + eeprom_write_byte(&display_stored_brightness, new_brightness); + } +} +uint8_t load_display_brightness() { + uint8_t display_brightness = eeprom_read_byte(&display_stored_brightness); + if (display_brightness < 1 || display_brightness > 16) { + // erratic values + display_brightness = 10; + store_display_brightness(display_brightness); + } + return display_brightness; +} + + +void set_display_contrast(uint8_t display_contrast) { + // set "runtime-contrast", will be lost at poweroff! + if (display_contrast > 32) { + // erratic values + display_contrast = 16; + } + OCR1A = 0xff - 64 + 2 * display_contrast; +} +void store_display_contrast(uint8_t new_contrast) { + // store contrast-value to eeprom for next boot + if (new_contrast > 32) { + // erratic values + return; + } + uint8_t cur_contrast = eeprom_read_byte(&display_stored_contrast); + if (new_contrast != cur_contrast) { + // value hast changed, save to eeprom + eeprom_write_byte(&display_stored_contrast, new_contrast); + } +} +uint8_t load_display_contrast() { + uint8_t display_contrast = eeprom_read_byte(&display_stored_contrast); + if (display_contrast > 32) { + // erratic values + display_contrast = 16; + store_display_contrast(display_contrast); + } + return display_contrast; +} + + + +void set_flowtemp(uint8_t new_flowtemp) { + // set "runtime-flowtemp", will be lost at poweroff! + if ((new_flowtemp > FLOWTEMP_MAX) || (new_flowtemp < FLOWTEMP_MIN)) { + // erratic values + flowtemp = FLOWTEMP_DEFAULT; + } + flowtemp = new_flowtemp; +} +void store_flowtemp(uint8_t new_flowtemp) { + // store flowtemp-value to eeprom for next boot + if ((new_flowtemp > FLOWTEMP_MAX) || (new_flowtemp < FLOWTEMP_MIN)) { + // erratic values + return; + } + uint8_t cur_flowtemp = eeprom_read_byte(&flowtemp_stored); + if (new_flowtemp != cur_flowtemp) { + // value hast changed, save to eeprom + eeprom_write_byte(&flowtemp_stored, new_flowtemp); + } +} +uint8_t load_flowtemp() { + flowtemp = eeprom_read_byte(&flowtemp_stored); + if ((flowtemp > FLOWTEMP_MAX) || (flowtemp < FLOWTEMP_MIN)) { + // erratic values + flowtemp = FLOWTEMP_DEFAULT; + store_flowtemp(flowtemp); + } + return flowtemp; +} + + + +void set_flowtemp_range(uint8_t new_flowtemp_range) { + // set "runtime-flowtemp_range", will be lost at poweroff! + if (new_flowtemp_range > FLOWTEMP_RANGE_MAX) { + // erratic values + flowtemp_range = FLOWTEMP_RANGE_DEFAULT; + } + flowtemp_range = new_flowtemp_range; +} + +void store_flowtemp_range(uint8_t new_flowtemp_range) { + // store flowtemp-value to eeprom for next boot + if (new_flowtemp_range > FLOWTEMP_RANGE_MAX) { + // erratic values + return; + } + uint8_t cur_flowtemp_range = eeprom_read_byte(&flowtemp_stored_range); + if (new_flowtemp_range != cur_flowtemp_range) { + // value has changed, save to eeprom + eeprom_write_byte(&flowtemp_stored_range, new_flowtemp_range); + } +} + +uint8_t load_flowtemp_range() { + flowtemp_range = eeprom_read_byte(&flowtemp_stored_range); + if (flowtemp_range > FLOWTEMP_RANGE_MAX) { + // erratic values + flowtemp_range = FLOWTEMP_RANGE_DEFAULT; + store_flowtemp_range(flowtemp_stored_range); + } + return flowtemp_range; +} + + +void set_flowtemp_alarm(uint8_t new_flowtemp_alarm) { + // set "runtime-flowtemp_alarm", will be lost at poweroff! + flowtemp_alarm = new_flowtemp_alarm; +} + +void store_flowtemp_alarm(uint8_t new_flowtemp_alarm) { + // store flowtemp-alarm-value to eeprom for next boot + uint8_t cur_flowtemp_alarm = eeprom_read_byte(&flowtemp_stored_alarm); + if (new_flowtemp_alarm != cur_flowtemp_alarm) { + // value has changed, save to eeprom + eeprom_write_byte(&flowtemp_stored_alarm, new_flowtemp_alarm); + } +} + +uint8_t load_flowtemp_alarm() { + flowtemp_alarm = eeprom_read_byte(&flowtemp_stored_alarm); + if (flowtemp_alarm > FLOWTEMP_ALARM_MAX) { + // erratic values + flowtemp_alarm = FLOWTEMP_ALARM_DEFAULT; + store_flowtemp_alarm(flowtemp_stored_alarm); + } + return flowtemp_alarm; +} + + +ISR(TIMER0_OVF_vect){ + static uint8_t counter; + TCNT0 = 0xff-100; + + + counter+=1; + + ledsoftpwm(); + + if(counter%8 == 0){ //1.2kHz + buttonpoll(); + } + + if(counter%128 == 0){ //ca. 80Hz + run_mainloop = 1; + } + run_1wireloop = 1; // 10kHz +} + + + +/* +ISR(TIMER1_OVF_vect, ISR_NAKED){ + asm volatile ("in %0, %1\n" : "=r" (sreg_store) : "I" (_SFR_IO_ADDR(SREG))); + timer1_acc++; + asm volatile ("out %1, %0\n" : "=r" (sreg_store) : "I" (_SFR_IO_ADDR(SREG))); + reti(); +}*/ +ISR(TIMER1_OVF_vect){ + timer1_acc++; +} + + + + diff --git a/firmware/main.h b/firmware/main.h new file mode 100644 index 0000000..f06c8ac --- /dev/null +++ b/firmware/main.h @@ -0,0 +1,91 @@ +/* Anschlüsse sind: + * B0 - 1wire + * B1 - Kontrast-PWM + * B2 - Backlight-PWM + * B3-B5 - ISP + * C0-C1 - 2farb-LED + * C2 - LED + * C3-C4 - Knopf-drehung + * C5 - Knopf-taster + * C6 - ISP + * D0-6 - LCD (DB4-7, RS, R/W, EN) + * D7 - LED + */ + + +#ifndef __MAIN_H +#define __MAIN_H + +#include + +#define LED1PORT PORTC +#define LED1APIN 0 +#define LED1BPIN 1 +#define LED2PORT PORTC +#define LED2PIN 2 +#define LED3PORT PORTD +#define LED3PIN 7 +#define BACKLIGHTPORT PORTB +#define BACKLIGHTPIN 2 + + +// button handling +#define BUTTPIN PINC +#define BUTTLPIN 5 +#define BUTTRPIN 4 +#define BUTTTPIN 3 + +#define BUTTEV_PUSH 1 +#define BUTT_BOUNCE 25 //approx ms debounce time + +extern uint8_t buttonevent; +extern int8_t buttoninc; // how much the button turned. + // you might want to subtract turns you consumed since the variable + // is updated in an interrupt + + +//uint8_t volatile timer1_acc; + +#define FLOWTEMP_MAX 100 +#define FLOWTEMP_MIN 5 +#define FLOWTEMP_DEFAULT 70 +#define FLOWTEMP_ALARM_MIN 50 +#define FLOWTEMP_ALARM_MAX 100 +#define FLOWTEMP_ALARM_DEFAULT 87 +#define FLOWTEMP_RANGE_MAX 40 +#define FLOWTEMP_RANGE_DEFAULT 15 +extern uint8_t flowtemp_alarm; +extern uint8_t flowtemp_range; +extern uint8_t flowtemp; + + + +void set_display_brightness(uint8_t display_brightness); +void store_display_brightness(uint8_t new_brightness); +uint8_t load_display_brightness(); + +void set_display_contrast(uint8_t display_contrast); +void store_display_contrast(uint8_t new_contrast); +uint8_t load_display_contrast(); + +void set_flowtemp(uint8_t new_flowtemp); +void store_flowtemp(uint8_t new_flowtemp); +uint8_t load_flowtemp(); + +void set_flowtemp_range(uint8_t new_flowtemp_range); +void store_flowtemp_range(uint8_t new_flowtemp_range); +uint8_t load_flowtemp_range(); + +void set_flowtemp_alarm(uint8_t new_flowtemp_alarm); +void store_flowtemp_alarm(uint8_t new_flowtemp_alarm); +uint8_t load_flowtemp_alarm(); + + +// clock +extern struct clockfmt { + uint8_t hour; + uint8_t minute; + uint8_t second; +} clock; + +#endif //__MAIN_H