Really strange LED problem

I use a RGB led on a Arduino Uno. My program lit the colors in setup during a LED test and then leave all off. This works as expected. Then in my program I lit colors depending an value from a soundsensor. When this value is between 100 and 150 the green should light up. And with a breakpoint I can conclude that this happen. But then after the program continues the green LED extinguishes. This is beyond my understanding. In the LOOP I only set LED in the SetLED function and I have set breakpoints on the lines that turn off the green led and these are never hit. But still the green is turned of. Values that should lit blue and red does so but when new data comes first the green occasionally lit up before the blue or red turns on and remains on. Full program below

#include <LiquidCrystal.h>
#include <RH_ASK.h>
#include <SPI.h>

const int RED     =  9;
const int GREEN   = 10;
const int BLUE    =  8;
const int Gate =    13;
const int Envelope = 1;
const int Pressure = 0;



LiquidCrystal lcd(6,7,5,4,3,2); 

RH_ASK  rf_driver;

void setup()
{
  pinMode(Gate, INPUT);
  pinMode(RED, OUTPUT);                           //Red
  pinMode(BLUE, OUTPUT);                          //Blue
  pinMode(GREEN, OUTPUT);                         //Green 
  pinMode(12, OUTPUT);                            //Radio module data
  Serial.begin(9600);
  lcd.begin(16,2);
  Serial.println();
  if (!rf_driver.init())
      Serial.println("RF init failed");
  else
      Serial.println("RF init OK");
 
  Serial.println();
  Serial.println("SUPERVISOR STARTED");
  lcd.print("** Supervisor **");
  lcd.setCursor(0, 1);
  lcd.print("Test LEDS"); 
  lcd.setCursor(10, 1);
  lcd.print("RED");
  digitalWrite(RED,HIGH);
  delay(2900);
  lcd.setCursor(10, 1);
  lcd.print("BLUE");
  digitalWrite(RED,LOW);
  digitalWrite(BLUE,HIGH);
  delay(2900);
  lcd.setCursor(10, 1);
  lcd.print("GREEN");
  digitalWrite(BLUE,LOW);
  digitalWrite(GREEN,HIGH);
  delay(2900);
  digitalWrite(GREEN,LOW);
  delay(2900);
  NewDisplayLCDHeaders();
}

unsigned long int soundLowTime = 0;
unsigned long int soundMidTime = 0;
unsigned long int soundHigTime = 0;
unsigned long int soundGTime = 0;
unsigned long int pulsetime = 0;
bool    gateevent, lowevent, midevent, highevent;
bool CompletePulse = false;         //With regard to threshold 50
bool soundLowFlag = false;
bool soundMidFlag = false;
bool soundHigFlag = false;
bool soundGFlag = false;
bool soundgate = false;
bool gatePulse = false;
bool lowPulse = false;
bool midPulse = false;
bool highPulse = false;
bool newData = false;
bool newsndmax = false;
bool newpulse = false;
unsigned int soundlevel;
unsigned int soundGlevel = 0;       //soundlevel when active gate is detected
unsigned int soundMinGlevel = 0xFFF;//min detected soundlevel when gate triggered
unsigned int soundLowLevel = 0;     //Soundlevel when low soundlevel detected
unsigned int soundMidLevel = 0;     //Soundlevel when mid soundlevel detected
unsigned int soundHigLevel = 0;     //Soundlevel when high soundlevel detected
unsigned int pdrlevel;
unsigned int soundmax;
unsigned int soundmin;
unsigned int pdrmax;
unsigned int pdrmin;
unsigned long int pdrsum;
unsigned int pdravg;
unsigned int soundGateNr = 0;
unsigned int soundLowNr =  0;
unsigned int soundMidNr =  0;
unsigned int soundHigNr =  0;
unsigned int soundPrevGateNr = 0;
unsigned int soundPrevLowNr  = 0;
unsigned int soundPrevMidNr  = 0;
unsigned int soundPrevHigNr  = 0;
char sndlowdur[7] = "      ";
char sndmiddur[7] = "      ";
char sndhigdur[7] = "      ";
char sndGdur[7] = "      ";
char sndnr[6] = "     ";
char sndgnr[6] = "     ";
char sndlownr[6] = "     ";
char sndmidnr[6] = "     ";
char sndhignr[6] = "     ";
char sndmax[5] = "    ";
char sndmin[5] = "    ";
char sndlev[6] = "     ";
char pdrlev[6] = "     ";
char sndlowlevel[5] = "    ";
char sndmidlevel[5] = "    ";
char sndhiglevel[5] = "    ";
char prsmax[5] = "    ";
char prsmin[5] = "    ";
char prsavg[5] = "    ";
char GateLevelString[5] = "    ";
char LowLevelString[5] = "    ";
char MidLevelString[5] = "    ";
char HighLevelString[5] = "    ";
char datastring[50];
char tempstr[10];
int  MaxPulseLevel = 0;

