Autor: Michał Wójcik
Redakcja: Dondu
Drugie rozwiązaniem konkursu generowania obwiedni ADSR z płynną regulacją czasu trwania zbocza Release zostało nadesłane przez Michała Wójcika i realizowane na mikrokontrolerze ATmega644p.
Rozwiązanie to nie zostało przeze mnie zweryfikowane, ale ponieważ dotyczy rzadziej używanego mikrokontrolera, a przesłany program był przetestowany przez autora, stąd prezentujemy je poniżej.
Do wejścia ADC0 (PA0) podłączony suwak potencjometru tworzącego dzielnik pomiędzy GND i VCC. Potencjometr służy do regulacji czasu opadania ostatniego fragmentu zbocza ADSR, zwanego Release.
Wyjścia PWM realizowane jest na pinie PD5, do którego dodany jest oczywiście filtr dolnoprzepustowy zgodnie z pierwowzorem: Generator obwiedni ADSR na mikrokontrolerze ATmega8
Do pełni szczęścia brakuje jednak obsługi pomiaru ADC, za pomocą przerwań. Michał zastosował pulling flagi ADSC, czyli czekanie w pętli na zakończenie pomiaru. O ile nie ma to wpływu na to zadanie konkursowe, o tyle w końcowej wersji syntezatora dźwięków, na takie rozwiązanie pozwolić sobie nie będziemy mogli :-)
Przesłany program:
/* * main.c * * Created on: 2013-10-07 * Autor: Wojcik98 * Mikrokontroler: ATMega644P * Częstotliwość: 16MHz */ #include <avr/io.h> #include <avr/interrupt.h> #define PWM_MIN 5 #define OBWIEDNIA_ILOSC_ODCINKOW 4 //Tablice z parametrami określającymi kształt obwiedni volatile unsigned int obwiednia_kroki[OBWIEDNIA_ILOSC_ODCINKOW]= {250, 100, 350, 300}; volatile int16_t obwiednia_nachylenie[OBWIEDNIA_ILOSC_ODCINKOW]= {((102<<8)/100), ((-1)*(102<<8)/100), 0<<8, (-1) *(1<<7)}; volatile unsigned int obwiednia_licznik_krokow = 1; volatile unsigned char obwiednia_indeks = 3; volatile uint16_t war; volatile uint8_t flag=0; uint16_t pomiar(uint8_t kanal) //funkcja pomiaru ADC { ADMUX = (ADMUX & 0xF0)|kanal; //Wybór kanalu ADCSRA |= (1<<ADSC); //Start pomiaru while(ADCSRA & (1<<ADSC)); return ADCW; } int main(void) { DDRD &= ~(1<<PD0); //Ustawiwnie PD0 na wejście PORTD |= (1<<PD0); //Podciągnięcie do VCC DDRD |= (1<<PD5); //Ustawienie PD5 na wyjście TCCR1A |= (1<<COM1A1)|(1<<COM1A0); //Wyjście timera na pin PD5 TCCR1A |= (1<<WGM10); //Tryb Fast PWM 8-bit TCCR1B |= (1<<WGM12) |(1<<CS10); //Brak Preskalera OCR1A=0; //Inicjalizacja ADC ADCSRA |= (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0); ADMUX |= (1 << REFS0); ADCSRA |= (1 << ADEN); TCCR0A |= (1<<WGM01); //Tryb CTC TCCR0B |= (1<<CS01)|(1<<CS00); //Preskaler 64 OCR0A = 250; //Zliczanie do 250: 16MHz/64/1000=250 (przrwanie co 1ms) TIMSK0 |= (1<<OCIE0A); //Włączenie przerwania od timera0 sei(); //Globalne włączenie przerwań while(1) { //Pętla nieskończona if(flag) { flag=0; obwiednia_kroki[3]=5*(pomiar(0)+1); obwiednia_nachylenie[3]=((150<<8)/(obwiednia_kroki[3]))*(-1); } } } //Procedura obsługi przerwania od Timera0 ISR(TIMER0_COMPA_vect) { //czy to już ostatnia próbka w tej części obwiedni? if(--obwiednia_licznik_krokow == 0) { //Czy to już koniec obwiedni? if(++obwiednia_indeks > (OBWIEDNIA_ILOSC_ODCINKOW-1)) { //koniec obwiedni war = 0; //ustaw minimum wypełnienia PWM obwiednia_indeks = 0; //resetuj licznik odcinków obwiedni obwiednia_licznik_krokow = obwiednia_kroki[0]; } else { flag=1; //nowy fragment obwiedni if(obwiednia_nachylenie[obwiednia_indeks]>0) { war += (obwiednia_nachylenie[obwiednia_indeks]); } else { war -= ((-1)*((obwiednia_nachylenie[obwiednia_indeks]))); } obwiednia_licznik_krokow = obwiednia_kroki[obwiednia_indeks]; } } else { //dodaj do PWM kolejny krok stopnia nachylenia if(obwiednia_nachylenie[obwiednia_indeks]>0) { war += (obwiednia_nachylenie[obwiednia_indeks]); } else { war -= ((-1)*((obwiednia_nachylenie[obwiednia_indeks]))); } } OCR1A = (war >> 8); }Do pobrania kompletny projekt AVR Studio 4.18 wraz z plikiem .hex dla kwarcu 16 MHz:
ADSR-by-Wojcik98.zip (kopia)
Zużycie pamięci:
AVR Memory Usage
----------------
Device: atmega644p
Program: 750 bytes (1.1% Full)
(.text + .data + .bootloader)
Data: 23 bytes (0.6% Full)
(.data + .bss + .noinit)
Build succeeded with 0 Warnings...
----------------
Device: atmega644p
Program: 750 bytes (1.1% Full)
(.text + .data + .bootloader)
Data: 23 bytes (0.6% Full)
(.data + .bss + .noinit)
Build succeeded with 0 Warnings...
Rozwiązanie to nagrodziliśmy książką (w wersji eBook) wybraną przez Michała:
Brak komentarzy:
Prześlij komentarz