Napisz do mnie

Wyślij prywatną wiadomość

MODULATOR ZURA 1120 AVR

opublikowano: 8 sty 2014 wyświetleń: 7066 komentarzy: 4

#modulator #zura #syrena #straż pożarna #avr #atmel #mikrokontroler

Kopia modulatora syreny Zura 1120 na mikrokontrolerze AVR. Dobra do zastosowania w modelach.

Pomysł

W 2012 roku postanowiłem wrócić trochę do korzeni ze szkoły średniej i pobawić się elektroniką mikrokontrolerową. Nigdy nie poświęciłem temu tematowi więcej czasu i ciągle tego żałuję ;). Jako, że byłem w trakcie budowy łóżeczka dla dziecka w postaci straży pożarnej, wypadałoby zainstalować w owej straży syreny. Oczywiście można iść na łatwiznę i wstawić prostego wyjca wyrwanego z jakiejś chińskiej zabawki, ale w tego typu zabawkach zawsze denerwowała mnie zbytnia prostota, niedoskonałość dźwięku i jego powtarzalność.
Jeśli już mieć syrenę to na wzór i podobieństwo prawdziwych syren stosowanych w wozach strażackich. Po przesłuchaniu różnych filmów z YouTuba padło na modulator Zura 1120. Często taki słyszę w przejeżdżających ulicami wozach, więc dzieciak powinien być zadowolony, że ma coś "prawdziwego" :).

Zurka w "prawdziwym" wozie

W trakcie realizacji i publikacji kolejnych wersji Zurki w serwisie YouTube nawiązał ze mną kontakt Andrzej Piluch, naczelnik OSP w Wieruszowie. Andrzej miał wizję stworzenia dziecięcej drużyny strażackiej, która miała by brać udziały w pokazach strażackich. W tym celu potrzebował stworzyć miniaturę wozu strażackiego zaopatrzonego w... syrenę oczywiście. Ale o tej realizacji później.

Architektura

Pod ręką miałem zakupiony jakiś czas wcześniej mikrokontroler ATMEL AVR ATTINY44. Po krótkiej analizie instrukcji do tego, nazwijmy go umownie procka, wyszło, że powinien dać radę. Pytanie czy ja dam ;).

Stwierdziłem, że dźwięk będzie syntezowany, czyli będzie to po prostu sygnał prostokątny o zmiennej częstotliwości. Na potrzeby domowe modulator emitował będzie dźwięki za pomocą membranki piezoelektrycznej - żeby nie ogłuchnąć ;). Do wspomnianej wcześniej miniatury straży pożarnej zakupiłem okazyjnie na wrocławskiej giełdzie elektronicznej głośniczek w postaci tuby, idealnie pasujący do repliki straży pożarnej. Okazało się, że w środku był również przetwornik piezoelektryczny.

Przetwornik napędzany jest przez bufor ULN2003A, aby nie stresować zbytnio procka dużymi prądami. Bufor ten posłuży również do napędzania świateł przednich LEDowych oraz kogutów.

Poniżej wstępna wersja działającego już modulatora z tubą, o której wspominałem. Dźwięk zmieniany jest na razie jednym przyciskiem, bo póki co skupiałem się na opanowaniu timerów AVRa. Jakość dźwięku raczej słaba, bo niestety telefon nie bardzo lubi słuchać takich dźwięków. W praktyce gra równo i jak na warunki domowe dosyć głośno.

 

Poniżej kolejne wcielenie, tym razem już dodane włączniki do poszczególnych funkcji i tonów, czyli PIES, WILK, LE-ON, MIX i SYR.R. - wtejemniczeni zapewne rozpoznają dźwięki z nazwy ;). Tym razem nagranie z nieco lepszego sprzętu, ale z kolei dla równowagi w gorszym oświetleniu ;).

Po wprowadzeniu licznych poprawek i gruntownej zmiany obsługi przycisków i sterowaniu dźwiękiem powstała wersja BETA, gotowa do przeniesienie w obudowę.

