Generate Signal: Fault Detection

I need help to generate a constant diagnostic signal with the arduino. The signal should be as in the figure.

I thought of something below, but I wanted to see if there is another more efficient solution.

//------------------------------------------------ Pins --------------------------------------------------------
const int CHANNEL1=1;
const int CHANNEL2=2;                               
const int CHANNEL3=3;
const int CHANNEL4=4;      
const int DIAGNOSTIC=5;   
const int FAULT_1=6;  
const int FAULT_2=7;  
int inic=1;                 

//------------------------------------------------ Setup ---------------------------------------------------------------------
void setup() 
{
  pinMode(CHANNEL1, INPUT);
  pinMode(CHANNEL2, INPUT);
  pinMode(CHANNEL3,INPUT);
  pinMode(CHANNEL4,INPUT);
  pinMode(FAULT_1,INPUT);
  pinMode(FAULT_2,INPUT);
  pinMode(DIAGNOSTIC,OUTPUT);
  digitalWrite(DIAGNOSTIC,LOW);
}
//------------------------------------------------ Loop --------------------------------------------------------
void loop() 
{
  if(inic==1)
  {
  delay(500);
  inic=0;
  }
  
   digitalWrite(DIAGNOSTIC,LOW);
   delay(50);
   digitalWrite(DIAGNOSTIC,HIGH);
   delay(50);
   digitalWrite(DIAGNOSTIC,LOW);
   delay(50);
   digitalWrite(DIAGNOSTIC,HIGH);
   delay(50);
   digitalWrite(DIAGNOSTIC,LOW);
   delay(100);

    if(digitalRead(CHANNEL1)==HIGH)
      {
      digitalWrite(DIAGNOSTIC,HIGH);
      delay(100);
      }
    else
      {
      digitalWrite(DIAGNOSTIC,LOW);
      delay(100); 
      }
    if(digitalRead(FAULT_1)==HIGH)
      {
      digitalWrite(DIAGNOSTIC,HIGH);
      delay(100);
      }
    else
      {
      digitalWrite(DIAGNOSTIC,LOW);
      delay(100); 
      }
    if(digitalRead(CHANNEL2)==HIGH)
      {
      digitalWrite(DIAGNOSTIC,HIGH);
      delay(100);
      }
    else
      {
      digitalWrite(DIAGNOSTIC,LOW); 
      delay(100);
      }
      if(digitalRead(FAULT_1)==HIGH)
      {
      digitalWrite(DIAGNOSTIC,HIGH);
      delay(100);
      }
    else
      {
      digitalWrite(DIAGNOSTIC,LOW);
      delay(100); 
      }
    if(digitalRead(CHANNEL3)==HIGH)
      {
      digitalWrite(DIAGNOSTIC,HIGH);
      delay(100);
      }
    else
      {
      digitalWrite(DIAGNOSTIC,LOW); 
      delay(100);
      }
    if(digitalRead(FAULT_2)==HIGH)
      {
      digitalWrite(DIAGNOSTIC,HIGH);
      delay(100);
      }
    else
      {
      digitalWrite(DIAGNOSTIC,LOW);
      delay(100); 
      }
    if(digitalRead(CHANNEL4)==HIGH)
      {
      digitalWrite(DIAGNOSTIC,HIGH);
      delay(100);
      }
    else
      {
      digitalWrite(DIAGNOSTIC,LOW); 
      delay(100);
      }
    if(digitalRead(FAULT_2)==HIGH)
      {
      digitalWrite(DIAGNOSTIC,HIGH);
      delay(100);
      }
    else
      {
      digitalWrite(DIAGNOSTIC,LOW);
      delay(100); 
      }
}

Image from Original Post so we don't have to download it. See this Simple Image Guide

...R

JonasSilva:
I need help to generate a constant diagnostic signal with the arduino.

Without a description of what you are trying to diagnose I can't make sense of your diagram.

Your program has several IF tests but seems to have no code to collect the data for those tests.

...R

At no point in your code do you actually read the CHANNELx & FAULT_x pins so the DIAGNOSTIC data is meaningless.
If the Arduino is expected to do nothing else but generate the diagnostics data then there is probably no need to change it to make it more efficient but if your wanting to do other things as well then on initial inspection I would probably use a timer interrupt set to a 50ms interval to push out the data.

