สารบัญ:
วีดีโอ: การเล่นไฟล์เสียง (Wav) ด้วย Arduino และ DAC: 9 ขั้นตอน
2025 ผู้เขียน: John Day | [email protected]. แก้ไขล่าสุด: 2025-01-13 06:58
เล่นไฟล์ wav เสียงจากการ์ด Audino SD ของคุณ คำแนะนำนี้จะแสดงให้คุณเห็นว่าไฟล์ wav ใน SdCard ของคุณสามารถเล่นผ่านวงจรง่ายๆ ไปยังลำโพงได้อย่างไร
ไฟล์ wav ต้องเป็นโมโน 8 บิต ฉันไม่มีปัญหาในการเล่นไฟล์ 44 KHz
แม้ว่าคุณภาพเสียงจะไม่ดีเยี่ยม แต่คุณภาพเสียงก็น่าพอใจมาก
ใช้มอนิเตอร์แบบอนุกรมเพื่อเลือกไฟล์ ไฟล์ต้องอยู่ในโฟลเดอร์ชื่อ adlog
คำแนะนำนี้ติดตามจากโครงการก่อนหน้านี้ที่ฉันบันทึกการบันทึก wav ลงใน SdCard:
วงจรนี้ใช้ตัวแปลงดิจิทัลเป็นอนาล็อก (DAC) 8 บิตราคาถูกและเครื่องขยายเสียงชิปตัวเดียว
ส่วนสำคัญสำหรับการตั้งค่าการขัดจังหวะนั้นนำมาจากบทความที่ยอดเยี่ยมโดย Amanda Ghassaei:
ขั้นตอนที่ 1: ข้อกำหนด
Arduino- ฉันใช้ Mega แต่ไม่มีเหตุผลใดที่ Uno จะไม่ทำงาน
เครื่องอ่าน SdCard- โปรแกรมได้รับการกำหนดค่าสำหรับ: MicroSD Breakout Board Regulated with Logic Conversion V2
ดูคำแนะนำนี้สำหรับรายละเอียดการตั้งค่า SdCard:
DAC0832 LCN- ตัวแปลงดิจิตอลเป็นอนาล็อก 8 บิตที่ยอดเยี่ยม- ไม่กี่ปอนด์
LM386 N-1 Op amp- ราคาถูกเหมือนชิพ
ซ็อกเก็ตชิป 20 ทาง
ซ็อกเก็ตชิป 8 ทาง
แหล่งจ่ายไฟ 9 โวลต์- แบตเตอรี่จะทำ
LM336 2.5 V อ้างอิงแรงดันไฟฟ้า
ตัวเก็บประจุ 10uF * 3 (แรงดันไฟฟ้าใด ๆ ที่มากกว่า 9V)
ตัวต้านทาน 10 โอห์ม
ตัวเก็บประจุ 50nF- (หรือที่ไหนสักแห่งใกล้ - 47nF, 56nf, 68nf- จะทำ)
ตัวเก็บประจุ 220uF
ลำโพง 64 โอห์ม
โพเทนชิออมิเตอร์เชิงเส้น 10K
สายเคเบิลเชื่อมต่อ 8 สายข้อมูลระหว่าง Arduino และวงจร-
บน Uno การเชื่อมต่อ 8 อยู่ในแนวเดียวกันบน Mega พวกเขาอยู่ในคู่
บน Mega ฉันใช้สายแพ 10 ทางพร้อมส่วนหัว IDC 10 ทาง (มีสายสำรอง 2 เส้น)
ขั้วต่อซ็อกเก็ตสำหรับเอาต์พุต 0V, 9V และ DAC
แผ่นทองแดง บัดกรี ลวด คัตเตอร์ ฯลฯ
ขั้นตอนที่ 2: ข้อมูลจำเพาะ
ตั้งค่า Serial ที่ 115200 บอด
รองรับ Hobbytronics MicroSD Breakout Board โดยใช้ Mega การเลือกชิปและพอร์ตอื่น ๆ จะเปลี่ยนแปลงระหว่าง Mega และ Uno
ไฟล์ Wav ต้องมีอยู่ในไดเร็กทอรีชื่อ adlog- อย่าลังเลที่จะตั้งชื่อไฟล์เป็นอย่างอื่นและจัดเรียงการเข้ารหัสที่จำเป็นใหม่
ไฟล์ wav ต้องเป็นโมโน 8 บิต ฉันทดสอบได้ถึง 44KHz
Serial monitor แสดงไฟล์ wav ในโฟลเดอร์ adlog ชื่อไฟล์จะถูกส่งจากบรรทัดเอาต์พุตของมอนิเตอร์
ขนาดไฟล์ถูกจำกัดโดยขนาด SdCard เท่านั้น
ขั้นตอนที่ 3: เริ่มต้นใช้งาน
เชื่อมต่อเครื่องอ่านการ์ด SD สิ่งเหล่านี้คือความเชื่อมโยงของเมก้า
0, 5V
CLK เพื่อตรึง 52
D0 เพื่อตรึง 50
D1 เพื่อตรึง 51
CS เพื่อตรึง 53
(ดูเว็บไซต์ซัพพลายเออร์สำหรับการเชื่อมต่อพอร์ต Uno)
คุณจะต้องการทดสอบว่าการ์ดของคุณใช้งานได้ในขั้นตอนนี้ - ใช้สคริปต์ที่ผู้ขายจัดหาให้
เราจำเป็นต้องสร้างวงจรขนาดเล็ก
เราจะส่งกระแสข้อมูลไบต์เสียงจาก Arduino
ตัวเลขเหล่านี้อยู่ระหว่าง 0 ถึง 255 ซึ่งแสดงถึงแรงดันไฟฟ้า
ความเงียบคือ 127-128
255 เป็นลำโพงทรงกรวยแข็งทางเดียว
0 คือกรวยลำโพงแข็งในอีกทางหนึ่ง
ดังนั้นเสียงจึงถูกบันทึกเป็นตัวเลขที่บันทึกไว้ ซึ่งสร้างแรงดันไฟฟ้าที่แตกต่างกัน ซึ่งจะสร้างกรวยลำโพงเคลื่อนที่
เราสามารถส่งตัวเลขจาก 8 บรรทัดบน Arduino ได้พร้อมกันโดยใช้ "พอร์ต"
ถ้าเราป้อน 8 บรรทัดลงในตัวแปลงดิจิทัลเป็นแอนะล็อก มันจะทำตามที่เขียนไว้บนกระป๋องและสร้างแรงดันแอนะล็อกซึ่งเป็นสัดส่วนกับตัวเลขดิจิทัล
สิ่งที่เราต้องทำคืออัดแรงดันไฟไปที่แอมพลิฟายเออร์สำหรับการทำงานขนาดเล็กแล้วต่อกับลำโพง
ขั้นตอนที่ 4: วงจรขนาดเล็ก
DAC0832 LCN
นี่คือตัวแปลงดิจิตอลเป็นอนาล็อก 8 บิตที่ยอดเยี่ยมและราคาถูก (ดีเอซี)
สามารถควบคุมได้อย่างเต็มที่ด้วยอาร์เรย์ของการเก็บข้อมูล เส้นตัวอย่างข้อมูล
หรือจะตั้งค่าให้ทำทั้งหมดโดยอัตโนมัติใน "Flow through operation" ก็ได้
เพื่ออ้างอิงคู่มือ:
เพียงแค่ต่อสายดิน CS, WR1, WR2 และ XFER และผูก ILE ให้สูง ช่วยให้รีจิสเตอร์ภายในทั้งสองติดตามอินพุตดิจิตอลที่ใช้ (โฟลว์ทรู) และส่งผลโดยตรงต่อเอาต์พุตแอนะล็อก DAC
ตกลงนั่นคือการเชื่อมต่อสี่ตัวกับชิปที่ตั้งค่าต่ำและหนึ่งชุดเป็น 9V - ง่าย
เราไม่ต้องการให้มีแรงดันลบใดๆ ดังนั้นคู่มือบอกว่าเราควรใช้ "โหมดสลับแรงดันไฟ" และให้ไดอะแกรม
สิ่งที่เราต้องทำคือเปลี่ยนแอมป์เสียงขนาดเล็กแทนแอมป์ที่แนะนำ
แอมป์เสียง LM386-N
คู่มือของแอมป์มีไดอะแกรมชิ้นส่วนขั้นต่ำ - ให้เกน 20 (มากเกินไปสำหรับเรา - แต่มีตัวควบคุมระดับเสียง)
สิ่งที่เราต้องทำคือเพิ่มตัวเก็บประจุระหว่าง DAC และแอมป์ เพื่อให้เราขยายสัญญาณ AC เท่านั้น
เราต้องเพิ่มตัวเก็บประจุสองสามตัวใกล้กับขาจ่ายไฟของชิปแต่ละตัว ไม่เช่นนั้นเราจะได้ยินเสียงฮัมจากแหล่งจ่าย 9V ของเรา
ขั้นตอนที่ 5: นำหัวแร้งออก
เนื่องจากวงจรนั้นง่าย ฉันไม่ได้ตั้งใจจะตีด้วยบัญชี
นี่คือคำแนะนำบางส่วน:
- เตรียมแผ่นแถบทองแดงอย่างน้อย 28 x 28 รู (ใช่ฉันรู้ว่าศัลยแพทย์สมองสามารถทำให้เล็กลงได้)
- หากคุณต้องการยึดด้วยสกรู ให้อนุญาตในตอนเริ่มต้น!
- ติดตั้งชิปบนซ็อกเก็ต ใส่ชิปเฉพาะเมื่อตรวจสอบทุกอย่างแล้ว
- เก็บสายอินพุตให้ห่างจากเอาต์พุต
- สังเกตขั้วที่ถูกต้องสำหรับตัวเก็บประจุ
- อ้างถึงไดอะแกรมสำหรับมุมมองฐานของการอ้างอิงแรงดันไฟฟ้า LM336 ขาปรับระดับไม่ได้ใช้และสามารถตัดได้
- สังเกตการเชื่อมต่อโดยตรงกับพิน 8 ของ DAC- ซึ่งมีประโยชน์มากสำหรับการทดสอบ
- ฉันเชื่อมต่อกับ Audino ด้วยสายแพและตัวเชื่อมต่อ IDC 10 ทาง
- บน Uno การเชื่อมต่อเป็นเส้นตรง - คุณอาจพบว่าการจัดการเชื่อมต่ออินพุต 8 รายการในเส้นตรงเส้นเดียวช่วยให้คุณสามารถเชื่อมโยงกับ Arduino ด้วยตัวเชื่อมต่อ 8 ทางที่ซื้อมาและพร้อมใช้งาน
เมื่อเสร็จแล้วให้ตรวจสอบการบัดกรีและตรวจสอบช่องว่างระหว่างรางทองแดง
ฉันพบว่าใบเลื่อยแฮ็คจูเนียร์ 36 tpi มีประโยชน์มากสำหรับการล้างเศษซาก ฉันถอดหมุดระบุตำแหน่งของใบมีดและเลื่อนส่วนปลายของใบมีดเข้าไปในราง - เห็นได้ชัดว่าใบมีดไม่อยู่ในเฟรม
ขั้นตอนที่ 6: ทดสอบ DAC
ปล่อยให้การเชื่อมต่อระหว่างวงจรและ Arduino ปิด
ตั้งค่าตัวควบคุมระดับเสียงบนวงจรของคุณให้อยู่ตรงกลาง
เปิดไฟ DC 9V ไปยังวงจรใหม่ของคุณ
ตรวจสอบว่าวงจรโอเค- ฉันไม่สามารถรับผิดชอบต่อวงจรของคุณได้!
ปิดลง
เชื่อมต่อวงจรของคุณกับ Arduino
บนเมก้าใช้พิน 22-29 (PORTA) อย่าพลาดพิน 5V สองตัวข้างบนนี้!
บน Uno ใช้พิน 0-7 นี่คือ PORTD
เชื่อมต่อ 0V ของแหล่งจ่ายไฟของคุณกับ 0V บน Arduino
เพิ่มพลัง.
เปิดโปรแกรมทดสอบนี้ DAC_TEST
สำหรับ UNO ให้แทนที่การอ้างอิงทั้งหมดไปยัง PORTA เป็น PORTD
แทนที่ DDRA ด้วย DDRD- คำแนะนำนี้จะตั้งค่าทั้ง 8 บรรทัดเป็นเอาต์พุตในครั้งเดียว นี่คือการลงทะเบียนทิศทางข้อมูล
ตั้งค่ามอนิเตอร์ซีเรียลของคุณที่ 115200
เชื่อมต่อโวลต์มิเตอร์ระหว่าง DAC out และ OV
โปรแกรมจะตั้งค่าเอาต์พุตเป็น 255- เปิดทุกบรรทัด - แรงดันไฟฟ้าสูงสุด
เอาท์พุทแรงดันไฟฟ้าสูงสุด 128- ครึ่งหนึ่ง
เอาต์พุต 0- แรงดันศูนย์ (หรือเกือบเป็นศูนย์)
จากนั้นจะเป็นขั้นตอนระดับบิต: 1, 2, 4, 8, 16, 32, 64, 128
แรงดันไฟฟ้าควรเพิ่มขึ้นอย่างต่อเนื่อง
หากแรงดันไฟฟ้าลดลงในขณะที่จำนวนเพิ่มขึ้น คุณอาจมีสายที่เชื่อมต่อถึงกันสองเส้นกลับด้าน
คุณควรได้ยินเสียงลำโพงคลิกเบาๆ เมื่อแรงดันไฟฟ้าเปลี่ยนแปลง
ขั้นตอนที่ 7: การอ่าน Wav Header
ไฟล์ Wav จะถูกบันทึกด้วยความถี่และขนาดข้อมูลที่ระบุ
ข้อมูลนี้มีอยู่ในส่วนหัวขนาด 44 ไบต์ที่จุดเริ่มต้นของไฟล์ wav
แม้ว่าซอฟต์แวร์บางตัวจะขยายส่วนหัว (หลังไบต์ 35) ทำให้ตำแหน่งของขนาดข้อมูลยากขึ้นในการค้นหา
หากต้องการอ่านส่วนหัว เราสร้างบัฟเฟอร์และคัดลอกจุดเริ่มต้นของไฟล์
ความถี่จะถูกเก็บไว้ในไฟล์ 4 ไบต์เริ่มต้น 24 ไบต์ในไฟล์
// ความถี่ในการอ่านที่ระบุในส่วนหัวของไฟล์ wav
ไบท์เฮดบัฟ[60]
tempfile.seek(0);
tempfile.read (เฮดบัฟ 60);
retval=headbuf[27];
retval=(retval<<8) | ผ้าโพกศีรษะ[26];
retval=(retval<<8) | ผ้าโพกศีรษะ[25];
retval=(retval<<8) | ผ้าโพกศีรษะ[24];
Serial.print(F("ความถี่ไฟล์ "));
Serial.print(retval);
วิธีที่ดีที่สุดในการค้นหาข้อมูลขนาดข้อมูลคือการค้นหาคำว่า "data" ในส่วนหัว
จากนั้นแยก 4 ไบต์ที่ตามมาซึ่งประกอบขึ้นเป็นค่ายาว
การหดตัวแบบยาวที่ไม่ได้ลงนาม
int mypos=40;
สำหรับ (int i=36; i<60;i++) {
ถ้า (headbuf == 'd') {
if(headbuf[i+1]=='a') {
if(headbuf[i+2]=='t') {
if(headbuf[i+3]=='a') {
//ในที่สุดเราก็มี
mypos=i+4;
ผม=60;
}
}
}
}
}
tempfile.seek (mypos);
retval=headbuf[mypos+3];
retval=(retval<<8) | หัวบัฟ[mypos+2];
retval=(retval<<8) | หัวบัฟ[mypos+1];
retval=(retval<<8) | หัวบัฟ[mypos];
ตกลง เรามีข้อมูลความยาวและความถี่!
ข้อมูลเสียงตาม 4 ไบต์สร้างค่าความยาวข้อมูล
ขั้นตอนที่ 8: ขัดจังหวะ ขัดจังหวะ…
เราใช้ข้อมูลความถี่เพื่อสร้างการขัดจังหวะของซอฟต์แวร์ที่ หรือใกล้กับความถี่ที่ต้องการ
ไม่สามารถตั้งค่าการขัดจังหวะได้อย่างแม่นยำเสมอไป แต่ก็เพียงพอแล้ว ความถี่ที่อ่านจากไฟล์ถูกส่งไปยังรูทีนย่อย setintrupt
โมฆะ setintrupt (ความถี่ลอย) {float bitval=8; // 8 สำหรับตัวจับเวลา 8 บิต 0 และ 2, 1024 สำหรับตัวจับเวลา 1 byte
เซโตโครอา=(16000000/(ความถี่*บิตวาล)) - 0.5;
// ค่าเซโตโครอาต้องการการลบ -1 อย่างไรก็ตามการเพิ่ม 0.5 รอบเป็น 0.5. ที่ใกล้ที่สุด
// ความละเอียดของตัวจับเวลามีจำกัด
// กำหนดในที่สุดโดยขนาดของบิตวาล
cli(); // ปิดการใช้งานอินเตอร์รัปต์ // ตั้งเวลา 2 อินเตอร์รัปต์
TCCR2A = 0; // ตั้งค่าการลงทะเบียน TCCR2A ทั้งหมดเป็น 0
TCCR2B = 0; // เหมือนกันสำหรับ TCCR2B
TCNT2 = 0; // เริ่มต้นค่าตัวนับเป็น0
// ตั้งค่าเปรียบเทียบการลงทะเบียนการจับคู่สำหรับความถี่ (hz) ที่เพิ่มขึ้น
OCR2A = เซโตโครอา; // = (16*10^6) / (ความถี่*8) - 1 (ต้อง <256)
// เปิดโหมด CTC
TCCR2A |= (1 << WGM21); // ตั้งค่าบิต CS21 สำหรับ 8 พรีสเกลเลอร์
TCCR2B |= (1 << CS21); // เปิดใช้งานตัวจับเวลาเปรียบเทียบการขัดจังหวะ
// TIMSK2 |= (1 << OCIE2A); // ใช้งานได้เช่นเดียวกับบรรทัดต่อไปนี้
sbi(TIMSK2, OCIE2A); // เปิดใช้งานการขัดจังหวะบนตัวจับเวลา2
เส (); // เปิดใช้งานการขัดจังหวะ
ผู้อ่านที่ฉลาดจะพบเห็น sbi(TIMSK2, OCIE2A)
ฉันตั้งค่าฟังก์ชัน (รับอินเทอร์เน็ต) สองสามอย่างสำหรับการตั้งค่าและล้างรีจิสเตอร์บิต:
// กำหนดสำหรับการล้างบิตรีจิสเตอร์#ifndef cbi
#define cbi(sfr, บิต) (_SFR_BYTE(sfr) &= ~_BV(บิต))
#endif
// กำหนดการตั้งค่าบิตรีจิสเตอร์
#ifndef sbi
#define sbi(sfr, บิต) (_SFR_BYTE(sfr) |= _BV(บิต))
#endif
ฟังก์ชันเหล่านี้ช่วยให้ตั้งค่าการโทรหรือล้างการขัดจังหวะได้ง่าย
ดังนั้นอินเทอร์รัปต์จึงทำงาน เราจะทำอย่างไร?
ขั้นตอนที่ 9: การขัดจังหวะและการบัฟเฟอร์สองเท่า
ที่ 22 Khz ข้อมูลเสียงหนึ่งไบต์จะถูกส่งออกทุกๆ 0.045 ms
อ่าน 512 ไบต์ (ขนาดบัฟเฟอร์) ใน 2.08 ms
ดังนั้นจึงไม่สามารถอ่านบัฟเฟอร์จาก SDCard ในรอบการเขียนเดียว
อย่างไรก็ตาม 512 ไบต์ถูกเขียนไปยังพอร์ตใน 23.22ms
สิ่งที่เราต้องทำคือตั้งค่าไฟล์ใหม่ให้อ่านทุกครั้งที่บัฟเฟอร์ว่างเปล่า และเรามีเวลาเพียงพอที่จะรับข้อมูลก่อนที่จะต้องมีบล็อกข้อมูลใหม่… สมมติว่าเราใช้บัฟเฟอร์สองตัว ล้างไฟล์หนึ่งขณะที่เราเติมอีกอัน
นี่คือการบัฟเฟอร์สองครั้ง
การอ่านไฟล์จะช้าลงโดยการขัดจังหวะซ้ำๆ แต่จะทำเสร็จ
ฉันได้ตั้งค่าบัฟเฟอร์ 512 ไบต์สองตัวที่เรียกว่า bufa และ bufb
หากพื้นที่ธงเป็นจริง เราอ่านจาก porta มิฉะนั้น เราจะอ่านจาก portb
เมื่อตำแหน่งบัฟเฟอร์ (bufcount) ถึงขนาดบัฟเฟอร์ (BUF_SIZE 512) เราตั้งค่าสถานะที่เรียกว่า readit เป็นจริง
รูทีน void loop จะค้นหาแฟล็กนี้และเริ่มอ่านบล็อก:
if(readit){ถ้า (! aready){
// เริ่มการบล็อก SDCard เพื่ออ่าน bufa
tempfile.read (bufa, BUF_SIZE);
} อื่น {
// เริ่มการบล็อก SDCard เพื่ออ่านเป็นbufb
tempfile.read (bufb, BUF_SIZE);
}
readit=เท็จ;
}
เมื่อเสร็จสิ้นงานประจำ ตั้งค่าสถานะ readit=false
ภายในรูทีนการขัดจังหวะ เราต้องตรวจสอบว่าลูป void เสร็จสิ้นโดยตรวจสอบว่า readit== false
ในกรณีนี้เราส่งสัญญาณว่าจำเป็นต้องอ่านอีกครั้งและสลับแฟล็ก aready เพื่อสลับบัฟเฟอร์
หากการ์ด SD ยังอ่านอยู่ เราต้องย้อนรอยการอ่านหนึ่งครั้ง (ตัวนับ--; bufcount--;) และออกจากการขัดจังหวะเพื่อลองอีกครั้งในภายหลัง (การคลิกในสัญญาณเอาท์พุตเสียงบ่งบอกว่าสิ่งนี้เกิดขึ้น)
เมื่ออ่านข้อมูลทั้งหมดแล้ว การขัดจังหวะจะถูกยกเลิก พอร์ตจะตั้งค่าใหม่เป็นค่าแรงดันไฟฟ้ากลางที่ 128 และไฟล์เสียงปิด
ก่อนเรียกใช้สคริปต์ dac2.ino เป็นครั้งแรก ให้ตั้งค่าระดับเสียงเป็น 50% นี้จะดังเกินไป แต่จะดีกว่า 100%!
หากตัวควบคุมระดับเสียงของคุณทำงานแบบย้อนกลับ ให้สลับสายที่ปลายอีกด้านของโพเทนชิออมิเตอร์ 10K
ให้ฉันรู้ว่ามันฟังดู