interrupt and zero crossing problem

Hi, following by my spot weld machine base on Arduino, I got stuck and need your help again.
First of all, I want to trigger the solid-state-relay to turn on a power transformer, and the SSR is only turn on at zero crossing, and I need the exact time set for each pulse.

Therefore, I'm thinking about using interrupt on pin 2 Arduino to detect zero and turn-on time for SSR right at the zero to eliminate delay between zero and time of pushing the button. However, it doesn't work as I expected. With the time set less than 10ms, the trigger for SSR is not stable working, sometimes it triggers the transformer but sometimes it does not (it act as the same way before I'm using interrupt)

So could you please tell me that I'm thinking in the wrong way or the zero isn't working as I expected

in my country, using 50hz and 230VAC line, so each half-circle is 10ms

for wiring, pin 2 I follow bristolwatch but the 2.2k resistor I replaced with 1k. The output from pin 2 is exactly as described in bristolwatch website



pin 5 for triggering

here is my code, I removed some irrelevant code to make it clear

Thank so much for reading my issue

//
//
//
//
//
//--------------------------------------------------------------------------------------
//                                         INCLUDES
//--------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------
//                                        DEFINES
//--------------------------------------------------------------------------------------


#define timerPin       12

//--------------------------------------------------------------------------------------
//                                       VARIABLES
//--------------------------------------------------------------------------------------

int controlValue;
int timerValue;
volatile float j;
int period = 500;
unsigned long time_now = 0;
long lastDebounceTime = 0;  // the last time the output pin was toggled
long debounceDelay = 50;    // the debounce time; increase if the output flickers

//--------------------------------------------------------------------------------------
//                                       MAIN PROGRAM
//--------------------------------------------------------------------------------------

void setup()
{
  Serial.begin(9600);
  pinMode(5, INPUT_PULLUP);         // set D5 as input of pedal
  pinMode(2, INPUT);
  pinMode(timerPin, OUTPUT);
  digitalWrite(timerPin, LOW);

}

void loop()
{
  
  int Switch = digitalRead(5);
  int Switch1 = digitalRead(3);
  
  // check if the pushbutton is pressed. If it is, the buttonState is LOW:

    if (Switch == LOW) {
    attachInterrupt(0, trig, CHANGE);
    
  }
void trig() {
  delayMicroseconds(9900);
  digitalWrite(13, HIGH);
  digitalWrite(timerPin, HIGH);
  delayMicroseconds(j * 1000); // weld time
  digitalWrite(timerPin, LOW);
  digitalWrite(13, LOW);
  detachInterrupt(0);
}

You obviously don't understand how to implement an interrupt service routine. The normal place to attach an interrupt is one time, in setup().

You have posted code using quote tags instead of code tags. The code tags make the code look

like this

when posting source code files. It makes it easier to read, and can be copied with a single mouse click. Also, if you don't do it, some of the character sequences in the code can be misinterpred by the forum code as italics or funny emoticons. The "Code: [Select]" feature allows someone to select the entire sketch so it can be easily copied and pasted into the IDE for testing.
If you have already posted without using code tags, open your message and select "modify" from the pull down menu labelled, "More", at the lower right corner of the message. Highlight your code by selecting it (it turns blue), and then click on the "</>" icon at the upper left hand corner. Click on the "Save" button. Code tags can also be inserted manually in the forum text using the code and /code metatags.

Also, please do post your entire sketch, not a snippet of code. Really, a snippet does not permit useful troubleshooting.

Take a look here: Arduino Playground - ACPhaseControl

Next time, please post your code properly using Code Tags as described in Item #6 at this Link.

Zero-crossing solid state relays are super-common. :wink:

Thank you for noting me about [ code], I just edited my post
I read all your suggestions but I still not easy to reach

Embehu:
Thank you for noting me about [ code], I just edited my post
I read all your suggestions but I still not easy to reach

What about the one about not attaching an ISR thousands of times per second? Your thoughts?

in my country, using 50hz and 230VAC line, so each half-circle is 10ms

for wiring, pin 2 I follow bristolwatch but the 2.2k resistor I replaced with 1k. The output from pin 2 is exactly as described in bristolwatch website

So how do you convert down to 24v ? doesn't a coil have a response time ?
I did a Zero-crossing detection for a AC dimmer. and i used this
Zero-cross.JPG
Using resistors to reduce the Voltage. (the choice of opto-coupler is not so important, both should work)
but Aarg's suggestion should be followed, put

attachInterrupt(0, trig, RISING); // use only rising we need only a single trigger per crossing

in setup() (and remove it from loop)
make

int Switch;

a global variable
now within the ISR
do

if (Switch == HIGH) return; // exiting the isr

and remove the detachInterrupt().
You might still want way to make sure that 'Switch' Goes HIGH before it goes LOW again, so that your button press results in a single weld.

Zero-cross.JPG

Actually nearly all this can be moved to the main loop and out of the ISR

  delayMicroseconds(9900);  // no need to wait a near ms, you should be on time to fire the pin
  digitalWrite(13, HIGH);
  digitalWrite(timerPin, HIGH);  // only setting the timerPin High
  delayMicroseconds(j * 1000); // weld time  do all the waiting outside of the ISR, just use a volatile bool to show it has started the weld
  digitalWrite(timerPin, LOW);
  digitalWrite(13, LOW);
  detachInterrupt(0);

Hello all, I'm back.
Dear AARG, just a simple sentence but I have to take several days to know what did you imply here.
Dear Deva, thank you so much for explaining me and give me a new idea

Since I may be wrong in thinking of programming, so I refreshed my mind with a new way of thinking. Reading tones of paper from the internet but the issues here is they are dimming light with a long period of time but for me I just want it to work in a very short time (10ms 20ms 30 ms 40 ms ..... )

So I came up with a new idea and coding the program. However, it's still not as I expected, therefore I need your help again.

here are my code and explanations.

  1. I'm using pin 12 to trigger my triac, is it possible or I have to change to PWM pin?
  2. If I put triggerState = false on loop, the triac never be turned on
    if I remove triggerState, the triac on and off continuously . I expect it will on for a period of time as 10 -60 mS
//                chuong trinh chay may han cell pin
//         A0 noi chan giua trimer chinh thoi gian
//         A1 trimer dieu chinh cong suat
//         D2 ra zero crossing detector
//         D5 chan ra pedal
//         D12 tin hieu ra triac
//         D13 den bao hien thi
//         D9 stepp
//         D8 Dir
//
//
//
//
//
//--------------------------------------------------------------------------------------
//                                         INCLUDES
//--------------------------------------------------------------------------------------
#include <SPI.h>
#include <TimerOne.h>
#include <Wire.h>                           // I2C Library
#include <Adafruit_SSD1306.h>               // OLED driver Library
#include <Adafruit_GFX.h>                   // GFX driver Library
//--------------------------------------------------------------------------------------
//                                        DEFINES
//--------------------------------------------------------------------------------------

#define OLED_RESET     4
#define timerPin       12  // for nano is this pin able to export signal to trigger the triac?
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
//--------------------------------------------------------------------------------------
//                                        OBJECTS
//--------------------------------------------------------------------------------------
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);       //create instance of OLED

//--------------------------------------------------------------------------------------
//                                       VARIABLES
//--------------------------------------------------------------------------------------

volatile boolean zeroCross = false;
boolean trigState = false;
int timerValue; //1-6
int powerValue; //0-50
int j;
int Switch;
int Switch1;
int displayValue;
unsigned long time_now = 0;
long lastDebounceTime = 0;  // the last time the output pin was toggled
long debounceDelay = 50;    // the debounce time; increase if the output flickers

//--------------------------------------------------------------------------------------
//                                       MAIN PROGRAM
//--------------------------------------------------------------------------------------

void setup()
{
  Serial.begin(9600);
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  //delay(10);
  display.clearDisplay();
  display.setTextSize(1);                   // set text size
  display.setTextColor(WHITE);
  display.display();
  delay(1000);
  display.clearDisplay();
  pinMode(5, INPUT_PULLUP);         // set D5 as input of pedal
  pinMode(3, INPUT_PULLUP);         // set D3 as input of step control
  pinMode(2, INPUT);                // set D2 input for zero crossing detect
  pinMode(timerPin, OUTPUT);
  digitalWrite(timerPin, LOW);
  attachInterrupt(digitalPinToInterrupt(2), trig, RISING);  // call interrupt
  Timer1.initialize(10000);
  Timer1.attachInterrupt(powerCheck, 10000);    // attach powercheck function every 10ms
}

void loop()
{
  timerValue = map (analogRead(A1), 0, 1023, 1, 6);
  powerValue = map (analogRead(A0), 0, 1023, 5, 61);
  Switch1 = digitalRead(3);
  Switch = digitalRead(5);
  displayValue = (122 - (powerValue * 2));
  j = timerValue * 10;
  display.drawLine(0, 10, 127, 10, WHITE);    // draw 1st line
  display.drawLine(0, 20, 127, 20, WHITE);    // draw 2nd line
  display.drawLine(63, 10, 63, 63, WHITE);    // draw 3rd line
  display.setTextSize(1);                   // set text size 1
  display.setCursor(25, 0);
  display.print("Weld Controller");                   // print text 1
  //display.startscrollright(0x00, 0x00);
  display.setCursor(14, 11);
  display.print("Pul.W:");        //text 2
  display.setCursor(77, 11);
  display.print("Power:");        // text3
  display.setTextSize(3);
  display.setCursor(2, 31);
  display.print(j);                    // print timer
  display.setTextSize(1);
  // display.print("mS");        // text unit
  display.setCursor(70, 31);
  display.setTextSize(3);
  display.print(displayValue);       // print power
  display.setTextSize(1);
  // display.print("%");        // text unit
  display.display();                        // display all we just printed
  while (millis() < time_now + 500) {      //wait approx. [period] ms
    display.clearDisplay();                   // clear display
  }
  time_now = millis();
  if (Switch == LOW) {
    delay(500);                // debouncing button
    digitalWrite(13, HIGH);
    trigState = true;
    delayMicroseconds(timerValue * 10000);
    // trigState = false;       // when elimilate, program repeatedly running. When including it never start
    digitalWrite(13, LOW);

  }


  void powerCheck() {
    if (zeroCross == true && trigState == true) {  // check if it's zero cross and trigstate to fire up triac
      delayMicroseconds(powerValue * 150); //power changing from 5 (max) - 61 (min)
      digitalWrite(timerPin, HIGH);
      delayMicroseconds(10);
      digitalWrite(timerPin, LOW);
    }
  }
  void trig()
  {
    zeroCross = true;  // set flag for zero crossing when detected
  }

DVDdoug:
Zero-crossing solid state relays are super-common. :wink:

In other words, if the one you have is NOT already zero crossing switching, then you have one of the rare ones.

Paul

first of all any variable that gets modified within an ISR and referenced outside of it must be declared volatile, that includes this oneboolean trigState = false;
With all the writing to the display, the main loop() is going to be quite slow, and you want you program to respond straight away to a Zero-cross. Also the writing to the display code is really obstructing the view of what is going on.
So first create a function in which all that writing is done.
Now, only do the writing to the display if the power button is not pressed.
Once the power button is pressed, then wait for the zero-cross and fire the Triac for the time you want it. Then wait for the power button to be released. before you start over with the whole process.

So you will have to create a state machine (look up the tutorial)
The timer ISR does not need to be an ISR, but can be of course, but you firing of the triac should outside of the ISR, in a part of code that is held up waiting for the zero-cross detection. That is the moment to act ! not every 10ms in the timer ISR !!

In other words, if the one you have is NOT already zero crossing switching, then you have one of the rare ones.

Yes, but idea here is to create a spot welder that weld for a specific period of time, it is of course important to make sure that the timing is accurate, and for that you need to have a consistent starting point. Still it may be that the solid-state relay doesn't turn off until the next zero-crossing, but that is a different matter.