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