AD9833 Programmable Waveform Generator with Arduino UNO

การทดลองใช้งานงานโมดูล GY-9833 กับการสร้างสัญญาณในรูปแบบต่างๆ หรือเรียก ฟังก์ชั่นเจนเนอร์เรเตอร์ (Programmable Waveform Generator) ซึ่งภายในโมดูลจะใช้ไอซีเบอร์ AD9833 ในการประมวลผลที่สามารถโปรแกรมการทำงานได้ โดยในการทดลองจะเชื่อมต่อกับบอร์ดควบคุม Arduino UNO ซึ่งตัวโมดูลตัวนี้จะมีขนาดที่ค่อนข้างเล็ก ควบคุมการทำงานได้ง่ายด้วยการสื่อสารแบบ SPI Protocol ที่ความละเอียดขนาด 28 บิต สามารถสร้างสัญญาณต่างๆ ได้ในช่วง 0Hz-12.5MHz ในรูปแบบสัญญาณโซน์เวฟ (Sinusoidal wave) สัญญาณสามเหลี่ยม (Triangular wave) และสัญญาณพัลซ์สี่เหลี่ยม (Square wave)


รูปที่ 1 และรูปที่ 2 แสดงลักษณะของโมดูล GY-9833 ที่นำมาทดลองโครงงานซึ่งมีขนาดเล็กสามารถเชื่อมต่อกับบอร์ดควบคุมไมโครคอนโทรลเลอร์ต่างๆ ได้ทันที โดยในรูปที่ 2 จะเป็นการเตรียมบอร์ดควบคุม Arduino UNO ที่สามารถหาซื้อได้ง่ายและราคาไม่แพง

