mirror of
https://github.com/RobTillaart/Arduino.git
synced 2024-10-03 18:09:02 -04:00
150 lines
2.8 KiB
C++
150 lines
2.8 KiB
C++
//
|
|
// FILE: PulsePattern.cpp
|
|
// AUTHOR: Rob Tillaart
|
|
// VERSION: 0.1.7
|
|
// DATE: 2012-11-23
|
|
// PURPOSE: Arduino Library to generate repeating pulse patterns
|
|
|
|
|
|
#include "PulsePattern.h"
|
|
|
|
|
|
// Predefined generator (singleton)
|
|
PulsePattern PPGenerator;
|
|
|
|
|
|
ISR(TIMER1_COMPA_vect)
|
|
{
|
|
PPGenerator.worker();
|
|
}
|
|
|
|
|
|
PulsePattern::PulsePattern()
|
|
{
|
|
_size = 0;
|
|
_state = NOTINIT;
|
|
_ar = NULL;
|
|
_cnt = 0;
|
|
_level = LOW;
|
|
_prescaler = 0;
|
|
_pin = 0;
|
|
}
|
|
|
|
|
|
void PulsePattern::init(const uint8_t pin, const uint16_t * ar, const uint8_t size,
|
|
const uint8_t level, const uint8_t prescaler)
|
|
{
|
|
_pin = pin;
|
|
pinMode(_pin, OUTPUT);
|
|
stop();
|
|
|
|
_ar = (uint16_t *) ar;
|
|
_size = size;
|
|
_level = level ? LOW : HIGH;
|
|
_prescaler = constrain(prescaler, PRESCALE_1, PRESCALE_1024);
|
|
_cnt = 0;
|
|
|
|
digitalWrite(_pin, _level);
|
|
_state = STOPPED;
|
|
|
|
// fast low level AVR ports
|
|
uint8_t _pinport = digitalPinToPort(_pin);
|
|
_pinout = portOutputRegister(_pinport);
|
|
_pinbit = digitalPinToBitMask(_pin);
|
|
}
|
|
|
|
|
|
void PulsePattern::start(uint32_t times)
|
|
{
|
|
if (_state == RUNNING) return; // no restart
|
|
_cnt = 0; // start from begin
|
|
_times = times;
|
|
cont();
|
|
}
|
|
|
|
|
|
void PulsePattern::cont()
|
|
{
|
|
if (_state == RUNNING) return; // no continue
|
|
if (_size == 0) return; // no pattern
|
|
setTimer(1); // start asap
|
|
_state = RUNNING;
|
|
}
|
|
|
|
|
|
void PulsePattern::stop()
|
|
{
|
|
stopTimer();
|
|
_state = STOPPED;
|
|
_level = LOW;
|
|
digitalWrite(_pin, _level);
|
|
}
|
|
|
|
|
|
void PulsePattern::worker()
|
|
{
|
|
if (_state != RUNNING) return;
|
|
// set next period & flip signal
|
|
_level = !_level;
|
|
// digitalWrite(_pin, _level);
|
|
// direct port much faster
|
|
if (_level == 0) *_pinout &= ~_pinbit;
|
|
else *_pinout |= _pinbit;
|
|
|
|
if (_factor != 4096)
|
|
{
|
|
OCR1A = _ar[_cnt] * _factor * (F_CPU/1000000UL) / 4096;
|
|
}
|
|
else
|
|
{
|
|
OCR1A = _ar[_cnt] * (F_CPU/1000000UL);
|
|
}
|
|
_cnt++;
|
|
if (_cnt >= _size)
|
|
{
|
|
_cnt = 0; // reset pattern
|
|
switch(_times)
|
|
{
|
|
case PP_CONTINUOUS:
|
|
break;
|
|
case 1:
|
|
_times--;
|
|
case 0:
|
|
stop();
|
|
break;
|
|
default:
|
|
_times--;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// TIMER code based upon - http://www.gammon.com.au/forum/?id=11504
|
|
void PulsePattern::stopTimer()
|
|
{
|
|
TCCR1A = 0; // reset timer 1
|
|
TCCR1B = 0;
|
|
}
|
|
|
|
|
|
void PulsePattern::setTimer(const uint16_t cc) const
|
|
{
|
|
TCCR1A = 0; // stop timer first
|
|
TCCR1B = 0;
|
|
TCNT1 = 0; // reset counter
|
|
OCR1A = cc * 16; // compare A register value;
|
|
// * 16 makes max period 4095
|
|
// min period 12?
|
|
|
|
// 4: CTC mode, top = OCR1A
|
|
TCCR1A = _BV (COM1A1); // clear on compare
|
|
TCCR1B = _BV (WGM12) | _prescaler;
|
|
TIFR1 |= _BV (OCF1A); // clear interrupt flag
|
|
TIMSK1 = _BV (OCIE1A); // interrupt on Compare A Match
|
|
}
|
|
|
|
|
|
// -- END OF FILE --
|
|
|