parent
c97a583bab
commit
2b91c6fadb
@ -0,0 +1,9 @@
|
||||
DEFINES += -DF_CPU=8e6
|
||||
CFLAGS += -save-temps
|
||||
|
||||
OBJECTS = main.o
|
||||
|
||||
|
||||
|
||||
include 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)
|
||||
@ -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])
|
||||
|
||||
@ -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 "<nonamespace>"
|
||||
|
||||
|
||||
if __name__=="__main__":
|
||||
main()
|
||||
@ -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))
|
||||
|
||||
|
||||
|
||||
|
||||
@ -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()
|
||||
@ -0,0 +1,264 @@
|
||||
#include <string.h>
|
||||
#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<a; ++i){
|
||||
ret *= 10;
|
||||
}
|
||||
return(ret);
|
||||
}
|
||||
|
||||
void display_temperature(int16_t temperature){
|
||||
// temperature is a signed int of 16* the actual temperature
|
||||
int8_t fillzero=0, i;
|
||||
char c;
|
||||
|
||||
temperature *= 10;
|
||||
// debug_int(PSTR("temperature"),temperature);
|
||||
for(i=3; 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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -0,0 +1,35 @@
|
||||
#include <avr/pgmspace.h>
|
||||
|
||||
#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);
|
||||
@ -0,0 +1,314 @@
|
||||
/****************************************************************************
|
||||
Title : HD44780U LCD library / stripped down version for lcd@usb
|
||||
Author: Peter Fleury <pfleury@gmx.ch> http://jump.to/fleury
|
||||
lcd@usb modifications by Till Harbaum <till@harbaum.org>
|
||||
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 <inttypes.h>
|
||||
#include <avr/io.h>
|
||||
#include <avr/pgmspace.h>
|
||||
#include <avr/wdt.h>
|
||||
|
||||
#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 <us> 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<<LCD_BUSY))
|
||||
busy = 1;
|
||||
|
||||
if(ctrl & LCD_CTRL_1)
|
||||
if((lcd_read(LCD_CTRL_1, 0)) & (1<<LCD_BUSY))
|
||||
busy = 1;
|
||||
|
||||
/* wait until busy flag is cleared */
|
||||
} while (busy);
|
||||
#else
|
||||
/* check all controllers at once (ugly!!!) */
|
||||
while ( (lcd_read(ctrl, 0)) & (1<<LCD_BUSY));
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
** PUBLIC FUNCTIONS
|
||||
*/
|
||||
|
||||
/*************************************************************************
|
||||
Send LCD controller instruction command
|
||||
Input: instruction to send to LCD controller, see HD44780 data sheet
|
||||
Returns: none
|
||||
*************************************************************************/
|
||||
void lcd_command(uint8_t ctrl, uint8_t cmd)
|
||||
{
|
||||
lcd_waitbusy(ctrl);
|
||||
lcd_write(ctrl, cmd, 0);
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
Send data byte to LCD controller
|
||||
Input: data to send to LCD controller, see HD44780 data sheet
|
||||
Returns: none
|
||||
*************************************************************************/
|
||||
void lcd_data(uint8_t ctrl, uint8_t data)
|
||||
{
|
||||
lcd_waitbusy(ctrl);
|
||||
lcd_write(ctrl, data, 1);
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
Clear display and set cursor to home position
|
||||
*************************************************************************/
|
||||
void lcd_clrscr(uint8_t ctrl)
|
||||
{
|
||||
lcd_command(ctrl, 1<<LCD_CLR);
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
Display string without auto linefeed
|
||||
Input: string to be displayed
|
||||
Returns: none
|
||||
*************************************************************************/
|
||||
void lcd_puts(uint8_t ctrl, const char *s)
|
||||
/* print string on lcd (no auto linefeed) */
|
||||
{
|
||||
while ( (*s) )
|
||||
lcd_data(ctrl, *s++);
|
||||
|
||||
}/* lcd_puts */
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
Initialize display
|
||||
Returns: 0 on failure, 1 else
|
||||
*************************************************************************/
|
||||
uint8_t lcd_init(uint8_t ctrl)
|
||||
{
|
||||
/*
|
||||
* Initialize LCD to 4 bit I/O mode
|
||||
*/
|
||||
|
||||
/* configure all port bits as output (all LCD lines on same port) */
|
||||
DDR(LCD_DATA_PORT) |= 0x0F;
|
||||
|
||||
/* configure all port bits as output (all LCD data lines on same */
|
||||
/* port, but control lines on different ports) */
|
||||
DDR(LCD_RS_PORT) |= _BV(LCD_RS_PIN);
|
||||
DDR(LCD_RW_PORT) |= _BV(LCD_RW_PIN);
|
||||
DDR(LCD_E_PORT) |= _BV(LCD_E0_PIN); /* first controller */
|
||||
DDR(LCD_E_PORT) |= _BV(LCD_E1_PIN); /* seconds controller */
|
||||
|
||||
delay(16000); /* wait 16ms or more after power-on */
|
||||
|
||||
/* initial write to lcd is 8bit */
|
||||
LCD_DATA_PORT = (LCD_DATA_PORT & 0xF0)| ( _BV(LCD_FUNCTION) |
|
||||
_BV(LCD_FUNCTION_8BIT)>>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<<LCD_BUSY))
|
||||
return 0;
|
||||
|
||||
/* function set: display lines */
|
||||
lcd_command(ctrl, LCD_FUNCTION_DEFAULT);
|
||||
|
||||
/* wait some time */
|
||||
delay(64);
|
||||
|
||||
/* display must not be busy anymore */
|
||||
if((lcd_read(ctrl, 0)) & (1<<LCD_BUSY))
|
||||
return 0;
|
||||
|
||||
lcd_command(ctrl, LCD_DISP_OFF); /* display off */
|
||||
lcd_clrscr(ctrl); /* display clear */
|
||||
lcd_command(ctrl, LCD_MODE_DEFAULT); /* set entry mode */
|
||||
lcd_command(ctrl, LCD_DISP_ON); /* display/cursor control */
|
||||
|
||||
return 1;
|
||||
}/* lcd_init */
|
||||
|
||||
|
||||
@ -0,0 +1,189 @@
|
||||
#ifndef LCD_H
|
||||
#define LCD_H
|
||||
/*************************************************************************
|
||||
Title : C include file for the HD44780U LCD library (lcd.c)
|
||||
Author: Peter Fleury <pfleury@gmx.ch> 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 <lcd.h> @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 <a href="http://homepage.sunrise.ch/mysunrise/peterfleury/avr-lcd44780.html" target="_blank">Interfacing a HD44780 Based LCD to an AVR</a>
|
||||
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 <inttypes.h>
|
||||
#include <avr/pgmspace.h>
|
||||
|
||||
/**
|
||||
* @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<<LCD_ENTRY_MODE) | (1<<LCD_ENTRY_INC) )
|
||||
|
||||
|
||||
/* local additions */
|
||||
#define LCD_SET_RAM_ADDR 0x80
|
||||
#define LCD_SET_CG_ADDR 0x40
|
||||
#define LCD_LINE2_ADDR 0x40
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @name Functions
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
@brief Initialize display and select type of cursor
|
||||
@param dispAttr \b LCD_DISP_OFF display off\n
|
||||
\b LCD_DISP_ON display on, cursor off\n
|
||||
\b LCD_DISP_ON_CURSOR display on, cursor on\n
|
||||
\b LCD_DISP_ON_CURSOR_BLINK display on, cursor on flashing
|
||||
@return 0 on failure, 1 on success
|
||||
*/
|
||||
extern uint8_t lcd_init(uint8_t ctrl);
|
||||
|
||||
|
||||
/**
|
||||
@brief Clear display and set cursor to home position
|
||||
@param void
|
||||
@return none
|
||||
*/
|
||||
extern void lcd_clrscr(uint8_t ctrl);
|
||||
|
||||
/**
|
||||
@brief Display string without auto linefeed
|
||||
@param s string to be displayed
|
||||
@return none
|
||||
*/
|
||||
extern void lcd_puts(uint8_t ctrl, const char *s);
|
||||
|
||||
/**
|
||||
@brief Send LCD controller instruction command
|
||||
@param cmd instruction to send to LCD controller, see HD44780 data sheet
|
||||
@return none
|
||||
*/
|
||||
extern void lcd_command(uint8_t ctrl, uint8_t cmd);
|
||||
|
||||
|
||||
/**
|
||||
@brief Send data byte to LCD controller
|
||||
|
||||
Similar to lcd_putc(), but without interpreting LF
|
||||
@param data byte to send to LCD controller, see HD44780 data sheet
|
||||
@return none
|
||||
*/
|
||||
extern void lcd_data(uint8_t ctrl, uint8_t data);
|
||||
|
||||
|
||||
|
||||
|
||||
/*@}*/
|
||||
#endif //LCD_H
|
||||
|
||||
|
||||
@ -0,0 +1,484 @@
|
||||
#include <avr/io.h>
|
||||
#include <avr/interrupt.h>
|
||||
#include <avr/pgmspace.h>
|
||||
#include <avr/eeprom.h>
|
||||
#include <util/delay.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#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++;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@ -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 <stdint.h>
|
||||
|
||||
#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
|
||||
Loading…
Reference in new issue