Ostatecznie, wersja gotowa do zabudowy z wyprowadzonymi przewodami do podłączenia peryferiów typu głośnik, koguty, światła i oczywiście źródło zasilania. Przy okazji wyszedł mały bonus, dźwięk trąb po wciśnięciu jednocześnie dwóch przycisków co widać na filmie poniżej.

Układ zmontowałem na płytce uniwersalnej, aby nie babrać się w trawienie PCB. Obudowa trochę zbyt niska, z trudem upchałem w środku układ z przyciskami. Na płytce widać też interfejs do programowania, na wypadek poprawek w firmwarze ;).

generator syreny ZURA na avr płytka pcb

Schemat

Schemat oraz wstępny przebieg ścieżek opracowałem w programie DipTrace. Nie znałem wcześniej tego narzędzia więc był to mój debiut. Raczej jednak program nie przypadł mi do gustu.

schemat syreny zura na avr

Schemat należy traktować raczej jako drogowskaz, bo wtedy dopracowałem go tylko do własnych potrzeb, a teraz po prostu już wszystkich połączeń nie pamiętam ;).

Kod

Sam kod powstawał w języku C w środowisku AVR Studio 5, które jest oparte na IDE Visual Studio. Nie będę twierdził, że jest to szczyt inżynierii, bo w wielu miejscach wymaga jeszcze doszlifowania. Miałem ograniczony czas na zapoznanie się z platformą a po wypuszczeniu urządzenia w świat, chęci jego dalszej poprawy zmalały. Spędziłem sporo czasu nad dobraniem odpowiednich parametrów dla timerów oraz ustalenie samego ich trybu pracy.

Nie będę opisywał całego kodu, tylko jego najważniejsze fragmenty. W funkcji main() znajduje się inicjalizacja wejść i wyjść oraz pętla, w której kręci się cały program. Poniżej podana jest konfiguracja wejść i wyjść. Timer1 ustawiony jest w trybie Fast PWM a jego przerwanie powoduje zmianę stanu wyjścia OC1A na przeciwne. Przerwanie generowane jest gdy Timer1 doliczy do wartości wpisanej w rejestrze OCR1A. Zmieniając wartość w tym rejestrze można zatem sterować częstotliwością sygnału wyjściowego.


// - buttons config -------------------
// PA0 - LE-ON
// PA1 - WILK
// PA2 - PIES
// PA3 - MIX
// PA4 - SYR.R
// PA5 - światła

 // - outputs config ------------------------
// PA6 (OC1A) - piezo
// PA7 - koguty
// PB0 - LED1
// PB1 - LED2

Program nieustannie bada stan przycisków i w razie wykrycia naciśnięcia jednego z nich odpala funkcje obsługi przycisków OnButtonPressed(). Następnie wywoływana jest funkcja UpdateSireneTone(), która jak się można domyślić, aktualizuje częstotliwość generowanego sygnału zgodnie z aktualnym stanem generatora. Zmienna mixHelperCounter służy do wyliczania czasu zmiany tonu syreny na następny w trybie Mix.

    while(1)
    {
        int8_t button = ReadButtons();
        if( button )
            OnButtonPressed( button );
            
        sireneLoopCounter++;
        
        UpdateSireneTone();
        
        mixHelperCounter++;
        if( mixHelperCounter ==5 )
        {
            mixHelperCounter = 0;        
            UpdateMix();
        }        
   }

Funkcja Read Buttons() odczytuje stan portu A i nakłada maskę bitową tak aby wyfiltrować pierwsze 6 bitów, do których podłączone są przyciski.

uint8_t ReadButtons()
{
	return PINA & 63U;
}

Wynik tego działania przekazywany jest do funkcji OnButtonPressed(), która porównuje go z wartościami przypisanymi kolejnym przyciskom i uruchamia m.in. funkcję EnableSirene() z argumentem wskazującym na to jaka modulacja ma być włączona.

