Example #1
0
static void rfSourceNotify(RFSource &r, unsigned char event)
{
  for (unsigned char i=0; i<TEMP_COUNT; ++i)
    if ((pid.Probes[i]->getProbeType() == PROBETYPE_RF12) &&
    ((rfMap[i] == RFSOURCEID_ANY) || (rfMap[i] == r.getId()))
    )
    {
      if (event == RFEVENT_Remove)
        pid.Probes[i]->calcTemp(0);
      else if (r.isNative())
        pid.Probes[i]->setTemperatureC(r.Value / 10.0f);
      else
      {
        unsigned int val = r.Value;
        unsigned char adcBits = rfmanager.getAdcBits();
        // If the remote is lower resolution then shift it up to our resolution
        if (adcBits < pid.getAdcBits())
          val <<= (pid.getAdcBits() - adcBits);
        pid.Probes[i]->calcTemp(val);
      }
    } /* if probe is this source */

  if (event & (RFEVENT_Add | RFEVENT_Remove))
    outputRfStatus();
}
Example #2
0
static void reportFanParams(void)
{
  print_P(PSTR("HMFN" CSV_DELIMITER));
  SerialX.print(pid.getMinFanSpeed(), DEC);
  Serial_csv();
  SerialX.print(pid.getMaxFanSpeed(), DEC);
  Serial_csv();
  SerialX.print(pid.getMinServoPos(), DEC);
  Serial_csv();
  SerialX.print(pid.getMaxServoPos(), DEC);
  Serial_csv();
  SerialX.print(pid.getOutputFlags(), DEC);
  Serial_nl();
}
Example #3
0
static void newTempsAvail(void)
{
  static unsigned char pidCycleCount;

  updateDisplay();
  ++pidCycleCount;
    
  if ((pidCycleCount % 0x20) == 0)
    outputRfStatus();

  outputCsv();
  // We want to report the status before the alarm readout so
  // receivers can tell what the value was that caused the alarm
  checkAlarms();

  if (g_LogPidInternals)
    pid.pidStatus();

  if ((pidCycleCount % 0x04) == 1)
    outputAdcStatus();

  ledmanager.publish(LEDSTIMULUS_Off, LEDACTION_Off);
  ledmanager.publish(LEDSTIMULUS_LidOpen, pid.isLidOpen());
  ledmanager.publish(LEDSTIMULUS_FanOn, pid.isOutputActive());
  ledmanager.publish(LEDSTIMULUS_FanMax, pid.isOutputMaxed());
  ledmanager.publish(LEDSTIMULUS_PitTempReached, pid.isPitTempReached());
  ledmanager.publish(LEDSTIMULUS_Startup, pid.getPitStartRecover() == PIDSTARTRECOVER_STARTUP);
  ledmanager.publish(LEDSTIMULUS_Recovery, pid.getPitStartRecover() == PIDSTARTRECOVER_RECOVERY);

#ifdef HEATERMETER_RFM12
  rfmanager.sendUpdate(pid.getPidOutput());
#endif
}
Example #4
0
void TempProbe::calcTemp(void)
{
  const float ADCmax = (1 << (10+TEMP_OVERSAMPLE_BITS)) - 1;
  if (_accumulatedCount != 0)
  {
    unsigned int ADCval = _accumulator / _accumulatedCount;
    _accumulatedCount = 0;

    // Units 'A' = ADC value
    if (pid.getUnits() == 'A')
    {
      Temperature = ADCval;
      return;
    }

    if (ADCval != 0)  // Vout >= MAX is reduced in readTemp()
    {
      float R, T;
      // If you put the fixed resistor on the Vcc side of the thermistor, use the following
      R = Steinhart[3] / ((ADCmax / (float)ADCval) - 1.0f);
      // If you put the thermistor on the Vcc side of the fixed resistor use the following
      //R = Steinhart[3] * ADCmax / (float)Vout - Steinhart[3];

      // Units 'R' = resistance, unless this is the pit probe (which should spit out Celsius)
      if (pid.getUnits() == 'R' && this != pid.Probes[TEMP_PIT])
      {
        Temperature = R;
        return;
      };

      // Compute degrees K
      R = log(R);
      T = 1.0f / ((Steinhart[2] * R * R + Steinhart[1]) * R + Steinhart[0]);

      setTemperatureC(T - 273.15f);
    } /* if ADCval */
    else
      Temperature = NAN;
  } /* if accumulatedcount */

  if (hasTemperature())
  {
    calcExpMovingAverage(TEMPPROBE_AVG_SMOOTH, &TemperatureAvg, Temperature);
    Alarms.updateStatus(Temperature);
  }
  else
    Alarms.silenceAll();
}
Example #5
0
void ProbeAlarm::updateStatus(int value)
{
  // Low: Arming point >= Thresh + 1.0f, Trigger point < Thresh
  // A low alarm set for 100 enables at 101.0 and goes off at 99.9999...
  if (getLowEnabled())
  {
    if (value >= (getLow() + 1))
      Armed[ALARM_IDX_LOW] = true;
    else if (value < getLow() && Armed[ALARM_IDX_LOW])
      Ringing[ALARM_IDX_LOW] = true;
  }

  // High: Arming point < Thresh - 1.0f, Trigger point >= Thresh
  // A high alarm set for 100 enables at 98.9999... and goes off at 100.0
  if (getHighEnabled())
  {
    if (value < (getHigh() - 1))
      Armed[ALARM_IDX_HIGH] = true;
    else if (value >= getHigh() && Armed[ALARM_IDX_HIGH])
      Ringing[ALARM_IDX_HIGH] = true;
  }

  if (pid.isLidOpen())
    Ringing[ALARM_IDX_LOW] = Ringing[ALARM_IDX_HIGH] = false;
}
Example #6
0
static void outputCsv(void)
{
#ifdef HEATERMETER_SERIAL
  print_P(PSTR("HMSU" CSV_DELIMITER));
  pid.status();
  Serial_nl();
#endif /* HEATERMETER_SERIAL */
}
Example #7
0
static void reportLidParameters(void)
{
  print_P(PSTR("HMLD" CSV_DELIMITER));
  SerialX.print(pid.LidOpenOffset, DEC);
  Serial_csv();
  SerialX.print(pid.getLidOpenDuration(), DEC);
  Serial_nl();
}
Example #8
0
static void storeProbeType(unsigned char probeIndex, unsigned char probeType)
{
  unsigned char ofs = getProbeConfigOffset(probeIndex, offsetof( __eeprom_probe, probeType));
  if (ofs != 0)
  {
    pid.setProbeType(probeIndex, probeType);
    econfig_write_byte((unsigned char *)ofs, probeType);
  }
}
Example #9
0
void storeSetPoint(int sp)
{
  // If the setpoint is >0 that's an actual setpoint.  
  // 0 or less is a manual fan speed
  boolean isManualMode;
  if (sp > 0)
  {
    config_store_word(setPoint, sp);
    pid.setSetPoint(sp);
    
    isManualMode = false;
  }
  else
  {
    pid.setPidOutput(-sp);
    isManualMode = true;
  }

  config_store_byte(manualMode, isManualMode);
}
Example #10
0
void TempProbe::setTemperatureC(float T)
{
  // Sanity - anything less than -20C (-4F) or greater than 500C (932F) is rejected
  if (T <= -20.0f || T > 500.0f)
    Temperature = NAN;
  else
  {
    if (pid.getUnits() == 'F')
      Temperature = (T * (9.0f / 5.0f)) + 32.0f;
    else
      Temperature = T;
    Temperature += Offset;
  }
}
Example #11
0
void storeLidParam(unsigned char idx, int val)
{
  if (val < 0)
    val = 0;

  switch (idx)
  {
    case 0:
      pid.LidOpenOffset = val;
      config_store_byte(lidOpenOffset, val);
      break;
    case 1:
      pid.setLidOpenDuration(val);
      config_store_word(lidOpenDuration, val);
      break;
    case 2:
      if (val)
        pid.resetLidOpenResumeCountdown();
      else
        pid.LidOpenResumeCountdown = 0;
      break;
  }
}
Example #12
0
static void storePidParam(char which, float value)
{
  unsigned char k;
  switch (which)
  {
    case 'b': k = 0; break;
    case 'p': k = 1; break;
    case 'i': k = 2; break;
    case 'd': k = 3; break;
    default:
      return;
  }
  pid.setPidConstant(k, value);

  unsigned char ofs = offsetof(__eeprom_data, pidConstants[0]);
  econfig_write_block(&pid.Pid[k], (void *)(ofs + k * sizeof(float)), sizeof(value));
}
Example #13
0
void hmcoreLoop(void)
{ 
#ifdef HEATERMETER_SERIAL 
  serial_doWork();
#endif /* HEATERMETER_SERIAL */

#ifdef HEATERMETER_RFM12
  if (rfmanager.doWork())
    ledmanager.publish(LEDSTIMULUS_RfReceive, LEDACTION_OneShot);
#endif /* HEATERMETER_RFM12 */

  Menus.doWork();
  if (pid.doWork())
    newTempsAvail();
  tone_doWork();
  ledmanager.doWork();
}
Example #14
0
static void eepromLoadBaseConfig(unsigned char forceDefault)
{
  // The compiler likes to join eepromLoadBaseConfig and eepromLoadProbeConfig s
  // this union saves stack space by reusing the same memory area for both structs
  union {
    struct __eeprom_data base;
    struct __eeprom_probe probe;
  } config;

  econfig_read_block(&config.base, 0, sizeof(__eeprom_data));
  forceDefault = forceDefault || config.base.magic != EEPROM_MAGIC;
  if (forceDefault != 0)
  {
    memcpy_P(&config.base, &DEFAULT_CONFIG[forceDefault - 1], sizeof(__eeprom_data));
    econfig_write_block(&config.base, 0, sizeof(__eeprom_data));
  }
  
  pid.setSetPoint(config.base.setPoint);
  pid.LidOpenOffset = config.base.lidOpenOffset;
  pid.setLidOpenDuration(config.base.lidOpenDuration);
  memcpy(pid.Pid, config.base.pidConstants, sizeof(config.base.pidConstants));
  if (config.base.manualMode)
    pid.setPidOutput(0);
  setLcdBacklight(config.base.lcdBacklight);
#ifdef HEATERMETER_RFM12
  memcpy(rfMap, config.base.rfMap, sizeof(rfMap));
#endif
  pid.setUnits(config.base.pidUnits == 'C' ? 'C' : 'F');
  pid.setMinFanSpeed(config.base.minFanSpeed);
  pid.setMaxFanSpeed(config.base.maxFanSpeed);
  pid.setOutputFlags(config.base.pidOutputFlags);
  g_HomeDisplayMode = config.base.homeDisplayMode;
  pid.setMinServoPos(config.base.minServoPos);
  pid.setMaxServoPos(config.base.maxServoPos);

  for (unsigned char led = 0; led<LED_COUNT; ++led)
    ledmanager.setAssignment(led, config.base.ledConf[led]);
}
Example #15
0
static void reportFanParams(void)
{
  print_P(PSTR("HMFN" CSV_DELIMITER));
  SerialX.print(pid.getFanMinSpeed(), DEC);
  Serial_csv();
  SerialX.print(pid.getFanMaxSpeed(), DEC);
  Serial_csv();
  SerialX.print(pid.getServoMinPos(), DEC);
  Serial_csv();
  SerialX.print(pid.getServoMaxPos(), DEC);
  Serial_csv();
  SerialX.print(pid.getOutputFlags(), DEC);
  Serial_csv();
  SerialX.print(pid.getFanMaxStartupSpeed(), DEC);
  Serial_csv();
  SerialX.print(pid.getFanActiveFloor(), DEC);
  Serial_csv();
  SerialX.print(pid.getServoActiveCeil(), DEC);
  Serial_nl();
}
Example #16
0
void hmcoreSetup(void)
{
  pinModeFast(PIN_WIRELESS_LED, OUTPUT);
  blinkLed();
  
#ifdef HEATERMETER_SERIAL
  Serial.begin(HEATERMETER_SERIAL);
  // don't use SerialX because we don't want any preamble
  Serial.write('\n');
  reportVersion();
#endif  /* HEATERMETER_SERIAL */
  // Disable Analog Comparator
  ACSR = bit(ACD);
  // Disable Digital Input on ADC pins
  DIDR0 = bit(ADC5D) | bit(ADC4D) | bit(ADC3D) | bit(ADC2D) | bit(ADC1D) | bit(ADC0D);
  // And other unused units
  power_twi_disable();

  // Switch the pin mode first to INPUT with internal pullup
  // to take it to 5V before setting the mode to OUTPUT. 
  // If we reverse this, the pin will go OUTPUT,LOW and reboot.
  // SoftReset and WiShield are mutually exlusive, but it is HIGH/OUTPUT too
  digitalWriteFast(PIN_SOFTRESET, HIGH);
  pinModeFast(PIN_SOFTRESET, OUTPUT);

  tone4khz_init();

  pid.Probes[TEMP_PIT] = &probe0;
  pid.Probes[TEMP_FOOD1] = &probe1;
  pid.Probes[TEMP_FOOD2] = &probe2;
  pid.Probes[TEMP_AMB] = &probe3;

  eepromLoadConfig(0);
  pid.init();
  lcdDefineChars();
#ifdef HEATERMETER_RFM12
  checkInitRfManager();
#endif

  Menus.setState(ST_HOME_NOPROBES);
}
Example #17
0
static void storeFanActiveFloor(unsigned char fanActiveFloor)
{
  pid.setFanActiveFloor(fanActiveFloor);
  config_store_byte(fanActiveFloor, pid.getFanActiveFloor());
}
Example #18
0
static void storeMaxFanSpeed(unsigned char maxFanSpeed)
{
  maxFanSpeed = constrain(maxFanSpeed, 0, 100);
  pid.setMaxFanSpeed(maxFanSpeed);
  config_store_byte(maxFanSpeed, maxFanSpeed);
}
Example #19
0
static void storePidUnits(char units)
{
  pid.setUnits(units);
  if (units == 'C' || units == 'F')
    config_store_byte(pidUnits, units);
}
Example #20
0
void updateDisplay(void)
{
  // Updates to the temperature can come at any time, only update 
  // if we're in a state that displays them
  state_t state = Menus.getState();
  if (!isMenuHomeState())
    return;

  char buffer[17];
  unsigned char probeIdxLow, probeIdxHigh;

  // Fixed pit area
  lcd.setCursor(0, 0);
  if (state == ST_HOME_ALARM)
  {
    toneEnable(true);
    if (ALARM_ID_TO_IDX(g_AlarmId) == ALARM_IDX_LOW)
      lcdprint_P(PSTR("** ALARM LOW  **"), false);
    else
      lcdprint_P(PSTR("** ALARM HIGH **"), false);

    probeIdxLow = probeIdxHigh = ALARM_ID_TO_PROBE(g_AlarmId);
  }  /* if ST_HOME_ALARM */
  else
  {
    toneEnable(false);

    /* Big Number probes overwrite the whole display if it has a temperature */
    if (g_HomeDisplayMode >= TEMP_PIT && g_HomeDisplayMode <= TEMP_AMB)
    {
      TempProbe *probe = pid.Probes[g_HomeDisplayMode];
      if (probe->hasTemperature())
      {
        lcdPrintBigNum(probe->Temperature);
        return;
      }
    }

    /* Default Pit / Fan Speed first line */
    int pitTemp;
    if (pid.Probes[TEMP_CTRL]->hasTemperature())
      pitTemp = pid.Probes[TEMP_CTRL]->Temperature;
    else
      pitTemp = 0;
    if (!pid.getManualOutputMode() && !pid.Probes[TEMP_CTRL]->hasTemperature())
      memcpy_P(buffer, LCD_LINE1_UNPLUGGED, sizeof(LCD_LINE1_UNPLUGGED));
    else if (pid.LidOpenResumeCountdown > 0)
      snprintf_P(buffer, sizeof(buffer), PSTR("Pit:%3d"DEGREE"%c Lid%3u"),
        pitTemp, pid.getUnits(), pid.LidOpenResumeCountdown);
    else
    {
      char c1,c2;
      if (pid.getManualOutputMode())
      {
        c1 = '^';  // LCD_ARROWUP
        c2 = '^';  // LCD_ARROWDN
      }
      else
      {
        c1 = '[';
        c2 = ']';
      }
      snprintf_P(buffer, sizeof(buffer), PSTR("Pit:%3d"DEGREE"%c %c%3u%%%c"),
        pitTemp, pid.getUnits(), c1, pid.getPidOutput(), c2);
    }

    lcd.print(buffer);
    // Display mode 0xff is 2-line, which only has space for 1 non-pit value
    if (g_HomeDisplayMode == 0xff)
      probeIdxLow = probeIdxHigh = state - ST_HOME_FOOD1 + TEMP_FOOD1;
    else
    {
      // Display mode 0xfe is 4 line home, display 3 other temps there
      probeIdxLow = TEMP_FOOD1;
      probeIdxHigh = TEMP_AMB;
    }
  } /* if !ST_HOME_ALARM */

  // Rotating probe display
  for (unsigned char probeIndex=probeIdxLow; probeIndex<=probeIdxHigh; ++probeIndex)
  {
    if (probeIndex < TEMP_COUNT && pid.Probes[probeIndex]->hasTemperature())
    {
      loadProbeName(probeIndex);
      snprintf_P(buffer, sizeof(buffer), PSTR("%-12s%3d"DEGREE), editString,
        (int)pid.Probes[probeIndex]->Temperature);
    }
    else
    {
      // If probeIndex is outside the range (in the case of ST_HOME_NOPROBES)
      // just fill the bottom line with spaces
      memset(buffer, ' ', sizeof(buffer));
      buffer[sizeof(buffer) - 1] = '\0';
    }

    lcd.setCursor(0, probeIndex - probeIdxLow + 1);
    lcd.print(buffer);
  }
}
Example #21
0
static void storePidOutputFlags(unsigned char pidOutputFlags)
{
  pid.setOutputFlags(pidOutputFlags);
  config_store_byte(pidOutputFlags, pidOutputFlags);
}
Example #22
0
static void storeServoMaxPos(unsigned char servoMaxPos)
{
  pid.setServoMaxPos(servoMaxPos);
  config_store_byte(servoMaxPos, servoMaxPos);
}
Example #23
0
static void storeMinServoPos(unsigned char minServoPos)
{
  pid.setMinServoPos(minServoPos);
  config_store_byte(minServoPos, minServoPos);
}
Example #24
0
static void checkInitRfManager(void)
{
  if (pid.countOfType(PROBETYPE_RF12) != 0)
    rfmanager.init(HEATERMETER_RFM12);
}
Example #25
0
void TempProbe::calcTemp(void)
{
  const float ADCmax = (1 << (10+TEMP_OVERSAMPLE_BITS)) - 1;
  if (_accumulatedCount != 0)
  {
    unsigned int ADCval = _accumulator / _accumulatedCount;
    _accumulatedCount = 0;

    // Units 'A' = ADC value
    if (pid.getUnits() == 'A')
    {
      Temperature = ADCval;
      return;
    }

    if (ADCval != 0)  // Vout >= MAX is reduced in readTemp()
    {
      if (_probeType == PROBETYPE_TC_ANALOG)
      {
        float mvScale = Steinhart[3];
        // Commented out because there's no "divide by zero" exception so
        // just allow undefined results to save prog space
        //if (mvScale == 0.0f)
        //  mvScale = 1.0f;
        // If scale is <100 it is assumed to be mV/C with a 3.3V reference
        if (mvScale < 100.0f)
          mvScale = 3300.0f / mvScale;
        setTemperatureC(ADCval / ADCmax * mvScale);
      }
      else {
        float R, T;
        // If you put the fixed resistor on the Vcc side of the thermistor, use the following
        R = Steinhart[3] / ((ADCmax / (float)ADCval) - 1.0f);
        // If you put the thermistor on the Vcc side of the fixed resistor use the following
        //R = Steinhart[3] * ADCmax / (float)Vout - Steinhart[3];

        // Units 'R' = resistance, unless this is the pit probe (which should spit out Celsius)
        if (pid.getUnits() == 'R' && this != pid.Probes[TEMP_PIT])
        {
          Temperature = R;
          return;
        };

        // Compute degrees K
        R = log(R);
        T = 1.0f / ((Steinhart[2] * R * R + Steinhart[1]) * R + Steinhart[0]);

        setTemperatureC(T - 273.15f);
      } /* if PROBETYPE_INTERNAL */
    } /* if ADCval */
    else
      Temperature = NAN;
  } /* if accumulatedcount */

  if (hasTemperature())
  {
    calcExpMovingAverage(TEMPPROBE_AVG_SMOOTH, &TemperatureAvg, Temperature);
    Alarms.updateStatus(Temperature);
  }
  else
    Alarms.silenceAll();
}
Example #26
0
static void storeServoActiveCeil(unsigned char servoActiveCeil)
{
  pid.setServoActiveCeil(servoActiveCeil);
  config_store_byte(servoActiveCeil, pid.getServoActiveCeil());
}
Example #27
0
static void storeFanMaxStartupSpeed(unsigned char fanMaxStartupSpeed)
{
  pid.setFanMaxStartupSpeed(fanMaxStartupSpeed);
  config_store_byte(fanMaxStartupSpeed, pid.getFanMaxStartupSpeed());
}
Example #28
0
static void storeMaxServoPos(unsigned char maxServoPos)
{
  pid.setMaxServoPos(maxServoPos);
  config_store_byte(maxServoPos, maxServoPos);
}