360 lines
8.9 KiB
C++
Raw Normal View History

2021-06-25 18:35:16 +02:00
#include "treppe.h"
2021-06-23 21:23:31 +02:00
/*
- dimmt stufe (0 - 15, PCA9685 outputs) mit linearen ticks
2021-07-05 21:20:00 +02:00
von idle bis active pwm
- return false solange gedimmt wird
- return true bei nächster stufe
*/
bool Treppe::dimm_stufe(uint8_t stufe)
2021-07-03 17:51:14 +02:00
{
if (fsm_outputs.dimmrichtung == DR_AUFDIMMEN)
dimmer_stufe.pwm += dimmer_stufe.delta_pwm;
else
dimmer_stufe.pwm -= dimmer_stufe.delta_pwm;
Serial.printf("%3.0f", dimmer_stufe.pwm);
pwmController.setChannelPWM(stufe, static_cast<uint16_t>(dimmer_stufe.pwm));
2021-07-03 17:51:14 +02:00
dimmer_stufe.tick++;
if (dimmer_stufe.tick >= dimmer_stufe.ticks)
{
Serial.println("");
return false;
}
Serial.print(" - ");
return true;
2021-06-23 21:23:31 +02:00
}
2021-07-05 21:20:00 +02:00
/*
- dimmt treppe (all PCA9685 outputs) mit linearen ticks
von idle bis active brightness
- return false solange gedimmt wird
- return true bei ende
*/
bool Treppe::dimm_treppe()
{
// needs to be in state machine
return true;
}
/*
- nach dem dimmen einer stufe wird die stufe weitergezählt
- abbruch am ende => anim_beendet = true;
*/
void Treppe::anim_tick()
2021-06-25 04:53:06 +02:00
{
if (!dimm_stufe(dimmer_stufe.stufe))
{
// Serial.printf("anim_tick(): stufe: %d, start: %d, ziel: %d, current %f\n",
// stufe, start_pwm, ziel_pwm, current_pwm);
if (fsm_outputs.laufrichtung == LR_HOCH)
{
if (dimmer_stufe.stufe >= stufen - 1)
{
anim_beendet = true;
return;
}
dimmer_stufe.stufe++;
}
else
2021-07-03 17:51:14 +02:00
{
if (dimmer_stufe.stufe <= 0)
{
anim_beendet = true;
return;
}
dimmer_stufe.stufe--;
2021-07-03 17:51:14 +02:00
}
dimmer_stufe.tick = 0;
dimmer_stufe.pwm = dimmer_stufe.start_pwm;
}
2021-06-25 04:53:06 +02:00
}
// startbedingunen für animation
void Treppe::start_animation()
{
anim_beendet = false;
2021-07-03 17:51:14 +02:00
if (fsm_outputs.laufrichtung == LR_HOCH)
dimmer_stufe.stufe = 0;
else
dimmer_stufe.stufe = stufen - 1;
if (fsm_outputs.dimmrichtung == DR_AUFDIMMEN)
{
dimmer_stufe.start_pwm = idle_pwm_ist;
dimmer_stufe.ziel_pwm = active_pwm;
}
else
{
dimmer_stufe.start_pwm = active_pwm;
dimmer_stufe.ziel_pwm = idle_pwm_ist;
}
dimmer_stufe.tick = 0;
dimmer_stufe.pwm = dimmer_stufe.start_pwm;
2021-06-23 21:23:31 +02:00
}
2021-06-25 18:35:16 +02:00
2021-07-03 17:51:14 +02:00
void Treppe::print_state_on_change()
{
static FSMTreppeModelClass::ExtU_FSMTreppe_T last_in;
static FSMTreppeModelClass::ExtY_FSMTreppe_T last_out;
if (
fsm_inputs.anim_beendet != last_in.anim_beendet ||
fsm_inputs.sensor_oben != last_in.sensor_oben ||
fsm_inputs.sensor_unten != last_in.sensor_unten ||
fsm_inputs.ldr_schwelle != last_in.ldr_schwelle ||
fsm_outputs.dimmrichtung != last_out.dimmrichtung ||
fsm_outputs.laufrichtung != last_out.laufrichtung ||
fsm_outputs.status != last_out.status)
{
last_in.anim_beendet = fsm_inputs.anim_beendet;
last_in.sensor_oben = fsm_inputs.sensor_oben;
last_in.sensor_unten = fsm_inputs.sensor_unten;
last_in.ldr_schwelle = fsm_inputs.ldr_schwelle;
last_out.dimmrichtung = fsm_outputs.dimmrichtung;
last_out.laufrichtung = fsm_outputs.laufrichtung;
last_out.status = fsm_outputs.status;
Serial.printf("FSM IN: s_u: %d, s_o: %d, a_b: %d, l_s: %d => ",
fsm_inputs.sensor_oben, fsm_inputs.sensor_unten,
fsm_inputs.anim_beendet, fsm_inputs.ldr_schwelle);
Serial.printf("OUT: LR: %d DR: %d ST: %d\n",
fsm_outputs.laufrichtung, fsm_outputs.dimmrichtung, fsm_outputs.status);
}
}
bool Treppe::read_sensor(int sensor)
{
/*
2021-07-05 15:16:43 +02:00
reads sensors with edge detection
returns true if motion was detected
returns false if no motion was detected
returns false if motion was detected, but state did not change back to not detected
*/
uint8_t pegel = digitalRead(sensor);
static uint8_t pegel_alt[2] = {0, 0};
uint8_t index = 0;
if (sensor == SENSOR_OBEN)
index = 0;
else
index = 1;
if (pegel == 1 && pegel_alt[index] == 0)
{
pegel_alt[index] = pegel;
return true;
}
else
{
pegel_alt[index] = pegel;
return false;
}
//return static_cast<bool>(pegel);
}
2021-07-05 11:48:31 +02:00
float Treppe::read_ldr()
{
/*
Reads Illuminance in Lux
FUTURE USE : show current Illuminance on Webserver in order to calibrate
Voltage Divider 1 (R13, R14):
R13 = 220k, R14 = 82k
V(ADC) = V(in1) * R14/(R13+R14)
-> V(in1) = V(ADC) * (R13+R14)/R14
V(ADC) = analogRead(A0)/1023.00
-> V(in1) = analogRead(A0)/1023.00 * (R13+R14)/R14
= analogRead(A0) * (R13+R14)/(R14*1023.00)
= analogRead(A0) * (220k+82k)/(82k*1023.00)
= analogRead(A0) * 0.0036
Voltage Divider 2 (LDR, R1 || (R13+R14))
R1 = 47k, R13+R14 = 302k -> R1||(R13+R14) = 40,67k
Vcc/V(in1) = R(LDR) / (R1||(R13+R14))
-> R(LDR) = Vcc/V(in1) * (R1||(R13+R14))
R(LDR) = 3.3V * 40.67k / V(in1)
Join formulas:
R(LDR) = 3.3V * 40.67k / (0.0036 * analogRead(A0))
= 37280.00/analogRead(A0)
ldr_ohm = R(LDR)
E(LDR) = 6526.5 * R(LDR)^-2 (see Excel Regression)
E(LDR) = 6526.5 / (R(LDR)^2)
ldr_value = E(LDR)
*/
float ldr_ohm = 37280.00 / analogRead(A0);
float ldr_value = 6526.6/(ldr_ohm*ldr_ohm);
return ldr_value;
}
bool Treppe::check_ldr()
{
2021-07-05 11:48:31 +02:00
static uint8_t active = 0;
2021-07-05 11:48:31 +02:00
#ifdef LDRDEBUG
Serial.printf("R(LDR) = %f kOhm %f lux\n", ldr_value, lux);
return true;
2021-07-05 11:48:31 +02:00
#endif
// follow up: averaging over many samples?
2021-07-05 11:48:31 +02:00
float ldr = read_ldr();
if (ldr < ldr_schwelle) {
idle_pwm_soll = idle_pwm_max;
active = true;
}
if (ldr > ldr_schwelle + LDR_HYS) {
idle_pwm_soll = 0;
active = false;
}
if (idle_pwm_soll != idle_pwm_ist) {
}
activate_idle_pwm(active);
2021-07-05 11:48:31 +02:00
return active;
2021-06-23 21:23:31 +02:00
}
2021-07-03 17:51:14 +02:00
void Treppe::task()
{
uint32_t m=micros();
fsm_inputs.ldr_schwelle = check_ldr();
Serial.print("1:");
Serial.println(micros()-m);
m=micros();
fsm_inputs.sensor_oben = read_sensor(SENSOR_OBEN);
fsm_inputs.sensor_unten = read_sensor(SENSOR_UNTEN);
fsm_inputs.anim_beendet = anim_beendet;
Serial.print("2:");
Serial.println(micros()-m);
m=micros();
FSMTreppe_Obj.setExternalInputs(&fsm_inputs);
FSMTreppe_Obj.step();
fsm_outputs = FSMTreppe_Obj.getExternalOutputs();
Serial.print("3:");
Serial.println(micros()-m);
m=micros();
print_state_on_change();
Serial.print("4:");
Serial.println(micros()-m);
m=micros();
if( fsm_outputs.status == ST_AUFDIMMEN_HOCH ||
fsm_outputs.status == ST_ABDIMMEN_HOCH ||
fsm_outputs.status == ST_AUFDIMMEN_RUNTER ||
fsm_outputs.status == ST_ABDIMMEN_RUNTER )
{
if(anim_beendet)
start_animation();
else
anim_tick();
}
Serial.print("5:");
Serial.println(micros()-m);
m=micros();
// else if (fsm_outputs.status == ST_DIMMEN_LDR) {
// if(anim_beendet) {
// berechne_dimmer();
// anim_beendet = false;
// }
// anim_beendet = dimm_treppe();
// }
Serial.print("6:");
Serial.println(micros()-m);
2021-07-03 17:51:14 +02:00
}
void Treppe::berechne_dimmer()
{
dimmer_stufe.ticks = time_per_stair / INT_TIME; // [ms]
dimmer_stufe.delta_pwm = (float)(active_pwm - idle_pwm_ist)
/ (float)dimmer_stufe.ticks;
dimmer_ldr.ticks = time_ldr / INT_TIME; // [ms]
dimmer_ldr.delta_pwm = (float)(idle_pwm_soll - idle_pwm_ist)
/ (float)dimmer_ldr.ticks;
2021-06-23 21:23:31 +02:00
}
void Treppe::setup()
2021-07-03 17:51:14 +02:00
{
pwmController.resetDevices();
// Deactive PCA9685 Phase Balancer due to LED Flickering
// https://github.com/NachtRaveVL/PCA9685-Arduino/issues/15
// see also lib/PCA9685-Arduin/PCA9685.h:204
pwmController.init(PCA9685_PhaseBalancer_None);
//pwmController.init(PCA9685_PhaseBalancer_Linear);
pwmController.setPWMFrequency(100);
2021-07-05 21:20:00 +02:00
//pwmController.setAllChannelsPWM(idle_pwm);
pinMode(A0, INPUT);
pinMode(SENSOR_OBEN, INPUT);
pinMode(SENSOR_UNTEN, INPUT);
pinMode(OE, OUTPUT);
digitalWrite(OE, 0);
Serial.printf("dimmer_stufe.delta_pwm %f\n", dimmer_stufe.delta_pwm);
Serial.printf("Treppe: initial parameters: stufen=%d\n", stufen);
2021-06-23 21:23:31 +02:00
}
void Treppe::set_idle_prozent(const int prozent)
{
2021-07-05 21:33:08 +02:00
uint16_t new_pwm = active_pwm * prozent / 100;
set_idle_pwm_max(new_pwm);
}
void Treppe::set_idle_pwm_max(const uint16_t new_pwm)
2021-07-03 17:51:14 +02:00
{
if(new_pwm > active_pwm) {
idle_pwm_max = active_pwm;
} else {
idle_pwm_max = new_pwm;
}
Serial.printf("Treppe: idle_pwm_max=%d\n", idle_pwm_max);
2021-07-05 21:20:00 +02:00
berechne_dimmer();
activate_idle_pwm(true);
2021-06-23 21:23:31 +02:00
}
2021-07-05 16:57:09 +02:00
void Treppe::activate_idle_pwm(bool active)
{
2021-07-06 01:06:46 +02:00
static uint16_t last_pwm = 0;
2021-07-05 16:57:09 +02:00
if (fsm_outputs.status == ST_RUHEZUSTAND || fsm_outputs.status == ST_INAKTIV_LDR)
{
idle_pwm_ist = idle_pwm_max * active;
if (idle_pwm_ist != last_pwm)
2021-07-05 16:57:09 +02:00
{
// Dimming Function for all LEDS ?
2021-07-06 01:06:46 +02:00
berechne_dimmer();
pwmController.setAllChannelsPWM(idle_pwm_ist);
last_pwm = idle_pwm_ist;
2021-07-05 16:57:09 +02:00
}
}
}
2021-07-05 21:20:00 +02:00
void Treppe::set_active_pwm(uint16_t _active_pwm)
2021-07-03 17:51:14 +02:00
{
2021-07-05 21:20:00 +02:00
active_pwm = _active_pwm;
berechne_dimmer();
2021-07-05 21:20:00 +02:00
Serial.printf("Treppe: active_pwm=%d\n", active_pwm);
2021-06-23 21:23:31 +02:00
}
void Treppe::set_time_per_stair(uint16_t _time_per_stair)
2021-07-03 17:51:14 +02:00
{
time_per_stair = _time_per_stair;
berechne_dimmer();
Serial.printf("Treppe: time_per_stair=%d\n", time_per_stair);
2021-06-25 19:23:02 +02:00
}