void OnButtonPressed(uint8_t buttons)
{
	
	if( !(buttons & ButtonLeOn) && sireneSound != SireneSound_LeOn )
	{
		EnableSirene( SireneSound_LeOn, 0 );
	}		
	else if (!(buttons  & ButtonWilk) && sireneSound != SireneSound_Wilk)
	{
		// if previus sound mode was le-on then siren starts from the lowest frequency - modulator specific behavior
		if( sireneSound & SireneSound_LeOn)
			OCR1A = max1;
		EnableSirene(SireneSound_Wilk, 0);
	}
	else if (!(buttons  & ButtonPies) && sireneSound != SireneSound_Pies)
	{
		EnableSirene(SireneSound_Pies, 0);
	}		
	else if (!(buttons  & ButtonMix))
	{
		EnableSirene( SireneSound_LeOn, 1 );
		loopCounter = 0;
	}
	else if( !(buttons  & ButtonSyr_R) && sireneSound != SireneSound_SyrR)
	{
		EnableSirene(SireneSound_SyrR, 0);
	}
	else if( !(buttons  & ButtonLights) )
	{
		_delay_loop_2(0);
		if( !(buttons & ButtonLights ))
			ToggleLights();
	}
}

Powoli dochodzimy do sedna programu ;). Funkcja EnableSirene() ustawia wartości początkowe dla poszczególnych tonów modulatora, m.in. wartości dla timera generującego określoną częstotliwość, szybkość zmian częstotliwości.

void EnableSirene(uint8_t sireneSoundToEnable, uint8_t autoMode )
{
	EnableLights();
	
	sireneConfig |= SireneEnabledFlag;
	sireneSound = sireneSoundToEnable;
	if( !autoMode )
		sireneConfig &= ~AutoChangeSoundModeFlag; 
	else sireneConfig |= AutoChangeSoundModeFlag; 
	
	TCCR1B |= _BV(CS10);	// enables timer1
	sireneLoopCounter = 0U;
	switch( sireneSoundToEnable )
	{
		case SireneSound_LeOn:
			OCR1A = min;
			sireneSpeed = 2500;
			break;
		case SireneSound_Wilk:
			sireneSpeed = 90;
			break;
		case SireneSound_Pies:
			sireneSpeed = 2;
			break;
		case SireneSound_SyrR:
			// start from the lowest frequency
			OCR1A = max1;
			sireneSpeed = 10;
			direction = -2; 
			break;
		default:
			DisableSirene();
	}
}

Występujące tutaj wartości min, max oraz wartości skalarne są dobrane tak aby częstotliwości generowane oraz szybkość zmian odpowiadały fabrycznemu generatorowi Zura. Przy modyfikacjach kodu może okazać się konieczna zmiana niektórych z nich.

Najważniejszą funkcją, która robi robotę jest UpdateSireneTone(). Wywoływana jest ona w każdym obrocie pętli głównej programu. Monitoruje ona zmienną sireneLoopCounter inkrementowaną przy każdym obrocie pętli i w zależności od trybu modulacji zmienia częstotliwość generowanego sygnału wyjściowego zmieniając zawartość rejestru OCR1A (Output Compare Register 1 Channel A).

void UpdateSireneTone()
{
	if( !(sireneConfig & SireneEnabledFlag) )
		return;
				
	if (sireneSound & SireneSound_LeOn)
	{
		if( sireneLoopCounter > sireneSpeed )
		{
			if( OCR1A == max)
				OCR1A = min;
			else
				OCR1A = max;
			
			sireneLoopCounter = 0;
		}
	}
	else if( sireneSound & SireneSound_SyrR )
	{
		if( sireneLoopCounter > sireneSpeed )
		{
			if( !(sireneLoopCounter%sireneSpeed))
				OCR1A+=direction;
				
			if(sireneLoopCounter == sireneSpeed*200)
			{
				direction = 0;
			}
			if(sireneLoopCounter == sireneSpeed*250)
				direction = 2;
				
			if( sireneLoopCounter == sireneSpeed*520)	
			{
				DisableSirene();
				sireneLoopCounter = 0;
			}		
		}		
	}
	else 
	{
		if( sireneLoopCounter > sireneSpeed )
		{
			OCR1A+=direction;

			if(OCR1A > max1)
				direction = -2;
			if(OCR1A < min1)
				direction = 2;					
			
			sireneLoopCounter = 0;
		}				
	}					
	
}

