Continue to Site

Transformer less DC to AC inverter Loading without Real Load.

codemaster11

Full Member level 2
Full Member level 2
Joined
Sep 2, 2019
Messages
122
Helped
9
Reputation
18
Reaction score
7
Trophy points
18
Activity points
1,276
Capture.JPG

here is schematic diagram. arduino uno Pin9, 10 is for 10khz spwm frequency while pin 11, 12 for fundamental 50hz frequency.
below is a code i'm trying with dc to ac full bridge transformer less inverter with TLP250 instead IR2110. on real hardware it is
showing loading effect without real load with series light trick. study the code a little but didn't diagnose where the problem comes from. below is arduino code for atmega328p. any help will be appreciated. here is the code.

Code:
#include <avr/io.h>
#include <avr/interrupt.h>

/*
   SPWM_Nano_VFB3.ino

   Created : 8/11/2021
   Author  : yopie DIY

   Left bridge used for fundamental signal (50Hz/60Hz), Right bridge for SPWM (10kHz carrier freq.)
   Sampling per Cycle
   ---> 10kHz/50Hz = 200
   ---> 10kHZ/60hz = 166
   Look Up table entries use only half cycles (identical positive and negative cycles)
   50 Hz --->  200/2 = 100 entries
   60 Hz --->  167/2 = 83 entries
 
   SPWM clock = fXTAL/freq. carrier = 16.000.000/10.000 = 1.600 clock.
   WGM mode 8 is used, so ICR1 = 1.600/2 = 800 clk
   Look up tables for a half cycle (100 or 83 entries), max value = 800 (100% duty cycle)is loaded into register ICR1.

  This code is for 50Hz !!!
  for 60Hz use the Lookup Table for 60Hz and use the code marked on the ISR(TIMER1_OVF_vect) !!!
*/

const byte      vfbPin = A0,
                tfbPin = A1,
                battPin = A2;
volatile double percentMod;
int             phs;

//---------------------------------Look Up Table for 50 Hz---------------------------------------
int lookUp1[] = {
  0,  25, 50, 75, 100, 125, 150, 175, 199, 223, 247, 271, 294, 318, 341, 363, 385, 407, 429, 450,
  470, 490, 510, 529, 548, 566, 583, 600, 616, 632, 647, 662, 675, 689, 701, 713, 724, 734, 744, 753,
  761, 768, 775, 781, 786, 790, 794, 796, 798, 800, 800, 800, 798, 796, 794, 790, 786, 781, 775, 768,
  761, 753, 744, 734, 724, 713, 701, 689, 675, 662, 647, 632, 616, 600, 583, 566, 548, 529, 510, 490,
  470, 450, 429, 407, 385, 363, 341, 318, 294, 271, 247, 223, 199, 175, 150, 125, 100, 75, 50, 25, 0
};


/*
//---------------------------------Look Up Table for 60 Hz---------------------------------------
int lookUp1[] = {
  0, 30, 60, 90, 120, 150, 179, 208, 237, 266, 294, 322, 349, 376, 402, 428, 453, 478, 501, 524,
  547, 568, 589, 609, 628, 646, 664, 680, 695, 710, 723, 735, 747, 757, 766, 774, 781, 787, 792, 796,
  798, 800, 800, 799, 797, 794, 790, 784, 778, 770, 762, 752, 741, 729, 717, 703, 688, 672, 655, 637,
  619, 599, 579, 558, 536, 513, 489, 465, 441, 415, 389, 363, 335, 308, 280, 252, 223, 194, 164, 135,
  105, 75, 45, 15, 0};
*/


void setup() {
  // Register initilisation, see datasheet for more detail.
  TCCR1A = 0b10110000;
  /*      10xxxxxx Clear OC1A/OC1B on compare match when up-counting. Set OC1A/OC1B on compare match when down counting
          xx11xxxx Set OC1A/OC1B on compare match when up-counting. Clear OC1A/OC1B on compare match when down counting.
          xxxxxx00 WGM1 1:0 for waveform 8 (phase freq. correct).
  */
  TCCR1B = 0b00010001;
  /*      000xxxxx
          xxx10xxx WGM1 3:2 for waveform mode 8.
          xxxxx001 no prescale on the counter.
  */
  TIMSK1 = 0b00000001;
  /*      xxxxxxx1 TOV1 Flag interrupt enable. */
  ICR1   = 800;      /* Counter TOP value (at 16MHz XTAL, SPWM carrier freq. 10kHz, 200 samples/cycle).*/
  sei();             /* Enable global interrupts.*/
  DDRB = 0b00011110; /* Pin 9, 10, 11, 12 as outputs.*/
  PORTB = 0;

  pinMode(13, OUTPUT);
  pinMode(8, OUTPUT);
  pinMode(7, OUTPUT);
  pinMode(2, INPUT_PULLUP);

  percentMod = 0.01;
  for (int i = 0; i < 75; i++) {              // Soft Start
    percentMod = percentMod + 0.01;
    delay(20);
  }
}


void alarmIndication(int alarm)
{
  TCCR1A = 0;                             // shutdown SPWM output
  TIMSK1 = 0;
  PORTB &= 0b11100001;
loopX:
  for (int i = 0; i < alarm; i++) {
    digitalWrite(7, HIGH);                // turn ON LED and Buzzer
    digitalWrite(13, HIGH);
    delay(200);
    digitalWrite(7, LOW);                 // then turn OFF
    digitalWrite(13, LOW);
    delay(200);
  }
  delay(1000);
  goto loopX;                           //never ending story... until reset
}

void feedBackTest(float vfbIn, int tfbIn, int battIn) {
  long alrm;
  static int alrmCnt;
 
  if (digitalRead(2) == LOW) return;
  if (phs != 1) return;
 
  alrm = constrain(vfbIn, 462, 660);
  if (alrm !=vfbIn) alrmCnt++; else alrmCnt=0;
  if (alrm == 462 && alrmCnt >= 150) alarmIndication(2);        // underVoltage @ 2.5V --> 2.75 / 5 x 1023 = 562
  if (alrm == 660 && alrmCnt >=15) alarmIndication(3);          // overVoltage @ 3.15V --> 3.15 / 5 x 1023 = 645
  if (tfbIn >= 924) alarmIndication(4);                         // over temp @ 80C --> 10k/(10k + 1.068k) x 1023 =924
  if (battIn <= 457) alarmIndication(5);                        // low batt @ 10.5V --> (2k7/12.7k x 10.5) / 5 x 1023 = 457
  if (tfbIn >= 725 && digitalRead(8) == LOW)  digitalWrite(8, HIGH);  // fan ON @45C --> 725
  if (tfbIn <= 679 && digitalRead(8) == HIGH) digitalWrite(8, LOW);   // fan OFF @40C --> 679

}

void loop() {
  static int vfbValue;
  static int vfbValue1;
  static int vfbRise = 0;
  static float vMax;
  float alrm = 0;
  static int alrmCnt = 0;
  float ampDiff;

  if (phs = 1) {
    vfbValue1 = vfbValue;
    vfbValue = analogRead(vfbPin);                              // vfbPin = 0 to 5V ---> vfbValue = 0 to 1023

    if (vfbValue > vfbValue1 && vfbValue > 200) vfbRise = 1;     //check for positif cycle, bigger than noise
     if (vfbValue < vfbValue1 && vfbRise == 1) {                 // maximum vfb value reached
      vfbRise = 0;
      vMax = vfbValue1;
      ampDiff = 614 - vMax;    
      if (ampDiff > 5 || ampDiff < -5) {
        percentMod = percentMod + (ampDiff / vMax);               // voltage correction
        if (percentMod > 0.97) percentMod = 0.97;               // limit duty cycle to 97%     
      }
      
     feedBackTest(vMax, analogRead(tfbPin), analogRead(battPin));
      vMax = 0;
    }
  }
}


/*---------------------------------------------------------------------------------------------------------*/
ISR(TIMER1_OVF_vect) {
  static int num;
  static int  ph;
  static int dtA = 0;
  static int dtB = 5;

  if (num >= 99) {    // <------------------ 50 Hz !!!
//  if (num >= 82) {    // <------------------ 60 Hz !!!
    if (ph == 0) {         // OC1A as SPWM out
      TCCR1A = 0b10110000; // clear OC1A, set OC1B on compare match
      dtA = 0;             // no dead time
      dtB = 5;            // adding dead time to OC1B
    } else {
      TCCR1A = 0b11100000; // OC1B as SPWM out
      dtA = 5;
      dtB = 0;
    }
    ph ^= 1;
  }
  OCR1A = int(lookUp1[num] * percentMod) + dtA; // SPWM width update
  OCR1B = int(lookUp1[num] * percentMod) + dtB; // note: 0.7 used to reduce inveter output voltage

  num++;
  if (num >= 100) {                   // toggle left bridge (50Hz) !!!
//  if (num >= 83) {                   // toggle left bridge (60Hz) !!!
    delayMicroseconds(60);
    if (ph == 1) {
      digitalWrite(12, LOW);
      digitalWrite(11, HIGH);
      phs = 1;
    } else {
      digitalWrite(11, LOW);
      digitalWrite(12, HIGH);
      phs = 0;
    }
    num = 0;
  }
}
 
Last edited by a moderator:
Hello!

Instead of dropping 200 lines of code, I think the best thing would be to explain exactly what you
want to do because honestly I have no idea. The only explanation you give is in the title. I understand
that you want to digitally make PWM signal simulating a sine wave, right?
And I understand that you want to generate a 50Hz SPWM wave from 10 kHz.

I don't know how to write this gently, but your code is mostly unreadable.
The first setup instruction. You use a hardcoded value, and the use 3 lines to explain what it is. Why not defining
your constants properly. Example, you would have somewhere:
#define COMP_UP_CLR 0x10000000 // This defines the 10xxxxxx part. Then do the same for the xx11xxxx and so on
Then when setting the timer:
TCCR1A = COMP_UP_CLR |
SOME_OTHER_BITS |
YET_OTHER_BITS;
This allows:
1. To make the code self explanatory because each line says what it does. At least the 1st one in this pseudo code.
2. Yet it allows to add comments on every corresponding constant.

Beside this, there is an almost golden rule in embedded programming: Never use floating point unless you really
need it.

Next, you should use more #define statements. Example: ampdiff = 614 - vMax. Why 614? Nobody knows but you
and there isn't a single comment at that line.
#define MY_BLOODY_VALUE 614; // Replace MY_BLOODY_VALUE with anything meaningful in the context.
This way, again, your code would be self explanatory. This remark also stands for all parameters in feedBackTest
function. If battIn <= 457: why this value, what is 457? Etc, etc...

Something more I would worry about: you use interrupts, which is good. Now you are using a delay(1000). Not sure
it's a good idea.

In alramIndication:
You use loops which is good, but you use a gotoX that you should avoid. Why not enclosing your loop in while(!reset) {}?

So to summarize, you should explain what you want to do with words, you should explain what your problem is
with words, you should use #define statements, there is none in the whole code.

As Henry Bergson said, a well defined problem is half solved.

Dora
 
Last edited:


Write your reply...

LaTeX Commands Quick-Menu:

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top