but this is led lights
Of what kind ? 12v ? 240v ?
But as calling a function needs a "jump back" adress to the calling position storing this adress needs memory too.
again you are totally correct ! and when passing an argument to a function (i think you do that, though your code is rather un-transparent), this counts as a declared variable. Your point about the ESP32 is correct, but recursion with care and never infinitely.
If possible, can you share your code that you used to control multiple lights ?
Here it is provided 'as is' without much support. This runs on a pro-mini, which receives it's data over Serial from another pro-mini that receives DMX and controls an LCD screen with menu options. Freqstep is actually a bit low at 16us, putting a bit more stress on the CPU than it should. Just came out like an easy equation, but should probably be 24us (some other variables would have to change for that as well though)
The concept is simple.
- poll for data.
- sort data,
- wait for zero-X
- copy data into active buffer.
and in the ISR
- fire the pins one by one, every time just checking the next dimming level, starting at the longest first.
It uses TimerOne, AVR's ticker equevalent
#include <TimerOne.h>
#define ZERO_X 2 // zero-cross detection pin
#define LED_PIN 13
#define NR_LIGHTS 12
#define BAUD 9600
#define M_DELAY 1200
const uint8_t seq[NR_LIGHTS] = {A2, A1, A0, 6, 12, 11, 10, 9, 8, 7, 5, 4}; // pin sequence got a little disturbed
uint16_t dim[NR_LIGHTS], minBright[NR_LIGHTS], maxBright[NR_LIGHTS];
uint16_t sdim[NR_LIGHTS], cdim[NR_LIGHTS];
uint8_t sseq[NR_LIGHTS], cseq[NR_LIGHTS];
uint8_t freqstep = 16, hz = 50;
volatile uint16_t i = 0;
volatile uint8_t pinon;
volatile uint8_t state = 0;
void setup() {
Serial.begin(BAUD);
for (uint8_t i = 0; i < NR_LIGHTS; i++) {
pinMode(seq[i], OUTPUT);
dim[i] = 300;
minBright[i] = 600;
maxBright[i] = 90;
}
delay(20);
pinMode(ZERO_X, INPUT);
pinMode(LED_PIN, OUTPUT);
attachInterrupt(digitalPinToInterrupt(ZERO_X), ZeroCrossed, RISING);
Timer1.initialize(freqstep);
Timer1.attachInterrupt(DimCheck, freqstep);
digitalWrite(LED_PIN, LOW);
}
void loop() {
if (state == 0) DoRequest();
if (state == 1) Sort();
if (state == 3) CopySort();
}
void Sort() {
memcpy(sdim, dim, 2 * NR_LIGHTS);
memcpy(sseq, seq, NR_LIGHTS);
for (uint8_t c = 0; c < NR_LIGHTS - 1; c++) { // do a bubble sort
for (uint8_t d = 0; d < NR_LIGHTS - c - 1; d++) {
if (sdim[d] > sdim[d + 1]) { // compare
uint8_t tempseq = sseq[d];
sseq[d] = sseq[d + 1];
sseq[d + 1] = tempseq;
uint16_t tempdim = sdim[d];
sdim[d] = sdim[d + 1];
sdim[d + 1] = tempdim;
}
}
}
state = 2; // ready to copy
}
void CopySort() {
memcpy(cdim, sdim, 2 * NR_LIGHTS);
memcpy(cseq, sseq, NR_LIGHTS);
state = 0;
}
void ZeroCrossed() {
if (state = 2) state = 3; // ready to copy, start copy !!
pinon = 0; // reset array pointers
PORTD = PORTD | B11110000; // Turn all the pins HIGH
PORTB = PORTB | B11111;
PORTC = PORTC | B111;
i = 0; // reset timer counter
}
void DimCheck() {
i++; // up the counter
while ((pinon < NR_LIGHTS) && (i >= cdim[pinon])) { // compare the next pin
digitalWrite(cseq[pinon], LOW); // turn on light
pinon++;
}
}
//-----------------------------------------------------------------------------------------
void DoRequest() {
const uint32_t MSG[] = {0x53455453, 0x444D5852 };
uint8_t sbuffer[30];
if (ClearSerial(M_DELAY, 40));
Serial.flush();
Serial.print("DMXR");
uint32_t moment = millis();
while (Serial.available() < 4) {
if (millis() - moment > 200) {
if (!Serial.available()) BlinkLed(3, 150);
state = 1;
return;
}
}
for (uint8_t i = 0; i < 4; i++) sbuffer[i] = Serial.read();
uint32_t RecMSG;
for (uint8_t m = 0; m < 4; m++) {
RecMSG = RecMSG << 8;
RecMSG = RecMSG | sbuffer[m];
}
if (RecMSG == MSG[1]) { // DMXR
while (Serial.available() < NR_LIGHTS) {
if (millis() - moment > 200) { // timeout not enough data
BlinkLed(4, 100);
state = 1;
return;
}
}
for (uint8_t i = 0; i < NR_LIGHTS; i++) sbuffer[i] = Serial.read();
if (Serial.available()) {
BlinkLed(5, 70); // too much data
state = 1;
return;
}
for (uint8_t i = 0; i < NR_LIGHTS; i++) {
dim[i] = map(sbuffer[i], 0, 255, minBright[i], maxBright[i]);
}
state = 1;
return;
} // end DMXR
if (RecMSG == MSG[0]) { // SETS
while (Serial.available() < (NR_LIGHTS * 2)) {
if (millis() - moment > 200) { // timeout not enough data
BlinkLed(7, 50);
state = 1;
return;
}
}
for (uint8_t i = 0; i < NR_LIGHTS * 2; i++) sbuffer[i] = Serial.read();
if (Serial.available()) {
BlinkLed(5, 50); // too much data
state = 1;
return;
}
for (uint8_t i = 0; i < NR_LIGHTS; i++) {
minBright[i] = (uint16_t) sbuffer[i * 2] * 3 + 30;
maxBright[i] = (uint16_t) sbuffer[(i * 2) + 1] * 3 + 30;
}
state = 1;
return;
}
BlinkLed(3, 300);
state = 1;
return;
}
inline void Meditate(uint32_t us) {
uint32_t moment = micros();
while (micros() - moment < us) ;
}
inline bool WaitForSerial(uint32_t timeout) {
uint32_t moment = millis();
while (!Serial.available()) {
if (millis() - moment > timeout ) return false;
}
return true;
}
inline bool ClearSerial(uint16_t waittime, uint8_t maxbytes) {
uint8_t byt = 0;
while ((byt < maxbytes) && (Serial.available())) {
char c = Serial.read();
byt++;
if (!Serial.available()) Meditate(M_DELAY); // it is not actually required to wait every time around
}
if (byt == maxbytes) return false;
return true;
}
inline void BlinkLed(uint8_t times, uint16_t del) {
delay(400);
for (uint8_t j = 0; j < times; j++) {
digitalWrite(LED_PIN, HIGH);
delay(del);
digitalWrite(LED_PIN, LOW);
delay(del);
}
}