Reading a steady HIGH from an optocopler [SOLVED]

Hello All,

I have this simple circuit from which i wish to read a steady high using an Arduino when the source are shorted or when the source is OFF. I get the below output on the serial

CS State:0
CS State:1
CS State:0
CS State:1
CS State:0
CS State:1
CS State:0
CS State:1
CS State:0
CS State:1

My code is as follows,

const byte ZERO_PIN = 2; //Input pin from zero cross detector
const byte TRIAC = A1; //Output pin to TRIAC / SSR
const byte cs = 10;
const byte Ready = 4;
byte count = 0;
byte prevCS_State;
byte cs_State;
byte currCS_State;
byte autoWeldFlag;
volatile boolean zeroCrossingFlag = false;
unsigned long dTime = 50;
unsigned long currT;
//int SET_PIN = A3; //Analog pin for setting the dutyCycle value with a pontentiometer
 
void setup()
{
  pinMode(ZERO_PIN, INPUT_PULLUP);
  pinMode(Ready, OUTPUT);
  pinMode(cs, INPUT_PULLUP);
  pinMode(TRIAC, OUTPUT);
  Serial.begin (115200);
  attachInterrupt(0, setFlag, FALLING); // zero cross
}
void setFlag()
{
  zeroCrossingFlag = true; // interrupt sets flag true
}
 
void weld()
{
  Serial.println("STEADY HIGH");
}
 
void loop()
{
  zeroCrossingFlag = false;
  while (!zeroCrossingFlag) {}
  delayMicroseconds(8500);
  digitalWrite(TRIAC, HIGH);
  delayMicroseconds(200);
  digitalWrite(TRIAC, LOW);
 
  cs_State = digitalRead(cs);
  currCS_State = cs_State;
  currT = millis();
  Serial.print("CS State:");
  Serial.println(currCS_State);
  if (currCS_State == HIGH && millis() - currT >= dTime)
  {
  currCS_State = cs_State;
  if (currCS_State == HIGH)
  {
  Serial.print("Second IF:");
  Serial.println(digitalRead(cs));
  digitalWrite(Ready, HIGH);
  weld();
  digitalWrite(Ready, LOW);
  }
  }
  //prevCS_State = currCS_State;
}

As i understand it, after the CS_State goes HIGH then wait for a pre-defined time and read the pin-state again to check if it a steady HIGH is seen, then execute the code.

I don't know what's going on. You should probably simplify your program (something like the [u]Digital Read Serial Example[/u]) to see what you're getting. With the AC connected I'd expect a lot of highs with an occasional low when you "catch" a zero-crossing.

while (!zeroCrossingFlag) {}That's a do-nothing loop that you can't break out of (AKA an infinite loop). And you always set zeroCrossingFlag to false so I don't understand how your program ever gets past that point.

What's your AC voltage? If it's power-line voltage your opto-isolator may be fried (with a 1K current-limiting resistor).

What is connected to pin 10?

unsigned long dTime = 50;
 currT = millis();
  Serial.print("CS State:");
  Serial.println(currCS_State);
  if (currCS_State == HIGH && millis() - currT >= dTime)

With currT set to millis() two serial print statments ahead of the conditional, it will never be entered. Two print statements at 115200 certainly don't take 50 ms.

I've managed to read a steady HIGH on pin CS. But i need to run the weld() function only once when called. Now it reads continuously.

const byte ZERO_PIN = 2; //Input pin from zero cross detector
const byte TRIAC = A1; //Output pin to TRIAC / SSR
const byte cs = 10;
const byte Ready = 4;
byte count = 0;
byte prevCS_State = HIGH;
byte cs_State;
byte currCS_State;
byte autoWeldFlag;
int steadyState;
int prevSteadyState;
volatile boolean zeroCrossingFlag = false;
//unsigned long dTime = 10;
//unsigned long currT;
//int SET_PIN = A3; //Analog pin for setting the dutyCycle value with a pontentiometer

void setup()
{
  pinMode(ZERO_PIN, INPUT_PULLUP);
  pinMode(Ready, OUTPUT);
  pinMode(cs, INPUT_PULLUP);
  pinMode(TRIAC, OUTPUT);
  Serial.begin (115200);
  attachInterrupt(0, setFlag, FALLING); // zero cross
}
void setFlag()
{
  zeroCrossingFlag = true; // interrupt sets flag true
}

void weld()
{
  if (prevSteadyState == steadyState && autoWeldFlag == 1) // Run only Once when this function is called
  {
    Serial.println("STEADY HIGH");
    steadyState = 0;
    autoWeldFlag = 0;
  }
}

void loop()
{
  steadyState = 0; // added to replicate the state of a button, here set LOW
zeroCrossingFlag = false;
  while (!zeroCrossingFlag) {}
  delayMicroseconds(8500);
  digitalWrite(TRIAC, HIGH);
  delayMicroseconds(200);
  digitalWrite(TRIAC, LOW);

  cs_State = digitalRead(cs);
  currCS_State = cs_State;
  if (currCS_State == prevCS_State && autoWeldFlag == 0)
  {
    digitalWrite(Ready, HIGH);
    steadyState = 1; // added to replicate the state of a button, here goes HIGH
    
    cs_State = digitalRead(cs);
    if (cs_State == HIGH)
    {
      autoWeldFlag = 1;
      weld();
    }
    digitalWrite(Ready, LOW);
    prevSteadyState = steadyState;
  }
  prevCS_State = currCS_State;
}

I've managed to read a steady HIGH on pin CS. But i need to run the weld() function only once when called. Now it reads continuously.

Your management of the autoWeldFlag is obviously not correct for what you want to do.

This setting of the autoWeldFlag to 0 looks correct for the run once, but why is this logic not used where you call weld()?

if (prevSteadyState == steadyState && autoWeldFlag == 1) // Run only Once when this function is called
  {
    Serial.println("STEADY HIGH");
    steadyState = 0;
    autoWeldFlag = 0;
  }

Why does the autoWeldFlag need to be LOW here?

if (currCS_State == prevCS_State && autoWeldFlag == 0)

Why do you reset the flag to HIGH here?

if (cs_State == HIGH)
    {
      autoWeldFlag = 1;
      weld();
    }

I'm really not clear on what you are trying to do with the cs pin reading and the autoWeld but your do it once logic should probably be where you call weld()

Another ( later ?) issue may well be noise from welding , affecting Arduino directly and also in distorting any measured voltage waveform .

I've removed all those now i do get a pulse when needed. Would this be the right way to do ?

const byte ZERO_PIN = 2; //Input pin from zero cross detector
const byte TRIAC = A1; //Output pin to TRIAC / SSR
const byte cs = 10;
const byte Ready = 4;
byte count = 0;
byte prevCS_State = HIGH;
byte cs_State;
byte currCS_State;
byte autoWeldFlag;
byte ctc;
byte noCtc;
int prevSteadyState;
volatile boolean zeroCrossingFlag = false;
//unsigned long dTime = 10;
//unsigned long currT;
//int SET_PIN = A3; //Analog pin for setting the dutyCycle value with a pontentiometer

void setup()
{
  pinMode(ZERO_PIN, INPUT_PULLUP);
  pinMode(Ready, OUTPUT);
  pinMode(cs, INPUT_PULLUP);
  pinMode(TRIAC, OUTPUT);
  Serial.begin (115200);
  attachInterrupt(0, setFlag, FALLING); // zero cross
}
void setFlag()
{
  zeroCrossingFlag = true; // interrupt sets flag true
}

void weld()
{
  if (noCtc != ctc) // Run only Once when this function is called
  {
    noCtc = 1;
    delay(300);
    Serial.println("STEADY HIGH");
  }
}

void loop()
{
  zeroCrossingFlag = false;
  while (!zeroCrossingFlag) {}
  delayMicroseconds(8600);
  digitalWrite(TRIAC, HIGH);
  delayMicroseconds(200);
  digitalWrite(TRIAC, LOW);
  cs_State = digitalRead(cs);
  currCS_State = cs_State;
  if (currCS_State != prevCS_State)
  {
    noCtc = 0;
  } else if (currCS_State == prevCS_State)
  {
    ctc = 1;
  }
  if (currCS_State == prevCS_State)
  {
    digitalWrite(Ready, HIGH);
    weld();
    digitalWrite(Ready, LOW);
  }
  prevCS_State = currCS_State;
}

i do get a pulse when needed. Would this be the right way to do ?

If it's doing what you want, then its the "right way". Do you understand the code and how the logic is working?

I'm not very clear about the "big picture" and what you are actually trying to do with the cs pin10 setting, or what is connected to pin 10 so I can't really comment further.

One thing I do see is that the weld() function is enabled when the cs pin changes state. For example, if there were a button or toggle switch connected to pin 10, I think you would get the weld() function called when the button is pressed or released.

One thing I do see is that the weld() function is enabled when the cs pin changes state. For example, if there were a button or toggle switch connected to pin 10, I think you would get the weld() function called when the button is pressed or released.

True ! the principle is the same. Except here the button press is a steady LOW when pins 1 and 2 are shorted and a HIGH when they are not.

since the AC signal fluctuates between low and high its hard to ready them so i just read the state of CS when it is not shorted (a steady LOW) and when idle (goes HIGH and LOW as the sine wave changes polarity)