Tony Wilk i Pies są obsługiwane tak samo, poprzez inkrementację do wartości maksymalnej i minimalnej naprzemiennie. Różni się tylko szybkość zmian (zmienna sireneSpeed). Ton Le-On po odliczeniu zdefiniowanej liczby obrotów pętli zmienia częstotliwość skokowo pomiędzy wysoką i niską. Wartości min i max odpowiadające tym częstotliwością są inne niż w przypadku Wilka i Psa (min1, max1). Podobnie dla Syr.R mamy zapisany odpowiednio algorytm sterujący wartościami zmiennych aby wytworzyć charakterystyczne zakończenie nadawania sygnału dla Zury.

Z głównej pętli wywoływana jest również funkcja UpdateMix(), która w zależności od zmiennej loopCounter włącza kolejne tony modulatora za pomocą EnableSirene.

Jak widać, szybkość zmian częstotliwości zależy od czasu wykonywania pętli głównej programu, co nie jest najlepszym rozwiązaniem bo jakakolwiek ingerencja w "główny wątek" wpłynie na generowany ton. W tym konkretnym zastosowaniu to rozwiązanie wystarczyło, bo AVRek nie zajmuje się niczym więcej poza generowanie sygnału i sterowaniem światłami. Światła akurat sterowane są z przerwań Timera0 i jako, że nie miałem zbytnio czasu na inne rozwiązania to wykonałem to tak, jak tego się robić nie powinno :) - dlatego nie umieszczam tego fragmentu na stronie.

Poniżej cały kod do pobrania.

modulator-zura1120-avr.zip
downloads: 20

W praktyce

Jak wspomniałem na początku artykułu, syrenę robiłem pod konkretne "zamówienie". Miniatura wozu strażackiego dla dzieciaków z OSP Wieruszów. Premiera pokazu w ich wykonaniu odbyła się na dni Wieruszowa w czerwcu 2013.

miniaturowy wóz strażacki z syreną zura

miniaturowy wóz strażacki z syreną zura

Panel z modulatorem zamontowany został z tyłu wozu. Więcej na ten temat można znaleźć w Internecie.

Pozdrowienia dla Andrzeja i jego drużyny.


Comments (4)

  1. Z.B:
    sty 13, 2016 at 01:42

    Urządzenie jest OK! chętnie je zbuduję dla naszych młodych miłośników Straży Pożarnej
    Czy mogę liczyć na pomoc

  2. Bartek:
    sty 13, 2016 at 06:19

    Od dłuższego czasu nie zajmowałem się programowaniem mikrokontrolerów, ale jeśli będę potrafił to pomogę ;).
    W zasadzie gdybym teraz miał to robić ponownie, zastosowałbym raczej platformę Arduino - jest łatwiejsza w obsłudze i oprogramowaniu. Zamiast dźwięku generowanego można posłużyć się samplami w postaci plików wave i na ich podstawie generować ton syreny. Można też całkowicie iść na łatwiznę i wręcz odtwarzać gotowy dźwięk - ale wtedy syrena nie będzie żyła własnym życiem :).

  3. mgr:
    paź 10, 2017 at 08:59

    Świetny projekt, właśnie uzbroiłem w syrenę jeździk dla syna :)
    Do stroju strażaka brakowało mu właśnie tylko wozu bojowego :D ;)

  4. Bartek:
    paź 10, 2017 at 09:03

    @mgr czyżby udało Ci się odtworzyć projekt? Jeśli tak to chętnie obejrzę jakiś filmik pokazowy :)

  1. 1

Allowed tags: <b><i><br>


PODZIEL SIĘ

PODZIEL SIĘ