unsigned long int MaxPulseCount = 0;

void loop() 
{
  // put your main code here, to run repeatedly:
  soundlevel = analogRead(Envelope);
  pdrlevel = analogRead(Pressure);
  soundmax=soundlevel; 
  soundmin=soundlevel;
  pdrmax=pdrlevel;
  pdrmin=pdrlevel;
  gateevent = lowevent = midevent = highevent = false;
  do
  {
      newData = false;                                     // No completed soundpulse detected
      soundgate = digitalRead(Gate);                       // Read the digitsal sound gate output
      soundlevel = analogRead(Envelope);                   // Read the analog envelope soundlevel value
      pdrlevel = analogRead(Pressure);                     // Read the analog pressure level 
      AnalyzeSoundPulse();                                 // With regard to threshold 50
      setSoundData();                                      // Set Max Min values and newsndmax flag
      if (newsndmax)
      {
          newsndmax = false;
          SetLED(soundmax);
          FillSpacesLCD(3, 0);
          lcd.setCursor(3, 0);
          itoa(soundmax, sndmax, 10);
          lcd.print(sndmax);                               //Max level during whole runtime in upper left corner of LCD    
      }
      setPressureData();                                   // Set Max Min values
      GetSoundDataPulses();                                // Check for below or above threshold for specific (G,L,M,H) completed soundpulses
      ResetDataString();
      SetDataString();
      if (newData)
      {
          Serial.println(datastring);
          rf_driver.send((const uint8_t *)datastring,strlen(datastring));
          if (CompletePulse)
          {
              CompletePulse = false;
              Serial.print("MaxPulseLevel=");
              Serial.println(MaxPulseLevel);
              DisplayPulseData();
          }
          PrintPulseCounts();
      }     
      NewDisplayLCDData();
  } while(true);
}

void  PrintPulseCounts()
{
    Serial.print("Gate count=");
    Serial.println(soundGateNr);
    Serial.print("Low count =");
    Serial.println(soundLowNr);
    Serial.print("Mid  count=");
    Serial.println(soundMidNr);
    Serial.print("High count=");
    Serial.println(soundHigNr);   
}

void  AnalyzeSoundPulse()
{
    if (soundlevel > 50)
    {
        if (!newpulse)                              //If a new pulse has started
        {
            pulsetime = millis();
            MaxPulseLevel = soundlevel;
            newpulse = true;
        }
        else
        {
            if (soundlevel > MaxPulseLevel)         //Track max soundlevel during pulse
                MaxPulseLevel = soundlevel;
        }
    }
    else if (newpulse)                              //Completed pulse for threshold 50
    {
        pulsetime = millis() - pulsetime;
        newpulse = false;
        CompletePulse = true;
        MaxPulseCount++;
    }
}

