Atmega8 bip. AVR. Bekerja dengan pemancar piezo. Memainkan melodi. Output kepada DAC selari luaran

  • 16.08.2024

Saya menulis modul perisian yang membolehkan anda menambah fungsi memainkan melodi atau urutan bunyi pada hampir mana-mana projek pada mikropengawal AVR.

Ciri-ciri modul:

Penyepaduan mudah dengan projek siap sedia

Hanya pemasa 8-bit t2 digunakan, sementara ia masih boleh digunakan untuk mengundi atau membentuk selang masa

Modul ini boleh dilaraskan kepada hampir semua frekuensi penjana jam

Pic nota ditentukan sebagai pemalar simbolik (C0, A2, dsb.) atau dalam Hertz

Tempoh ditentukan dalam bentuk standard (suku, lapan, dsb.) atau dalam milisaat

Anda boleh menetapkan tempo main balik melodi dan bilangan ulangannya

Semasa main balik, melodi boleh dijeda


Menyambung modul bunyi

1. Salin semua fail modul (tone.h, sound.h, sound.c) ke dalam folder projek.

2. Sambungkan fail sound.c ke projek.

Untuk IAR `a – klik kanan dalam tetingkap ruang kerja dan pilih Tambah > Tambah Fail…

Untuk WINAVR ia lebih kurang sama, hanya sound.c perlu ditambahkan pada fail make:

SRC = $(SASARAN).c bunyi.c

3. Sertakan bunyi fail pengepala.h dalam modul yang sepadan. Contohnya, dalam main.c

#include "sound.h"

4. Tetapkan tetapan modul dalam fail sound.h

//jika anda mengulas keluar, tempoh nota adalah

//dikira daripada BPM yang dinyatakan dalam melodi

//jika dibiarkan, maka dari nilai yang dinyatakan di bawah

//#define SOUND_BPM 24

//frekuensi jam μ

#define SOUND_F_CPU 16U

//keluaran mikropengawal di mana bunyi akan dihasilkan

#define PORT_SOUND PORTB

#define PINX_SOUND 0

//bilangan melodi yang ditentukan.

#define SOUND_AMOUNT_MELODY 4

5. Tambahkan melodi anda kepada bunyi.c dan tulis nama melodi ke dalam tatasusunan melodi.

Menambah nada dering

Melodi ialah susunan nombor 16-bit dan mempunyai struktur berikut

BPM (nota suku seminit) ialah pemalar yang digunakan untuk mengira tempoh not dan menentukan kelajuan melodi dimainkan.

BPM boleh berjulat dari 1 hingga 24, yang sepadan dengan 10 dan 240 nota suku seminit, masing-masing.

Jika tempoh nota/bunyi dinyatakan dalam milisaat, maka BPM yang ditulis dalam tatasusunan hendaklah sama dengan 1.

Jika pemalar SOUND_BPM diulas dalam bunyi fail header.h, maka tempoh nota dikira semasa pelaksanaan program mengikut BPM yang ditentukan dalam tatasusunan. Jika SOUND_BPM tidak diulas, tempoh nota dikira pada peringkat penyusunan, berdasarkan nilai pemalar ini, dan semua melodi akan dimainkan pada tempo yang sama. Ini mengehadkan kefungsian, tetapi menjimatkan beberapa bait kod.

Bilangan ulangan. Boleh mengambil nilai 1 ... 254 dan LOOP (255). LOOP - bermakna melodi akan berulang tanpa henti sehingga arahan SOUND_STOP atau SOUND_PAUSE diberikan.

Nota tempoh– masa semasa nada bunyi tertentu dijana atau jeda dikekalkan. Boleh ditentukan dalam ms, menggunakan makro ms(x), atau sebagai nilai nota standard - nota kelapan, nota keenam belas, dsb. Di bawah ialah senarai tempoh yang disokong. Jika terdapat keperluan untuk beberapa tempoh eksotik, anda sentiasa boleh menambahkannya dalam fail tone.h

n1 - nota keseluruhan

n2 - separuh not

n4 - suku

n8 - kelapan

n3 - triplet kelapan

n16 - keenam belas

n6 - sextole

n32 - tiga puluh saat

Nota nada ditentukan menggunakan pemalar simbolik yang diterangkan dalam fail tone.h, contohnya C2, A1, dsb. Juga, pic nota boleh ditentukan dalam Hertz menggunakan makro f(x).

Program ini mempunyai sekatan pada kekerapan bunyi minimum dan maksimum!

Penanda akhir melodi. Nilai elemen terakhir tatasusunan mestilah sifar.

Menggunakan modul bunyi

Pada permulaan main, anda mesti memanggil fungsi SOUND_Init(). Fungsi ini menetapkan pin keluaran mikropengawal, mengkonfigurasi pemasa T2, dan memulakan pembolehubah modul.

Kemudian anda perlu menetapkan bendera membolehkan gangguan - __enable_interrupt(), kerana modul menggunakan limpahan pemasa T2 dan gangguan kebetulan.

Selepas ini, anda boleh mula bermain melodi.

Sebagai contoh, seperti ini:

SOUND_SetSong(2);

SOUND_Com(SOUND_PLAY); //mainkan melodi

//tetapkan penunjuk kepada melodi ke-2

//dan mulakan main balik

SOUND_PlaySong(2);

Main semula melodi boleh dihentikan pada bila-bila masa dengan mengeluarkan arahan SOUND_STOP.
Anda juga boleh menjeda melodi menggunakan arahan SOUND_PAUSE. Pengeluaran seterusnya arahan SOUND_PLAY menyambung semula main semula melodi dari tempat ia dihentikan.

Pada dasarnya, fungsi ini tidak diperlukan terutamanya (saya hanya mengada-ada) dan apabila bekerja dengan modul, fungsi SOUND_PlaySong(unsigned char numSong) sudah mencukupi;

Fail

Anda boleh memuat turun contoh penggunaan modul bunyi daripada pautan di bawah. Saya tidak melukis gambar rajah kerana semuanya mudah di sana. disambungkan ke pin PB0, butang mula melodi disambungkan ke pin PD3. Terdapat 4 melodi yang ditakrifkan dalam projek. Menekan butang memulakan melodi baharu setiap kali. Mikrokontroler atmega8535 digunakan. Pada mulanya saya ingin mengganggu projek dengan empat butang - PLAY, STOP, PAUSE dan NEXT, tetapi kemudian saya fikir ia tidak perlu.

PS: Modul ini tidak menjalani ujian yang meluas dan disediakan "seadanya". Jika ada cadangan yang rasional, mari kita selesaikan.

Dalam artikel ini, kita akan melihat cara memainkan nada dan mempelajari cara memainkan melodi monofonik.

Bersedia untuk bekerja

Program ini mengisytiharkan dua tatasusunan. Susun atur dengan nota nota mengandungi senarai nota ringkas. Nota ini dipadankan dengan tempoh bunyi dalam tatasusunan berdegup. Tempoh dalam muzik ditentukan oleh pembahagi nota berhubung dengan keseluruhan not. Nilai yang diambil secara keseluruhannya ialah 255 . Separuh, suku, perlapan diperoleh dengan membahagikan nombor ini.
Sila ambil perhatian bahawa tempoh nota pertama tidak diperoleh dengan membahagikan 255 dengan kuasa dua. Di sini anda perlu beralih kepada teori muzik. Nota melodi asal boleh dilihat. Nota ini digabungkan menjadi kembar tiga. Apabila digabungkan dengan cara ini, tiga not kelapan berbunyi sama dengan not satu perempat. Oleh itu tempoh relatif mereka ialah 21.
Pengguna juga perlu menyatakan secara eksplisit bilangan nota dalam urutan dengan arahan:

# tentukan SEQU_SIZE 19

Dalam program utama, pertama sekali, tatasusunan frekuensi dikira semula dan tempoh ke dalam tempoh isyarat dan tempoh nota.
Dengan tempoh isyarat (tatasusunan tempoh_isyarat) semuanya mudah. Untuk mendapatkan tempoh tempoh dalam mikrosaat, hanya bahagikan 1,000,000 dengan frekuensi isyarat.
Untuk mengira tempoh mutlak nota, tempo kerja muzik mesti ditentukan. Ini dilakukan melalui arahan

# takrifkan TEMPO 108

Tempo dalam muzik ialah bilangan not suku seminit. Dalam barisan

# tentukan WHOLE_NOTE_DUR 240000 / TEMPO

Tempoh keseluruhan nota dalam milisaat dikira. Sekarang sudah cukup untuk mengira semula nilai relatif dari tatasusunan menggunakan formula berdegup kepada tatasusunan mutlak tempoh_catatan.
Dalam gelung utama, pembolehubah masa_berlalu dinaikkan selepas setiap tempoh isyarat dimainkan mengikut tempoh tempoh ini sehingga ia melebihi tempoh nota. Entri ini patut diberi perhatian:

sementara(masa_masa< 1000 * ((uint32_t) note_duration[ i] ) )

Pembolehubah masa_berlalu 32-bit, dan elemen tatasusunan nota_tempoh 16-bit. Jika nombor 16-bit didarab dengan 1000, maka limpahan dijamin dan pembolehubah masa_berlalu akan dibandingkan dengan sampah. Pengubah suai (uint32_t) menukarkan elemen tatasusunan nota_tempoh[i] dalam nombor 32-bit tiada limpahan.
Anda boleh melihat ciri lain dalam gelung audio. Ia tidak akan dapat menggunakan fungsi tersebut _delay_us(), kerana hujahnya tidak boleh menjadi pembolehubah.
Untuk membuat kelewatan sedemikian, gunakan fungsi VarDelay_us(). Di dalamnya, gelung dengan kelewatan 1 μs ditatal beberapa kali tertentu.

void VarDelay_us(uint32_t takt) ( manakala (takt- - ) ( _delay_us(1 ) ; ) )

Apabila memainkan melodi, dua lagi kelewatan digunakan. Jika not dimainkan tanpa jeda, ia akan bergabung menjadi satu. Untuk melakukan ini, kelewatan 1ms dimasukkan di antara mereka, ditentukan oleh arahan:

# tentukan NOTES_PAUSE 1

Selepas setiap kitaran lengkap memainkan melodi, program berhenti seketika selama 1s dan mula bermain semula.
Akibatnya, kami menerima kod yang mudah untuk menukar tempo, melaraskan tempoh atau menulis semula melodi sepenuhnya. Untuk melakukan ini, cukup untuk hanya mengubah bahagian program dengan arahan dan pengisytiharan berubah-ubah.

Tugas individu

  1. Dalam melodi yang dicadangkan, cuba tukar tempo dan jeda 5 saat antara ulangan.
  2. Elemen tatasusunan berdegup hanya menerima nilai dari 0 hingga 255. Tukar lebar bit elemen tatasusunan dan lihat dalam output pengkompil untuk melihat bagaimana ini mempengaruhi jumlah memori yang diduduki oleh atur cara.
  3. Sekarang cuba tukar melodi sendiri. Contohnya, berikut ialah "Imperial March" daripada filem yang sama: nota int = ( A4, R, A4, R, A4, R, F4, R, C5, R, A4, R, F4, R, C5, R, A4, R, E5, R, E5, R, E5, R, F5, R, C5, R, G5, R, F5, R, C5, R, A4, R);

    int beats = ( 50 , 20 , 50 , 20 , 50 , 20 , 40 , 5 , 20 , 5 , 60 , 10 , 40 , 5 , 20 , 5 , 60 , 80 , 5 , 20 , 5 , 60 , 10 , 40 , 5 , 20 , 5 , 60 , 80 , 20 , 5 , 50 20, 40, 5, 20

    Untuk tidak membebankan artikel dengan maklumat, saya tidak akan menerangkan struktur format fail wav terdapat lebih daripada cukup maklumat dalam enjin carian. Cukuplah untuk mengatakan bahawa jika anda membuka fail dengan sejenis editor Hex, maka 44 bait pertama mengandungi semua maklumat tentang jenis fail, kadar pensampelan, bilangan saluran, dll. Jika anda perlu menganalisis fail, baca ini header dan anda akan gembira.

    Data muatan bermula pada 44 bait, pada asasnya mengandungi tahap voltan yang membentuk bunyi. Kami telah bercakap tentang tahap voltan pada bahagian terakhir pelajaran. Oleh itu, semuanya mudah, anda perlu mengeluarkan langkah-langkah ini kepada pembesar suara pada kekerapan pensampelan fail.

    Bagaimana untuk membuat gegaran pembesar suara secara fizikal? Anda perlu mengeluarkan paras voltan ini menggunakan PWM, atau gunakan R2R. Walau apa pun, ia sangat mudah untuk digunakan, baca nombor, letakkannya sama ada dalam OCR atau PORTx. Kemudian, selepas masa tertentu, saya menggantikan nilai seterusnya dan seterusnya sehingga akhir fail.

    Contoh, fail wav tertentu, data berasal dari bait 44=0x2C, nombor 0x80 ditulis di sana, kami mengeluarkan semula bunyi, contohnya, oleh PWM pemasa pertama, tulis OCR1A=0x80; Katakan kekerapan pensampelan sampel ialah 8 kHz, jadi gangguan hendaklah ditetapkan kepada frekuensi yang sama. Dalam gangguan, gantikan nilai seterusnya 0x85 selepas 1/8000 = 125 µs.

    Bagaimana untuk menetapkan gangguan kepada 8kHz? Mari kita ingat bahawa jika pemasa beroperasi pada frekuensi 250 kHz, maka daftar perbandingan gangguan mesti digantikan (250/8)-1=31-1 atau 0x1E. Dengan PWM, semuanya juga mudah; semakin tinggi frekuensi ia beroperasi, semakin baik.

    Untuk perisian tegar berfungsi, kami akan bersetuju bahawa pemacu denyar diformatkan dalam FAT32, menggunakan lib PetitFat dari pelajaran 23.2. Fail dalam format wav, sama ada 8kHz atau 22.050kHz, mono. Nama fail 1.wav. Mari analisa firmware.

    #termasuk #include "diskio.h" #include "pff.h" unsigned char buffer[ 512 ] ; /* penimbal di mana maklumat disalin daripada pemacu kilat */ kiraan int tidak bertanda yang tidak menentu; //menyalin pembilang data sampuk [TIM2_COMP] pemasa batal2_comp_isr(tidak sah) //interrupt di mana nilai diganti( OCR1A = penimbal[ kiraan] ; // mengeluarkan bunyi ke pembesar suara jika (++ kiraan >= 512 ) //meningkatkan kaunter kiraan = 0 ; //jika 512 ditetapkan semula) void main(void) ( unsigned int br; /* pembilang baca/tulis fail */ unsigned char buf = 0 ; //pembolehubah menentukan bahagian penimbal yang dibaca FATFS fs; /* Ruang kerja (objek sistem fail) untuk pemacu logik */ PORTB= 0x00 ; DDRB= 0x02 ; //lompat shim ocr1a// Sumber jam: Jam Sistem // Nilai jam: 8000,000 kHz // Mod: PWM pantas atas=0x00FF // Output OC1A: Bukan Inv. TCCR1A= 0x81 ; TCCR1B= 0x09 ; TCNT1= 0x00 ; OCR1A= 0x00 ; // Permulaan Pemasa/Kaunter 2// Sumber jam: Jam Sistem // Nilai jam: 250,000 kHz // Mod: CTC top=OCR2 TCCR2= 0x0B ; TCNT2= 0x00 ;//OCR2=0x1E; //menyediakan daftar perbandingan untuk 8kHz OCR2= 0xA ;//untuk 22kHz #asm("sei") // Pemasa(s)/Counter(s) Interrupt(s) initialization jika (disk_initialize() == 0 ) //mulakan pemacu denyar( pf_mount(&fs) ; //lekapkan sistem fail pf_open("1.wav" ); //buka benang pf_lseek(44) ; //gerakkan penunjuk ke 44 pf_read(buffer, 512 ,& br);< 256 ) //buat pertama kali kita menelan 512 bait sekali gus TIMSK= 0x80 ;< 256 ) { pf_read(& buffer[ 256 ] , 256 ,& br) ; //hidupkan muzik sambil (1) ( jika (! buf && count> 255 )//jika lebih daripada 255 bait dihasilkan semula,< 256 ) break ; } } TIMSK = 0x00 ; //глушим все pf_mount(0x00 ) ; ( pf_read(& buffer[ 0 ], 256 ,& br);//kemudian kita membaca maklumat dari pemacu kilat ke dalam separuh pertama penimbal

    buf= 1 ; #include "diskio.h" #include "pff.h" unsigned char buffer; /* penimbal di mana maklumat disalin daripada pemacu kilat */ kiraan int tidak bertanda yang tidak menentu; //bilangan data yang disalin interrupt void timer2_comp_isr(void) //interrupt di mana nilai digantikan ( OCR1A = buffer; //bunyi output ke pembesar suara jika (++count >= 512) //naikkan bilangan counter = 0; //jika 512 set semula ) void main(void) ( unsigned int br; /* fail baca/tulis kaunter */ unsigned char buf = 0; //pembolehubah menentukan bahagian penimbal dibaca FATFS fs; /* Berfungsi kawasan (objek sistem fail) untuk pemacu logik */ PORTB=0x00; Atas PWM pantas=0x00FF // Output OC1A: Bukan Inv. TCCR1A=0x09; OCR2 TCCR2=0x0B; TCNT2=0x00; //OCR2=0x1E; //mengatur daftar perbandingan untuk 8kHz OCR2=0xA; ( s) permulaan jika(disk_initialize()==0) //memulakan pemacu denyar ( pf_mount(&fs); //lekapkan sistem fail pf_open("1.wav"); //buka cawangan pf_lseek(44); //gerakkan penunjuk ke 44 pf_read(buffer, 512,&br); //buat pertama kali kita menelan 512 bait sekaligus TIMSK=0x80; //hidupkan muzik sambil(1) ( if(!buf && count>255) //jika lebih daripada 255 bait telah dimainkan, ( pf_read(&buffer, 256,&br);//kemudian baca maklumat daripada denyar memandu ke separuh pertama buffer buf=1 ;< 256) //если буфер не содержит 256 значений значит конец файла break; } if(buf && count<256) { pf_read(&buffer, 256,&br); // читаем во вторую часть буфера с флешки buf = 0; if (br < 256) break; } } TIMSK = 0x00; //глушим все pf_mount(0x00); //демонтируем фат } while (1) { } }

    Untuk menyemak, kami menyambungkan pembesar suara ke pin OCR1A melalui kapasitor 100uF, "+" ke pin mikropengawal, "-" ke pembesar suara. "-" pembesar suara ke tanah, "+" ke kapasitor.

    Jangan mengharapkan isyarat kuat pada output; anda memerlukan penguat untuk berbunyi kuat. Ini jelas kelihatan dalam video. Untuk ujian, saya memuatkan ayam jantan dengan 8 kHz dan trek dengan 22 kHz.

    Mereka yang ingin dengan selamat boleh meningkatkan kekerapan pemasa2 untuk memainkan fail 44 kHz eksperimen menunjukkan bahawa kualiti bunyi yang cukup baik boleh dicapai. Dalam video itu, bunyinya lemah dan kualitinya kurang baik, tetapi sebenarnya ini disebabkan oleh fakta bahawa saya merakamnya dengan kamera.

    Saya juga menyiarkan bahan yang disediakan oleh Apparatchik - kod sumber untuk GCC, yang daripadanya perisian tegar untuk CAVR telah ditulis.

    Dan video dengan main balik 44kHz.

    Saya mengambil kesempatan ini untuk mengucapkan tahniah kepada semua orang pada Tahun Baru, saya berharap semua perisian tegar dan peranti berfungsi untuk anda :)

    projek pemain wav pada Atmega8

    Jika kereta anda tidak memasang siren bunyi, dan anda masih tidak dapat memutuskan yang mana satu untuk dibeli dan dipasang, maka artikel ini adalah untuk anda sahaja. Mengapa membeli penggera mahal jika anda boleh memasang semuanya sendiri dengan cara yang agak mudah?

    Saya membentangkan dua litar mudah sedemikian pada mikropengawal AVR ATmega8 dan Attiny2313, atau lebih tepatnya satu litar, hanya dilaksanakan untuk bekerja pada kedua-dua mikropengawal ini. Ngomong-ngomong, dalam arkib anda akan menemui dua versi perisian tegar untuk mikropengawal Atmega8, di mana yang pertama menghasilkan semula bunyi yang serupa dengan penggera kereta, dan bunyi kedua serupa dengan penggera keselamatan bangunan (isyarat yang cepat dan tajam) .

    Anda boleh memuat turun semua perisian tegar di bawah dalam arkib (semuanya ditandatangani), dalam arkib anda juga akan menemui simulasi litar dalam Proteus, yang bermaksud bahawa selepas mendengar semua lagu anda boleh memilih daripada senarai yang paling anda sukai .

    Di bawah ialah rajah isyarat untuk Atmega8

    Senarai komponen radio yang digunakan dalam litar Atmega8

    U1- Mikropengawal AVR 8-bit ATmega8-16PU, kuantiti. 1,
    R1- Perintang dengan nilai nominal 47 Ohms, no. 1,
    R2, R3 - Perintang dengan nilai nominal 270 Ohm, no. 2,
    D2,D3-LED, no. 2,
    LS1-pembesar suara, tidak. 1,
    S1-sensor.

    Dan dalam litar isyarat pada Attiny2313, hanya MK telah ditukar.
    U1- Mikropengawal AVR 8-bit ATtiny2313-20PU, kuantiti. 1.

    PCB untuk Atmega8 kelihatan seperti ini:

    Seperti yang anda lihat, litar ini sangat mudah, hanya terdapat satu mikropengawal, 3 perintang, 2 LED dan satu lagi pembesar suara. Daripada butang, anda boleh menggunakan suis buluh atau kenalan lain.

    Prinsip operasi adalah seperti berikut. Sebaik sahaja kami menggunakan kuasa, LED (dalam litar D3) serta-merta menyala atau mula berkelip (bergantung pada perisian tegar), dan jika kami tidak menyentuh sensor, penggera akan senyap. Sekarang, jika sensor dicetuskan, siren juga akan berfungsi, LED juga akan berkelip, tetapi D2.

    Jika anda mahu lampu kereta berkelip apabila penggera berfungsi, maka untuk melakukan ini anda perlu menyambungkan pin mikropengawal 24 PC1 ke geganti melalui transistor, dan geganti itu sendiri ke lampu depan. Untuk mematikan siren, anda perlu mematikan dan menghidupkan peranti sekali lagi, atau hanya tekan butang. Untuk mengendalikan mikropengawal, anda memerlukan pengayun dalaman 8 MHz,

    Jika anda ingin meningkatkan bunyi penggera, anda boleh memasang penguat dengan transistor dan menyambungkannya ke litar. Itulah yang saya lakukan, tetapi saya tidak menggambarkannya dalam rajah ini.

    Mari kita beralih ke litar pada Attiny 2313, seperti yang saya katakan sebelum ini, ia mempunyai semua butiran yang sama dan prinsip operasi yang sama, hanya MK telah diubah, dan akibatnya, pin yang disambungkan ini beroperasi dari pengayun dalaman 4 MHz, walaupun ia boleh dipancarkan pada 1 MHz.

    Di bawah ialah gambarajah sambungan yang sudah ada pada Attiny2313

    Untuk MK ini saya hanya menulis satu versi firmware, memasang segala-galanya di papan litar, menyemaknya, semuanya berfungsi dengan baik.
    Dan fius perlu ditetapkan seperti yang ditunjukkan di bawah: