Mikrokontrolery - Jak zacząć?

... czyli zbiór praktycznej wiedzy dot. mikrokontrolerów.

środa, 23 marca 2011

Obwiednia ADSR: Regulacja czasu trwania zbocza Release by Wojcik98


Autor: Michał Wójcik
Redakcja: Dondu

Generowanie obwiedni ADSR mikrokontroler ATmega644p by Wojcik98.
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...

Rozwiązanie to nagrodziliśmy książką (w wersji eBook) wybraną przez Michała:


Kod doskonały. Jak tworzyć oprogramowanie pozbawione błędów. Wydanie II Autor: Steve McConnell.


Oceń artykuł.
Wasze opinie są dla nas ważne, gdyż pozwalają dopracować poszczególne artykuły.
Pozdrawiamy, Autorzy
Ten artykuł oceniam na:

Brak komentarzy:

Prześlij komentarz

Działy
Działy dodatkowe
Inne
O blogu




Dzisiaj
--> za darmo!!! <--
1. USBasp
2. microBOARD M8


Napisz artykuł
--> i wygraj nagrodę. <--


Co nowego na blogu?
Śledź naszego Facebook-a



Co nowego na blogu?
Śledź nas na Google+

/* 20140911 Wyłączona prawa kolumna */
  • 00

    dni

  • 00

    godzin

  • :
  • 00

    minut

  • :
  • 00

    sekund

Nie czekaj do ostatniego dnia!
Jakość opisu projektu także jest istotna (pkt 9.2 regulaminu).

Sponsorzy:

Zapamiętaj ten artykuł w moim prywatnym spisie treści.