Arduino Control Pure sine wave inverter [EP1]

สำหรับโครงงานนี้เป็นตอนที่ 1 โดยใช้บอร์ด Arduino UNO ในการควบคุมอินเวอร์เตอร์ นี่เป็นการทดลองเบื้องต้นเพื่อสร้างสัญญาณ Sinusoidal Pulse Width Modulation : SPWM ที่ปรับความถี่ได้และเริ่มการสตาร์ทแบบนุ่มนวล โดยสัญญาณ SPWM ที่ได้ จะเป็นสัญญาณสำหรับขับกำลังของ H-Bridge และจ่ายกระแสไฟฟ้าให้กับโหลดและการทดลองใน EP1 แบ่งออกเป็น 4 ส่วน

  1. การวัดสัญญาณ SPWM สำหรับสร้างคลื่นไซน์
  2. การวัดสัญญาณคลื่นไซน์โดยใช้ตัวกรองแบบ RC (R =2K, C = 0.1uF/63V)
  3. การปรับความถี่เอาท์พุทของสัญญาณคลื่นไซน์
  4. การเริ่มต้นอย่างนุ่มนวลของสัญญาณคลื่นไซน์ที่เอาต์พุต
Arduino Control Pure sine wave inverter
รูปที่ 1 เตรียมอบอร์ด Arduino UNO สำหรับทดลองโปรแกรม

