Kanał - ATNEL tech-forum
Wszystkie działy
Najnowsze wątki



Teraz jest 9 kwi 2026, o 05:14


Strefa czasowa: UTC + 1





Utwórz nowy wątek Odpowiedz w wątku  [ Posty: 6 ] 
Autor Wiadomość
PostNapisane: 8 lip 2016, o 15:42 
Offline
Nowy
Avatar użytkownika

Dołączył(a): 03 paź 2013
Posty: 17
Pomógł: 0

Cześć,
Mam problem z PWM sterowanym z timera1 używanym do sterowania on buzzerem. Działa to tak, że timer2 odlicza konkretny czas, aby zmienić częstotliwość dla PWM. W tablicy mam zapisane kilka zestawów częstotliwości, na które po kolei ma się przestawiać PWM, co daje w efekcie krótką melodyjkę. Na potrzeby testów zmieniłem program, żeby po wywołaniu funkcji Play wywoływał na przemian tylko dwie częstotliwości i ku memu zdumieniu działa to bardzo losowo. Np. 30 sekund gra tak jak powinien, następnie zawieszą się i przez sekundę w ogóle nie wydaje dźwięku albo nie działa jeden z tonów i efekt jest taki, że na przemian gra i cichnie. Pomierzyłem oscyloskopem i wygląda na to, że winnym jest PWM, licznik timer2 wywołuje się prawidłowo - regularnie, natomiast zachowanie PWM jest totalnie losowe. Poniżej załączam kod obsługujący buzzer oraz krótki film z obrazem z oscyloskopu oraz dźwiękiem buzzera (przyciąłem tak, żeby było widać przejście, ale dzieję się tak za każdym razem inaczej i po kolejnym losowym czasie zestaw sam znowu wraca do tonu z początku). Męczę się już z tym jakiś czas i nie mam pojęcia co tam się może dziać. Funkcja Play jest wywoływana z raspberry pi pi I2C. Ogólnie komunikacja z Atmegą działa i jej inne zadania również, więc wnioskuje, że nie zawiesza (resetuje) się cały procesor, a jedynie PWM.

Film:



Kod:
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>


#include "buzzer.h"
volatile uint16_t prescaler_timer = 0;
volatile uint8_t test = 0;
uint8_t scheme_buffer[12];

const uint8_t schemes[] PROGMEM = {
                            0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
                            0x28, 0x2A, 0xFF, 0xFF, 0x28, 0x2A, 0x28, 0x2A, 0xFF, 0xFF, 0xFF, 0xFF,
                            0x28, 0x2A, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
                            0x28, 0x2A, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
                            0x28, 0xE0, 0xFF, 0xFF, 0x28, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
                            0x28, 0xE0, 0xFF, 0xFF, 0x28, 0xE0, 0xFF, 0xFF, 0x28, 0xE0, 0xFF, 0xFF,
                            0x28, 0x2A, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
                            0x28, 0x2A, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
                            0x28, 0x2A, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
                            0x28, 0x2A, 0xFF, 0xFF, 0x28, 0x2A, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
                        };

void set_frequency(const uint8_t* params)
{
   OCR1B = *params;
   ICR1 = *(params + 1);
}

ISR (TIMER2_COMPA_vect)
{
   if(prescaler_timer % 30 == 0)
   {
      //if(prescaler_timer < 120)
         set_frequency(scheme_buffer + ((prescaler_timer / 30) % 2));
      //else
      //   prescaler_timer = 99;
   }
   if(prescaler_timer == 300)
      prescaler_timer = 0;
   prescaler_timer++;

}

void Init_buzzer()
{
   DDRB |= (1 << PB2);

   TCCR1A |= (1 << COM1B1) | (1 << WGM11);
   TCCR1B |= (1 << WGM12) | (1 << WGM13);
   
   TCCR1B |= (1 << CS11) | (1 << CS10);
   
   OCR1B = 0xFF;
   ICR1 = 0xFFFF;

   
   TCCR2A = (1 << WGM21);
   TCCR2B = (1 << CS20) | (1 << CS21) | (1 << CS22);
   TCNT2 = 0;
   OCR2A = 71;
   TIMSK2 = (1 << OCIE2A);
}

void Play(uint8_t scheme)
{
   memcpy_P(scheme_buffer, schemes + (scheme * 12), 12);
   TCNT2 = 0;
   prescaler_timer = 0;
}



Góra
 Zobacz profil  
cytowanie selektywne  Cytuj  
PostNapisane: 8 lip 2016, o 16:29 
Offline
Nowy

Dołączył(a): 01 lip 2016
Posty: 19
Pomógł: 1

Tak na pierwszy rzut oka to tylko to że skoro scheme_bufer jest wykorzystywany i w przerwaniu i nie to powinno być z volatile.

Może jakaś inna część kodu bruździ?

Pozdrawiam



Góra
 Zobacz profil  
cytowanie selektywne  Cytuj  
PostNapisane: 8 lip 2016, o 17:27 
Offline
Użytkownik

Dołączył(a): 07 cze 2016
Posty: 563
Pomógł: 143