void  GetSoundDataPulses()                          //Detect max level and duration for specific (G,L,M,H) pulses and set flag for occured event
{
    if (soundgate)                                  //Is gate on soundsensor triggered ? Then G event
    {
        if (!soundGFlag)
        {
            soundGTime = millis();                  //First time gate event active start timer
            soundGlevel = soundlevel;               //And store soundlevel at time when event detected
            soundGFlag = true;                      //gate pulse started
        }
    }
    else if (soundGFlag)                            //If gate no longer active but have been thus soundgate event has ended
    {
        soundGTime = millis() - soundGTime;         //Calculate time in mS for soundgate event
        soundGFlag = false;
        gateevent = true;
        soundGateNr += 1;                           //Count up number of this pulse event has occured
    }

    if (soundlevel >= 100)                          //Low L event
    {
        if (!soundLowFlag)
        {
            soundLowTime = millis();
            soundLowLevel = soundlevel;
            soundLowFlag = true;
        }
        else
        {
            if (soundlevel > soundLowLevel)
                soundLowLevel = soundlevel;
        }
    }
    else if (soundLowFlag)                             //Have been over soundlevel threshold
    {
        soundLowTime = millis() - soundLowTime;
        soundLowFlag = false;
        lowevent = true;
        soundLowNr += 1;
    }

    if (soundlevel >= 150)
    {
        if (!soundMidFlag)
        {
            soundMidTime = millis();
            soundMidLevel = soundlevel;
            soundMidFlag = true;
        }
        else
        {
            if (soundlevel > soundMidLevel)
                soundMidLevel = soundlevel;
        }
    }
    else if (soundMidFlag)                             //Have been over soundlevel threshold
    {
        soundMidTime = millis() - soundMidTime;
        soundMidFlag = false;
        midevent = true;
        soundMidNr += 1;
    }

    if (soundlevel >= 250)
    {
        if (!soundHigFlag)
        {
            soundHigTime = millis();
            soundHigLevel = soundlevel;
            soundHigFlag = true;
        }
        else
        {
            if (soundlevel > soundHigLevel)
                soundHigLevel = soundlevel;
        }
    }
    else if (soundHigFlag)                             //Have been over soundlevel threshold
    {
        soundHigTime = millis() - soundHigTime;
        soundHigFlag = false;
        highevent = true;
        soundHigNr += 1;
    }
}

void  SetDataString()
{
    if (soundGateNr > soundPrevGateNr)                      //Check if new sound pulses (has it raised above and then back to below threshold?)
    {
        gatePulse = true;                                   //Gate pulse has happened
        soundPrevGateNr = soundGateNr;
        itoa(soundGateNr, sndgnr, 10);
        datastring[0] = 'G';
        strcat(datastring, sndgnr);
        itoa(soundGTime, sndGdur, 10);
        datastring[strlen(datastring)] = 'D';
        strcat(datastring, sndGdur);
        datastring[strlen(datastring)] = 'N';
        itoa(soundGlevel, sndlev, 10);
        strcat(datastring, sndlev);
        itoa(soundGlevel, GateLevelString, 10);
        newData = true;
    }

    if (soundLowNr > soundPrevLowNr)
    {
        lowPulse = true;                                  //Low pulse has happened
        soundPrevLowNr = soundLowNr;
        itoa(soundLowNr, sndlownr, 10);
        if (gateevent)
            datastring[strlen(datastring)] = 'L';
        else
            datastring[0] = 'L';

        strcat(datastring, sndlownr);
        itoa(soundLowTime, sndlowdur, 10);
        datastring[strlen(datastring)] = 'D';
        strcat(datastring, sndlowdur);
        datastring[strlen(datastring)] = 'N';
        itoa(soundLowLevel, sndlev, 10);
        strcat(datastring, sndlev);
        itoa(soundLowLevel, LowLevelString, 10);
        newData = true;
    }

    if (soundMidNr > soundPrevMidNr)
    {
        midPulse = true;                                  //Mid pulse has happened
        soundPrevMidNr = soundMidNr;
        itoa(soundMidNr, sndmidnr, 10);
        if (lowevent)
            datastring[strlen(datastring)] = 'M';
        else
            datastring[0] = 'M';

        strcat(datastring, sndmidnr);
        itoa(soundMidTime, sndmiddur, 10);
        datastring[strlen(datastring)] = 'D';
        strcat(datastring, sndmiddur);
        datastring[strlen(datastring)] = 'N';
        itoa(soundMidLevel, sndlev, 10);
        strcat(datastring, sndlev);
        itoa(soundMidLevel, MidLevelString, 10);
        newData = true;
    }

    if (soundHigNr > soundPrevHigNr)
    {
        highPulse = true;                                         //High pulse has happened
        soundPrevHigNr = soundHigNr;
        itoa(soundHigNr, sndhignr, 10);
        if (midevent)
            datastring[strlen(datastring)] = 'H';
        else
            datastring[0] = 'H';                                      //Start datastring with H indicating high level sound pulse

        strcat(datastring, sndhignr);                             //Add current numbers of high pulses to datastring
        itoa(soundHigTime, sndhigdur, 10);                        //Convert current high pulse duration to string
        datastring[strlen(datastring)] = 'D';                     //First add D to datastring to indicate duration
        strcat(datastring, sndhigdur);                            //Then add the value of the duration to datastring
        datastring[strlen(datastring)] = 'N';                     //Add N (for Nivå) till datastring
        itoa(soundlevel, sndlev, 10);                             //Convert soundlevel to string
        strcat(datastring, sndlev);                               //And add that string to datastring
        itoa(soundHigLevel, HighLevelString, 10);
        newData = true;
    }
}