รูปที่ 3 เป็นการต่ออุปกรณ์ร่วมกันระหว่างบอร์ดควบคุม Arduino UNO และโมดูล GY-9833 ในการทดลอง โดยที่ขาเอาต์พุตของโมดูลจะใช้สายโพรบของออสซิลโลสโคปวัดสัญญาณได้โดยตรง ซึ่งในการทดลองจะใช้ไฟเลี้ยงจากพอร์ต USB (+5V) ก็สามารถทำงานได้เป็นปกติ
/* AD9837 Pro Generator sample code This was written in Arduino 1.0.1, for an Arduino Pro Mini, 5V, 16MHz Pete Dokter, 9/2/12 With this code running, open up a teminal window at 9600 baud, enter your desired frequency followed by <enter>. The code translates the ascii characters and sets the frequency on the AD9837. The connections to the AD9837 board are: FSYNC -> 2 SCLK -> 13 (SCK) SDATA -> 11 (MOSI) +Vin = VCC on Pro Micro GND -> GND This code bears the license of the beer. If you make money off of this, you gotta beer me. */ #define FSYNC 2 #define SDATA 11 #define SCLK 13 long freq; void AD9837Write(char cmd, char dat); void set_freq(long frequency); unsigned char flag_type = 0; void setup() { pinMode(FSYNC, OUTPUT); pinMode(SDATA, OUTPUT); pinMode(SCLK, OUTPUT); Serial.begin(9600); digitalWrite(FSYNC, HIGH); digitalWrite(SDATA, HIGH); digitalWrite(SCLK, HIGH); String help = "<----Command---->\r\n"; help += "Set sine wave -- sine freq\r\n"; help += "Ex. set sine wave @1Mhz--> sin 1000000\r\n"; help += "Set set triangular wave -- tri freq\r\n"; help += "Ex. set triangular wave @100Khz--> tri 100000\r\n"; help += "Set set square -- sqr freq\r\n"; help += "Ex. set square wave @2Khz--> sqr 2000\r\n"; Serial.println(help); set_freq(100); } void loop() { if(Serial.available()) { String req = Serial.readStringUntil('\n'); if(req.indexOf(F("sin")) != -1) { flag_type=0; set_freq(freq_str_to_long(req)); } if(req.indexOf(F("sqr")) != -1) { flag_type=1; set_freq(freq_str_to_long(req)*2); } if(req.indexOf(F("tri")) != -1) { flag_type=2; set_freq(freq_str_to_long(req)); } } } long freq_str_to_long(String dat) { char index1 = dat.indexOf(F(" ")); return(dat.substring(index1+1).toInt()); } void set_freq(long frequency) { // int MSB; int LSB; int phase = 0; //We can't just send the actual frequency, we have to calculate the "frequency word". //This amounts to ((desired frequency)/(reference frequency)) x 0x10000000. //calculated_freq_word will hold the calculated result. long calculated_freq_word; float AD9837Val = 0.00000000; AD9837Val = (((float)(frequency))/25000000); calculated_freq_word = AD9837Val*0x10000000; /* Serial.println(""); Serial.print("Frequency word is "); Serial.print(calculated_freq_word); Serial.println(""); */ //Once we've got that, we split it up into separate bytes. MSB = (int)((calculated_freq_word & 0xFFFC000)>>14); //14 bits LSB = (int)(calculated_freq_word & 0x3FFF); //Set control bits DB15 ande DB14 to 0 and one, respectively, for frequency register 0 LSB |= 0x4000; MSB |= 0x4000; //set for 5KHz //LSB = 0x47AE; //MSB = 0x4005; //set for 10KHz //LSB = 0x4F5C; //MSB = 0x400A; //set for ? // LSB = 0x6F5C; //MSB = 0x40F5; phase &= 0xC000; AD9837Write(0x2100); delay(100); //Set the frequency========================== AD9837Write(LSB); //lower 14 bits AD9837Write(MSB); //upper 14 bits AD9837Write(phase); //mid-low delay(10); switch(flag_type) { case 0: AD9837Write(0x2000); // sin Serial.print("Sine "); break; case 1: AD9837Write(0x2020); // square Serial.print("Square "); frequency = (frequency/2); break; case 2: AD9837Write(0x2002); // triangle Serial.print("Triangle "); break; } Serial.print(frequency); Serial.println(" Hz"); } //This is the guy that does the actual talking to the AD9837 //via bit-bang SPI... void AD9837Write(int dat) { int x; digitalWrite(FSYNC, LOW); //Set FSYNC low for (x = 0; x < 16; x++) { if (dat & 0x8000) { digitalWrite(SDATA, HIGH); //Set SDATA according to MSB in cmd } else { digitalWrite(SDATA, LOW); } digitalWrite(SCLK, LOW); //CLK transistion to latch the bit into the AD9835 digitalWrite(SCLK, HIGH); dat <<= 1; //Shift to next bit in cmd } digitalWrite(FSYNC, HIGH); //Set FSYNC high }
สำหรับโปรแกรมที่แสดงข้างบนนี้ (Code Program Arduino) เป็นโปรแกรมที่สามารถโปรแกรมให้กับบอร์ด Arduino UNO ได้ทันทีโดยไม่ใช้ไลบราลีเพิ่มเติม (Arduino Library) ซึ่งผู้พัฒนาโปรแกรมนี้คือ Pete Dokter และผู้อ่านสามารถปรับแต่งโปรแกรมให้สามารถนำไปใช้งานในด้านต่างๆ ตามที่ต้องการ

ในรูปที่ 4 แสดงตัวอย่างการป้อนค่าให้กับบอร์ดควบคุม Arduino UNO สำหรับเป็นคำสั่งในการสร้างสัญญาณต่างๆ โดยในรูปจะเห็นตัวอย่างในกรอบสี่เหลี่ยมสีส้ม เช่น ต้องการสร้างสัญญาณพัลซ์สี่เหลี่ยมที่ความถี่ 1000kHz จะใช้คำสั่ง sqr 1000 โดยให้เราป้อนที่ช่อง SEND (ข้างบน) และตามด้วยกด Enter ซึ่งหลังจากที่เราป้อนแล้วโปรแกรมจะมีข้อความตอบกลับให้ทราบ


