การใช้งานโมดูล MAX4466 Sound Sensor#
▷ MAX4466 Electret Microphone Amplifier#
ในบทความนี้กล่าวถึง การทดลองใช้งานโมดูล GY-MAX4466 ที่มีราคาไม่แพง และใช้ไอซี MAX4466 ของบริษัท Maxim Integrated / Analog Devices สำหรับการขยายสัญญาณแอนะล็อก จากไมโครโฟนเสียงประเภท ** Electret Condenser Microphone และสามารถปรับอัตราการขยายสัญญาณได้ (Adjustable Gain**)
รูป: ตัวอย่างวงจรสำหรับการใช้งานไอซี MAX4466 (ปรับค่า Gain ไม่ได้)
รูป: ผังวงจรของโมดูล MAX4466 Electret Microphone Amplifier ของบริษัท Adafruit (ปรับค่า Gain ได้)
คุณลักษณะของโมดูล GY-MAX4466
- โมดูลมีขาสำหรับการเชื่อมต่อ 3 ขา
- ขา VCC (Supply Voltage: 2.4V ~ 5V)
- ขา GND (Ground)
- ขา OUT (Analog Output)
- สัญญาณเอาต์พุตที่ขา OUT เป็นแบบ DC-biased และระดับแรงดันไฟฟ้าจะอยู่ที่ประมาณ VCC/2 (ถ้าไม่มีเสียง) และมีค่าแอมพลิจูดประมาณ 1Vpp (peak-to-peak)
- มีตัวต้านทานปรับค่าได้ (Trimpot / Potentiometer) ขนาด 100k เพื่อปรับเลือกค่าอัตราการขยายสัญญาณ (ปรับค่าได้ในช่วงประมาณ 25 ~ 125 เท่า)
รูป: ตัวอย่างโมดูล MAX4466 (มุมมองด้านหน้าและด้านหลัง)
อีกตัวอย่างหนึ่งสำหรับโมดูลไมโครโฟนเสียงในประเภทเดียวกันคือ MAX9814 Microphone Amplifier ซึ่งมีไอซีขยายสัญญาณที่ได้จากไมโครโฟนเสียงประเภท ** Electret Condenser Microphone และมีการปรับอัตราขยายแบบอัตโนมัติได้ในขณะทำงาน (Automatic Gain Control) และเลือกอัตราขยายสูงสุดได้ 3 ระดับ คือ 40dB / 50dB / 60dB ตอบสนองต่อความถี่เสียงได้ดีในย่าน 20Hz – 20 kHz สัญญาณเอาต์พุตเป็นแบบแอนะล็อก มีแอมพลิจูดไม่เกิน 2Vpp และมีค่ากลางอยู่ที่ 1.25V (DC bias) โดยประมาณ แรงดันไฟเลี้ยงใช้ได้อยู่ในช่วง 2.7V ~ 5.5V **
รูป: ตัวอย่างโมดูล MAX9814 (มุมมองด้านหน้าและด้านหลัง)
▷ การอ่านค่าสัญญาณจากโมดูล MAX4466 ด้วย Arduino-ESP32#
ถัดไปเป็นตัวอย่างโค้ดสำหรับ Arduino-ESP32 v3.0.0 เพื่ออ่านค่าสัญญาณแอนะล็อกจากโมดูล MAX4466 (ใช้แรงดันไฟเลี้ยง VCC=+3.3V) โดยใช้วงจร ADC ของไมโครคอนโทรลเลอร์ ESP32 และรับสัญญาณอินพุตเข้าที่ขา GPIO34
การอ่านค่าสัญญาณอินพุตจะเกิดขึ้นด้วยอัตราคงที่ โดยมีการเปิดใช้งานวงจรตัวนับ หรือ Hardware Timer ของ ESP32 ให้นับขึ้นด้วยความเร็ว 1MHz (หรือความละเอียดในการนับ 1usec) และเปิดใช้งานอินเทอร์รัพท์เมื่อนับตามช่วงเวลา (Time Interval) ที่ได้กำหนดไว้ ซึ่งเป็นตัวกำหนดความถี่ในการอ่านค่า (Sampling Rate) เช่น 10kHz
เมื่อมีการนับตามจังหวะได้หนึ่งรอบตามช่วงเวลาที่ได้กำหนดไว้ จะเกิดอินเทอร์รัพท์และมีการเริ่มต้นนับใหม่ที่ 0
และมีการเรียกฟังก์ชันที่ทำหน้าที่เป็น Callback Function หรือ ISR
(Interrupt Service Routine)
(ฟังก์ชันชื่อ timer_callback
ในโค้ดตัวอย่าง) ถ้าตัวแปรสำหรับเงื่อนไข sampling
มีค่าเป็น true
ก็จะมีการอ่านค่าสัญญาณแอนะล็อกและบันทึกค่าที่ได้ลงในอาร์เรย์ที่ได้เตรียมไว้ (samples[]
)
เมื่อฟังก์ชัน timer_callback()
ทำงานในแต่ละครั้ง ขา GPIO สำหรับ LED
จะมีลอจิกเป็น High และเมื่อจบการทำงานของฟังก์ชันจะมีลอจิกเป็น Low
ดังนั้นถ้าวัดสัญญาณเอาต์พุตนี้ด้วยออสซิลโลสโคป จะทำให้เห็นช่วงเวลาในการทำงานของฟังก์ชันนี้
ตัวแปร sampling
เริ่มต้นมีค่าเป็น false
ดังนั้นจึงจะไม่มีการอ่านค่าอินพุต
จนกว่าจะมีการส่งข้อความใด ๆ ก็ได้มาหนึ่งบรรทัด จึงจะเริ่มต้นการอ่านและบันทึกข้อมูล
การอ่านค่าสัญญาณแอนะล็อกด้วย ADC จะได้เป็นเลขจำนวนเต็ม (ขนาด 12 บิต) โดยใช้ฟังก์ชัน
analogReadMilliVolts(...)
ได้ค่าเป็นตัวเลขที่มีหน่วยเป็นมิลลิโวลต์
เมื่อเก็บค่าลงในอาร์เรย์จนครบตามจำนวน (ตั้งค่า N
ไว้เท่ากับ 1024)
ก็จะหยุดการอ่านสัญญาณอินพุตและบันทึกข้อมูลในอาร์เรย์ชั่วคราว
และถัดไปจะมีการส่งข้อมูลทั้งหมด แปลงให้เป็นข้อความ หนึ่งค่าตัวเลขต่อหนึ่งบรรทัด
ส่งออกไปตามลำดับทาง Serial Port โดยใช้ค่า Baudrate เท่ากับ 921600
เมื่อส่งข้อมูลได้ครบตามจำนวนที่ต้องการแล้ว จึงเริ่มการอ่านสัญญาณอินพุตและบันทึกค่าในรอบถัดไป
const int ADC_PIN = 34; // ADC1_CH6 / GPIO34 pin
const int LED_PIN = 22; // LED pin
uint32_t sample_index = 0;
bool sampling = false;
QueueHandle_t adc_queue;
const uint32_t Fs = 10000; // Sampling frequency (Hz)
const uint32_t N = 1024; // Number of samples
uint32_t sample_count = 0;
uint16_t samples[N];
//----------------------------------------------------------------
// Callback function of the hardware timer.
void IRAM_ATTR timer_callback() {
if (!sampling)
return;
digitalWrite( LED_PIN, HIGH );
uint16_t value = (uint16_t)analogReadMilliVolts( ADC_PIN );
samples[sample_count++] = value;
if ( sample_count == N ) {
sampling = false;
sample_count = 0;
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
xQueueSendFromISR(adc_queue, &sampling, &xHigherPriorityTaskWoken);
if (xHigherPriorityTaskWoken == pdTRUE) {
portYIELD_FROM_ISR();
}
}
digitalWrite( LED_PIN, LOW );
}
// Initialize the ADC input channel.
void initADC() {
// Set ADC resolution to 12 bits
analogSetWidth( 12 );
// Set attenuation level to 11 dB.
analogSetPinAttenuation( ADC_PIN, ADC_11db );
}
// Initialize the hardware timer.
void initTimer( uint32_t hw_timer_unit=0 ) {
static hw_timer_t *timer = NULL;
timer = timerBegin( 1000000UL ); // 1MHz (1us tick)
timerWrite(timer, 0);
// Attach the callback function (ISR) to the timer
timerAttachInterrupt( timer, &timer_callback );
timerAlarm(timer, 1000000UL/Fs /*interval*/,
true /*reload*/, 0 /*reload value*/);
timerRestart(timer);
}
void setup() {
Serial.begin(921600);
Serial.setTxBufferSize(1024);
Serial.flush();
pinMode( LED_PIN, OUTPUT );
digitalWrite( LED_PIN, LOW );
adc_queue = xQueueCreate(1, sizeof(uint32_t));
initADC(); // Initialize the ADC.
initTimer(); // Initialize the hardware timer.
}
void loop() {
uint32_t flag;
while (Serial.available()) {
if (Serial.read() == '\n') {
sampling = true; // Start the ADC sampling process.
}
}
// Wait for an event from the ISR (with 5 msec timeout).
if (xQueueReceive(adc_queue, &flag, 5)) {
// Send out the samples.
for ( uint32_t i=0; i < N; i++ ) {
Serial.printf("%lu\n", samples[i] );
}
Serial.flush();
sampling = true; // Restart the ADC sampling process.
}
}
การวัดสัญญาณที่ขา LED เมื่อทดสอบการทำงานของโค้ดตัวอย่าง จะทำให้เห็นช่วงเวลาในการทำงานของ ISR
รูป: ช่วงเวลาที่มีการทำงานของ ISR ตามจังหวะของ Hardware Timer เพื่ออ่านค่าจากสัญญาณแอนะล็อก
จากรูปจะเห็นได้ว่า มีการเกิดอินเทอร์รัพท์และการทำงานของ ISR หรือ Callback Function ทุก ๆ 100 usec (หรือ 10kHz Sampling Rate) และใช้เวลาในการทำงานประมาณ 50 usec (ช่วงที่ LED มีสถานะเป็น High)
รูป: ช่วงเวลาที่มีการทำงานของ ISR และช่วงเวลาที่ส่งข้อมูลออกทาง Serial Port
จากรูปจะเห็นได้ว่า ช่วงที่ไม่มีการทำงานของ ISR สถานะลอจิกของ LED จะเป็น Low และเป็นช่วงที่มีการส่งข้อมูลออกทาง Serial Port โดยใช้เวลาประมาณ 52 msec
การทดสอบการทำงานของระบบ แนะนำให้เริ่มต้นด้วยการสร้างสัญญาณภายนอกจากเครื่องกำเนิดสัญญาณ (Function Generator) เช่น สัญญาณรูปคลื่นไซน์ Vpp=2V, DC Offset=1.5V, Frequency=440Hz แล้วป้อนเข้าที่ขา ADC Input (GPIO34) แล้วแสดงกราฟข้อมูลด้วย Arduino Serial Plotter (ตั้งค่า Baudrate เท่ากับ 921600)
รูป: ตัวอย่างสัญญาณทดสอบจาก Function Generator และวัดสัญญาณด้วยออสซิลโลสโคป
รูป: การแสดงลำดับข้อมูลที่ได้รับในรูปของกราฟสัญญาณด้วย Arduino Serial Plotter
รูป: การต่อวงจรทดลองเพื่อวัดสัญญาณแอนะล็อกจากเครื่อง Function Generator
▷ การทดสอบด้วยสัญญาณเสียง#
ถัดไปเป็นตัวอย่างการทดสอบด้วยสัญญาณเสียง และใชโมดูล MAX4466 เป็นเซนเซอร์สำหรับสัญญาณเสียง โดยนำสัญญาณเอาต์พุตที่ได้ ไปต่อเข้ากับขา ADC Input (GPIO34) ของบอร์ด ESP32
จากนั้นลองเปิดเสียงความถี่คงที่โดยใช้คอมพิวเตอร์ เช่น การเปิดคลิปจาก YouTube ที่สร้างสัญญาณเสียงความถี่ 440Hz https://www.youtube.com/watch?v=xGXYFJmvIvk และเปิด Arduino Serial Plotter เพื่อแสดงลำดับข้อมูลที่ได้รับในรูปของกราฟสัญญาณ
รูป: การต่อวงจรทดลองโดยใช้โมดูล MAX4466
รูป: การวัดสัญญาณจากโมดูล MAX4466 ด้วยออสซิลโลสโคป แสดงผลในโหมด DC Coupling Mode วัดค่าแอมพลิจูดได้ประมาณ 1.12Vpp (peak-to-peak)
รูป: ตัวอย่างสัญญาณที่มีแอมพลิจูดมีค่าประมาณ 0.76Vpp (peak-to-peak) เนื่องจากเพิ่มระยะห่างระหว่างโมดูล MAX4466 กับลำโพงเสียงของคอมพิวเตอร์
รูป: ตัวอย่างสัญญาณจากโมดูล MAX4466 แสดงผลในโหมด AC Coupling Mode (แอมพลิจูดได้ประมาณ 1Vpp)
รูป: ตัวอย่างสัญญาณจากโมดูล MAX4466 แสดงผลในโหมด AC Coupling Mode (แอมพลิจูดได้ประมาณ 0.68Vpp)
หากลองเปลี่ยนเป็นสัญญาณเสียงของ Piano เช่น เล่นโน้ตดนตรี A4 (440Hz) โดยมีการเว้นระยะเวลาและวนซ้ำไปเรื่อย ๆ (https://www.youtube.com/watch?v=1af5Ms62RDQ) แล้ววัดสัญญาณเสียงด้วยโมดูล MAX4466 ก็มีตัวอย่างดังนี้
รูป: การวัดสัญญาณด้วยออสซิลโลสโคป ในโหมด FFT (Fast-Fourier Transform) เพื่อดูสเปกตรัมของสัญญาณตามความถี่
รูป: สัญญาณเสียงเมื่อวัดด้วยออสซิลโลสโคป (Time/Div = 100msec)
รูป: สัญญาณเสียงเมื่อวัดด้วยออสซิลโลสโคป (Time/Div = 500usec)
รูป: การแสดงลำดับข้อมูลที่ได้รับจาก ESP32 โดยใช้ Arduino Serial Plotter
▷ กล่าวสรุป#
บทความนี้ได้นำเสนอการใช้งานโมดูลที่มีไอซี MAX4466 ของบริษัท Maxim Integrated / Analog Devices สำหรับการขยายสัญญาณแอนะล็อก จากไมโครโฟนเสียงประเภท ** Electret Condenser Microphone และตัวอย่างการเขียนโค้ด Arduino Sketch สำหรับ ESP32 เพื่ออ่านค่าสัญญาณแอนะล็อกจากโมดูลเสียงด้วยวงจร ADC และส่งค่าออกทางพอร์ต Serial** และสามารถนำข้อมูลไปใช้ในการประมวผลด้วยคอมพิวเตอร์ในขั้นตอนต่อไปได้
บทความที่เกี่ยวข้อง
This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.
Created: 2023-11-14 | Last Updated: 2023-11-17