void  DisplayPulseData()                                           //Display pulse flag in upper right part of LCD
{
    if (MaxPulseLevel<100)
    {
        lcd.setCursor(9, 0);
        lcd.print("G");
        lcd.setCursor(11, 0);
        itoa(MaxPulseLevel, sndlev, 10);
        lcd.print(sndlev);
    }
    if (MaxPulseLevel>=100 && MaxPulseLevel<150)
    {
        lcd.setCursor(9, 0);
        lcd.print("L");
        lcd.setCursor(11, 0);
        itoa(MaxPulseLevel, sndlev, 10);
        lcd.print(sndlev);
    }
    if (MaxPulseLevel >= 150 && MaxPulseLevel < 250)
    {
        lcd.setCursor(9, 0);
        lcd.print("M");
        lcd.setCursor(11, 0);
        itoa(MaxPulseLevel, sndlev, 10);
        lcd.print(sndlev);
    }
    if (MaxPulseLevel >= 250)
    {
        lcd.setCursor(9, 0);
        lcd.print("H");
        lcd.setCursor(11, 0);
        itoa(MaxPulseLevel, sndlev, 10);
        lcd.print(sndlev);
    }
    MaxPulseLevel = 0;
}

void  NewDisplayLCDData()                           //Display duration for specific (G,L,M,H) pulse
{
    if (highPulse)
    {
        highPulse = false;
       
        FillSpacesLCD(2,1);
        lcd.setCursor(2, 1);
        itoa(soundHigTime, sndhigdur, 10);
        lcd.print(sndhigdur);
        lcd.setCursor(15, 1);
        lcd.print("H");
        highevent = false;
    }
    else if (midPulse)
    {
        midPulse = false;
        
        FillSpacesLCD(2,1);
        lcd.setCursor(2, 1);
        lcd.print(sndmiddur);
        lcd.setCursor(14, 1);
        lcd.print("M");                             //Indicate that mid pulse has occured
        midevent = false;
    }
    else if (lowPulse)
    {
        lowPulse = false;
        FillSpacesLCD(2,1);
        lcd.setCursor(2, 1);
        lcd.print(sndlowdur);
        lcd.setCursor(13, 1);
        lcd.print("L");                             //Indicate that low pulse has occured
        lowevent = false;
    }
    else if (gatePulse)
    {
        gatePulse = false;
        lcd.setCursor(9, 0);
        lcd.print("G");
        FillSpacesLCD(11,0);
        lcd.setCursor(11, 0);
        lcd.print(GateLevelString);
        lcd.setCursor(2, 1);
        lcd.print(sndGdur);
        lcd.setCursor(12, 1);
        lcd.print("G");                             //Indicate that gate pulse has occured
        gateevent = false;
    }   
}

