Generowanie sygnału sinusoidalnego przy użyciu PWM

16

Nie jesteśmy w stanie poprawnie wygenerować sygnału sinusoidalnego za pomocą mikrokontrolera MC68HC908GP32 . Opis PWM zaczyna się na stronie 349. Częstotliwość taktowania wynosi 2,4 MHz, a my wykorzystaliśmy PWM 7 kHz, używając preskalera i ustawiając moduł modulo na 350 w następujący sposób:

T1SC = 0x60;    // Prescaler: Div entre 64
//Counter modulo = 0x015E = 350
T1MODH = 0x01;   // High
T1MODL = 0x5E;   // Low

Wyjście PWM jest filtrowane przez następujący filtr RLC, a następnie DC jest usuwany za pomocą nasadki serii 1uF. Częstotliwość odcięcia jest znacznie poniżej 7 kHz PWM.

wprowadź opis zdjęcia tutaj

Najpierw próbowaliśmy użyć LUT, które próbki zostały wygenerowane przy użyciu tej strony (100 próbek, amplituda = 250). Obejmuje to jeden okres.

 int seno[100]={ 125, 133, 141, 148, 156, 164, 171, 178, 185, 192, 198, 205, 211, 216, 221, 226, 231, 235, 238, 241, 244, 246, 248, 249, 250, 250, 250, 249, 248, 246, 244, 241, 238, 235, 231, 226, 221, 216, 211, 205, 198, 192, 185, 178, 171, 164, 156, 148, 141, 133, 125, 117, 109, 102, 94, 86, 79, 72, 65, 58, 52, 45, 39, 34, 29, 24, 19, 15, 12, 9, 6, 4, 2, 1, 0, 0, 0, 1, 2, 4, 6, 9, 12, 15, 19, 24, 29, 34, 39, 45, 52, 58, 65, 72, 79, 86, 94, 102, 109, 117}; 

Szerokość następującego impulsu jest obliczana dla każdego cyklu PWM:

interrupt 4 void rsi_t1ch0 (void)
{
    //-- disable interruption flag
    T1SC0&=(~0x80);
    //-- pwm to '0' 
    PTB&=0xFD;

    //some sensor measures are done here.... 100 out of the 350 cycles are left for this                
}
/************************************************************/
/* TIM1 overflow rutine                                     */
/************************************************************/
interrupt 6 void rsi_ov1 (void)
{

    T1SC&=(~0x80);
    //-- set PWM to 1
    PTB|=0x02;
    T1CH0H = ((seno[fase])>>8);   // high bits
    T1CH0L = (seno[fase])&0xFF;   // low bits
    fase+=1;
    if (fase >= 99)
      fase=0;
}

void main(void)
{
float temp;
    int i;

    CONFIG1|=0x01;  
    DDRB=0xFF;      //-- Port B is set as output
    PTB=0x00;       
    //Timer setup
    T1SC = 0x60;    // Prescaler: Div by 64  
    T1MODH = 0x01;   //Counter modulo
    T1MODL = 0x5E;  
    T1SC0 = 0x50;  //Comparator setup
    //-- Initial width
    T1CH0H = 0x00;
    T1CH0L = 0x53;

    EnableInterrupts;
    T1SC&=~(0x20); //Run timer forever
    for(;;);   
}

Po podłączeniu do zakresu otrzymujemy następujący sygnał. Nie jesteśmy w stanie uniknąć tego dziwnego szczytu w pobliżu minimum.

wprowadź opis zdjęcia tutaj

Podczas przybliżania tego piku możemy zobaczyć, jak wyjście PWM (w górę) jest w rzeczywistości nieprawidłowe.

wprowadź opis zdjęcia tutaj

Więc po tym, jak przez jakiś czas bawiliście się i nie mogąc się go pozbyć, próbowaliśmy obliczyć sygnał sinusoidalny w MCU, zamiast mocno kodować wartość dla każdej próbki. Dodaliśmy następujący kod w głównej funkcji, tuż przed wszystkimi ustawieniami licznika:

 for(i=0;i<99;i++) {
     temp=100*(sin(2*3.14159*i/100)+1);
     seno[i]=(int)temp;
 }

Ale wyniki nawet nie wyglądają jak sinusoidy:

wprowadź opis zdjęcia tutaj

Po wielu godzinach zmagania się z tym nie udało nam się znaleźć naszego błędu. Będziemy wdzięczni za radę.

Serge
źródło
Czy możesz opublikować całą listę wartości PWM?
pjc50 24.04.13
@ pjc50 Oto: pastebin.com/sNyA0Hki . Dziękuję Ci bardzo.
Serge
Spróbuj zamienić wszystkie wartości „0” pośrodku na „1”; Podejrzewam, że 0 daje ci szeroki, wysoki sygnał, a nie niski, który chcesz.
pjc50 24.04.13
@ Serge - proszę wstawić dane. Pasta może zniknąć i byłoby źle stracić część pytania. Ale sformatuj go, aby nie zajmował tyle miejsca. Dzięki.
Trygve Laugstøl
Wyraźnie nie jest to filtr - powodzenia - wygląda na to, że twój stół jest uszkodzony lub tracisz wskaźnik do niego.
Andy alias

Odpowiedzi:

16

Na dole strony 350 arkusza danych mikrokontrolera wspomniano, że zapisanie małej wartości do rejestru wartości timera podczas przerwania przepełnienia może spowodować, że następne przerwanie zostanie uruchomione tylko podczas następnej iteracji PWM, ponieważ licznik kontynuuje liczenie, podczas gdy wykonywana jest procedura przerwania.

Niezsynchronizowany zapis do rejestrów kanału TIM w celu zmiany wartości szerokości impulsu może spowodować nieprawidłowe działanie do dwóch okresów PWM. Na przykład zapisanie nowej wartości, zanim licznik osiągnie starą wartość, ale gdy licznik osiągnie nową wartość, uniemożliwia jakiekolwiek porównanie w tym okresie PWM. Również użycie procedury przerwania przepełnienia TIM do napisania nowej, mniejszej wartości szerokości impulsu może spowodować pominięcie porównania. TIM może przekazać nową wartość przed jej zapisaniem.

Potwierdza to fakt, że wartość pwm jest utrzymywana na wysokim poziomie przez cały okres zegara pwm + to, co wygląda jak długość timera (w oparciu o otaczające długości). Wartość zapisywana do rejestru długości timera jest prawdopodobnie bliska zeru w momencie błędu, więc jest całkiem realne, że licznik przekroczył mniejszą wartość podczas przerwania i uruchomiłby się dopiero w następnym cyklu.

Można to naprawić, zwiększając minimalny poziom sinusoidy do poziomu wyższego niż czas potrzebny do wykonania ISR lub zmieniając mechanizm ustalania nowego poziomu. Góra strony 351 zawiera szczegółowe informacje na temat tego, jak można to zrobić.

stanri
źródło
1
Nie wiem, jak mogłem to pominąć podczas czytania arkusza danych. Dziękuję Ci!
Serge