Riva:
At no point in your code do you actually read the CHANNELx & FAULT_x pins so the DIAGNOSTIC data is meaningless.
If the Arduino is expected to do nothing else but generate the diagnostics data then there is probably no need to change it to make it more efficient but if your wanting to do other things as well then on initial inspection I would probably use a timer interrupt set to a 50ms interval to push out the data.

The code will do other tasks, it would need that while it was sending this diagnostic signal to carry out the other tasks. I changed the code, because really he was not reading any signal.

Robin2:
Without a description of what you are trying to diagnose I can't make sense of your diagram.

Your program has several IF tests but seems to have no code to collect the data for those tests.

...R

The program should read the 4 digital inputs that will inform if the CHANNELX signals are active or not. It will also read 2 digital inputs(FAULT_1 or FAULT_2) that will tell you if there is a fault in the system or not. It should generate a continuous signal as described in the post image. The program will also perform other tasks, such as generating pwm signal, reading analog ports, calculating temperature, etc. The difficulty at the moment is to generate this DIAGNOSTIC signal interruptly while performing the other tasks.

JonasSilva:
The program should read the 4 digital inputs that will inform if the CHANNELX signals are active or not. It will also read 2 digital inputs(FAULT_1 or FAULT_2) that will tell you if there is a fault in the system or not.

That's not going to happen unless you have the appropriate digitalRead()s in your program.

It should generate a continuous signal as described in the post image.

Your image probably makes sense to you but I don't understand how it should be created. Start by describing the sequence of events that should happen for a single input.

...R

JonasSilva:
It should generate a continuous signal as described in the post image. The program will also perform other tasks, such as generating pwm signal, reading analog ports, calculating temperature, etc. The difficulty at the moment is to generate this DIAGNOSTIC signal interruptly while performing the other tasks.

Have a look at the attached code. It will hopefully do the required continual diagnostics using interrupts and all you need to do in loop is to construct the next set of diagnostic data to send else the ISR will just send the last values again and again.
I will leave it to you to determine how it works but if you get stuck in figuring it out then please ask.

Here is a logic capture.

sketch_may08a_Diagnostics.ino (4.11 KB)

Riva:
Have a look at the attached code. It will hopefully do the required continual diagnostics using interrupts and all you need to do in loop is to construct the next set of diagnostic data to send else the ISR will just send the last values again and again.
I will leave it to you to determine how it works but if you get stuck in figuring it out then please ask.

Here is a logic capture.

Thank you Riva, that's almost what I need. What should I change in the code to define how often the diagnostic signal is sent? I need it sent every 2 seconds.

What is the function "void dec2bin32 (uint32_t myNum, NumberOfBits byte)" ?

JonasSilva:
What should I change in the code to define how often the diagnostic signal is sent? I need it sent every 2 seconds.

Ha, you just moved the goalposts. Your original post says "I need help to generate a constant diagnostic signal with the arduino.", you mentioned nothing about every two seconds.
I'm at work this weekend but will hopefully get time to change the code to suit your needs. The simple way would be to use a uint64_t data type and just add 20 zero bits on to generate 1 second silence and then the diagnostic data.

JonasSilva:
What is the function "void dec2bin32 (uint32_t myNum, NumberOfBits byte)" ?

It is just a bit of code to display the constructed diag data during testing. Just delete it or remove the call to it from loop.

EDIT: In a slack moment I changed to code to send diag data every 2 seconds instead of continually.
To save confusion I have commented out all code I used for testing

sketch_may08b_Diagnostics.ino (4.15 KB)

Riva:
Ha, you just moved the goalposts. Your original post says "I need help to generate a constant diagnostic signal with the arduino.", you mentioned nothing about every two seconds.
I'm at work this weekend but will hopefully get time to change the code to suit your needs. The simple way would be to use a uint64_t data type and just add 20 zero bits on to generate 1 second silence and then the diagnostic data.
It is just a bit of code to display the constructed diag data during testing. Just delete it or remove the call to it from loop.

EDIT: In a slack moment I changed to code to send diag data every 2 seconds instead of continually.
To save confusion I have commented out all code I used for testing

I'm sorry I did not talk about the 2 seconds earlier. I have a question, while the program is not sending the signal can I perform other tasks? Or will he be interrupted for these 2 seconds?

I need to put what's in the code below with what you did. Basically it reads 3 NTCs and generates a pwm signal on 2 different ports.

I've attached the two codes together, could you see if it works that way?

const int NTC_Pin = 8;  
const int NTC_Pin2 = 9;  
const int NTC_Pin3 = 10;  
const int Vout = 11;
const int Vout2 = 12;  


