Reading a steady HIGH from an optocopler [SOLVED]

Thread Starter

anishkgt

Joined Mar 21, 2017
549
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,
Code:
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.
Capture.PNG
 
Last edited:

bertus

Joined Apr 5, 2008
22,921
Hello,

I would put a diode anti parallel to the led in the optocoupler.
Most leds can not handle a reverse voltage of more than 5 Volts.

Bertus
 

ebeowulf17

Joined Aug 12, 2014
3,307
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


My code is as follows,
Code:
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.
View attachment 164987
What is connected to cs pin input? Does it have a predictable relationship with zero-crossing timing? What microcontroller inputs/outupts correspond with the opto circuit you showed? Is that AC source from the switched output of the TRIAC, or is that the unswitched mains just being checked for zero crossing detection? Does the opto output go to the cs pin, the zero crossing interrupt pin, or both? Too many unknowns right now to make sense of this.

Regardless, a couple things jump out at me:
Code:
currT = millis();
  Serial.print("CS State:");
  Serial.println(currCS_State);
  if (currCS_State == HIGH && millis() - currT >= dTime)
The conditional at the end of the snippet above can never be true, unless you've got an exceedingly slow controller, because currT is set equal to millis() and then almost immediately you check to see if millis() is 50ms beyond currT. Unless it takes 50ms to serial.print your variable, it'll never be true.

Also, your entire main loop is paused at the very beginning until a zero crossing is detected, then everything runs once before waiting for the next zero crossing. Is this what you want, or were you wanting the cs input to get checked regularly, regardless of zero crossing status?
 

Thread Starter

anishkgt

Joined Mar 21, 2017
549
What is connected to cs pin input?
I had renamed the schematic to help understand it better. cs is renamed as 'TO_MUC'. cs(contact Sense) is pulled up via code.

Does it have a predictable relationship with zero-crossing timing?
not really. No relation to it in anyway.
What microcontroller inputs/outupts correspond with the opto circuit you showed?
The opto is basically used as way to sense when the electrodes at the secondary of a spot welder. The spot welder is an AC spot welder which uses a Microwave Oven Transformer(MOT) with its secondary rewired to just 3 turns of 1AWG cable. The AC Source is connects in parallel with the electrodes. So when idle a Vpp of 4.2vac (720mV RMS)is seen at the "AC Source" and when shorted goes down to 600mVac (RMS 412mV)
Is that AC source from the switched output of the TRIAC or is that the unswitched mains just being checked for zero crossing detection?
yes it is, in fact it is a form of pwm, phase shift in AC, triggered after 8500 μseconds after zero cross. So for every half cycle within the code, it is triggered after 8500 μs. The zero cross is detected from another optocoupler. This would be used as a contact sense.
Does the opto output go to the cs pin, the zero crossing interrupt pin, or both?
yes it does to the cs pin, you guess it correct . This pin does not go to any interrupt pin. It is just a digital pin.
oo many unknowns right now to make sense of this.
I hope i've made it more clear now.
The conditional at the end of the snippet above can never be true, unless you've got an exceedingly slow controller, because currT is set equal to millis() and then almost immediately you check to see if millis() is 50ms beyond currT
yes i've moved it to the starting of the loop but that did not make any difference tho.

So basically the opotocoupler is there just to sense when the electrodes make contact and then trigger the actual dual pulse weld cycle. With my knowledge and expertise this was the simplest solution to Contact sense. I know some would use opamps but they are kinda new to me so stayed away from them. There was some level shifting involved there and so much more. Too much for me.

Also, your entire main loop is paused at the very beginning until a zero crossing is detected, then everything runs once before waiting for the next zero crossing. Is this what you want, or were you wanting the cs input to get checked regularly, regardless of zero crossing status?
The contact sense does not require zero cross. Need to sense when they are shorted. The zero cross is only used during weld and phase shift.


Here Ch1 is the output from 'TO MUC' and Ch2 is from the secondary of the MOT after phase shift.
Idle.png


This shows when the secondary are shorted. Ch1 is pulled up within the code hence reads 5.0V and Ch2 Vpp is 600mVac
Shorted.png
 

Thread Starter

anishkgt