doktur napisał(a):
Tak na pierwszy rzut oka to tylko to że skoro scheme_bufer jest wykorzystywany i w przerwaniu i nie to powinno być z volatile.
Przerwanie używa tylko wskaźnika do 'scheme_buffer', a ten jest stały, więc volatile nie jest potrzebne.

Proponowałbym spróbować tak:

Zadeklarować dwie zmienne globalne:
Składnia: [ Pobierz ] [ Ukryj ]
język c
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.


Funkcję set_frequency() zmienić na:
Składnia: [ Pobierz ] [ Ukryj ]
język c
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.


We funkcji Init_buzzer() włączyć przerwanie od przepełnienia timera 1:
Składnia: [ Pobierz ] [ Ukryj ]
język c
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.
i w procedurze obsługi tego przerwania:
Składnia: [ Pobierz ] [ Ukryj ]
język c
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.


Powinno pomóc ;)



Góra
 Zobacz profil  
cytowanie selektywne  Cytuj  
PostNapisane: 8 lip 2016, o 18:08 
Offline
Nowy
Avatar użytkownika

Dołączył(a): 03 paź 2013
Posty: 17
Pomógł: 0

Dzięki za szybkie odpowiedzi. Dopiero jutro sprawdzę jak zachowa mi się kontroler z proponowanymi zmianami, jednak mam pytanie co do rady o volatile. Samo scheme_buffer nie jest volatile, a tylko zmienna prescaler_time. Wydawało mi się, że skoro inkrementuje ją przerwanie oraz resetuje funkcja Play, to jednak trzeba użyć volatile.

Przez chwilę myślałem, że źródłem problememu jest zbyt duża częstotliwość modyfikowania rejestrów OCR1B oraz ICR1. Rozumiem, że skoro mogę to teoretycznie zmieniać przy każdym przepełnieniu timera1, to moja teoria raczej odpada?

Dodam, że wykonałem jeszcze jeden test, a mianowicie zmieniłem w przerwaniu timera2, żeby set_frequency nie było wywoływane co 20 przerwań, a co 100 i wtedy problem nie występował przez kilka minut ciągłej pracy.



Góra
 Zobacz profil  
cytowanie selektywne  Cytuj  
PostNapisane: 8 lip 2016, o 19:18 
Offline
Użytkownik

Dołączył(a): 07 cze 2016
Posty: 563
Pomógł: 143

stefan_bak napisał(a):
Przez chwilę myślałem, że źródłem problememu jest zbyt duża częstotliwość modyfikowania rejestrów OCR1B oraz ICR1. Rozumiem, że skoro mogę to teoretycznie zmieniać przy każdym przepełnieniu timera1, to moja teoria raczej odpada?

Raczej nie częstotliwość tu decyduje, a przypadkowość momentu zmiany wartości ICR1. Podejrzewam, że problem będzie podobnej natury jak w tym wątku: http://forum.atnel.pl/topic15630.html#p162736
tylko w Twoim przypadku wartość TOP znajduje się w ICR1. Rozwiązanie, które zaproponowałem, polega na tym, że w momencie zmiany ICR1 wartość TCNT1 będzie zawsze bardzo niska, więc ICR1 zawsze będzie większe. W tej chwili moment ten jest dosyć przypadkowy, bo timery 1 i 2 nie pracują synchronicznie, to znaczy mają inne interwały czasowe, które nie są prawdopodobnie podzielne przez siebie bez reszty, tym bardziej, że przecież okres zliczania timera 1 zmienia się po zmianie ICR1.


stefan_bak napisał(a):
Dodam, że wykonałem jeszcze jeden test, a mianowicie zmieniłem w przerwaniu timera2, żeby set_frequency nie było wywoływane co 20 przerwań, a co 100 i wtedy problem nie występował przez kilka minut ciągłej pracy.

Podejrzewam, że zmniejszenie częstotliwości wywołania funkcji set_frequency() to tylko zmniejszenie prawdopodobieństwa, a problem prędzej czy później i tak wystąpi. Chwila, w której to będzie następować może być zależna od melodii, czyli od wartości ICR1 z tablicy.


Autor postu otrzymał pochwałę


Góra
 Zobacz profil  
cytowanie selektywne  Cytuj  
PostNapisane: 13 lip 2016, o 00:58 
Offline
Nowy
Avatar użytkownika

Dołączył(a): 03 paź 2013
Posty: 17
Pomógł: 0

Sprawdziłem i faktycznie rozwiązanie z dodatkowym przerwaniem okazało się strzałem w dziesiątkę.

Wielkie dzięki za pomoc :)



Góra
 Zobacz profil  
cytowanie selektywne  Cytuj  
Wyświetl posty nie starsze niż:  Sortuj wg  
Utwórz nowy wątek Odpowiedz w wątku  [ Posty: 6 ] 

Strefa czasowa: UTC + 1


Kto przegląda forum

Użytkownicy przeglądający ten dział: Brak zidentyfikowanych użytkowników i 2 gości


Nie możesz rozpoczynać nowych wątków
Nie możesz odpowiadać w wątkach
Nie możesz edytować swoich postów
Nie możesz usuwać swoich postów
Nie możesz dodawać załączników

Szukaj:
Skocz do:  
Sitemap
Technologię dostarcza phpBB® Forum Software © phpBB Group phpBB3.PL
phpBB SEO