You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

485 lines
10 KiB

#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++;
}