รูปที่ 1 เป็นการทดลองเบื้องต้นของการใช้โปรแกรมเพื่อสร้างสัญญาณไซน์เวฟ โดยตัวโปรแกรมต้นฉบับจะเป็นโปรแกรมอ้างอิงที่ 1 (https://github.com/cmasenas/3-Phase-Sine-Arduino/blob/Release/DDS_Generator.ino) จากนั้นนำมาพัฒนาบางส่วนเพื่อใช้เป็นวงจรอินเวอร์เตอร์แบบ 1 เฟสแแบบไซน์เวฟ ซึ่งเดิมโปรแกรมจะเป็นการสร้างสัญญาณไซน์เวฟ 3 เฟส

Arduino Control Pure sine wave inverter
รูปที่ 2 ทดลองวัดสัญญาณเบื้องต้น

รูปที่ 2 เป็นการวัดสัญญาณที่ช่วงเวลาต่างๆ เพื่อตรวจสอบความถูกต้องในลักษณะของสัญญาณพัลซ์วิดมอดูเลตชั่น เช่น การหน่วงเวลาในช่วงเดตไทม์ การเลื่อนเฟสของสัญญาณทั้ง 2 ส่วนอยู่ในช่วงเวลาที่เหมาะสมเป็นต้น

Arduino Control Pure sine wave inverter
รูปที่ 3 การวัดสัญญาณลักษณะไซน์เวฟที่เกิดขึ้น

รูปที่ 3 เป็นการวัดสัญญาณที่เกิดขึ้นจากขาของบอร์ด Arduino UNO ที่ส่งสัญญาณไซน์ (Sinusoinal Pulse Width Modulation : SPWM) โดยในตอนนี้ จะใช้ตัวต้านทานและตัวเก็บประจุมาต่อแบบวงจรกรองความถี่ต่ำผ่าน (Low pass filter) ทั้งนี้เพื่อให้เห็นลักษณะของสัญญาณที่เกิดขึ้นว่าถูกต้องและไม่เกิดความผิดเพี้ยนใดๆ ซึ่งจะนำไปใช้ในส่วนของการขับกำลังอีกที

*** CodeProgram Arduino UNO [*Reference [1]]

 // 3 phase PWM sine INVERTER
 // (c) 2016 C. Masenas
 // Modified from original DDS from: 
 // KHM 2009 /  Martin Nawrath
 // https://3phaseinverter.blogspot.com/
 // https://github.com/cmasenas/3-Phase-Sine-Arduino/blob/Release/DDS_Generator.ino
 // table of 256 sine values / one sine period / stored in flash memory

 PROGMEM const unsigned char sine256[]  = {
   127,130,133,136,139,143,146,149,152,155,158,161,164,167,170,173,176,178,181,184,187,190,192,195,198,200,
 203,205,208,210,212,215,217,219,221,223,225,227,229,231,233,234,236,236,
   236,238,238,238,239,239,240,241,242,243,245,247,247,248,249,249,250,
 251,251,252,252,252,252,252,
 250,250,249,249,248,248,247,247,246,246,245,245,243,240,240,238,238,
   236,236,234,233,231,229,227,225,223,221,219,217,215,212,210,208,205,203,
 200,198,195,192,190,187,184,181,178,176,173,170,167,164,161,158,155,152,149,146,143,139,136,133,130,127,124,121,118,115,111,108,105,102,99,96,93,90,87,84,81,78,
   76,73,70,67,64,62,59,56,54,51,49,46,44,42,39,37,35,33,31,29,27,25,23,21,20,18,16,15,14,12,11,10,9,7,6,5,5,4,3,2,2,1,1,1,0,0,0,0,0,0,0,1,1,1,2,2,3,4,5,5,6,7,9,10,11,12,14,15,16,18,20,21,23,25,27,29,31,
   33,35,37,39,42,44,46,49,51,54,56,59,62,64,67,70,73,76,78,81,84,87,90,93,96,99,102,105,108,111,115,118,121,124
 };

 define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
 define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
 int testPin = 7;
 int enablePin = 8 ;
 int sensorPin = A0; 
 int sensorValue = 0;
 float k = 0;
 int Adj_Frq=25; 
 volatile  float freq=1;
 const float refclk=122.549  ;   // 16 MHz/510/256
 // variables used inside interrupt service declared as voilatile
 volatile unsigned long sigma;   // phase accumulator
 volatile unsigned long delta;   // phase increment
 byte phase0, phase1, phase2 ;

 void setup()
 {
 Serial.begin(9600);        // Connect to the serial port
 Serial.println("DDS Test"); 
 pinMode(enablePin,OUTPUT);    // sets the digital pin as output
 pinMode(testPin,OUTPUT);      // sets the digital pin as output
 pinMode(5,OUTPUT);
 pinMode(6,OUTPUT); 
 pinMode(9,OUTPUT);
 pinMode(10,OUTPUT);
 pinMode(11,OUTPUT);
 pinMode(3,OUTPUT); 
 Setup_timer2();
 Setup_timer1();
 Setup_timer0(); 
 digitalWrite(enablePin, HIGH);

 // the waveform index is the highest 8 bits of sigma
 // choose refclk as freq to increment the lsb of the 8 highest bits
 // for every call to the ISR of timer2 overflow
 // the lsb of the 8 highest bits is 1<<24 (1LL<<24 for long integer literal)
   delta = (1LL<<24)*freq/refclk ;  
 }

 void loop(){ 
  if(k<0.99) {k+=0.01;}  // Soft start  sensorValue = analogRead(sensorPin);    Adj_Frq = (sensorValue/9); 
 if (Adj_Frq <25) {
        Adj_Frq = 25;
      }  
  changeFreq(Adj_Frq);
 }
 void changeFreq(float _freq){
   cbi (TIMSK2,TOIE2);              // disable timer2 overflow detect  
   freq = _freq;
   delta=(1LL<<24)*freq/refclk;     // update phase increment    
   sbi (TIMSK2,TOIE2);              // enable timer2 overflow detect
 } 
 //**
 // timer2 setup
 // set prscaler to 1, fast PWM
 void Setup_timer2() {
 // Timer2 Clock Prescaler to : 1
   sbi (TCCR2B, CS20);  // set
   cbi (TCCR2B, CS21);  // clear
   cbi (TCCR2B, CS22);
 // Timer2 PWM Mode 
   cbi (TCCR2A, COM2A0);  // clear OC2A on Compare Match, PWM pin 11
   sbi (TCCR2A, COM2A1);
   sbi (TCCR2A, COM2B0);  // clear OC2A on Compare Match, PWM pin 3
   sbi (TCCR2A, COM2B1);
 // set to fast PWM
   sbi (TCCR2A, WGM20);  // Mode 1, phase correct PWM
   cbi (TCCR2A, WGM21);
   cbi (TCCR2B, WGM22);
   sbi (TIMSK2,TOIE2);              // enable overflow detect
 }
 // timer1 setup  (sets pins 9 and 10)
 // set prscaler to 1, PWM mode to phase correct PWM, 16000000/510 = 31372.55 Hz clock
 void Setup_timer1() {
 // Timer1 Clock Prescaler to : 1
 sbi (TCCR1B, CS10);
 cbi (TCCR1B, CS11);
 cbi (TCCR1B, CS12);
 // Timer1 PWM Mode set to Phase Correct PWM
 cbi (TCCR1A, COM1A0);  // clear OC1A on Compare Match, PWM pin 9
 sbi (TCCR1A, COM1A1);  
 sbi (TCCR1A, COM1B0);  // clear OC1B on Compare Match, PWM pin 10
 sbi (TCCR1A, COM1B1);
 sbi (TCCR1A, WGM10);   // Mode 1  / phase correct PWM
 cbi (TCCR1A, WGM11);
 cbi (TCCR1B, WGM12);
 cbi (TCCR1B, WGM13);
 }
 void Setup_timer0() {    
 sbi (TCCR0B, CS00);
 cbi (TCCR0B, CS01);
 cbi (TCCR0B, CS02);  
 // Timer0 PWM Mode set to Phase Correct PWM
 cbi (TCCR0A, COM0A0);  // clear OC0A on Compare Match, PWM pin 
 sbi (TCCR0A, COM0A1);     
 sbi (TCCR0A, COM0B0);  // clear OC0B on Compare Match, PWM pin 
 sbi (TCCR0A, COM0B1);
 sbi (TCCR0A, WGM00);   // Mode 1  / phase correct PWM
 cbi (TCCR0A, WGM01);
 cbi (TCCR0B, WGM02);  
 }
 //**
 // Timer2 Interrupt Service at 31372,550 KHz = 32uSec
 // this is the timebase REFCLOCK for the DDS generator
 // runtime : 8 microseconds ( inclusive push and pop)
 // OC2A - pin 11
 // OC1B - pin 10
 // OC1A - pin 9
 // https://www.arduino.cc/en/Tutorial/SecretsOfArduinoPWM

ISR(TIMER2_OVF_vect) {    
sigma=sigma+delta;      // soft DDS, phase accu with 32 bits
phase0=sigma >> 24;     // use upper 8 bits for phase accu as frequency information
                           // read value fron ROM sine table and send to PWM DAC
phase1 = phase0 +55 ;   // 65
phase2 = phase0 +180 ;  // 200   

OCR1A = pgm_read_byte_near(sine256 + phase1)*k;  // pwm pin 9 (+B)
OCR1B = OCR1A+3; // pwm pin 10   
OCR0A = pgm_read_byte_near(sine256 + phase2)*k;  // pwm pin 6 (+B)
OCR0B = OCR0A+3; // pwm pin 5             
 }
Arduino Control Pure sine wave inverter
รูปที่ 4 วัดสัญญาณพัลซ์วิดเมื่อปรับความถี่ค่าใดๆ

รูปที่ 4 เป็นการวัดสัญญาณพัลซ์วิดมอดูเลตชั่นทั้ง 2 ช่องในช่วงเวลาการทำงานต่างๆ โดยสัญญาณที่เกิดขึ้นจะสามารถปรับสัดส่วนของการเปลี่ยนความถี่ไปที่ค่าต่างๆ ได้อย่างถูกต้อง

Arduino Control Pure sine wave inverter
รูปที่ 5 วัดสัญญาณไซน์เวฟและปรับความถี่ไปที่ค่าต่างๆ

รูปที่ 5 เป็นการวัดสัญญาณที่เกิดขึ้นแบบไซน์เวฟ โดยจะพิจารณารูปสัญญาณจะต้องไม่ผิดเพี้ยนตลอดช่วงความถี่ที่เรากำหนด ทั้งนี้เพื่อไม่ให้เกิดความเสียหายกับส่วนของวงจรขับกำลัง และเป็นการประเมินความถูกต้องของการทำงานในส่วนของโปรแกรมในอีกด้านหนึ่ง

Arduino Control Pure sine wave inverter
รูปที่ 6 วัดสัญญาณไซน์เวฟและเฟสที่เกิดขึ้นที่ความถี่ต่างๆ

รูปที่ 6 เป็นการวัดสัญญาณที่เกิดขึ้นและพิจารณาในส่วนของเฟสของสัญญาณทั้งสอง จะต้องต่างกัน 180 องศา ทั้งนี้ทำให้เกิดการสร้างสัญญาณที่เกิดขึ้นจากทั้ง 2 ส่วนได้อย่างต่อเนื่องและไม่เกิดพลังงานสูญเสียขึ้น

สำหรับการทดลองโครงงานนี้ยังคงเป็นตอนที่ 1 ซึ่งจะเป็นการทดลองสร้างสัญญาณ (SPWM) และเป็นการเริ่มต้นเพื่อที่จะนำไปใช้ในการทดลองในส่วนต่อไป โดยในแนวความคิดถัดไปจะนำสัญญาณที่ได้นี้ไปต่อเข้ากับส่วนของวงจรขับกำลังแบบบริดจ์ (H-Bridge) เพื่อให้สามารถสร้างสัญญาณไฟฟ้ากระแสสลับได้ในเบื้องต้นครับ.

Reference

  1. https://github.com/cmasenas/3-Phase-Sine-Arduino/blob/Release/DDS_Generator.ino
  2. 3-Phase-Sine-Arduino/DDS_Generator.ino at Release · cmasenas/3-Phase-Sine-Arduino · GitHub
  3. http://www.eprojectszone.com/how-to-generate-a-sine-wave-from-arduino-or-atmega-328/
  4. https://www.youtube.com/watch?v=mmwsh00No2c
  5. https://drive.google.com/file/d/1C91GSlEiPzmXDcwhuriaN-Rf8SkgqWoG/view?usp=sharing
  6. https://theorycircuit.com/arduino-inverter-circuit/
  7. https://www.electroschematics.com/sine-wave-generator-circuit/