Digitální bubeník s AVR

Tomáš Spáčil, UREL, FEEC, VUT Brno
xspaci08stud.feec.vutbr.cz.

Obsah:

  1. Úvod
  2. Realizace
  3. Závěr
  4. Soubory ke stažení
  5. Literatura

Úvod

Cílem tohoto projektu bylo vytvořit metronom s možností volby přehrávání zvuků bicího nástroje za pomocí mikrokontroléru AVR. Takovéto zařízení se plnohodnotně uplatní při hře a trénování na různé hudební nástroje.
        Koncept vzniku zadání byl podpořen myšlenkou vytvořit jednoduchého skladatele. Pomocí tlačítek maticové klávesnice jsou vybírány jednotlivé zvuky z paměti, přičemž každé tlačítko 1 až 8 představuje pozici v taktu, přesněji 1/8 dobu. Opakovaným stiskem stejného tlačítka se vybírá ze zvuků v paměti. Uživatel si tedy může vytvořit libovolnou zvukovou sekvenci z dostupných zvuků v rámci jednoho taktu, který se neustále přehrává. Rychlost přehrávání lze měnit změnou tempa jako u metronomu. Nastavení se zobrazuje na LCD.

Realizace

1) Princip přehrávání zvuku:

Údery bicích nástrojů jsou signály neharmonické. Nelze je tedy jednoduše popsat jediným kmitočtem jako v případě tónů harmonických. Z tohoto důvodu byla zvolena metoda přehrávání již zaznamenaného zvuku krátkého úseku ve formátu wav souboru. Jednotlivé vzorky zaznamenané sekvence představují okamžitou hodnotu přehrávaného zvuku.
        Pro přehrávání jednotlivých vzorků sekvence bylo nejprve zamýšleno použití jednoho ze dvou typů D/A převodu. První za pomocí jednoduchého D/A převodníku odporové sítě R2R připojeného na celý PORT, nebo pomocí sériového D/A převodníku např. TC1320EOA. Wav soubory měly být uloženy na externím paměťovém mediu SD karty a komunikace mezi mikrokontrolérem měla probíhat za pomocí rozhraní SPI.
        Z důvodu časové tísně byl nakonec zvolen jednodušší princip za pomocí rychlé PWM (pulzně šířková modulace). Fast PWM je speciální mód využití čítače/časovače kdy dochází ke změně úrovně na výstupním pinu OC2 u 8b časovače (OC1A/OC1B v případě 16b čas. ) během shody komparačního registru OCR s hodnotou časovače. Změnou hodnoty komparačního registru OCR vzniká pak na výstupu signál s proměnnou střídou.
        Wav soubory obsahující záznam jednotlivých úderů bicích byly nejprve převedeny na 8b rozlišení se vzorkovací frekvencí 8 kHz. Pomocí tohoto souboru byl poté vytvořen hlavičkový soubor obsahující pole hodnot pro nastavení komparačního registru OCR, které jsou úměrné okamžitým amplitudám vzorků. Tento hlavičkový soubor byl vytvořen za pomocí programu uvedeného na stránkách v příloze [3]. Na výstupním pinu OCR tedy dostáváme PWM signál, který se po přivedení na reproduktor díky jeho vlastní indukčnosti převede (vyfiltruje) na signál akustický.

2) Hardware:

Typ mikrokontroléru, který byl zvolen je ATmega32. Důvodem výběru je pouze vývojový kit, obsahující tento mikrokontrolér, na kterém byl program postupně odlaďován. Pro realizaci by se tedy hodil i jednodušší mikrokontrolér s dostatečným počtem I/O pinů (3 PORTY). ATmega32 má dále oproti nižším řadám (ATmega8, ATmega16) větší paměť flash. Pokud bychom však použili externí paměť, jak bylo původně plánováno, pak velikost paměti flash u čipu jako omezení ztrácí význam. Krystal byl použit 16 MHz externí, který je již součástí kitu. LCD byl vybrán dvouřádkový o 16 znacích, který pro dané zobrazení nastavení plně postačuje. Součástí Hardwaru je ještě maticová klávesnice 3x4 a obyčejný 8 ohm reproduktor zapojený přes tranzistor T1. Pro změnu tempa byly využity dva ze čtyř mikrospínačů na kitu a zapojeny s externími pull-up rezistory 4k7. Celé zařízení může být napájeno přes programátor BiProg UREL prostřednictvím ISP, nebo lépe přímo přes USB na vývojovém kitu.