รูปที่ 5 และรูปที่ 6 เป็นการทดลองให้โมดูล GY-9833 สร้างสัญญาณไซน์เวฟที่ความถี่ 100Hz (ความถี่ต่ำ) และสังเกตสัญญาณที่เกิดขึ้น


ในรูปที่ 7 และรูปที่ 8 เป็นการทดลองให้โมดูล GY-9833 สร้างสัญญาณไซน์เวฟที่ความถี่ 100kHz (ความถี่สูง) จากนั้นสังเกตลักษณะของสัญญาณที่เกิดขึ้นอีกครั้ง


ต่อมาในรูปที่ 9 และรูปที่ 10 เป็นการทดลองให้โมดูลสร้างสัญญาณสามเหลี่ยมที่ความถี่ 200Hz (ความถี่ต่ำ) และสังเกตสัญญาณที่เกิดขึ้น


ในรูปที่ 11 และรูปที่ 12 เป็นการทดลองให้โมดูล GY-9833 สร้างสัญญาณสามเหลี่ยมที่ความถี่ 200kHz (ความถี่สูง) อีกครั้ง จากนั้นสังเกตลักษณะของสัญญาณที่เกิดขึ้น


สำหรับรูปที่ 13 และรูปที่ 14 เป็นการทดลองให้โมดูลสร้างสัญญาณสี่เหลี่ยมความถี่ 300Hz (ความถี่ต่ำ) และสังเกตสัญญาณที่เกิดขึ้น


ในรูปที่ 15 และรูปที่ 16 เป็นการทดลองให้โมดูล GY-9833 สร้างสัญญาณสามเหลี่ยมที่ความถี่ 300kHz (ความถี่สูง) และสังเกตลักษณะของสัญญาณที่เกิดขึ้น การทดลองวัดสัญญาณทั้ง 3 แบบนั้นจะเห็นว่าแอมปริจูดของสัญญาณจะไท่เท่ากัน ดังนั้นแนะนำให้ออกแบบวงจรขยายสัญญาณเพิ่มเติมด้วยออปแอมป์ให้ได้ขนาดตามที่ต้องการนำไปใช้งานอีกครั้ง


กับโครงงานการสร้างสัญญาณฟังก์ชั่นเจนเนอร์เรเตอร์ด้วยโมดูล GY-9833 เป็นโครงงานเล็กๆ ซึ่งในบางครั้งเราอาจจะต้องใช้งานบ้าง เพื่อทำการทดลองแหล่งจ่ายไฟเลี้ยงแบบสวิตชิ่ง เพาเวอร์ซัพพลาย (Switching power supply) หรือวงจรดีซี ทู ดีซี คอนเวอร์เตอร์ (DC-to-DC converter) เป็นต้น ทั้งนี้จะช่วยให้เราสามารถทดลองวงจรด้วยการปรับความถี่สวิตชิ่งที่ความถี่ต่างๆ ได้ง่ายและปรับเลือกรูปแบบสัญญาณต่างๆ ในการทดลองได้ 3 รูปแบบ นอกจากนี้ยังเป็นวงจรที่สร้างได้ง่ายและราคาไม่แพงมากนักครับ.
Reference
- https://www.analog.com/media/en/technical-documentation/data-sheets/ad9833.pdf
- https://github.com/BasicCode/AD9833-arduino
- https://github.com/annem/AD9837/blob/master/PetesProGenExample/PetesProGenExample.ino
- https://github.com/y-x-c/wearable-microphone-jamming/issues/6
- https://github.com/Billwilliams1952/AD9833-Library-Arduino/blob/master/examples/AD9833_test_suite/AD9833_test_suite.ino
- https://www.electroniclinic.com/ad9833-programmable-waveform-generator-using-arduino/
- https://www.teachmemicro.com/arduino-ad9833-signal-generator/
- https://www.instructables.com/Portable-Function-Generator-on-Arduino/
- https://electronics.stackexchange.com/questions/226695/ad9833-problems-with-arduino-and-spi-cant-think-of-a-good-title
- https://leap.tardate.com/playground/ad9833/basicdemocycle/
- https://www.instructables.com/Signal-Generator-AD9833/