2021-01-29 06:31:58 -05:00
|
|
|
//
|
|
|
|
// FILE: HeartBeat.cpp
|
|
|
|
// AUTHOR: Rob Tillaart
|
2022-07-27 06:53:36 -04:00
|
|
|
// VERSION: 0.3.1
|
2021-01-29 06:31:58 -05:00
|
|
|
// PURPOSE: Arduino library for HeartBeat with frequency and dutyCycle
|
|
|
|
// DATE: 2019-06-12
|
|
|
|
// URL: https://github.com/RobTillaart/HeartBeat
|
|
|
|
//
|
|
|
|
// HISTORY:
|
|
|
|
// 0.1.0 2019-06-12 initial version
|
2022-02-05 10:53:02 -05:00
|
|
|
// 0.1.1 2020-12-24 Arduino-CI
|
2021-01-29 06:31:58 -05:00
|
|
|
// 0.1.2 2021-01-15 renamed all to HeartBeat
|
|
|
|
// added dutyCycle
|
2022-02-05 10:53:02 -05:00
|
|
|
// 0.1.3 2021-05-27 fix Arduino-lint
|
2022-07-27 06:53:36 -04:00
|
|
|
//
|
2021-11-02 12:26:51 -04:00
|
|
|
// 0.2.0 2021-11-02 update Build-CI, add badges
|
|
|
|
// add getFrequency(), getDutyCycle();
|
|
|
|
// add getState().
|
|
|
|
// removed set()
|
2021-12-19 06:08:01 -05:00
|
|
|
// 0.2.1 2021-12-18 update library.json, license, minor edits
|
2022-07-27 06:53:36 -04:00
|
|
|
//
|
2022-02-05 10:53:02 -05:00
|
|
|
// 0.3.0 2022-02-04 added HeartBeatDiag class.
|
|
|
|
// added HeartBeatSL class (slightly simpler).
|
2022-07-27 06:53:36 -04:00
|
|
|
// 0.3.1 2022-07-26 move all code to .cpp
|
|
|
|
// add isEnabled()
|
|
|
|
// rename examples
|
|
|
|
// add example SRF05 distance sensor
|
|
|
|
|
2021-01-29 06:31:58 -05:00
|
|
|
|
|
|
|
|
|
|
|
#include "HeartBeat.h"
|
|
|
|
|
|
|
|
|
|
|
|
HeartBeat::HeartBeat()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void HeartBeat::begin(const uint8_t pin, float frequency)
|
|
|
|
{
|
|
|
|
_pin = pin;
|
|
|
|
pinMode(_pin, OUTPUT);
|
|
|
|
|
|
|
|
setFrequency(frequency);
|
|
|
|
enable();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void HeartBeat::setFrequency(float frequency)
|
|
|
|
{
|
2021-11-02 12:26:51 -04:00
|
|
|
_frequency = frequency;
|
|
|
|
if (_frequency < 0) _frequency = -frequency;
|
|
|
|
if (_frequency < 0.001) _frequency = 0.001;
|
2021-01-29 06:31:58 -05:00
|
|
|
_setFreqDuty();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void HeartBeat::setDutyCycle(float dutyCycle)
|
|
|
|
{
|
2022-07-27 06:53:36 -04:00
|
|
|
_dutyCycle = dutyCycle;
|
|
|
|
if (_dutyCycle < 0) _dutyCycle = 0;
|
|
|
|
if (_dutyCycle > 100) _dutyCycle = 100;
|
2021-01-29 06:31:58 -05:00
|
|
|
_setFreqDuty();
|
|
|
|
}
|
|
|
|
|
2021-05-28 07:30:27 -04:00
|
|
|
|
2022-07-27 06:53:36 -04:00
|
|
|
float HeartBeat::getFrequency()
|
|
|
|
{
|
|
|
|
return _frequency;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
float HeartBeat::getDutyCycle()
|
|
|
|
{
|
|
|
|
return _dutyCycle;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
void HeartBeat::enable()
|
|
|
|
{
|
|
|
|
_running = true;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
void HeartBeat::disable()
|
|
|
|
{
|
|
|
|
_running = false;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
bool HeartBeat::isEnabled()
|
|
|
|
{
|
|
|
|
return _running;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2021-01-29 06:31:58 -05:00
|
|
|
void HeartBeat::beat()
|
|
|
|
{
|
2022-02-05 10:53:02 -05:00
|
|
|
if (_running == false)
|
2021-01-29 06:31:58 -05:00
|
|
|
{
|
2021-11-02 12:26:51 -04:00
|
|
|
_state = LOW;
|
2021-01-29 06:31:58 -05:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
uint32_t now = micros();
|
2021-11-02 12:26:51 -04:00
|
|
|
if ((_state == LOW) && (now - _lastHeartBeat) < _dutyCycleLow) return;
|
|
|
|
if ((_state == HIGH) && (now - _lastHeartBeat) < _dutyCycleHigh) return;
|
2021-01-29 06:31:58 -05:00
|
|
|
_lastHeartBeat = now;
|
2021-11-02 12:26:51 -04:00
|
|
|
_state = !_state;
|
2021-01-29 06:31:58 -05:00
|
|
|
}
|
2021-11-02 12:26:51 -04:00
|
|
|
digitalWrite(_pin, _state);
|
2021-01-29 06:31:58 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2022-07-27 06:53:36 -04:00
|
|
|
uint8_t HeartBeat::getState()
|
|
|
|
{
|
|
|
|
return _state;
|
|
|
|
};
|
2022-02-05 10:53:02 -05:00
|
|
|
|
|
|
|
|
2021-01-29 06:31:58 -05:00
|
|
|
/////////////////////////////////
|
2021-11-02 12:26:51 -04:00
|
|
|
//
|
2022-02-05 10:53:02 -05:00
|
|
|
// PROTECTED
|
2021-11-02 12:26:51 -04:00
|
|
|
//
|
2021-01-29 06:31:58 -05:00
|
|
|
void HeartBeat::_setFreqDuty()
|
|
|
|
{
|
|
|
|
float time = 10000.0/_frequency;
|
|
|
|
_dutyCycleHigh = round(_dutyCycle * time);
|
|
|
|
_dutyCycleLow = round((100 - _dutyCycle) * time);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2022-02-05 10:53:02 -05:00
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
|
|
// HEARTBEATDIAG
|
|
|
|
//
|
|
|
|
HeartBeatDiag::HeartBeatDiag():HeartBeat()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void HeartBeatDiag::beat()
|
|
|
|
{
|
|
|
|
// normal mode
|
|
|
|
if (_codeMask == 0)
|
|
|
|
{
|
|
|
|
_codeStart = 0;
|
|
|
|
HeartBeat::beat();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
// _code mode
|
|
|
|
if (_codeStart == 0)
|
|
|
|
{
|
|
|
|
// force a LOW first.
|
|
|
|
_codeStart = 1;
|
|
|
|
_lastHeartBeat = micros();
|
|
|
|
_state = LOW;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
uint32_t period = (_dutyCycleLow + _dutyCycleHigh)/2;
|
|
|
|
uint32_t now = micros();
|
|
|
|
if ((now - _lastHeartBeat) < period) return;
|
|
|
|
_lastHeartBeat = now;
|
|
|
|
if (_state == LOW)
|
|
|
|
{
|
|
|
|
while (_codeMask > _code)
|
|
|
|
{
|
|
|
|
_codeMask /= 10;
|
|
|
|
}
|
|
|
|
if (_codeMask == 0) return;
|
|
|
|
_pulseLength = _code / _codeMask;
|
|
|
|
_code -= ( _pulseLength * _codeMask );
|
|
|
|
_state = HIGH;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
_pulseLength--;
|
|
|
|
if (_pulseLength == 0)
|
|
|
|
{
|
|
|
|
_state = LOW;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
digitalWrite(_pin, _state);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool HeartBeatDiag::code(uint32_t pattern)
|
|
|
|
{
|
|
|
|
// already running an errorCode?
|
|
|
|
if (_code > 0) return false;
|
|
|
|
// pattern too long
|
|
|
|
if (pattern > 999999999) return false;
|
|
|
|
|
|
|
|
_code = pattern;
|
|
|
|
_codeMask = 100000000;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2022-07-27 06:53:36 -04:00
|
|
|
void HeartBeatDiag::codeOff()
|
|
|
|
{
|
|
|
|
_codeMask = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2022-02-05 10:53:02 -05:00
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
|
|
// HEARTBEATSL
|
|
|
|
//
|
|
|
|
// string LS version is simpler and somewhat smaller footprint,
|
|
|
|
//
|
|
|
|
|
|
|
|
#define HEARTBEATSL_SHORT 1
|
|
|
|
#define HEARTBEATSL_LONG 3
|
|
|
|
|
|
|
|
|
|
|
|
HeartBeatSL::HeartBeatSL():HeartBeat()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void HeartBeatSL::beat()
|
|
|
|
{
|
|
|
|
// normal mode
|
|
|
|
if (_codeMask == 0)
|
|
|
|
{
|
|
|
|
_codeStart = 0;
|
|
|
|
HeartBeat::beat();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
// _code mode
|
|
|
|
if (_codeStart == 0)
|
|
|
|
{
|
|
|
|
// force a LOW first.
|
|
|
|
_codeStart = 1;
|
|
|
|
_lastHeartBeat = micros();
|
|
|
|
_state = LOW;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
uint32_t period = (_dutyCycleLow + _dutyCycleHigh)/2;
|
|
|
|
uint32_t now = micros();
|
|
|
|
if ((now - _lastHeartBeat) < period) return;
|
|
|
|
_lastHeartBeat = now;
|
|
|
|
if (_state == LOW)
|
|
|
|
{
|
|
|
|
_pulseLength = HEARTBEATSL_SHORT;
|
|
|
|
if (_code & _codeMask) // 1 ==> LONG
|
|
|
|
{
|
|
|
|
_pulseLength = HEARTBEATSL_LONG;
|
|
|
|
}
|
|
|
|
_codeMask >>= 1;
|
|
|
|
_state = HIGH;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
_pulseLength--;
|
|
|
|
if (_pulseLength == 0)
|
|
|
|
{
|
|
|
|
_state = LOW;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
digitalWrite(_pin, _state);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool HeartBeatSL::code(const char * str)
|
|
|
|
{
|
|
|
|
// already running an errorCode?
|
|
|
|
if (_codeMask > 0) return false;
|
|
|
|
// pattern too long
|
|
|
|
uint8_t len = strlen(str);
|
|
|
|
if (len > 7) return false;
|
|
|
|
|
|
|
|
_code = 0;
|
|
|
|
_codeMask = 1 << len;
|
|
|
|
for (uint8_t i = 0; i < len; i++)
|
|
|
|
{
|
|
|
|
if (str[i] == 'L') _code |= 1;
|
|
|
|
_code <<= 1;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2022-07-27 06:53:36 -04:00
|
|
|
void HeartBeatSL::codeOff()
|
|
|
|
{
|
|
|
|
_codeMask = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-01-29 06:31:58 -05:00
|
|
|
// -- END OF FILE --
|
2021-11-02 12:26:51 -04:00
|
|
|
|