How to change the Duty Cycle to this code ?

Hello, I am building a sine inverter with Arduino nano, the code works perfectly like inverter , but I cannot find how to change the duty cycle to control the output voltage. I got in the transformer output 50 - 60 HZ but i can’t control the output voltage, I need to control the duty cycle to have a desired output voltage.

This the Code :

#define PWM1_HIGH digitalWrite(2, HIGH) 
#define PWM1_LOW  digitalWrite(2, LOW)

#define PWM2_HIGH digitalWrite(3, HIGH) 
#define PWM2_LOW  digitalWrite(3, LOW)

#define SW_ENABLE 4 

unsigned char i = 0;
char EN = 0;
unsigned char SPWM[48]={0,12,23,35,46,57,68,78,88,98,108,116,125,133,140,146,152,157,162,166,169,171,173,174,174,173,171,169,166,162,157,152,146,140,133,125,116,108,98,88,78,68,57,46,35,23,12,0};

void setup() {
 pinMode(2, OUTPUT);
 pinMode(3, OUTPUT);
 pinMode(4, INPUT_PULLUP);
 PWM1_LOW;
 PWM2_LOW;
}

void loop() {

     if(digitalRead(SW_ENABLE) == 0)
       {
           while(digitalRead(SW_ENABLE) == 0) delay(10);
           EN = !EN;
       }
       
      
      if(EN)
        {
        
           for(i=0;i<44;i++)//48 para 50hz, 44 para 60hz
            {  
               PWM2_LOW;
               PWM1_HIGH;
               delayMicroseconds(SPWM[i]);
               PWM1_LOW;
               delayMicroseconds(174-SPWM[i]);
            }
            
       
           for(i=0;i<44;i++)//48 para 50hz, 44 para 60hz
            {
               PWM1_LOW;
               PWM2_HIGH;
               delayMicroseconds(SPWM[i]);
               PWM2_LOW;
               delayMicroseconds(174-SPWM[i]);
            }
         }
        else
         {  PWM1_LOW;
            PWM2_LOW;  
         }

Homemade102.ino (1.39 KB)

You are mistaken. It can not possibly work with no indexing at all of SPWM. It might generate a square wave at 50/60Hz that you haven't really viewed with a scope to see the problem.

Indexing would select one of the values in the table like:

SPWM[i]

You need to fix this serious omission before you worry about output amplitude.

Also please edit your post to put the code inside code tags, as explained in the permanent help threads at the top of the forum.

Okay, I see that you went back and edited your original post to add code tags. Thank you! However, you also edited the program so that my comments don't make sense. Anyway, what was the result of adding indexing? Did you get a chance to test it? How are you testing it?

To address your main question, an integer can be scaled by a fraction with (somewhat obviously...) a multiplication and a division. You have to be careful that multiplication comes first before the division, and that the result won't overflow the data type you're using. Example:

unsigned int scaledByTwoThirds = SPWM[i] * 2 / 3;

Ok let me try to understand why English is not my original language and I am noob at this.
I really didn't understand much about the index, I imagine because I lack knowledge, but I'm testing it on an inverter, with its mosfets and with its 12v transformer with center tap. He is working for me, he is converting from 12v DC to 150 volts AC at 60 hz. I understand what you are telling me, I know that a square wave comes out of the outputs of the arduino but when it goes through the process and with a 2MF filter at the output it converts the wave into sinusoidal, because I am certain? because the sound it emits when it converts is almost zero and when I connect an inductive load like a fan it hardly makes any noise. Right now I don't have the oscilloscope to actually measure the wave. But finally what I cannot do is that through the microcontroller lower the duty cycle to be able to control the output voltage as conventional inverters do.

You have a table of 48 sine() values from 0 to 174 that you use to control the ratio of ON to OFF times. The table is for a 50 Hz output so you shave a little off every half cycle to make a 60 Hz signal. Currently, the ON times range from 0 to 174 and the OFF times range from 174 to 0.

To lower the output voltage you will need to keep the 174 the same but lower the maximum ON times. You can do that by reducing the values in the sine table. For example, if you cut the values in half the ON time would range from 0 to 87 and the OFF times would range from 174 to 87.

Thanks for you answers Mr john wasser.

I was making tests, I did that you told me, I changed the values in half the ON time would range from 0 to 87 and the OFF times would range from 174 to 87 I see the Output voltage changed . But making more testing can I see the frequency changed too, when the voltage going down the frequency going up . I need like the IC SG3524N or SG3526N and SG3525 work. It Can change the voltage output in a range like 100v to 150v moving the value of a resistor o potentiometer without change the frequency output. If I have a transformer with 150v AC output I need to control the output to 110v or 120v output keeping the same frequency or 60HZ in the output.

The way I did the change in the code was using two ("IF") I will to put the code below but I don't know if I did the right way.

If you have the better way to do I would like you to give me a hand.

Thanks for response !

#define PWM1_HIGH digitalWrite(10, HIGH) 
#define PWM1_LOW  digitalWrite(10, LOW)

#define PWM2_HIGH digitalWrite(9, HIGH) 
#define PWM2_LOW  digitalWrite(9, LOW)

#define SW_ENABLE 4 

unsigned char i = 0;
char EN = 0;
unsigned char SPWM[48]={0,12,23,35,46,57,68,78,88,98,108,116,125,133,140,146,152,157,162,166,169,171,173,174,174,173,171,169,166,162,157,152,146,140,133,125,116,108,98,88,78,68,57,46,35,23,12,0};

void setup() {
    
  pinMode(10, OUTPUT);
  pinMode(9, OUTPUT);
  pinMode(4, INPUT_PULLUP);
  PWM1_LOW;
  PWM2_LOW;
}

void loop() {

      if(digitalRead(SW_ENABLE) == 0)
        {
            while(digitalRead(SW_ENABLE) == 0) delay(10);
            EN = !EN;
        }
               
       if(EN)
         {
         
           for(i=0;i<42;i++)       //48 para 50hz, 44 para 60hz
             {  
                PWM2_LOW;
                PWM1_HIGH;
               delayMicroseconds(SPWM[i]);             
             }                 
                  for(i=23;i<42;i++)                 
                 {                 
                PWM1_LOW;
                delayMicroseconds(SPWM[i]);
                 }
                       
            for(i=0;i<42;i++)     //48 para 50hz, 44 para 60hz
             {
                PWM1_LOW;
                PWM2_HIGH;             
                delayMicroseconds(SPWM[i]);
             }
          
                for(i=23;i<42;i++)
                {
                PWM2_LOW;
                delayMicroseconds(SPWM[i]);
                }
          
          }
         else
          {  PWM1_LOW;
             PWM2_LOW;  
          }
 }

You didn’t change the SPWM table at all.

This is what I intended for you to do:

// Set this to a value from 0 to 256 to adjust the Sine table.  The lower the number the lower the voltage.
const int VOLTAGE_ADJUST = 256;


#define PWM1_HIGH digitalWrite(2, HIGH)
#define PWM1_LOW  digitalWrite(2, LOW)


#define PWM2_HIGH digitalWrite(3, HIGH)
#define PWM2_LOW  digitalWrite(3, LOW)


#define SW_ENABLE 4


unsigned char i = 0;
char EN = 0;
const unsigned char RawSine[48] =
{
  0, 12, 23, 35, 46, 57, 68, 78, 88, 98, 108, 116, 
  125, 133, 140, 146, 152, 157, 162, 166, 169, 171, 173, 174, 
  174, 173, 171, 169, 166, 162, 157, 152, 146, 140, 133, 125, 
  116, 108, 98, 88, 78, 68, 57, 46, 35, 23, 12, 0
};


unsigned char SPWM[48];
void setup()
{
  for (int i = 0; i < 48; i++)
  {
    SPWM[i] = (RawSine[i] * VOLTAGE_ADJUST) / 256;
  }
  pinMode(2, OUTPUT);
  pinMode(3, OUTPUT);
  pinMode(4, INPUT_PULLUP);
  PWM1_LOW;
  PWM2_LOW;
}


void loop()
{


  if (digitalRead(SW_ENABLE) == 0)
  {
    while (digitalRead(SW_ENABLE) == 0) delay(10);
    EN = !EN;
  }




  if (EN)
  {
    // Positive half cycle
    for (i = 0; i < 44; i++) //48 para 50hz, 44 para 60hz
    {
      PWM2_LOW;
      PWM1_HIGH;
      delayMicroseconds(SPWM[i]);
      PWM1_LOW;
      delayMicroseconds(174 - SPWM[i]);
    }


    // Negative half cycle
    for (i = 0; i < 44; i++) //48 para 50hz, 44 para 60hz
    {
      PWM1_LOW;
      PWM2_HIGH;
      delayMicroseconds(SPWM[i]);
      PWM2_LOW;
      delayMicroseconds(174 - SPWM[i]);
    }
  }
  else
  {
    PWM1_LOW;
    PWM2_LOW;
  }
}

I tried with your last code but not working. I changed the value from this variable (const int VOLTAGE_ADJUST =256)The voltage never go down and the the sound from the transformer up,
the no-load consumption of the inverter rises too. When I used other code (I will put below) the inverter work better, the sound
it is almost non-existent, and the consumption down to 1 AMP.

I managed to vary the voltage of 90V to 150V.

I go 110v to 60HZ to 1 AMP but when going to 80V the frequency up to 84 Hz and 150V the frequency down to 51 Hz.

#define PWM1_HIGH digitalWrite(2, HIGH) //ON TIME PWM1 
#define PWM1_LOW  digitalWrite(2, LOW)  // OFF TIME PWM1

#define PWM2_HIGH digitalWrite(3, HIGH) //ON TIME PWM2
#define PWM2_LOW  digitalWrite(3, LOW)  // OFF TIME PWM2

#define SW_ENABLE 4 

unsigned char i = 0;
char EN = 0;

unsigned char SPWM[48] =
{
  0, 12, 23, 35, 46, 57, 68, 78, 88, 98, 108, 116, 
  125, 133, 140, 146, 152, 157, 162, 166, 169, 171, 173, 174, 
  174, 173, 171, 169, 166, 162, 157, 152, 146, 140, 133, 125, 
  116, 108, 98, 88, 78, 68, 57, 46, 35, 23, 12, 0
};


void setup() {

  pinMode(2, OUTPUT);
  pinMode(3, OUTPUT);
  pinMode(4, INPUT_PULLUP);
  PWM1_LOW;
  PWM2_LOW;
}

void loop() {

      if(digitalRead(SW_ENABLE) == 0)
        {
            while(digitalRead(SW_ENABLE) == 0) delay(10);
            EN = !EN;
        }
               
       if(EN)
         {
         
            for(i=0;i<24;i++)              //ON TIME PWM1 
             {  
                PWM2_LOW;
                PWM1_HIGH;
               delayMicroseconds(SPWM[i]);             
             }                 
                  for(i=0;i<48;i++)        //OFF TIME PWM1         
                 {                 
                PWM1_LOW;
                delayMicroseconds(SPWM[i]);
                 }
                       
            for(i=0;i<24;i++)             //ON TIME PWM2 
             {
                PWM1_LOW;
                PWM2_HIGH;             
                delayMicroseconds(SPWM[i]);
             }
          
                for(i=0;i<48;i++)         //OFF TIME PWM2  
                {
                PWM2_LOW;
                delayMicroseconds(SPWM[i]);
                }
          
          }
         else
          {  PWM1_LOW;
             PWM2_LOW;  
          }
 }

Any more suggestions?

I'm not into all the details how this works. But I think it can work this way:

reducing the amplitude is done by reducing the ON-time. To keep the frequency constant the OFF-time has to increase the same amount as the ON-time decreases.

best regards Stefan