Пример #1
0
void GrillPid::setOutputDevice(unsigned char outputDevice)
{
  TIMSK1 = 0;
  // Fast PWM Timer with TOP=ICR1 with no OC1x output
  TCCR1A = bit(WGM11);

  switch (outputDevice)
  {
    case PIDOUTPUT_Default:
    case PIDOUTPUT_Fan:
      _outputDevice = PIDOUTPUT_Fan;
      // 64 prescaler
      TCCR1B = bit(WGM13) | bit(WGM12) | bit(CS11) | bit(CS10);
      // 511 TOP to be close to original 488Hz and allows OCR1B to be set to
      // 512 to prevent COMB_vect from firing (which means no LOW when at 100%)
      ICR1 = 511;
      break;
    case PIDOUTPUT_Servo:
      _outputDevice = PIDOUTPUT_Servo;
      // 8 prescaler gives us down to 30Hz with 0.5usec resolution
      TCCR1B = bit(WGM13) | bit(WGM12) | bit(CS11);
      // TOP = servo refresh
      ICR1 = uSecToTicks(SERVO_REFRESH);
      break;
  }

  // Interrupt on overflow, and OCB
  TIMSK1 = bit(OCIE1B) | bit(TOIE1);
}
Пример #2
0
inline void GrillPid::commitServoOutput(void)
{
#if defined(GRILLPID_SERVO_ENABLED)
  unsigned char output;
  if (bit_is_set(_outputFlags, PIDFLAG_SERVO_ANY_MAX) && _pidOutput > 0)
    output = 100;
  else
    output = _pidOutput;

  if (bit_is_set(_outputFlags, PIDFLAG_INVERT_SERVO))
    output = 100 - output;

  // Get the output speed in 10x usec by LERPing between min and max
  output = mappct(output, _minServoPos, _maxServoPos);
  // Servo output is actually set on the next interrupt cycle
  _servoOutput = uSecToTicks(10U * output);
#endif
}
Пример #3
0
inline void GrillPid::commitFanSpeed(void)
{
  /* Long PWM period is 10 sec */
  const unsigned int LONG_PWM_PERIOD = 10000;
  const unsigned int PERIOD_SCALE = (LONG_PWM_PERIOD / TEMP_MEASURE_PERIOD);

  calcExpMovingAverage(FANSPEED_AVG_SMOOTH, &FanSpeedAvg, _fanSpeed);

  if (_outputDevice == PIDOUTPUT_Fan)
  {
    /* For anything above _minFanSpeed, do a nomal PWM write.
       For below _minFanSpeed we use a "long pulse PWM", where
       the pulse is 10 seconds in length.  For each percent we are
       emulating, run the fan for one interval. */
    unsigned char output;
    if (_fanSpeed >= _minFanSpeed)
    {
      output = _fanSpeed;
      _longPwmTmr = 0;
    }
    else
    {
      // Simple PWM, ON for first [FanSpeed] intervals then OFF
      // for the remainder of the period
      if (((PERIOD_SCALE * _fanSpeed / _minFanSpeed) > _longPwmTmr))
        output = _minFanSpeed;
      else
        output = 0;

      if (++_longPwmTmr > (PERIOD_SCALE - 1))
        _longPwmTmr = 0;
    }  /* long PWM */

    if (_invertPwm)
      output = _maxFanSpeed - output;
    OCR1B = (unsigned int)output * 512 / 100;
  }
  else
  {
    // GrillPidOutput::Servo
    unsigned char output;
    if (_invertPwm)
      output = 100 - _fanSpeed;
    else
      output = _fanSpeed;
    // Get the output speed in 10x usec by LERPing between min and max
    output = ((_maxFanSpeed - _minFanSpeed) * (unsigned int)output / 100) + _minFanSpeed;
    OCR1B = uSecToTicks(10U * output);
  }

#if defined(TIMER1_DEBUG)
  SerialX.print("HMLG,0,");
  SerialX.print(" ICR1="); SerialX.print(ICR1, DEC);
  SerialX.print(" OCR1B="); SerialX.print(OCR1B, DEC);
  SerialX.print(" TCCR1A=x"); SerialX.print(TCCR1A, HEX);
  SerialX.print(" TCCR1B=x"); SerialX.print(TCCR1B, HEX);
  SerialX.print(" TCCR1C=x"); SerialX.print(TCCR1C, HEX);
  SerialX.print(" TIMSK1=x"); SerialX.print(TIMSK1, HEX);
  if (ovf) { ovf = false; SerialX.print(" ovf"); }
  if (rst) { SerialX.print(' '); SerialX.print(rst, DEC); rst = 0; }
  if (bit_is_set(TIFR1, TOV1)) { SerialX.print(" TOV1"); TIFR1 = bit(TOV1); }
  SerialX.nl();
#endif
}