void  NewDisplayLCDHeaders()
{
    lcd.setCursor(0, 0);
    lcd.print("LM=     L =     ");
    lcd.setCursor(0, 1);
    lcd.print("D=              ");
}

void  SetLED(int max)
{
    Serial.print("SetLED max=");
    Serial.println(max);
    if (max>=100 && max<150)
    {
        Serial.println("Light GREEN");
        digitalWrite(BLUE, LOW);
        digitalWrite(GREEN, HIGH);
        digitalWrite(RED, LOW);
    }
    if (max>=150 && max<250)
    {
        Serial.println("Light BLUE");
        digitalWrite(BLUE, HIGH);
        digitalWrite(GREEN, LOW);
        digitalWrite(RED, LOW);
    }
    if (max>=250)
    {
        Serial.println("Light RED");
        digitalWrite(BLUE, LOW);
        digitalWrite(GREEN, LOW);
        digitalWrite(RED, HIGH);
    }
}

void  setPressureData()
{
    if (pdrlevel > pdrmax)
        pdrmax = pdrlevel;
    if (pdrlevel < pdrmin)
        pdrmin = pdrlevel;
}

void  setPdrDataString()
{
    itoa(pdravg, pdrlev, 10);
    strcat(datastring, pdrlev);
    datastring[strlen(datastring)] = ' ';
    itoa(pdrmin, pdrlev, 10);
    strcat(datastring, pdrlev);
    datastring[strlen(datastring)] = ' ';
    itoa(pdrmax, pdrlev, 10);
    strcat(datastring, pdrlev);
}

void  setSoundData()
{
    if (soundlevel > soundmax)
    {
        soundmax = soundlevel;
        newsndmax = true;
    }
    if (soundlevel<soundmin)
      soundmin=soundlevel;
}

void ResetDataString()
{
    for (int i = 0; i < 50; i++)
        datastring[i] = '\0';
}

void FillSpacesLCD(int col,int row)
{
    lcd.setCursor(col, row);
    lcd.print("     ");
}

With all those arrays, you might be running out of memory. Reduce dynamic memory usage by replacing all lines with character strings like this

        Serial.println("Light GREEN");

with this, which stores the string in program memory.

        Serial.println(F("Light GREEN"));

Test the LED and get it working properly with very simple code.

I see this info from the build
Program size: 13500 bytes (used 42% of a 32256 byte maximum) (0,97 secs)
Minimum Memory Usage: 1192 bytes (58% of a 2048 byte maximum)
And I get no messages of low on memory.
And this can hardly be the explanation for the strange LED behaviour

The next suspect is writing outside of array bounds.

The following will likely lead to overflowing the datastring array, because datastring[] is not properly initialized as a zero-terminated character array.

Replace this

        itoa(soundGateNr, sndgnr, 10);
        datastring[0] = 'G';
        strcat(datastring, sndgnr);

with this

        itoa(soundGateNr, sndgnr, 10);
        datastring[0] = 'G';
        datastring[1]=0;  //terminate the initial C-string
        strcat(datastring, sndgnr);

or with this

        itoa(soundGateNr, sndgnr, 10);
        strcpy(datastring,"G");
        strcat(datastring, sndgnr);

Same problem here, and likely elsewhere. You MUST properly terminate C-strings before using string functions like strcat(), etc.

        else
            datastring[0] = 'L';  //where is the terminating zero byte?

        strcat(datastring, sndlownr);
        itoa(soundLowTime, sndlowdur, 10);

I must reformulate the question since I have found which line actually extinguishes the green led.
So how can the program line below turn off the green LED ?

rf_driver.send((const uint8_t *)datastring,strlen(datastring));

It cannot, directly - but with undefined and ill-defined behavior elsewhere, it might very well seem to.

2 Likes

No, please address the obvious problems with array boundary violations before jumping to conclusions.

1 Like

No jumping to conclusion here. I discovered that RH_ASK uses the green led pin by default. So I changed the class definition to

RH_ASK  rf_driver(2000,0,12,1);

And now I don't see the problem anymore

The terminating zero byte come in the function
ResetDataString()

Good luck with the project!

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.