Joined Mar 21, 2017
549
Not sure if this would the correct way to do it but i've got what i was expecting.
Code:
void loop()
{
  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 == HIGH && prevCS_State == HIGH)
  {
  cs_State = digitalRead(cs);
  if (cs_State == HIGH)
  {
  digitalWrite(Ready, HIGH);
  weld();
  digitalWrite(Ready, LOW);
  }
  }
  prevCS_State = currCS_State;
}
 

ebeowulf17

Joined Aug 12, 2014
3,307
Not sure if this would the correct way to do it but i've got what i was expecting.
Code:
void loop()
{
  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 == HIGH && prevCS_State == HIGH)
  {
  cs_State = digitalRead(cs);
  if (cs_State == HIGH)
  {
  digitalWrite(Ready, HIGH);
  weld();
  digitalWrite(Ready, LOW);
  }
  }
  prevCS_State = currCS_State;
}
Seems like you've got more reads on that cs pin than are really necessary, but if it's working for you, that's great!
 

Thread Starter

anishkgt

Joined Mar 21, 2017
549
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.
Code:
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;
}
 

ebeowulf17

Joined Aug 12, 2014
3,307
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.
Code:
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 got a bad cold, and I'm not thinking clearly, so no promises here, but I *think* I see what's going on...

Every time you weld, you set autoWeldFlag to 0, so on the next pass of code, it's all clear and ready to weld again. You need to keep autoWeldFlag set to 1, preventing more weld actions, until contact us released. Try this:

  1. Eliminate (or just comment out) the "autoWeldFlag=0" in your weld() function call at line 38.
  2. Between lines 64 and 65, add the following "else" statement to your "cs_State" conditional:
Code:
else {
autoWeldFlag = 0;
}
If I'm reading things correctly, this will mean that when cs_State goes high, the flag gets set to 1 and the weld happens, but all future welds are prevented by the flag still reading 1...
Until cs_State goes low, at which point you set the flag to 0 so it's ready for the next new contact.
 

Thread Starter

anishkgt

Joined Mar 21, 2017
549
Sorry to hear that you've got a cold.

The suggestion did not work, however i've got it to fire once with the below code but not sure it would be the correct way to do. If you know how i can make it better then please do

Code:
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;
}
 

eetech00

Joined Jun 8, 2013
4,705
Hi

Sorry for jumping in but a little curious on this statement:

The opto is basically used as way to sense when the electrodes at the secondary of a spot welder. The spot welder is an AC spot welder which uses a Microwave Oven Transformer(MOT) with its secondary rewired to just 3 turns of 1AWG cable. The AC Source is connects in parallel with the electrodes. So when idle a Vpp of 4.2vac (720mV RMS)is seen at the "AC Source" and when shorted goes down to 600mVac (RMS 412mV)
What frequency is the AC source?

4.2v pk-pk= 1.485 vrms
0.6v pk-pk=0.212 vrms

For the circuit shown in post #1, no short on the AC source would turn on the transistor causing the output be close to ground, a short on the AC source should turn off the transistor and cause the output to reach the internal "weak pullup" voltage source level. The assumptions are that the diode is biased correctly for the CTR needed (I haven't checked datasheet) and the MCU internal weak-pullup is enabled. For PIC, I usually don't use the internal pullup and connect an external one.

eT
 

ebeowulf17

Joined Aug 12, 2014
3,307
Sorry to hear that you've got a cold.

The suggestion did not work, however i've got it to fire once with the below code but not sure it would be the correct way to do. If you know how i can make it better then please do

Code:
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;
}
Sorry my attempt didn't help. Glad you got it working though!

I'm definitely not thinking clearly enough to give advice on optimizing things. If your new code is doing what you want, then that sounds good to me!
 

Thread Starter

anishkgt

Joined Mar 21, 2017
549
Seemed to have solved it.

Learned not complicate things, here just go with what i was looking for. That being a steady HIGH,
Code:
if (currCS_State == prevCS_State)
    {
      ctc = 0;
    }
    else
    {
      ctc = 1;
    }
prevCS_State = currCS_State;
This would give a '0' when pin 1 and 2 are shorted depicting a contact and '1' when idle.
 
Top