Schéma

Obr. 1: Schéma zapojení

Poznámka: Ve schématu zapojení nejsou uvedeny všechny části vývojového kitu, ale pouze ty, které byly využity.

Realizace

Obr. 2: Zapojení na nepájivém poli

3) Software a popis nejdůležitějších částí kódu:

Řízení tempa je programově realizováno pomocí vektoru přerušení při shodě 16b časovače s komparačním registrem OCR1A. Během přerušení se nastaví hodnota pomocné proměnné (registru) tempo_1_8, která představuje osminové doby v taktu. Změna tempa se pak provede přenastavením OCR1A.

  ISR(TIMER1_COMPA_vect){  //vektor preruseni pri shode 16b Timer/Counter1 s hodnotou v OCR1A
	
	sample=0;                          //zajisteni prehravani sekvence vzdy od zacatku po kazdem preruseni
	tempo_1_8++;                       //inkrementace pomocne pro tempo 1/8 dob (casovani)
	if(tempo_1_8 == 9) tempo_1_8 = 1;  //nulovani pomocne -> pozadujeme jen 8 stavu
  }
	

Pomocí skenování tlačítek na pinech PD4 a PD5 se po stisku mění pomocná proměnná tempo. Ta je jako vstupní proměnná pro funkce zobrazení na LCD a funkce výpočtu hodnoty registru OCR1A. Výpočet hodnoty registru OCR1A je čistě matematickou operací. Pro práci s LCD byla použita knihovna lcd.c.

  //TEMPO UP																							 	
  if((PIND & _BV(PD4)) == 0){         //provede se pouze pri stisku tlacitka (log uroven 0 -> pripojeni na zem)
    tempo++;                          //inkrementace tempa
    if(tempo == 251) tempo = 60;      //maximalni tempo 250 pak nastav 60 -> pojede dokola
    show_tempo_on_LCD(tempo);         //funkce pro zobrazeni tempa na LCD
    calculate_time_interrupt(tempo);  //volani funkce pro vypocet casu do preruseni TIMER1_COMPA_vect 
  }
  //TEMPO DOWN																								
  if((PIND & _BV(PD5)) == 0){         //provede se pouze pri stisku tlacitka (log uroven 0 -> pripojeni na zem)
    tempo--;                          //dekrementace tempa														
    if(tempo == 59) tempo = 250;      //minimalni tempo 60 pak nastav 250 -> pojede dokola
    show_tempo_on_LCD(tempo);         //funkce pro zobrazeni tempa na LCD
    calculate_time_interrupt(tempo);  //volani funkce pro vypocet casu do preruseni TIMER1_COMPA_vect	
  }
  

Skenování klávesnice je založeno na stejném principu jako skenování tlačítek, avšak pro zajištění všech kombinací je použit cyklus for.

 
  uint8_t key_value(void){  //funkce pro urceni stisku tlacitka s klavesnice
    uint8_t i, key = 0;     //pomocna i pro cyklus a key jako navratova hodnota funkce
    for(i=0;i<3;i++){       //cyklus pro skenovani 3 sloupců
      PORTA =~(0x10 << i);  //negace bitu PA4 az PA6 -> skenovani sloupcu
      PINA = PORTA;
      if((PINA & _BV(PA3))==0) key = 1+i;   //podminka pro stisk tlacitka 1. radku
      if((PINA & _BV(PA2))==0) key = 4+i;   //podminka pro stisk tlacitka 2. radku
      if((PINA & _BV(PA1))==0) key = 7+i;   //podminka pro stisk tlacitka 3. radku
      if((PINA & _BV(PA0))==0) key = 10+i;  //podminka pro stisk tlacitka 4. radku	
    }
    return key; //navratova hodnota funkce
  }
  

