Welcome, Guest: Register On Nairaland / LOGIN! / Trending / Recent / New
Stats: 3,143,490 members, 7,781,468 topics. Date: Friday, 29 March 2024 at 02:55 PM

Sine Wave Inverter Using Arduino - Programming - Nairaland

Nairaland Forum / Science/Technology / Programming / Sine Wave Inverter Using Arduino (3581 Views)

How To Create A Motion-detection Camera Using Arduino, Webcam And Pir Sensor / I Teach You How To Build A Pure Sine Wave Inverter With Arduino Or (atmega328) / Learn How To Programme Using Arduino And Raspberry Pi (2) (3) (4)

(1) (Reply) (Go Down)

Sine Wave Inverter Using Arduino by pakingzzzzz(m): 10:59am On Nov 23, 2017
I am going to show in this thread, a method of generating sine wave signal for your inverter projects..
Re: Sine Wave Inverter Using Arduino by pakingzzzzz(m): 11:03am On Nov 23, 2017
PROGRAM FOR 50Hz void setup() { pinMode(7, OUTPUT); pinMode(8, OUTPUT); } void loop() { digitalWrite(7, HIGH); delayMicroseconds(15); digitalWrite(7, LOW); delayMicroseconds(285); digitalWrite(7, HIGH); delayMicroseconds(30); digitalWrite(7, LOW); delayMicroseconds(270); digitalWrite(7, HIGH); delayMicroseconds(45); digitalWrite(7, LOW); delayMicroseconds(255); digitalWrite(7, HIGH); delayMicroseconds(60); digitalWrite(7, LOW); delayMicroseconds(240); digitalWrite(7, HIGH); delayMicroseconds(75); digitalWrite(7, LOW); delayMicroseconds(225); digitalWrite(7, HIGH); delayMicroseconds(90); digitalWrite(7, LOW); delayMicroseconds(210); digitalWrite(7, HIGH); delayMicroseconds(105); digitalWrite(7, LOW); delayMicroseconds(195); digitalWrite(7, HIGH); delayMicroseconds(120); digitalWrite(7, LOW); delayMicroseconds(180); digitalWrite(7, HIGH); delayMicroseconds(135); digitalWrite(7, LOW); delayMicroseconds(165); digitalWrite(7, HIGH); delayMicroseconds(150); digitalWrite(7, LOW); delayMicroseconds(150); digitalWrite(7, HIGH); delayMicroseconds(165); digitalWrite(7, LOW); delayMicroseconds(135); digitalWrite(7, HIGH); delayMicroseconds(195); digitalWrite(7, LOW); delayMicroseconds(105); digitalWrite(7, HIGH); delayMicroseconds(225); digitalWrite(7, LOW); delayMicroseconds(75); digitalWrite(7, HIGH); delayMicroseconds(255); digitalWrite(7, LOW); delayMicroseconds(45); digitalWrite(7, HIGH); delayMicroseconds(270); digitalWrite(7, LOW); delayMicroseconds(30); digitalWrite(7, HIGH); delayMicroseconds(285); digitalWrite(7, LOW); delayMicroseconds(15); digitalWrite(7, HIGH); delayMicroseconds(270); digitalWrite(7, LOW); delayMicroseconds(30); digitalWrite(7, HIGH); delayMicroseconds(255); digitalWrite(7, LOW); delayMicroseconds(45); digitalWrite(7, HIGH); delayMicroseconds(225); digitalWrite(7, LOW); delayMicroseconds(75); digitalWrite(7, HIGH); delayMicroseconds(195); digitalWrite(7, LOW); delayMicroseconds(105); digitalWrite(7, HIGH); delayMicroseconds(165); digitalWrite(7, LOW); delayMicroseconds(135); digitalWrite(7, HIGH); delayMicroseconds(150); digitalWrite(7, LOW); delayMicroseconds(150); digitalWrite(7, HIGH); delayMicroseconds(135); digitalWrite(7, LOW); delayMicroseconds(165); digitalWrite(7, HIGH); delayMicroseconds(120); digitalWrite(7, LOW); delayMicroseconds(180); digitalWrite(7, HIGH); delayMicroseconds(105); digitalWrite(7, LOW); delayMicroseconds(195); digitalWrite(7, HIGH); delayMicroseconds(90); digitalWrite(7, LOW); delayMicroseconds(210); digitalWrite(7, HIGH); delayMicroseconds(75); digitalWrite(7, LOW); delayMicroseconds(225); digitalWrite(7, HIGH); delayMicroseconds(60); digitalWrite(7, LOW); delayMicroseconds(240); digitalWrite(7, HIGH); delayMicroseconds(45); digitalWrite(7, LOW); delayMicroseconds(255); digitalWrite(7, HIGH); delayMicroseconds(30); digitalWrite(7, LOW); delayMicroseconds(270); digitalWrite(7, HIGH); delayMicroseconds(15); digitalWrite(7, LOW); delayMicroseconds(285); digitalWrite(8, HIGH); //22 delayMicroseconds(15); digitalWrite(8, LOW); delayMicroseconds(285); digitalWrite(8, HIGH); delayMicroseconds(30); digitalWrite(8, LOW); delayMicroseconds(270); digitalWrite(8, HIGH); delayMicroseconds(45); digitalWrite(8, LOW); delayMicroseconds(255); digitalWrite(8, HIGH); delayMicroseconds(60); digitalWrite(8, LOW); delayMicroseconds(240); digitalWrite(8, HIGH); delayMicroseconds(75); digitalWrite(8, LOW); delayMicroseconds(225); digitalWrite(8, HIGH); delayMicroseconds(90); digitalWrite(8, LOW); delayMicroseconds(210); digitalWrite(8, HIGH); delayMicroseconds(105); digitalWrite(8, LOW); delayMicroseconds(195); digitalWrite(8, HIGH); delayMicroseconds(120); digitalWrite(8, LOW); delayMicroseconds(180); digitalWrite(8, HIGH); delayMicroseconds(135); digitalWrite(8, LOW); delayMicroseconds(165); digitalWrite(8, HIGH); delayMicroseconds(150); digitalWrite(8, LOW); delayMicroseconds(150); digitalWrite(8, HIGH); delayMicroseconds(165); digitalWrite(8, LOW); delayMicroseconds(135); digitalWrite(8, HIGH); delayMicroseconds(195); digitalWrite(8, LOW); delayMicroseconds(105); digitalWrite(8, HIGH); delayMicroseconds(225); digitalWrite(8, LOW); delayMicroseconds(75); digitalWrite(8, HIGH); delayMicroseconds(255); digitalWrite(8, LOW); delayMicroseconds(45); digitalWrite(8, HIGH); delayMicroseconds(270); digitalWrite(8, LOW); delayMicroseconds(30); digitalWrite(8, HIGH); delayMicroseconds(285); digitalWrite(8, LOW); delayMicroseconds(15); digitalWrite(8, HIGH); delayMicroseconds(270); digitalWrite(8, LOW); delayMicroseconds(30); digitalWrite(8, HIGH); delayMicroseconds(255); digitalWrite(8, LOW); delayMicroseconds(45 ); digitalWrite(8, HIGH); delayMicroseconds(225); digitalWrite(8, LOW); delayMicroseconds(75); digitalWrite(8, HIGH); delayMicroseconds(195); digitalWrite(8, LOW); delayMicroseconds(105); digitalWrite(8, HIGH); delayMicroseconds(165); digitalWrite(8, LOW); delayMicroseconds(135); digitalWrite(8, HIGH); delayMicroseconds(150); digitalWrite(8, LOW); delayMicroseconds(150); digitalWrite(8, HIGH); delayMicroseconds(135); digitalWrite(8, LOW); delayMicroseconds(165); digitalWrite(8, HIGH); delayMicroseconds(120); digitalWrite(8, LOW); delayMicroseconds(180); digitalWrite(8, HIGH); delayMicroseconds(105); digitalWrite(8, LOW); delayMicroseconds(195); digitalWrite(8, HIGH); delayMicroseconds(90); digitalWrite(8, LOW); delayMicroseconds(210); digitalWrite(8, HIGH); delayMicroseconds(75); digitalWrite(8, LOW); delayMicroseconds(225); digitalWrite(8, HIGH); delayMicroseconds(60); digitalWrite(8, LOW); delayMicroseconds(240); digitalWrite(8, HIGH); delayMicroseconds(45); digitalWrite(8, LOW); delayMicroseconds(255); digitalWrite(8, HIGH); delayMicroseconds(30); digitalWrite(8, LOW); delayMicroseconds(270); digitalWrite(8, HIGH); delayMicroseconds(15); digitalWrite(8, LOW); delayMicroseconds(285); }
Re: Sine Wave Inverter Using Arduino by KeDv: 11:04am On Nov 23, 2017
pakingzzzzz:
PROGRAM FOR 50Hz
void setup()
{
pinMode(7, OUTPUT); pinMode(8, OUTPUT);
}
void loop()
{
digitalWrite(7, HIGH);
delayMicroseconds(15);
digitalWrite(7, LOW);
delayMicroseconds(285);
digitalWrite(7, HIGH);
delayMicroseconds(30);
digitalWrite(7, LOW);
delayMicroseconds(270);
digitalWrite(7, HIGH);
delayMicroseconds(45);
digitalWrite(7, LOW);
delayMicroseconds(255);
digitalWrite(7, HIGH);
delayMicroseconds(60);
digitalWrite(7, LOW);
delayMicroseconds(240);
digitalWrite(7, HIGH);
delayMicroseconds(75);
digitalWrite(7, LOW);
delayMicroseconds(225);
digitalWrite(7, HIGH);
delayMicroseconds(90);
digitalWrite(7, LOW);
delayMicroseconds(210);
digitalWrite(7, HIGH);
delayMicroseconds(105);
digitalWrite(7, LOW);
delayMicroseconds(195);
digitalWrite(7, HIGH);
delayMicroseconds(120);
digitalWrite(7, LOW);
delayMicroseconds(180);
digitalWrite(7, HIGH);
delayMicroseconds(135);
digitalWrite(7, LOW);
delayMicroseconds(165);
digitalWrite(7, HIGH);
delayMicroseconds(150);
digitalWrite(7, LOW);
delayMicroseconds(150);
digitalWrite(7, HIGH);
delayMicroseconds(165);
digitalWrite(7, LOW);
delayMicroseconds(135);
digitalWrite(7, HIGH);
delayMicroseconds(195);
digitalWrite(7, LOW);
delayMicroseconds(105);
digitalWrite(7, HIGH);
delayMicroseconds(225);
digitalWrite(7, LOW);
delayMicroseconds(75);
digitalWrite(7, HIGH);
delayMicroseconds(255);
digitalWrite(7, LOW);
delayMicroseconds(45);
digitalWrite(7, HIGH);
delayMicroseconds(270);
digitalWrite(7, LOW);
delayMicroseconds(30);
digitalWrite(7, HIGH);
delayMicroseconds(285);
digitalWrite(7, LOW);
delayMicroseconds(15);
digitalWrite(7, HIGH);
delayMicroseconds(270);
digitalWrite(7, LOW);
delayMicroseconds(30);
digitalWrite(7, HIGH);
delayMicroseconds(255);
digitalWrite(7, LOW);
delayMicroseconds(45);
digitalWrite(7, HIGH);
delayMicroseconds(225);
digitalWrite(7, LOW);
delayMicroseconds(75);
digitalWrite(7, HIGH);
delayMicroseconds(195);
digitalWrite(7, LOW);
delayMicroseconds(105);
digitalWrite(7, HIGH);
delayMicroseconds(165);
digitalWrite(7, LOW);
delayMicroseconds(135);
digitalWrite(7, HIGH);
delayMicroseconds(150);
digitalWrite(7, LOW);
delayMicroseconds(150);
digitalWrite(7, HIGH);
delayMicroseconds(135);
digitalWrite(7, LOW);
delayMicroseconds(165);
digitalWrite(7, HIGH);
delayMicroseconds(120);
digitalWrite(7, LOW);
delayMicroseconds(180);
digitalWrite(7, HIGH);
delayMicroseconds(105);
digitalWrite(7, LOW);
delayMicroseconds(195);
digitalWrite(7, HIGH);
delayMicroseconds(90);
digitalWrite(7, LOW);
delayMicroseconds(210);
digitalWrite(7, HIGH);
delayMicroseconds(75);
digitalWrite(7, LOW);
delayMicroseconds(225);
digitalWrite(7, HIGH);
delayMicroseconds(60);
digitalWrite(7, LOW);
delayMicroseconds(240);
digitalWrite(7, HIGH);
delayMicroseconds(45);
digitalWrite(7, LOW);
delayMicroseconds(255);
digitalWrite(7, HIGH);
delayMicroseconds(30);
digitalWrite(7, LOW);
delayMicroseconds(270);
digitalWrite(7, HIGH);
delayMicroseconds(15);
digitalWrite(7, LOW);
delayMicroseconds(285);
digitalWrite(8, HIGH); //22
delayMicroseconds(15);
digitalWrite(8, LOW);
delayMicroseconds(285);
digitalWrite(8, HIGH);
delayMicroseconds(30);
digitalWrite(8, LOW);
delayMicroseconds(270);
digitalWrite(8, HIGH);
delayMicroseconds(45);
digitalWrite(8, LOW);
delayMicroseconds(255);
digitalWrite(8, HIGH);
delayMicroseconds(60);
digitalWrite(8, LOW);
delayMicroseconds(240);
digitalWrite(8, HIGH);
delayMicroseconds(75);
digitalWrite(8, LOW);
delayMicroseconds(225);
digitalWrite(8, HIGH);
delayMicroseconds(90);
digitalWrite(8, LOW);
delayMicroseconds(210);
digitalWrite(8, HIGH);
delayMicroseconds(105);
digitalWrite(8, LOW);
delayMicroseconds(195);
digitalWrite(8, HIGH);
delayMicroseconds(120);
digitalWrite(8, LOW);
delayMicroseconds(180);
digitalWrite(8, HIGH);
delayMicroseconds(135);
digitalWrite(8, LOW);
delayMicroseconds(165);
digitalWrite(8, HIGH);
delayMicroseconds(150);
digitalWrite(8, LOW);
delayMicroseconds(150);
digitalWrite(8, HIGH);
delayMicroseconds(165);
digitalWrite(8, LOW);
delayMicroseconds(135);
digitalWrite(8, HIGH);
delayMicroseconds(195);
digitalWrite(8, LOW);
delayMicroseconds(105);
digitalWrite(8, HIGH);
delayMicroseconds(225);
digitalWrite(8, LOW);
delayMicroseconds(75);
digitalWrite(8, HIGH);
delayMicroseconds(255);
digitalWrite(8, LOW);
delayMicroseconds(45);
digitalWrite(8, HIGH);
delayMicroseconds(270);
digitalWrite(8, LOW);
delayMicroseconds(30);
digitalWrite(8, HIGH);
delayMicroseconds(285);
digitalWrite(8, LOW);
delayMicroseconds(15);
digitalWrite(8, HIGH);
delayMicroseconds(270);
digitalWrite(8, LOW);
delayMicroseconds(30);
digitalWrite(8, HIGH);
delayMicroseconds(255);
digitalWrite(8, LOW);
delayMicroseconds(45 );
digitalWrite(8, HIGH);
delayMicroseconds(225);
digitalWrite(8, LOW);
delayMicroseconds(75);
digitalWrite(8, HIGH);
delayMicroseconds(195);
digitalWrite(8, LOW);
delayMicroseconds(105);
digitalWrite(8, HIGH);
delayMicroseconds(165);
digitalWrite(8, LOW);
delayMicroseconds(135);
digitalWrite(8, HIGH);
delayMicroseconds(150);
digitalWrite(8, LOW);
delayMicroseconds(150);
digitalWrite(8, HIGH);
delayMicroseconds(135);
digitalWrite(8, LOW);
delayMicroseconds(165);
digitalWrite(8, HIGH);
delayMicroseconds(120);
digitalWrite(8, LOW);
delayMicroseconds(180);
digitalWrite(8, HIGH);
delayMicroseconds(105);
digitalWrite(8, LOW);
delayMicroseconds(195);
digitalWrite(8, HIGH);
delayMicroseconds(90);
digitalWrite(8, LOW);
delayMicroseconds(210);
digitalWrite(8, HIGH);
delayMicroseconds(75);
digitalWrite(8, LOW);
delayMicroseconds(225);
digitalWrite(8, HIGH);
delayMicroseconds(60);
digitalWrite(8, LOW);
delayMicroseconds(240);
digitalWrite(8, HIGH);
delayMicroseconds(45);
digitalWrite(8, LOW);
delayMicroseconds(255);
digitalWrite(8, HIGH);
delayMicroseconds(30);
digitalWrite(8, LOW);
delayMicroseconds(270);
digitalWrite(8, HIGH);
delayMicroseconds(15);
digitalWrite(8, LOW);
delayMicroseconds(285);
}

Wtf
Re: Sine Wave Inverter Using Arduino by pakingzzzzz(m): 11:13am On Nov 23, 2017
Below is the circuit diagram.. Mind you, the pins have been swapped from 8,9 to 13, and 14..
The signals are fed into the half bridge driver Is ( FAN7392)..
I shall upload a proteus spice simulation of the signals here later.

For those who do not know how to simulate an arduino in your Proteus, contact me..
The Proteus does not support an arduino. Because it does not have it in its library.. You will have to do that manually by adding the required files. The files are of two types of it must work.

Once the necessary files I've been added in the Proteus library, you can simulate your staying circuit with ease henceforth using the Proteus.
But you will have to feed the arduino a Hex file of your code, and not the code you write in your arduino IDE.
You can convert your code to Hex file using the Arduino IDE. You just need to apply the "comilation" option to do that in the reference option.
Once that is done, you can go ahead and click on the "compile" button to compile your code.
When you see "Done compiling", head straight to your temp folder in your C drive, look for the code and you will see it in a .Hex format.
It is this Hex file that you will feed to the Proteus to make it run your arduino code perfectly.

Re: Sine Wave Inverter Using Arduino by pakingzzzzz(m): 11:16am On Nov 23, 2017
For enquiries, you can reach me through my contacts;

Re: Sine Wave Inverter Using Arduino by pakingzzzzz(m): 10:26pm On Nov 23, 2017
HOW TO GENERATE SPWM SIGNALS WITH ATMEGA16

The microcontroller I’ve chosen is the ATMEGA16. However, the concept can be used on any AVR that has a PWM module. The output sine wave is to have a frequency of 50Hz. I have chosen to use a switching frequency of 16kHz for SPWM.
So, here I talk about how to generate sine wave using sinusoidal pulse width modulation (SPWM) signals using the PWM module as can be commonly found on most Atmel AVR microcontrollers.


Now let's move on to sine wave generation using ATMEGA16.
Let’s take a look at the code first:
//----------------------------------------------------------------------------------------
//Programmer: Pakingzzzzz
//Target Microcontroller: ATMEGA16
//Compiler: mikroC PRO for AVR (Can easily port to any other compiler)
//-----------------------------------------------------------------------------------------
unsigned int sin_table[32]={0, 100, 199, 296, 390, 480, 566, 645, 718,
783, 840, 889, 928, 958, 979, 989, 989, 979, 958, 928, 889, 840, 783,
718, 645, 566, 480, 390, 296, 199, 100,0};
#define MOSA PORTD0_bit
#define MOSB PORTD1_bit
#define MOSC PORTD2_bit
#define MOSD PORTD3_bit
unsigned char FlagReg;
#define Direction FlagReg.B0
//0 -> MOS A + D
//1 -> MOS B + C
unsigned int TBL_POINTER_NEW, TBL_POINTER_OLD, TBL_POINTER_SHIFT, SET_FREQ;
unsigned int TBL_temp;
unsigned char DUTY_CYCLE;
void interrupt() org IVT_ADDR_TIMER1_OVF{
TBL_POINTER_NEW = TBL_POINTER_NEW + SET_FREQ;
if (TBL_POINTER_NEW < TBL_POINTER_OLD){
if (Direction == 0){
MOSA = 0;
MOSD = 0;
MOSB = 1;
MOSC = 1;
Direction = 1;
}
else{
MOSB = 0;
MOSC = 0;
MOSA = 1;
MOSD = 1;
Direction = 0;
}
}
TBL_POINTER_SHIFT = TBL_POINTER_NEW >> 11;
DUTY_CYCLE = TBL_POINTER_SHIFT;
TBL_POINTER_SHIFT = sin_table[DUTY_CYCLE];
OCR1AH = TBL_POINTER_SHIFT >> 8;
OCR1AL = TBL_POINTER_SHIFT & 0x0F;
TBL_POINTER_OLD = TBL_POINTER_NEW;
}
void main() {
SET_FREQ = 410;
TBL_POINTER_SHIFT = 0;
TBL_POINTER_NEW = 0;
TBL_POINTER_OLD = 0;
DUTY_CYCLE = 0;
DDRC = 0xFF;
DDRD = 0XFF;
OCR1AH = 0;
OCR1AL = 0;
TCCR1A = 0x82;
ICR1H = 0x03;
ICR1L = 0xE7;
//ICR1 = 999 -> TOP -> 16kHz
TIMSK = 0x04;
TCCR1B = 0x19;
SREG_I_bit = 1;
while(1);
}
That’s the code. Quite simple really. And pretty short!
Re: Sine Wave Inverter Using Arduino by pakingzzzzz(m): 10:28pm On Nov 23, 2017
Now let's analyze the code and see what I've done.
Here, I’ve used the Fast PWM mode. I chose to use an oscillator frequency (for ATMEGA16) of 16MHz and an SPWM switching frequency of 16kHz. For this, I selected ICR1 as the TOP and assigned 999 to ICR1. I used a prescaler divider (N) = 1. I used PWM mode 14. So that gives a switching frequency of:

Re: Sine Wave Inverter Using Arduino by pakingzzzzz(m): 10:29pm On Nov 23, 2017
In PWM mode 14, ICR1 sets TOP and OCR1 sets the duty cycle.
I’ve assigned 0x82 to TCCR1A and 0x19 to TCCR1B. This sets PWM mode to mode 14. This also sets Compare Output mode for OCR1A to non-inverting mode: Clear OCR1A on compare match, clear at BOTTOM. I have selected the sine table such that the peak value is smaller than TOP. To generate the sine table, I used my software “Smart Sine” with a peak value of 990. Also notice how there’s a zero at the beginning and ending of the sine table. These act to create a “deadtime” so that there isn’t a short circuit due to cross-conduction between the MOSFETs in the same leg being driven. I did this by generating a sine table with 31 values and a peak of 990 and then adding a zero at the end.

The SPWM generation is done by the single PWM module and which MOSFETs to send the signals to is set by the "Direction" bit and the hardware trick employing the AND gates. When "Direction" is equal to 0, the high side MOSFET A is kept on for 10ms during which time the SPWM signals on PWM (OC1A) output (PORTD5) are sent to low side MOSFET D by sending a "1" to PORTD3, which, with the help of the AND gate "diverts" the OC1A signal to the low side MOSFET D (see Fig. 1 above). The same thing is achieved when "Direction" is equal to 1, just with high side MOSFET C and low side MOSFET B. When MOSFETs A and D are operated, MOSFETs B and C are kept off and vice versa. For MOSFET drive, we need 4 pins for the 4 drive signals and I’ve chosen PORTD bits 0 to 3. I’ve arbitrarily chosen these four pins but you can choose any four pins really. The MOSFETs are first turned off before the other two are turned on, as can be seen in the code block:
if (Direction == 0){
MOSA = 0;
MOSD = 0;
MOSB = 1;
MOSC = 1;
Direction = 1;
}
else{
MOSB = 0;
MOSC = 0;
MOSA = 1;
MOSD = 1;
Direction = 0;
}
Use of the table pointer in the interrupt:
When Timer/Counter 1 reaches TOP, TOV1 flag is set and since interrupt is enabled, the ISR in the corresponding interrupt vector is served. There table pointer is made use of to retrieve the required values off the sine table and assign them to OCR1AH and OCR1AL – the 16-bit resultant in OCR1A sets the duty cycle. The sine table stores the duty cycle in such a way that when these are subsequently sent to the MOSFETs in the specific order in which they are set, at the required frequency, the output, when filtered, will produce a sine wave.
Every 62.5us the ISR is served – 62.5us because the SPWM frequency was set to 16kHz. Time period for a 16kHz frequency is 62.5us as time period = 1 / freqeuncy.
In the main() function, I had assigned the value of 410 to SET_FREQ . SET_FREQ determines the output frequency of the sine wave, which in our case here is 50Hz. You’ll soon see how.
In the interrupt, the variable TBL_POINTER_NEW is updated – every 62.5us it is increased by 410.
TBL_POINTER_NEW is a 16-bit variable and at the beginning of program execution has a value of 0. So, after the first interrupt it holds 410, after the second interrupt 820, after the third 1230 and so on. After 159 interrupts, TBL_POINTER_NEW holds 65190. So, at the next interrupt,
TBL_POINTER_NEW overflows and holds 64.
The interrupt occurs every 62.5us. At each interrupt TBL_POINTER_NEW is increased by 410. At the 160 th interrupt, TBL_POINTER_NEW overflows, just as it does the 320 th interrupt, the 480 th interrupt and so on.
Initially TBL_POINTER_NEW holds 0 and on subsequent interrupts, TBL_POINTER_NEW holds 410, 820, 1230, 1640, 2050, 2460, 2870, 3280, 3690, 4100 and so on.
TBL_POINTER_SHIFT right-shifts
TBL_POINTER_NEW eleven times and stores that value. Right shifting 11 times is the same as dividing by 2 11 (2 11 = 2048) – just more efficient. When the microcontroller starts up,
TBL_POINTER_SHIFT holds 0 and on subsequent interrupts, TBL_POINTER_SHIFT holds 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3 ….. and so on. Now, the trend is that TBL_POINTER_SHIFT holds the same value for 5 consecutive interrupts – go on, you can do the math. Why 5 times? We’ll see that a little later.
After TBL_POINTER_NEW is shifted 11 times,
DUTY_CYCLE is assigned the resultant 5-bit value. This acts as – or rather is – the table pointer and the required value is retrieved off the sine table. This 16-bit value is then split into two 8-bit values to be assigned to OCR1AH and OCR1AL, thus setting the appropriate duty cycle.
Now let’s see why TBL_POINTER_SHIFT is needed to be incremented every 5 interrupts and how we’ve done that.
Our frequency is 50Hz – time period is 20ms. A half cycle takes 10ms. Recall that the sine table used is only for half a cycle. So, the 32 values must be called such that they make up the half cycle. The interrupt service routine is executed each 62.5us and so, retrieving all the values from the sine table and using them to update the duty cycle takes a total time of 62.5us * 32 = 2000us (assuming each value is retrieved/called once). That’s 2ms. But our half cycle is 10ms – 5 times larger than what we have now. So, we increase the time five folds. How? By calling each value from the table 5 times instead of only once. So, the time involved is now 32 * 62.5us * 5 = 10000us = 10ms.
This calculation we’ve just done is related to the frequency – 50Hz desired frequency and thus 10ms half cycle. I’ve shown this “backward” to explain why this has been chosen but remember that the microcontroller doesn’t know you want 50Hz frequency. The microcontroller doesn’t know that the desired time is 10ms.
So, now you know the answer to why I’ve called each sine table value 5 times: to ensure that the sine table that has 32 values occupies the entire 10ms. Now, how did I make it repeat 5 times? By setting SET_FREQ to 410. You might be wondering how this works. Well, it works this way.
SET_FREQ = 410. Each interrupt,
TBL_POINTER_NEW is increased by 410. Every 5 interrupts, TBL_POINTER_NEW is increased by 2050 (compared to the initial value). 2 11 = 2048. Since TBL_POINTER_SHIFT divides
TBL_POINTER_NEW by 2048, when
TBL_POINTER_NEW increases 5*410 times,
TBL_POINTER_SHIFT increases once. So, the number of repeats (5 in this case) is equal to the number of interrupts it takes for
TBL_POINTER_SHIFT to increase by one, which is equal to the number of times it takes for
SET_FREQ to equal or cross 2 11 (=2048). Since
SET_FREQ = 410, the number of times to cross 2048 is 5 and that is the number of times each table value is called. So, the table pointer is incremented every 5 interrupts. Thus SET_FREQ determines the frequency. If we had set
SET_FREQ to 200, the number of times to cross 2048 would be 11, as 200*10 = 2000 (less than 2048) but 200*11 = 2200 (more than 2048). Thus each sine table value would be called 11 times – the table pointer would be incremented every 11 interrupts. The output time period of the sine wave would then be 2 * 32 * 62.5us * 11 = 44000us = 44ms. The output frequency would thus be 22.7 Hz instead of the 50Hz we have now.
SET_FREQ can be calculated as {65536/ (32 * 5)} = 409.6 = 410 rounded off to the nearest integer. That’s SET_FREQ = [2 16 /{(Number of sine table values) * (Number of times each value is to be called)}].
I’ve talked about SET_FREQ , TBL_POINTER_NEW ,
TBL_POINTER_SHIFT and right shifting eleven times. Now you may ask why eleven times. Why not 5 or 10 or 12 or any other value? The reason is that we have a sine table with 32 values. 32 = 2 5 . Shifting a 16-bit variable eleven times to the right leaves us with a 5-bit value – one between 0 and 31. These 5 bits are the upper most (most significant) 5 bits. This 5-bit value is the sine table pointer. This works in conjunction with the number of sine table values and the value of
SET_FREQ to set or determine the output sine wave frequency. If we had 64 sine table values, we would right-shift TBL_POINTER_NEW 10 times instead of 11 so that the shifting operation results in a 6-bit value. 2 6 = 64 and that is the number of sine table values we have – the table pointer would have a value between 0 and 63.
In the interrupt, after the duty cycle is set,
TBL_POINTER_OLD is assigned the value of
TBL_POINTER_NEW . When TBL_POINTER_NEW is first assigned 410, TBL_POINTER_OLD holds 0. The 11-bit shifting is done. The duty cycle is set and then TBL_POINTER_OLD is set. So, the
TBL_POINTER_OLD update trails
TBL_POINTER_NEW update. So, every interrupt until TBL_POINTER_NEW overflows,
TBL_POINTER_NEW is greater than
TBL_POINTER_OLD .
When TBL_POINTER_NEW = 64370 and the ISR is to be executed, TBL_POINTER_OLD also holds 64370. TBL_POINTER_NEW is increased to 64780 and then the sine table value is called and
TBL_POINTER_OLD is then updated to 64780. The next interrupt, TBL_POINTER_NEW is increased to 65190 and the “if condition” is again false since at that stage TBL_POINTER_OLD holds 64780 – TBL_POINTER_NEW >
TBL_POINTER_OLD . Then at the end of the ISR,
TBL_POINTER_OLD is assigned 65190. And now comes the interesting part. TBL_POINTER_NEW now holds 65190 and TBL_POINTER_OLD holds 65190. 410 is to added to TBL_POINTER_OLD and TBL_POINTER_OLD overflows to hold 64. Now, TBL_POINTER_NEW (which holds 64) is less than TBL_POINTER_OLD (which holds 65190) and the if condition is true. So, the direction of MOSFET drive is reversed. If MOSFETs A and D were driven previously, MOSFETs B and C will now be driven and vice versa. Remember that by sending a logic high to PORTD1 or PORTD3, due to the AND gate, we’re just diverting the OC1 PWM to the required low side MOSFET. Thus 2 MOSFETs are driven with the same signals but in alternate half cycles. By inverting the direction of the full-bridge drive, we are carrying out the next half cycle with the same duty cycle values and sequence, but in the opposite direction – as is necessary (think AC waveform and opposite half cycle). This happens every (32*5 = 160) interrupts – when all the values of the table have each been called 5 times. Since TBL_POINTER_OLD then has a small value again, since it overflowed,
TBL_POINTER_SHIFT will then be equal to 0, meaning that the table pointer has restarted from zero and the SPWM starts over again. So,
TBL_POINTER_SHIFT , on subsequent interrupts has the values: 0,0,0,0,1,1,1,1,1,2,2,2,2,2,3,3,3,3,3,………..30,30,30,30,30,31,31,31,31,31,0,0,0,0,0,1,1,1,1,1,……. And so on.
That's about it regarding the code.
Re: Sine Wave Inverter Using Arduino by pakingzzzzz(m): 12:39am On Nov 29, 2017
Still on Spwm
Re: Sine Wave Inverter Using Arduino by pakingzzzzz(m): 7:44pm On Dec 13, 2017
The sun shines on those who stand before it, than those who kneel before it!!
Call us now...
Re: Sine Wave Inverter Using Arduino by pakingzzzzz(m): 12:57am On Dec 16, 2017
Make hay while the sun shines!!
Re: Sine Wave Inverter Using Arduino by pakingzzzzz(m): 2:11pm On Dec 18, 2017
Learn to build a sine wave inverter using Arduino.
Re: Sine Wave Inverter Using Arduino by pakingzzzzz(m): 10:47pm On Dec 23, 2017
Call
Re: Sine Wave Inverter Using Arduino by pakingzzzzz(m): 10:55pm On Dec 23, 2017
Here we are
Re: Sine Wave Inverter Using Arduino by pakingzzzz: 9:55am On Jan 13, 2018
Get a special skill today.
Re: Sine Wave Inverter Using Arduino by pakingzzzzz(m): 3:11pm On Jan 27, 2018
Avail
Re: Sine Wave Inverter Using Arduino by pakingzzzzz(m): 2:49pm On Feb 03, 2018
How goes your project? In what way do you want it? We can get the job done.
Re: Sine Wave Inverter Using Arduino by pakingzzzzz(m): 8:39pm On Feb 06, 2018
Still in the house...
Re: Sine Wave Inverter Using Arduino by pakingzzzz: 5:44pm On Sep 27, 2018
Nice
Re: Sine Wave Inverter Using Arduino by majasaint: 7:51am On Sep 28, 2018
Hi pakingzzzzz,

You are doing a good job in Nigeria.
Meanwhile, I saw your code and want to call your attention to the method you used.

There is no need writing so long lines. Your code can be minimised to less than 10 lines of code.
Use a "for" loop and call each delay and variables from an array.

Thanks

Let me know if you need more info.
Re: Sine Wave Inverter Using Arduino by pakingzzzz: 9:21am On Sep 28, 2018
majasaint:
Hi pakingzzzzz,

You are doing a good job in Nigeria.
Meanwhile, I saw your code and want to call your attention to the method you used.

There is no need writing so long lines. Your code can be minimised to less than 10 lines of code.
Use a "for" loop and call each delay and variables from an array.

Thanks

Thanks

Let me know if you need more info.
Re: Sine Wave Inverter Using Arduino by majasaint: 9:27am On Sep 28, 2018
well-done Pakingzzz.

Contact me on majasaint@ yahoodotcodotuk.. let us do some intereseting work.

(1) (Reply)

Advice On Software Testing / Please Don't Learn To Code / Programming Challenge

(Go Up)

Sections: politics (1) business autos (1) jobs (1) career education (1) romance computers phones travel sports fashion health
religion celebs tv-movies music-radio literature webmasters programming techmarket

Links: (1) (2) (3) (4) (5) (6) (7) (8) (9) (10)

Nairaland - Copyright © 2005 - 2024 Oluwaseun Osewa. All rights reserved. See How To Advertise. 65
Disclaimer: Every Nairaland member is solely responsible for anything that he/she posts or uploads on Nairaland.