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