Mercurial > ~darius > hgwebdir.cgi > tempctrl
view main.c @ 77:ca5fc59ec4f0
Change default temperature to 18C - better for Ale yeast.
author | darius@Inchoate |
---|---|
date | Wed, 21 Jan 2009 22:51:59 +1030 |
parents | 56165caf744b |
children |
line wrap: on
line source
/* * Monitor fermenter temperature and control it by switching cooler & heater. * * Copyright (c) 2009 * Daniel O'Connor <darius@dons.net.au>. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include <avr/io.h> #include <avr/interrupt.h> #include <avr/pgmspace.h> #include <stdio.h> #include <string.h> #include <ctype.h> #include <stdlib.h> #include <util/delay.h> #include <avr/wdt.h> #include "cons.h" #include "1wire.h" #include "tempctrl.h" #include "ds1307.h" /* * Mirror of the MCUCSR register, taken early during startup. */ uint8_t mcucsr __attribute__((section(".noinit"))); void process_cmd(void); /* * Read out and reset MCUCSR early during startup. */ void handle_mcucsr(void) __attribute__((section(".init3"))) __attribute__((naked)); void handle_mcucsr(void) { wdt_disable(); mcucsr = MCUCSR; MCUCSR = 0; } int main(void) { /* Disable interrupts while we frob stuff */ cli(); #if 0 /* Disable JTAG (yes twice) */ MCUCSR |= _BV(JTD); MCUCSR |= _BV(JTD); #endif DDRA = 0xff; PORTA = 0x00; DDRB = 0x00; PORTB = 0x00; /* GPIO (0:7) */ DDRC = 0xff; PORTC = 0x00; /* USART (0:1), IDBus (2:5), 485 (6:6), GPIO (7:7) */ DDRD = 0xf7; PORTD = 0xf7; /* Beep * * Fpwm = Fclk / (N * 510) * = 16e6 / (8 * 510) * = 3921Hz * * Behind ifndef because PB3 is A0 on PDI chip * * Phase correct PWM, non-inverted output, divide by 8 */ TCCR0 = _BV(WGM00) | _BV(WGM11) | _BV(COM00) | _BV(COM01) | _BV(CS01); OCR0 = 128; /* Set up the one wire stuff */ OWInit(); /* Setup IIC */ ds1307_init(); /* Init UART */ cons_init(); /* Init temperature control stuff */ tempctrl_init(); printf_P(PSTR("\r\n\r\n===============\r\n" "Inited!\r\n\r\n")); if ((mcucsr & _BV(PORF)) == _BV(PORF)) printf_P(PSTR("Power on reset\r\n")); if ((mcucsr & _BV(EXTRF)) == _BV(EXTRF)) printf_P(PSTR("External reset\r\n")); if ((mcucsr & _BV(BORF)) == _BV(BORF)) printf_P(PSTR("Brown-out reset\r\n")); if ((mcucsr & _BV(WDRF)) == _BV(WDRF)) printf_P(PSTR("Watchdog reset\r\n")); if ((mcucsr & _BV(JTRF)) == _BV(JTRF)) printf_P(PSTR("JTAG reset\r\n")); /* Ready to go! */ sei(); /* * Enable the watchdog with the largest prescaler. Will cause a * watchdog reset after approximately 2 s @ Vcc = 5 V * * Gets reset in the loop below and in the tempctrl.c timer IRQ */ wdt_enable(WDTO_2S); printf_P(PSTR("> ")); cmd.state = 0; /* Wait for user input or an "interrupt" */ while (1) { wdt_reset(); tempctrl_update(); if (cmd.state == 255) { process_cmd(); printf_P(PSTR("> ")); /* Allow new characters to be processed */ cmd.state = 0; } } } void process_cmd(void) { uint8_t ROM[8], crc, buf[9], temp; int8_t i, arg; int16_t t; /* User just pressed enter */ if (cmd.len == 0) return; if (!strcasecmp_P((char *)cmd.buf, PSTR("?")) || !strcasecmp_P((char *)cmd.buf, PSTR("help"))) { printf_P(PSTR("rs Reset and check for presence\r\n" "sr Search the bus for ROMs\r\n" "re Read a bit\r\n" "rb Read a byte\r\n" "wr bit Write a bit\r\n" "wb byte Write a byte (hex)\r\n" "wc cmd [ROMID] Write command\r\n" "te ROMID Read the temperature from a DS1820\r\n" "in port Read from a port\r\n" "ou port val Write to a port (val in hex)\r\n" "dd port [val] Read/write DDR for a port (val in hex)\r\n" "rt ROMID Read DS2502 status page\r\n" "we ROMID adr val Write data into a DS2502 PROM (adr & val in hex)\r\n" "rr ROMID Read DS2502 PROM\r\n" "zz Reset MCU\r\n" "gc Get time of day\r\n" "sc time Set time of day (time is YYYY/MM/DD HH:MM:SS)\r\n" "tc ... Temperature control related (tc help for more)\r\n")); return; } else if (!strncasecmp_P((char *)cmd.buf, PSTR("zz"), 2)) { cli(); wdt_enable(WDTO_15MS); for (;;) ; } else if (!strncasecmp_P((char *)cmd.buf, PSTR("rs"), 2)) { printf_P(PSTR("Resetting... ")); if (OWTouchReset() == 1) printf_P(PSTR("No presence pulse found\r\n")); else printf_P(PSTR("Presence pulse found\r\n")); } else if (!strncasecmp_P((char *)cmd.buf, PSTR("re"), 2)) { if (OWReadBit()) printf_P(PSTR("Read a 1\r\n")); else printf_P(PSTR("Read a 0\r\n")); } else if (!strncasecmp_P((char *)cmd.buf, PSTR("rb"), 2)) { printf_P(PSTR("Read a 0x%02x\r\n"), OWReadByte()); } else if (!strncasecmp_P((char *)cmd.buf, PSTR("wr"), 2)) { arg = strtol((char *)cmd.buf + 3, (char **)NULL, 10); OWWriteBit(arg); printf_P(PSTR("Wrote a %c\r\n"), arg ? '1' : '0'); } else if (!strncasecmp_P((char *)cmd.buf, PSTR("wb"), 2)) { arg = (int)strtol((char *)cmd.buf + 3, (char **)NULL, 16); OWWriteByte(arg); } else if (!strncasecmp_P((char *)cmd.buf, PSTR("rt"), 2)) { if (sscanf_P((char *)cmd.buf, PSTR("rt %hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hhx"), &ROM[0], &ROM[1], &ROM[2], &ROM[3], &ROM[4], &ROM[5], &ROM[6], &ROM[7]) != 8) { printf_P(PSTR("Unable to parse ROM ID\r\n")); return; } if (ROM[0] != OW_FAMILY_ROM) { printf_P(PSTR("ROM specified isn't a DS2502\r\n")); return; } if (OWTouchReset() != 0) { printf_P(PSTR("No presence\r\n")); return; } crc = 0; OWCRC(OW_READ_STATUS, &crc); OWSendCmd(ROM, OW_READ_STATUS); OWWriteByte(0x00); OWCRC(0x00, &crc); OWWriteByte(0x00); OWCRC(0x00, &crc); if (crc != OWReadByte()) { printf_P(PSTR("CRC mismatch on command & address\r\n")); return; } crc = 0; for (i = 0; i < 8; i++) { temp = OWReadByte(); printf_P(PSTR("%02x "), temp); OWCRC(temp, &crc); } printf_P(PSTR("\r\n")); if (crc != OWReadByte()) { printf_P(PSTR("CRC mismatch on data\r\n")); return; } } else if (!strncasecmp_P((char *)cmd.buf, PSTR("we"), 2)) { uint8_t adr, data; if (sscanf_P((char *)cmd.buf, PSTR("we %hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hhx %hhx %hhx"), &ROM[0], &ROM[1], &ROM[2], &ROM[3], &ROM[4], &ROM[5], &ROM[6], &ROM[7], &adr, &data) != 10) { printf_P(PSTR("Unable to parse ROM ID\r\n")); return; } if (ROM[0] != OW_FAMILY_ROM) { printf_P(PSTR("ID specified isn't a ROM\r\n")); return; } if (OWTouchReset() != 0) { printf_P(PSTR("No presence\r\n")); return; } printf_P(PSTR("OWProgROM returned %S\r\n"), OWProgROM_Status[OWProgROM(ROM, buf[0], 2, &buf[1], 0, 0)]); } else if (!strncasecmp_P((char *)cmd.buf, PSTR("rr"), 2)) { if (sscanf_P((char *)cmd.buf, PSTR("rr %hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hhx"), &ROM[0], &ROM[1], &ROM[2], &ROM[3], &ROM[4], &ROM[5], &ROM[6], &ROM[7]) != 8) { printf_P(PSTR("Unable to parse ROM ID\r\n")); return; } if (ROM[0] != OW_FAMILY_ROM) { printf_P(PSTR("ROM specified isn't a ROM\r\n")); return; } crc = 0; OWSendCmd(ROM, OW_READ_MEMORY); OWCRC(OW_READ_MEMORY, &crc); OWWriteByte(0x00); OWCRC(0x00, &crc); OWWriteByte(0x00); OWCRC(0x00, &crc); if (crc != OWReadByte()) { printf_P(PSTR("CRC mismatch on command & address\r\n")); return; } crc = 0; for (buf[0] = 0; buf[0] < 128; buf[0]++) { buf[1] = OWReadByte(); if (buf[0] > 0) { if (buf[0] % 16 != 0) printf_P(PSTR(" ")); else printf_P(PSTR("\r\n")); } printf_P(PSTR("%02x"), buf[1]); OWCRC(buf[1], &crc); } printf_P(PSTR("\r\n")); if (crc != OWReadByte()) { printf_P(PSTR("CRC mismatch on data\r\n")); return; } } else if (!strncasecmp_P((char *)cmd.buf, PSTR("wc"), 2)) { uint8_t c; i = sscanf_P((char *)cmd.buf, PSTR("wc %hhx %hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hhx"), &ROM[0], &ROM[1], &ROM[2], &ROM[3], &ROM[4], &ROM[5], &ROM[6], &ROM[7], &c); if (i != 1 && i != 9) { printf_P(PSTR("Incorrect usage\r\n")); return; } if (i == 1) { OWSendCmd(i == 1 ? NULL : ROM, c); return; } } else if (!strncasecmp_P((char *)cmd.buf, PSTR("te"), 2)) { if (sscanf_P((char *)cmd.buf, PSTR("te %hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hhx"), &ROM[0], &ROM[1], &ROM[2], &ROM[3], &ROM[4], &ROM[5], &ROM[6], &ROM[7]) != 8) { printf_P(PSTR("Unable to parse ROM ID\r\n")); return; } t = OWGetTemp(ROM); switch (t) { case OW_TEMP_WRONG_FAM: printf_P(PSTR("ROM specified isn't a temperature sensor\r\n")); break; case OW_TEMP_CRC_ERR: printf_P(PSTR("CRC mismatch\r\n")); break; case OW_TEMP_NO_ROM: printf_P(PSTR("No ROM found\r\n")); break; default: printf_P(PSTR("%d.%02d\r\n"), GETWHOLE(t), GETFRAC(t)); break; } } else if (!strncasecmp_P((char *)cmd.buf, PSTR("sr"), 2)) { memset(ROM, 0, 8); i = OWFirst(ROM, 1, 0); do { switch (i) { case OW_BADWIRE: printf_P(PSTR("Presence pulse, but no module found, bad module/cabling?\r\n")); break; case OW_NOPRESENCE: printf_P(PSTR("No presence pulse found\r\n")); break; case OW_BADCRC: printf_P(PSTR("Bad CRC\r\n")); break; case OW_NOMODULES: case OW_FOUND: break; default: printf_P(PSTR("Unknown error from 1 wire library\r\n")); break; } if (i != OW_FOUND) break; for (i = 0; i < 8; i++) printf_P(PSTR("%02x%S"), ROM[i], i == 7 ? PSTR("\r\n") : PSTR(":")); i = OWNext(ROM, 1, 0); } while (1); } else if (!strncasecmp_P((char *)cmd.buf, PSTR("in"), 2)) { uint8_t inp; switch (tolower(cmd.buf[3])) { case 'a': inp = PINA; break; case 'b': inp = PINB; break; case 'c': inp = PINC; break; case 'd': inp = PIND; break; default: printf_P(PSTR("Unknown port\r\n")); return; } printf_P(PSTR("0x%02x\r\n"), inp); } else if (!strncasecmp_P((char *)cmd.buf, PSTR("ou"), 2)) { char port; int val; if (sscanf_P((char *)cmd.buf, PSTR("ou %c %x"), &port, &val) != 2) { printf_P(PSTR("Unable to parse ou arguments\r\n")); return; } switch (port) { case 'a': PORTA = val & 0xff; break; case 'b': PORTB = val & 0xff; break; case 'c': PORTC = val & 0xff; break; case 'd': PORTD = val & 0xff; break; default: printf_P(PSTR("Unknown port\r\n")); return; } printf_P(PSTR("PORT%c <= 0x%02x\r\n"), toupper(port), val); } else if (!strncasecmp_P((char *)cmd.buf, PSTR("dd"), 2)) { char port; uint8_t val; int num; num = sscanf_P((char *)cmd.buf, PSTR("dd %c %x"), &port, &val); if (num != 2 && num != 3) { printf_P(PSTR("Unable to parse dd arguments\r\n")); return; } if (num == 2) { switch (port) { case 'a': val = DDRA; break; case 'b': val = DDRB; break; case 'c': val = DDRC; break; case 'd': val = DDRD; break; default: printf_P(PSTR("Unknown port\r\n")); return; } printf_P(PSTR("DDR%c => 0x%02x\r\n"), toupper(port), val); } else { switch (port) { case 'a': DDRA = val & 0xff; break; case 'b': DDRB = val & 0xff; break; case 'c': DDRC = val & 0xff; break; case 'd': DDRD = val & 0xff; break; default: printf_P(PSTR("Unknown port\r\n")); return; } printf_P(PSTR("DDR%c <= 0x%02x\r\n"), toupper(port), val); } } else if (!strncasecmp_P((char *)cmd.buf, PSTR("tc"), 2)) { tempctrl_cmd((char *)cmd.buf); } else if (!strncasecmp_P((char *)cmd.buf, PSTR("gc"), 2)) { ds1307_printtime(PSTR(""), PSTR("\r\n")); } else if (!strncasecmp_P((char *)cmd.buf, PSTR("sc"), 2)) { if (cmd.len < 17) { printf_P(PSTR("Command not long enough\r\n")); } else { if (ds1307_settod((char *)cmd.buf + 3) != 1) printf_P(PSTR("Unable to set time of day\r\n")); } } else { printf_P(PSTR("Unknown command, help for a list\r\n")); } }