Arduino Control Pure sine wave inverter [EP1]
สำหรับโครงงานนี้เป็นตอนที่ 1 โดยใช้บอร์ด Arduino UNO ในการควบคุมอินเวอร์เตอร์ นี่เป็นการทดลองเบื้องต้นเพื่อสร้างสัญญาณ Sinusoidal Pulse Width Modulation : SPWM ที่ปรับความถี่ได้และเริ่มการสตาร์ทแบบนุ่มนวล โดยสัญญาณ SPWM ที่ได้ จะเป็นสัญญาณสำหรับขับกำลังของ H-Bridge และจ่ายกระแสไฟฟ้าให้กับโหลดและการทดลองใน EP1 แบ่งออกเป็น 4 ส่วน
- การวัดสัญญาณ SPWM สำหรับสร้างคลื่นไซน์
- การวัดสัญญาณคลื่นไซน์โดยใช้ตัวกรองแบบ RC (R =2K, C = 0.1uF/63V)
- การปรับความถี่เอาท์พุทของสัญญาณคลื่นไซน์
- การเริ่มต้นอย่างนุ่มนวลของสัญญาณคลื่นไซน์ที่เอาต์พุต
รูปที่ 1 เป็นการทดลองเบื้องต้นของการใช้โปรแกรมเพื่อสร้างสัญญาณไซน์เวฟ โดยตัวโปรแกรมต้นฉบับจะเป็นโปรแกรมอ้างอิงที่ 1 (https://github.com/cmasenas/3-Phase-Sine-Arduino/blob/Release/DDS_Generator.ino) จากนั้นนำมาพัฒนาบางส่วนเพื่อใช้เป็นวงจรอินเวอร์เตอร์แบบ 1 เฟสแแบบไซน์เวฟ ซึ่งเดิมโปรแกรมจะเป็นการสร้างสัญญาณไซน์เวฟ 3 เฟส
รูปที่ 2 เป็นการวัดสัญญาณที่ช่วงเวลาต่างๆ เพื่อตรวจสอบความถูกต้องในลักษณะของสัญญาณพัลซ์วิดมอดูเลตชั่น เช่น การหน่วงเวลาในช่วงเดตไทม์ การเลื่อนเฟสของสัญญาณทั้ง 2 ส่วนอยู่ในช่วงเวลาที่เหมาะสมเป็นต้น
รูปที่ 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 }
รูปที่ 4 เป็นการวัดสัญญาณพัลซ์วิดมอดูเลตชั่นทั้ง 2 ช่องในช่วงเวลาการทำงานต่างๆ โดยสัญญาณที่เกิดขึ้นจะสามารถปรับสัดส่วนของการเปลี่ยนความถี่ไปที่ค่าต่างๆ ได้อย่างถูกต้อง
รูปที่ 5 เป็นการวัดสัญญาณที่เกิดขึ้นแบบไซน์เวฟ โดยจะพิจารณารูปสัญญาณจะต้องไม่ผิดเพี้ยนตลอดช่วงความถี่ที่เรากำหนด ทั้งนี้เพื่อไม่ให้เกิดความเสียหายกับส่วนของวงจรขับกำลัง และเป็นการประเมินความถูกต้องของการทำงานในส่วนของโปรแกรมในอีกด้านหนึ่ง
รูปที่ 6 เป็นการวัดสัญญาณที่เกิดขึ้นและพิจารณาในส่วนของเฟสของสัญญาณทั้งสอง จะต้องต่างกัน 180 องศา ทั้งนี้ทำให้เกิดการสร้างสัญญาณที่เกิดขึ้นจากทั้ง 2 ส่วนได้อย่างต่อเนื่องและไม่เกิดพลังงานสูญเสียขึ้น
สำหรับการทดลองโครงงานนี้ยังคงเป็นตอนที่ 1 ซึ่งจะเป็นการทดลองสร้างสัญญาณ (SPWM) และเป็นการเริ่มต้นเพื่อที่จะนำไปใช้ในการทดลองในส่วนต่อไป โดยในแนวความคิดถัดไปจะนำสัญญาณที่ได้นี้ไปต่อเข้ากับส่วนของวงจรขับกำลังแบบบริดจ์ (H-Bridge) เพื่อให้สามารถสร้างสัญญาณไฟฟ้ากระแสสลับได้ในเบื้องต้นครับ.
Reference
- https://github.com/cmasenas/3-Phase-Sine-Arduino/blob/Release/DDS_Generator.ino
- 3-Phase-Sine-Arduino/DDS_Generator.ino at Release · cmasenas/3-Phase-Sine-Arduino · GitHub
- http://www.eprojectszone.com/how-to-generate-a-sine-wave-from-arduino-or-atmega-328/
- https://www.youtube.com/watch?v=mmwsh00No2c
- https://drive.google.com/file/d/1C91GSlEiPzmXDcwhuriaN-Rf8SkgqWoG/view?usp=sharing
- https://theorycircuit.com/arduino-inverter-circuit/
- https://www.electroschematics.com/sine-wave-generator-circuit/