สารบัญ:

การเล่นไฟล์เสียง (Wav) ด้วย Arduino และ DAC: 9 ขั้นตอน
การเล่นไฟล์เสียง (Wav) ด้วย Arduino และ DAC: 9 ขั้นตอน

วีดีโอ: การเล่นไฟล์เสียง (Wav) ด้วย Arduino และ DAC: 9 ขั้นตอน

วีดีโอ: การเล่นไฟล์เสียง (Wav) ด้วย Arduino และ DAC: 9 ขั้นตอน
วีดีโอ: Arduino C++: Serial UART mp3/WAV player tutorial 2024, กรกฎาคม
Anonim
การเล่นไฟล์เสียง (Wav) ด้วย Arduino และ DAC
การเล่นไฟล์เสียง (Wav) ด้วย Arduino และ DAC
การเล่นไฟล์เสียง (Wav) ด้วย Arduino และ DAC
การเล่นไฟล์เสียง (Wav) ด้วย Arduino และ DAC
การเล่นไฟล์เสียง (Wav) ด้วย Arduino และ DAC
การเล่นไฟล์เสียง (Wav) ด้วย Arduino และ DAC

เล่นไฟล์ 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

การทดสอบ DAC
การทดสอบ 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
การอ่านส่วนหัวของ Wav

ไฟล์ 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

ให้ฉันรู้ว่ามันฟังดู

แนะนำ: