forked from pa-pa/AskSinPP
-
Notifications
You must be signed in to change notification settings - Fork 0
/
PhaseCut.cpp
134 lines (113 loc) · 2.98 KB
/
PhaseCut.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
//- -----------------------------------------------------------------------------------------------------------------------
// AskSin++
// 2017-03-29 papa Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/
// 2019-01-11 scuba82: highly inspired by https://github.com/blackhack/ArduLibraries/tree/master/DimmerOne
//- -----------------------------------------------------------------------------------------------------------------------
/*
Fires an interrupt, each time the zero-cross detection pin changes. Output pin will be held up high (trailing-edge phase cut) for a certain time,
correspondig to the called dim value. The pre defined values are calculated for 50Hz mains, 8Mhz CPU frequence and a prescaler of 1024.
PHASECUTMODE == 1 -> leading-edge phase cut; PHASECUTMODE == 0 trailing-edge phase cut
*/
#include "PhaseCut.h"
namespace as {
#ifndef SENSOR_ONLY
#if defined(ARDUINO_ARCH_AVR) && ! (defined(ARDUINO_AVR_ATmega32) ||defined(__AVR_ATmega128__))
PhaseCut phaseCut;
PhaseCut::PhaseCut()
{
isInit = false;
}
void PhaseCut::init(uint8_t output_pin)
{
if (isInit)
return;
isInit = true;
ZERO_CROSS_PIN = ZEROPIN;
OUTPUT_PIN = output_pin;
_timer = 0;
running = false;
pinMode(OUTPUT_PIN, OUTPUT);
pinMode(ZERO_CROSS_PIN, INPUT);
TCCR2A = 0;
TCCR2B = 0;
uint8_t oldSREG = SREG;
cli();
SetTimer();
SREG = oldSREG;
TIMSK2 |= (1 << OCIE2A); // Enable COMPA and COMPB interruptions of TIMER2
_valid_zero_crossing = true;
}
bool PhaseCut::Start()
{
if (!isInit)
return false;
uint8_t oldSREG = SREG;
cli();
SREG = oldSREG;
attachInterrupt(digitalPinToInterrupt(ZERO_CROSS_PIN), ZeroCrossEventCaller, CHANGE);
running = true;
return true;
}
bool PhaseCut::Stop()
{
if (!isInit)
return false;
detachInterrupt(digitalPinToInterrupt(ZERO_CROSS_PIN));
digitalWrite(OUTPUT_PIN, LOW);
running = false;
return false;
}
bool PhaseCut::isrunning()
{
return running;
}
bool PhaseCut::SetDimValue(double value)
{
if (!isInit)
return false;
_timer = value;
return true;
}
void PhaseCut::SetTimer()
{
OCR2A = _timer;
}
void ZeroCrossEventCaller()
{
phaseCut.ZeroCrossEvent();
}
ISR(TIMER2_COMPA_vect)
{
phaseCut.CmpAEvent();
}
void PhaseCut::ZeroCrossEvent()
{
if (!_valid_zero_crossing)
return;
_valid_zero_crossing = false;
phaseCut.Fire();
TCNT2 = 0; // Restart counter (no need to call cli() inside an ISR)
TCCR2B |= (1 << WGM21) | (1 << CS20) | (1 << CS21) | (1 << CS22) ; // Enable/start CTC and set prescaler to 1024
}
void PhaseCut::Fire()
{
#if PHASECUTMODE == 1
digitalWrite(OUTPUT_PIN, LOW);
#else
if ( _timer > 0 ) digitalWrite(OUTPUT_PIN, HIGH);
#endif
}
void PhaseCut::CmpAEvent()
{
#if PHASECUTMODE == 1
if ( _timer < 75 )digitalWrite(OUTPUT_PIN, HIGH);
#else
digitalWrite(OUTPUT_PIN, LOW);
#endif
TCCR2B = 0; // Disable/stop CTC
SetTimer();
_valid_zero_crossing = true;
}
#endif
#endif
}