Pomocí návratové hodnoty key ze skenování klávesnice určujeme pozici v taktu. Pomocná memory_buffer slouží pro zapamatování nastavení vybraného zvuku pro všechny pozice v taktu a jejich plynulé procházení při opakovaném stisku.

 
  //URCENI POZICE V TAKTU	
  if((key_value() != 0)&(key_value() < 9)){  //8 dob -> zajma nas tedy pouze cisla 1 az 8 na klavesnici	
    takt_pozition = key_value();             //zjisteni doby v taktu	
	
  //URCENI ZVUKU Z PAMETI
    uint8_t i;
    for(i=1;i<9;i++){                                       //skenuje se co bylo zmacknuto a podle toho se nastavi buffer	
      if(takt_pozition == i){
        memory_buffer[i-1]++;			
        if (memory_buffer[i-1] > 7) memory_buffer[i-1] = 0; //mame pouze 7 zvuku -> staci tedy inkrementovat 7x pro kazdou bunku bufferu	
        sound_type = memory_buffer[i-1];                    //ulozeni hodnoty z bufferu do promenne pro zobrazeni typu zvuku na LCD						
        _delay_ms(200);                                     //ochrana proti zakmitum pri stisku tlacitka s klavesnice	
        show_sound_on_LCD(takt_pozition, sound_type);       //funkce pro zobrazeni doby/zvuku na LCD		
      }
    }
  }
  

Přehrávání zvuku je podmíněno cyklem for, který zajišťuje skenování všech možných kombinací výběru. Jednotlivé sekvence zvuku jsou přehrávány pouze během osminových dob, což je řízeno obsluhou přerušení.

 
  uint8_t i,j;
  for(j=1;j<8;j++){                                         //vsechny kombinace vyberu zvuku (0 -> nehraje se nic -> pauza)		
    for(i=1;i<9;i++){                                       //vsechny kombinace pozic v taktu
      if((tempo_1_8 == i)&(memory_buffer[i-1] == j)){       //zvuk bude prehran pouze v odpovidajici dobe dane casovanim tempa v preruseni (1/8 doby)
        _delay_us(125);                                     //zpozdeni pro korekci prehravani 
        OCR2 = pgm_read_byte(&pcm_samples[j-1][sample++]);  //nastavovani komparacniho registru pro PWM ze sekvenci vzorku
        if(sample>sequence_length)sample=0;                 //pokud si na konci sekvence skonci
      }
    }
  }
  

Ukázka hlavičkového souboru obsahující jednotlivé sekvence zvuku.

 
  static const unsigned char pcm_samples[][4098] PROGMEM ={
	
    //bass_drum
    {116,97,....
    },

    //snare_drum_1
    {116,97,....
    },

    //ride_cymbal
    {116,97,....
    },

    //hi_hat_close
    {116,97,....
    },
  
    //hi_hat_open
    {116,97,....
    },

    //snare_drum_2
    {116,97,....
    },
	
    //cymbal
    {116,97,....
    }
  };
  

Závěr

Programově se podařilo realizovat veškeré požadované funkce a zařízení je plně funkční. Kvalita zvuku není úplně nejlepší, což je typické pro princip generování zvuku pomocí PWM. Jednotlivé údery lze však bez problému rozlišit. Také úroveň akustického signálu je poměrně nízká. Hlasitost můžeme zvyšovat snižováním odporu R6 u reproduktoru. Toto řešení však není úplně nejlepší, protože při přehrávání zvuku (sepnutím tranzistoru T1) se již přibližujeme ke zkratu napájení, což se projevuje např. poblikáváním LCD. Vhodným řešením v případě nutnosti zesílení akustické úrovně by bylo nejprve signál z pinu filtrovat pomocí dolní propusti a pak přivést na jednoduchý zesilovač např. s LM386. Nevýhodou při obsluze zařízení je, že při změně tempa dojde k dočasnému pozastavení přehrávané sekvence. Změna tempa se tedy neprojevuje plynule s přehráváním. Nicméně na těchto drobných nedokonalostech se bude dále pracovat. V plánu je také otestovat prvotně zamýšlený způsob zpracovaní zvuku pomocí D/A převodu a SD karty pro možnost uložení většího počtu zvukových sekvencí.

Soubory ke stažení:

Zdrojový kód

Literatura

[1] FEDRA, Z. Mikrokontroléry pro přístrojové aplikace. Přednášky. FEKT VUT Brno 2013.
[2] Atmel Corporation. Datasheet ATmega32L. [Online] citováno 2013-5-28. Dostupné na: http://www.atmel.com/Images/doc2503.pdf
[3] AVR PCM audio: http://avrpcm.blogspot.cz/2010/11/playing-8-bit-pcm-using-any-avr.html
[4] AVR Libc: http://www.nongnu.org/avr-libc/user-manual/modules.html
[5] FRÝZA,T., ŠEBESTA. J., FEDRA Z., ZELINKA P.: Mikroprocesorová technika a embedded systémy - Počítačová cvičení.