From 9beb2a4bd05d1e1e2db485ac903693cccde15c65 Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Thu, 21 Mar 2013 11:34:42 +0000 Subject: [PATCH] Plate warmer firmware. --- PlateWarmer.ino | 361 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 361 insertions(+) create mode 100644 PlateWarmer.ino diff --git a/PlateWarmer.ino b/PlateWarmer.ino new file mode 100644 index 0000000..22a45ab --- /dev/null +++ b/PlateWarmer.ino @@ -0,0 +1,361 @@ +/* -*- c++ -*- + * We have a LM35 temperature sensor connected to pin A0 and we + * shall use the internal 1.1V AREF for the ADC so we have a 10nF + * capacitor connecting AREF to GND. + * + * We then have a LTC-4727C 4 digit seven segment display wired up to + * Arduino pins 2-13 as in previous demos (eg TempDisplay). + * + * Otherwise the setup is a basic breadboard arduino (ATmega328) + * + */ + +#include +#include +#include // JeeLib library +#include +#include + +#define COMMON_CATHODE // This device is common cathode +#define HAVE_SHIFT_REGISTER 1 // We are using a shift register + +// declare the digital pins for each segment led +#define SEG_A 6 +#define SEG_B 8 +#define SEG_C 5 +#define SEG_D 2 +#define SEG_E 3 +#define SEG_F 4 +#define SEG_G 7 +#define SEG_DP 13 + +#define LED_PIN 13 +#define SHIFTREG_DATA 4 // DS pin +#define SHIFTREG_CLOCK 3 // SHCP pin +#define SHIFTREG_LATCH 2 // STCP pin + +#define BUTTON_L 6 // left button +#define BUTTON_R 5 // right button + +// declare the digit selector pins +#define SEL_1 12 +#define SEL_2 11 +#define SEL_3 10 +#define SEL_4 9 +const int select[4] = { SEL_1, SEL_2, SEL_3, SEL_4 }; + +#define LM35_PIN A0 +#define NUMSAMPLES 5 + +#ifdef COMMON_CATHODE +#define SEG_OFF LOW +#define SEG_ON HIGH +#else +#define SEG_OFF HIGH +#define SEG_ON LOW +#endif + +// Table of the bit patterns for each digit in gfedcba order +const byte Digits[10] = { + 0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f +}; + +// Buffer to hold the current display characters. +// This is read by the timer interrupt +static char Display[4] = {0, 0, 0, 0}; + +// The timer interrupt sets one digit at a time and that digit is +// shown until the next interrupt. This happens quickly enough that we +// don't see any flicker and all the digits appear to be lit all the +// time. This variable selects the digit to show and rotates around +// our buffer. +volatile int current_digit = 0; + +// The timer initial counter value. +static unsigned int tcnt2 = 0; + +static unsigned int led_cnt = 0; + +// Flag to make the display flash visibly +#define STATE_NORMAL 0 +#define STATE_USERPRESS 1 +#define STATE_FLASHING 2 +static byte display_state = STATE_NORMAL; +static byte flash_cntr = 0; +static long target_temp = 0; +static long last_target = 0; + +// Serial print using FLASH strings: Serial_print(PSTR(...)); +static void Serial_print(PGM_P s) +{ + char c; + while ((c = pgm_read_byte(s++)) != 0) + Serial.print(c); +} + +// Set the I/O lines for the digit bitpattern for the currently +// selected digit. +static void +set_segments(byte v) +{ +#if HAVE_SHIFT_REGISTER + digitalWrite(SHIFTREG_LATCH, LOW); + shiftOut(SHIFTREG_DATA, SHIFTREG_CLOCK, MSBFIRST, v); + digitalWrite(SHIFTREG_LATCH, HIGH); +#else + digitalWrite(SEG_G, (v & 0x40) ? SEG_ON : SEG_OFF); + digitalWrite(SEG_F, (v & 0x20) ? SEG_ON : SEG_OFF); + digitalWrite(SEG_E, (v & 0x10) ? SEG_ON : SEG_OFF); + digitalWrite(SEG_D, (v & 0x08) ? SEG_ON : SEG_OFF); + digitalWrite(SEG_C, (v & 0x04) ? SEG_ON : SEG_OFF); + digitalWrite(SEG_B, (v & 0x02) ? SEG_ON : SEG_OFF); + digitalWrite(SEG_A, (v & 0x01) ? SEG_ON : SEG_OFF); +#endif +} + +// Select one digit and display the value using the lookup table to +// get the bit pattern. This will be on until the next timer +// interrupt. +static void +display(int digit, const char *num) +{ + // clear all select lines + digitalWrite(SEL_1, HIGH); + digitalWrite(SEL_2, HIGH); + digitalWrite(SEL_3, HIGH); + digitalWrite(SEL_4, HIGH); + + // If flashing, leave off half the time. + if (display_state == STATE_FLASHING) { + ++flash_cntr; + if (flash_cntr > 127) + return; + } + + // select our digit and configure + digitalWrite(select[digit], LOW); +#if HAVE_SHIFT_REGISTER + set_segments( Digits[num[digit] - 0x30] | ((digit == 1) ? 0x80 : 0) ); +#else + set_segments(Digits[num[digit] - 0x30]); + // set the decimal point on digit 2 + digitalWrite(SEG_DP, (digit == 1) ? SEG_ON : SEG_OFF); +#endif +} + +// Initialize timer2 as interrupt source +// See section 18 of the datasheet +// Updating the display at 6ms intervals is as slow as we can get +// before we start to notice flickering. +void +Timer2Init() +{ + // 18.9: Disable the timer2 overflow interrupt for configuration + TIMSK2 &= ~(1 << TOIE2); + // 18.9b: Select clock source as internal i/o clock + ASSR &= ~(1< 166) { + PORTB ^= _BV(PB5); + led_cnt = 0; + } +} + +// We store the currently set target temperature in the EEPROM +// as a 32 bit little-endian integer. +static long stored_target_read() +{ + long t = 2000; + byte check = EEPROM.read(3); + if (check != 0xff) { + t = (check << 24) + | (EEPROM.read(2) << 16) + | (EEPROM.read(1) << 8) + | (EEPROM.read(0)); + } + Serial_print(PSTR("eeprom read: ")); + Serial.println(t); + return t; +} + +static void stored_target_write(long t) +{ + EEPROM.write(0, t & 0xff); + EEPROM.write(1, (t >> 8) & 0xff); + EEPROM.write(2, (t >> 16) & 0xff); + EEPROM.write(3, (t >> 24) & 0xff); + Serial_print(PSTR("eeprom write: ")); + Serial.println(t); +} + +static void setDisplay(long v) +{ + Display[3] = 0x30 + (v % 10); + Display[2] = 0x30 + ((v/10) % 10); + Display[1] = 0x30 + ((v/100) % 10); + Display[0] = 0x30 + ((v/1000) % 10); +} + +void +setup() +{ + // disable TWI, Timer1, SPI and USART0 + //PRR &= (1< 11000) target_temp = 11000; + setDisplay(target_temp); + Serial_print(PSTR("target: ")); + Serial.println(target_temp); +} + +MilliTimer timer0, timer1, timer2, timer3; +bool keypress_delay = false; + +void +loop() +{ + long v = 0, t[NUMSAMPLES]; + int n; + + if (timer1.poll(100)) { + bool left_button = digitalRead(BUTTON_L) != HIGH; + bool right_button = digitalRead(BUTTON_R) != HIGH; + switch (display_state) + { + case STATE_NORMAL: + if (left_button || right_button) { + setState(STATE_USERPRESS); + timer2.set(1000); + } + break; + case STATE_USERPRESS: + if (timer2.poll()) { + if (left_button || right_button) { + setState(STATE_FLASHING); + timer2.set(5000); + keypress_delay = true; + setDisplay(target_temp); + last_target = target_temp; + } + else { + setState(STATE_NORMAL); + } + } + break; + case STATE_FLASHING: + // avoid accepting presses for the first second + if (!keypress_delay) { + if (left_button) + incrementTargetTemp(-100); + if (right_button) + incrementTargetTemp(100); + } + if (left_button || right_button) // reset timeout + timer2.set(5000); + if (keypress_delay) { + if (timer2.remaining() < 4000) + keypress_delay = false; + } + if (timer2.poll()) { + setState(STATE_NORMAL); + if (target_temp != last_target) { + stored_target_write(target_temp); + } + } + break; + } + } + + if (timer0.poll(1000)) { + if (display_state != STATE_FLASHING) { + Serial.print(millis()); + Serial.print(" "); + for (n = 0; n < NUMSAMPLES; ++n) { + t[n] = getTemperature(); + delay(10); + } + for (n = 0 ; n < NUMSAMPLES; ++n) { + v += t[n]; + } + v /= NUMSAMPLES; + Serial.println(v); + setDisplay(v); + } + } +} -- 2.23.0