const int    SAMPLES      = 5;                 
const int RESISTOR_SERIE_LB   = 9710.0;         
const int RESISTOR_SERIE_HB   = 9710.0;        
const float RCS = 0.15;                         
const int RESISTOR_SERIE_LDD   = 9710.0;     
const float RCS2 = 0.15;                      
const int MAX_ADC            = 1023.0;
const float BETA               = 3974.0;             
const float BETA_HB               = 3974.0;         
const float BETA_LDD               = 3974.0;       
const int TEMP_AMB          = 298.15;         
const int NTC_TEMP_LB = 10000.0;             
const int NTC_TEMP_HB = 10000.0;           
const int NTC_TEMP_LDD = 10000.0;          


int tempAtual = 0;         
int tempAtual_HB = 0;      
int tempAtual_LDD = 0;    
float I = 0;               
float Viadj = 0;
int pwmvalor = 0;       
float I2 = 0;         
float Viadj2 = 0;
int pwmvalor2 = 0;   
int aux = 0;

void setup() {
  pinMode(NTC_Pin,INPUT);
  pinMode(Vout,OUTPUT);
  pinMode(NTC_Pin2,INPUT);
  pinMode(Vout2,OUTPUT);
  pinMode(NTC_Pin3,INPUT);
}

void loop() {
//---------------------------- NTC ---------------------------------// 

if(digitalRead(CHANNEL3==HIGH))
{
  tempAtual = readThermistor();
  if (tempAtual <= 25)
  {
    I=1;
  } 
  if (tempAtual > 25 && tempAtual <= 125)
  {
    I=(-5.26*(tempAtual-25)+1000)/1000;
  }
  if (tempAtual > 125)
  {
    I=0.5;
  }
  if(digitalRead(CHANNEL4==HIGH))
  {
      tempAtual_HB = readThermistor3();
      aux = tempAtual_HB - tempAtual;
      if (aux >= 10)
      {
          if (tempAtual_HB <= 25)
          {
            I=1;
          } 
          if (tempAtual_HB > 25 && tempAtual_HB <= 125)
          {
            I=(-5.26*(tempAtual_HB-25)+1000)/1000;
          }
          if (tempAtual_HB > 125)
          {
            I=0.5;
          }
      }   
}
 Viadj=14*I*RCS;
 pwmvalor=50.5*(Viadj-1.05)+54;       
 analogWrite(Vout, pwmvalor);
}

if(digitalRead(CHANNEL2==HIGH))
{
  tempAtual_LDD = readThermistor2();
  if (tempAtual_LDD <= 25)
  {
    I2=1;            
  } 
  if (tempAtual_LDD > 25 && tempAtual_LDD <= 125)
  {
    I2=(-5.26*(tempAtual_LDD-25)+1000)/1000;  
  }
  if (tempAtual_LDD > 125)
  {
    I2=0.5;               
  } 
  Viadj2=14*I2*RCS2;
  pwmvalor2=50.5*(Viadj2-1.05)+54; 
  analogWrite(Vout2, pwmvalor2); 
} 

}
//--------------Functions NTC--------------------//
int readThermistor() 
{
  int rThermistor = 0;            // Holds thermistor resistance value
  int tKelvin     = 0;            // Holds calculated temperature
  int tCelsius    = 0;            // Hold temperature in celsius
  int adcAverage  = 0;            // Holds the average voltage measurement
  int adcSamples[SAMPLES];       // Array to hold each voltage measurement

  for (int i = 0; i < SAMPLES; i++) 
  {
    adcSamples[i] = analogRead(NTC_Pin);  // read from pin and store
    delay(10);        // wait 10 milliseconds
  }

  for (int i = 0; i < SAMPLES; i++) 
  {
    adcAverage += adcSamples[i];      // add all samples up . . .
  }
  adcAverage /= SAMPLES;        // . . . average it w/ divide

  rThermistor = RESISTOR_SERIE_LB * ( (MAX_ADC / adcAverage) - 1);

  tKelvin = (BETA * TEMP_AMB) / 
            (BETA + (TEMP_AMB * log(rThermistor / NTC_TEMP_LB)));

  tCelsius = tKelvin - 273.15;  // convert kelvin to celsius 

  return tCelsius;    // Return the temperature in Celsius
}

int readThermistor3() 
{
  int rThermistor3 = 0;            // Holds thermistor resistance value
  int tKelvin3     = 0;            // Holds calculated temperature
  int tCelsius3    = 0;            // Hold temperature in celsius
  int adcAverage3  = 0;            // Holds the average voltage measurement
  int    adcSamples3[SAMPLES];  // Array to hold each voltage measurement

  for (int j = 0; j < SAMPLES; j++) 
  {
    adcSamples3[j] = analogRead(NTC_Pin3);  // read from pin and store
    delay(10);        // wait 10 milliseconds
  }
  for (int j = 0; j < SAMPLES; j++) 
  {
    adcAverage3 += adcSamples3[j];      // add all samples up . . .
  }
  adcAverage3 /= SAMPLES;        // . . . average it w/ divide

  rThermistor3 = RESISTOR_SERIE_HB * ( (MAX_ADC / adcAverage3) - 1);

  tKelvin3 = (BETA_HB * TEMP_AMB) / 
            (BETA_HB + (TEMP_AMB * log(rThermistor3 / NTC_TEMP_HB)));

  tCelsius3 = tKelvin3 - 273.15;  // convert kelvin to celsius 

  return tCelsius3;    // Return the temperature in Celsius
}

int readThermistor2() 
{

  int rThermistor2 = 0;            // Holds thermistor resistance value
  int tKelvin2     = 0;            // Holds calculated temperature
  int tCelsius2    = 0;            // Hold temperature in celsius
  int adcAverage2  = 0;            // Holds the average voltage measurement
  int    adcSamples2[SAMPLES];       // Array to hold each voltage measurement

  
  for (int k = 0; k < SAMPLES; k++) 
  {
    adcSamples2[k] = analogRead(NTC_Pin2);  // read from pin and store
    delay(10);        // wait 10 milliseconds
  }

  for (int k = 0; k < SAMPLES; k++) 
  {
    adcAverage2 += adcSamples2[k];      // add all samples up . . .
  }
  adcAverage2 /= SAMPLES;        // . . . average it w/ divide


  rThermistor2 = RESISTOR_SERIE_LDD * ( (MAX_ADC / adcAverage2) - 1);

  tKelvin2 = (BETA_LDD * TEMP_AMB) / 
            (BETA_LDD + (TEMP_AMB * log(rThermistor2 / NTC_TEMP_LDD)));


  tCelsius2 = tKelvin2 - 273.15;  // convert kelvin to celsius 

  return tCelsius2;    // Return the temperature in Celsius
}

sketch_may08c_Diagnostics.ino (9.71 KB)

JonasSilva:
I have a question, while the program is not sending the signal can I perform other tasks? Or will he be interrupted for these 2 seconds?

The diagnostic output is totally interrupt drive so wont stall loop for 2 seconds while sending. All you need to do in loop is construct the diag data to send and store it so the interrupt code can pick it up for output. If you don't update the diag data then the interrupt just keeps sending the last diag values.

 uint32_t constructedData = construct();         // Contruct data to send
  cacheData = constructedData << 1;               // Cache it after rotating to ensure double bits are not split across 8 bit boundries

Riva:
The diagnostic output is totally interrupt drive so wont stall loop for 2 seconds while sending. All you need to do in loop is construct the diag data to send and store it so the interrupt code can pick it up for output. If you don't update the diag data then the interrupt just keeps sending the last diag values.

 uint32_t constructedData = construct();         // Contruct data to send

cacheData = constructedData << 1;              // Cache it after rotating to ensure double bits are not split across 8 bit boundries

I dont understand. How is the loop what happens when the new input pins are read? Will it always send the same signal, even when the input signals change?

JonasSilva:
I dont understand. How is the loop what happens when the new input pins are read? Will it always send the same signal, even when the input signals change?

I have simplified the code a bit so that as long as you call the construct() procedure in loop the interrupt code will pick up the new data and send it (once it has finished sending the last set of data). If you don't call construct then the interrupt code will just keep sending the last value.

sketch_may08c_Diagnostics.ino (3.37 KB)

Riva:
I have simplified the code a bit so that as long as you call the construct() procedure in loop the interrupt code will pick up the new data and send it (once it has finished sending the last set of data). If you don't call construct then the interrupt code will just keep sending the last value.

Thank you. In this new modification does he still send the signal every 2 seconds? I noticed that it goes into interruption every 50 ms, is that correct?

JonasSilva:
Thank you. In this new modification does he still send the signal every 2 seconds? I noticed that it goes into interruption every 50 ms, is that correct?

Yes every 2 seconds. The timer1ISR is called every 50ms and sends 1 bit of data per call and it send 40 bits of data per message.