Witam wszystkich MAJSTERKOWICZÓW!
Dziś chciałbym się pochwalić swoją pierwszą od początku do końca zaprojektowaną i wykonaną przeze mnie konstrukcją “przelaną” na płytkę PCB. Zatem jest to moja pierwsza płytka więc proszę o wyrozumiałość Konstrukcją tą jest mianowicie wskaźnik wysterowania oparty o przetwornik ADC w ATtiny13. Projekt obmyśliłem w głowie sobie sam. W internecie można znaleźć pełno gotowych rozwiązań takich wskaźników, nawet takie oparte specjalizowane do tego celu układy scalone a nawet zwykłe tranzystory, ja jednak postanowiłem że zaprzęgnę do wykonania takiego układu jakiś procek i i kilka innych scalaków.
Zamysł projektu był taki aby układ badał chwilową wartość sygnału audio np. z komputera lub przenośnego odtwarzacza i w sposób wizualny pokazywał jego wartość poprzez zapalenie odpowiedniej ilości diod. Nikomu chyba nie trzeba nic więcej mówić bo każdy się z pewnością z takim układzikiem w swym życiu spotkał, choćby w jakimś lepszym magnetofonie czy gdziekolwiek indziej.
Wymagania jakie sobie postawiłem to:
– dwa kanały
– jak najtańszy i najmniejszy procesor
– co najmniej 12 diod na kanał
– spowodować aby wskaźnik odwzorowywał rzeczywisty rytm muzyki
– zrobienie funkcji chwilowego utrzymywania wartości szczytowej
– i najważniejsze, żeby układ działał
Wybór padł na ATtiny13, aby zwiększyć ilość wyjść procesora użyłem rejestrów przesuwnych 74HC595, dobrze wszystkim znany i lubiany scalak. Ten projekt był dla mnie potrzebny również po to aby ogarnąć magistrale SPI, i bardzo się cieszę bo w mikroprocesorze zaimplementowałem programowe SPI na podstawie kodu z “Mikrokontrolery AVR Język C – podstawy programowania” autorstwa Pana Mirosława Kardasia . Z CAŁĄ STANOWCZOŚCIĄ, JEŻELI KTOŚ CHCIAŁBY ZACZĄĆ PROGRAMOWAĆ W “C “A SIĘ BOI ZACZĄĆ TO POLECAM TĄ KSIĄŻKĘ. W DODATKU AUTOR NAGRYWA TEŻ ŚWIETNE PORADNIKI DO SWOICH KSIĄŻEK I UDZIELA PEŁNEGO WSPARCIA NA DRODZE MAILOWEJ CZY TEŻ NA FORUM. ŻEBY NIE BYŁO, NIE REKLAMUJE TYLKO POLECAM :)
DZIAŁANIE UKŁADU – HARDWARE
Układzik działa następująco, sygnał audio pobrany z jakiegoś urządzenia go emitującego, trafia na potencjometr. Ze środkowej nóżki potencjometru, sygnał wędruje na wejście wzmacniacza operacyjnego LM386 (typowy wzmacniacz audio malutkiej mocy), tam jest wzmacniany ze wzmocnieniem równym 20 ( schemat połączeń do osiągnięcia takiego wzmocnienia, wzięty jest wprost z noty katalogowej układu ), później poprzez kondensator sprzęgający trafia na bazę tranzystora bipolarnego NPN BC547. Napięcie z rezystora emiterowego (wtórnik emiterowy) trafia na wejście ADC mikroprocesora. Jednak na wejście to trafia tylko dodatnia połówka sygnału ponieważ ujemna odcinana jest przez tranzystor. aby go zabezpieczyć zastosowałem szybką diodę miedzy masą a bazą spolaryzowaną zaporowo dla dodatnich połówek sygnału aby zabezpieczyć układ. Sygnał jest zatem prostowany jednopołówkowo.
Oto schemacik układu narysowany w programie EAGLE:
Głowna płytka:
Płytka z diodami:
DZIAŁANIE UKŁADU – SOFTWARE
W programie który wgrałem do procesora napięcie zmierzone na nóżkach ADC jest uśrednianie i zależnie od wartości jaką przyjmuje w danym obiegu pętli głównej następuje wysłanie poprzez programowe SPI odpowiedniej wartości w celu zaświecenia odpowiedniej ilości diod. Ot cała filozofia. Oczywiście usredniony sygnał porównywany jest z tablicą w której znajdują się logarytmy obliczone dla wartości 0db = około 0.77V. W programie jest też zapamiętywanie wartości szczytowej. Poniżej zamieszczam kod:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 |
/*//////////////////////////////////////////////////////////////////// /// \ /// /// /// ATtiny13A VU meter by Rafał T. \ /// /// ///////////////////////////////////////////////////////////////////// */ //inkludowanie bibliotek #include <avr/io.h> #include <util/delay.h> #include <avr/interrupt.h> // makra dla większej przejrzystoci kodu #define MOSI PB2 #define SCK PB1 #define CS PB0 #define SCK_0 (PORTB &=~(1<<SCK)) #define SCK_1 (PORTB |= (1<<SCK)) #define MOSI_0 (PORTB &= ~(1<<MOSI)) #define MOSI_1 (PORTB |= (1<<MOSI)) #define LATCH_ON (PORTB |= (1<<CS)) #define LATCH_OFF (PORTB &=~(1<<CS)) //deklaracje funkcji // deklaracja fukcji do odczytu z ADC uint16_t analogRead (uint8_t pin); // deklaracja funkcji do wysłania bajtu po SPI void SPI_putBYTE(uint8_t bajt); //definicje stałych //ilosc liczb z których liczona jest srednia #define TIME_BASE 60 //definicje zmiennych //zmienne do wysłania na rejsetry int16_t z2; int16_t z1; //timery uint8_t counter; uint8_t counter1; uint8_t counter2; uint8_t counter3; //zmienna licznikowa uint8_t i; //zmienne "doganiające" obliczoną iloć diod uint8_t doganianieL; uint8_t doganianieR; //zmienne z którymi porówywane są zmienne doganiające uint8_t ilosc_diod_L; uint8_t ilosc_diod_R; //zmienne potrzebne do wyciągnięcia sredniej uint16_t srednia1; uint16_t srednia2; //zmienne przechowujące wartoć szczytową uint8_t peak_L; uint8_t peak_R; //tablica z wartosciami logarytmów dla 0dB = 710 = 0.77V, skala 0d -27db d0 +3dB uint16_t log_tab[] = { 32, // -27 dB 40, // -25 dB 50, // -23 dB 63, // -21 dB 80, // -19 dB 100, // -17 dB 126, // -15 dB 159, // -13 dB 200, // -11 dB 252, // -9 dB 317, // -7 dB 399, // -5 dB 503, // -3 dB 633, // -1 dB 710, // 0 db 797, // 1 dB 1003, // 3 db }; //funkcja główna int main (void) { //////////////////////////////////////// // inicjalizacja programowego SPI //////////////////////////////////////// DDRB |= ((1<<MOSI) | (1<<CS) | (1<<SCK)); //Ustaw MOSI, SCK i LATCH jako wyjcia na porcie B /////////////////////////////////////// // inicjalizacja ADC /////////////////////////////////////// ADMUX |= (1<<REFS0); //Wybór napięcia odniesienia - w tym wypadku wewnętrzne = 1,1V ADCSRA |= (1<<ADEN); //włącznie ADC ADCSRA |= (1<<ADPS0) | (1<<ADPS1); //preskaler na 9600000/2 /////////////////////////////////////// // konfiguracja timera /////////////////////////////////////// TCCR0A |= (1<<WGM01); TCCR0B |= (1<<CS01) | (1<<CS00); TIMSK0 |= (1<<OCIE0A); OCR0A = 74; //komandor programista zezwala na przerwania ;p sei(); while(1) { // usrednianie pomiaru srednia1 = srednia1 * TIME_BASE; srednia2 = srednia2 * TIME_BASE; srednia1 = srednia1 + analogRead(0b00000010); srednia2 = srednia2 + analogRead(0b00000011); srednia1 = srednia1 / (TIME_BASE + 1); srednia2 = srednia2 / (TIME_BASE + 1); //wyliczenie ile diod z danego pomiaru ma się zapalić for ( i = 0; i <= 16; i++ ) { if ( srednia1 > log_tab[i] ) ilosc_diod_L = i; if ( srednia2 > log_tab[i] ) ilosc_diod_R = i; } //jesli wybije czas == counter zmniejsz o 1 ilosc diod do zapalenia if (!counter) { counter = 35; //czas opadania if ( doganianieL > ilosc_diod_L ) doganianieL--; if ( doganianieR > ilosc_diod_R ) doganianieR--; } //jesli wybije czas == counter1 zwiększ o 1 ilosc diod do zapalenia if (!counter1) { counter1 = 20; //czas wznoszenia if ( doganianieL < ilosc_diod_L ) doganianieL++; if ( doganianieR < ilosc_diod_R ) doganianieR++; if (peak_L < doganianieL) //jeżeli wartoć szczytowa jest mniejsza od //ilosci diod do zapalenia to { //wartosc szczytowa = ilosc diod do zapalenia peak_L = doganianieL; } if (peak_R < doganianieR ) { peak_R = doganianieR; } } if (peak_L > doganianieL) //powolne opadanie wartoci szczytowej { if (!counter2) { counter2 = 200; peak_L--; } } if (peak_R > doganianieR) { if (!counter3) { counter3 = 200; peak_R--; } } //tu ustawiamy ilosc diod obliczoną wczesniej //poprzez ustawienie odpowiedniej ilosci jedynek w bajtach z1.z2 if ( peak_L == 0 ) z1 = ((1<<doganianieL)-1); else z1 = ((1<<doganianieL)-1) | (1<<peak_L); if ( peak_R == 0 ) z2 = ((1<<doganianieR)-1); else z2 = ((1<<doganianieR)-1) | (1<<peak_R); //wyslij wartosc na rejestry przesuwne SPI_putBYTE( z1 >> 8); //Wysłanie bajtów danych SPI_putBYTE( z1); SPI_putBYTE( z2 >> 8); SPI_putBYTE( z2); LATCH_OFF; // latchowanie LATCH_ON; LATCH_OFF; } } //wysyłanie bajtu na rejsetry void SPI_putBYTE(uint8_t bajt) { uint8_t cnt = 0x80; SCK_0; while (cnt) { if ( bajt & cnt ) MOSI_1; else MOSI_0; SCK_1; SCK_0; cnt>>= 1; } } //obsługa przerwania ISR(TIM0_COMPA_vect) { if ( counter ) counter--; if ( counter1 ) counter1--; if ( counter2 ) counter2--; if ( counter3 ) counter3--; } uint16_t analogRead (uint8_t pin) { ADMUX = (0b11111100 & ADMUX) | pin; // WYBÓR PINU Z KTÓREGO CHCEMY MIEĆ POMIAR ADCSRA |= (1<<ADSC); // ZACZNIJ KONWERSJE! while (ADCSRA & (1<<ADSC)); // czekaj return ADCW; //zwróć ADCW czyli ADCH i ADCL razem; } |
Kod oczywiście nie jest napisany liniowo. Nie ma w nim żadnych głupich i bezsensownych delay’ów. Są za to przerwania, timer’y programowe i inne fajne rozwiązania. Kod jest dość dobrze zoptymalizowany :)
Kilka zdjęć z prac nad płytką PCB:
A tutaj jest spakowany cały projekt w eagle, czyli schemat + płytka PCB gdyby ktoś chciał sobie ten układzik wykonać :)
Tutaj widok płytki PCB:
WIDEO – PRZEPRASZAM ZA JAKOŚĆ ALE NIE DYSPONUJE LEPSZYM SPRZĘTEM :)
Film pokazujący działanie układu – układ bez obudowy:
Film pokazujący działanie układu – układ z obudową:
Obudowa troszkę mi nie wyszła bo nie miałem wiertarki i nie za bardzo miałem jak dziurki na diody powiercić ale jakoś wyszło :)
To chyba by było wszystko. Kod, schemat, i krótkie wyjaśnienie jak układ działa zamieściłem. Kod jest dość dobrze okomentowany więc nie powinniście mieć problemu z jego zrozumieniem:)
POZDRAWIAM I ZAPRASZAM DO KOMENTOWANIA! :)
Gratuluje ! Naprawdę świetny projekt :)
R.A.U – Pompuj;) kawałek z drugiego filmu
;)
Jak dla mnie projekt rewelacja 5/5. Jedyna uwaga dotyczy efektu końcowego: trochę krzywo te LEDy wyszły ;-) Może ciekawiej wizualnie byłoby zastosować diody prostokątne? Z tego co pamiętam za czasów Unitry był dedykowany układ scalony który robił za sterownik paska LED.
Otóż to – szkoda, że te diody tak nierówno są ;) Na przyszłość proponowałbym zrobić tak:
Dzięki punktowaniu wiertło nie będzie uciekało i wszystkie otwory będą równiutkie. Warto też wstawiać diody w takich oprawkach, jak na załączonym obrazku. Są one bardzo tanie, a znacząco podnoszą walory estetyczne :)
Diody prostokątne rzeczywiście mogłyby fajniej wyglądać, ale na pewno ciężej by było wyciąć na nie otwory w obudowie ;)
Wiem że te diody są krzywo ale niestety nie dorobiłem się jeszcze wiertarki:) jak tylko takową zakupie to poprawie obudowe i efekt będzie lepszy;)
Wiem że te diody są krzywo ale niestety nie dorobiłem się jeszcze wiertarki:) jak tylko takową zakupie to poprawie obudowe i efekt będzie lepszy;)
Wiedziałem, że i tu Cię znajdę. Projekcik świetny!
no jak widać staram się bywać tam gdzie coś fajnego się dzieję ;)
Super. Najbardziej podoba mi się, że nie arduino na płytce stykowej z jakimiś dziwnymi rysunkami, tylko goły procesorek, prawdziwy schemat i prawdziwe “C”. Podziwiam takich co im się chce :) Poza tym nie spodziwałem się, że tak krótki programik załatwi to wszystko.
Poprosiłbym do kompletu informację jak trzeba ustawić “fuse bits” (zostawiłeś “produkcyjne”?). Chyba najlepiej jakbyś to umieścił po prostu w kodzie programu gdzieś na początku.
Fusy są fabryczne. Przestawiłem tylko oscylator wewnętrzny na 9,6 MHz programem mkAVRcalcultor gdyż posiadam pełną wersję:) ale wystarczy zmienić fuse od zegara tak żeby był na 9,6 MHz pędzony;)
Program krótki ale musiałem się namęczyć żeby go tak zoptymalizować:)
Otóż to, świetny projekt na samym uP. Dla formalności dodałbym tylko
link/wzmiankę jak to wgrać na “uP” i już oczami wyobraźni widzę ten
projekt na diodach smd. Jeszcze raz gratulacje za kod.
Z pewnością na SMD wyglądałoby to lepiej ale nie umiem jeszcze dobrze THT lutować a co dopiero SMD;) elektroniką interesuję się dopiero od kilku miesięcy więc wiesz:)
A co do programu i procka…
Cóż, jak widać do sterowania 32 diodami nie trzeba ATmegi256 lub jakiegoś ARM’a;p Myślę że jak ktoś będzie się za to brał to sobie doczyta jak wgrać wsad na procek. Poradników jest milion w internecie:) tym bardziej że na wstępie napisałem o człowieku który Tworzy najlepsze:)
UHUHUHIU nie tylko ja używam kabelków od skrętki internetowej :D :D
Do robienia obudowy bez wiertarki najlepiej użyć suwmiarki (może być dobry cyrkiel z dwoma ostrymi końcami i linijka) lutownicy z ostrym grotem (musi być bliski okrągłemu, to jest drut transformatorówki się nie nada – ewentualnie gwóźdź oraz palnik kuchenki), śrubokręta krzyżakowego o rozmiarze mniejszym lub równym żądanym otworom oraz jeżeli używamy mniejszego śrubokręta okrągły pilnik. Suwmiarką wyrzynamy (po stronie wewnętrznej…) najpierw krótkie linie a potem długie (oczywiście przecinać mają się w miejscach na otwory), potrzebujemy całkiem głębokich rowków jeżeli nie mamy doświadczenia w manipulacji plastikiem. W nacięcie wcelowujemy grot i możliwie pod kątem prostym wciskamy go w plastik (warto użyć najmniejszej możliwej temperatury, im większa tym łatwiej o błąd a i więcej toksycznych gazów się wytworzy). Jak już mamy otwory bez oczyszczania krawędzi przykładamy śrubokręt od frontu i naciskając tak mocno jak tylko mamy pewność że plastik wytrzyma obracamy lekko w obie strony, pod koniec grubości naciskamy słabiej i jeżeli wszystko jest jak należy to śrubokręt wypycha zadziory z wewnętrznej strony a te z zewnętrznej usuniemy nożykiem (sporo wprawy do tego potrzeba ale efekt może wyjść idealny, po wewnętrznej stronie za to może urwać się odrobina powierzchni plastiku a i nie musi być miejsca na nóż :). Teraz ewentualnie pilnikiem (okrągłym…) powiększamy otwór i voila!
Czemu na jednym kanale inaczej diody Ci migają niż na drugim? Coś za duże są te róznice.
Zawsze możesz zrobić lepiej ;) poza tym jest to wskażnik dwukanałowy stereo. Włącz sobie np Starwais to Heaven Zeppelinów. W takim utworze jeden kanał może być np wysterowany na maksa a drugi wcale nie. Zależy od jakości utworu, zróżnicowania i wielu innych czynników ;) więc nie komentuj jeśli nie posiadasz elementarnej wiedzy w tym zakresie ;) zapewniam Cie że po zapodaniu na wskaźnik szumu różowego obie linijki świecą na takim samym poziomie ;)
ooo lubię to :D chyba sobie zrobię bo lepszy soft od tego w moim “vu metrze” na mikrofon :D
Mam jeszcze pytanko. Mogę zamiast ATtiny użyć Atmega8?
Brak danych:
Jaki stabilizator napięcia użyłeś? Drogą dedukcji zapewne LM7805?
Układ zasilany 5V?
Jaka oporność potencjometru? Tutaj już nie zgadnę a na schemacie nie podałeś :D
Można by jeszcze podać szczegółową liste części bo artykuł w tej formie jest raczej nie dla laika tylko dla ludzi znających się na rzeczy.
Płytkę można by nieco ścieśnić bo widzę tu wiele wolnej przestrzeni :D
Rezystory do diód mogły by być w pozycji stojącej to od razu mniej miejsca zajmują :)
Pozwoliłem sobie trochę zmniejszyć płytkę także prosił bym o sprawdzenie :)
https://www.dropbox.com/s/dpdedd494ks09i6/VU%20Meter%20ATtiny13.rar
Witaj;)
stabilizator to klasyczny 7805 ale mozesz dać jakąś przetworniczke tylko etedy pamietaj że +5V na procek dajesz przez dławik. Płyteczkę masz zrobioną ok, nawet ładniejsza niż moja. Ja swoją robiłem na szybko i nie miałem czasu pomysleć. Super byłoby wykonać ją w SMD.
Zasilanie 5V (7805)
potencjometr z przedziału 50-500k żeby nie obciążać za bardzo źródła sygnału. Op-ampy nie potrzebują dużego pradu na wejsciach.
Z powodzeniem możesz użyć ATmega8, trzeba bedzie zmienić jedynie pinologie i konfiguracje timerów.
Życzę powodzenia w realizacji. Kod jest oczywiście open-source i mozna go do woli kopiować, zmieniać i rozpowszechniać.
Dzięki za odpowiedź :) Płytkę jeszcze bym trochę zmniejszył ale już mi się nie chce za bardzo dłubać :D Ogólnie im mniejsza tym lepiej bo teraz chciałbym wykonać pomniejszoną wersje mojego pseudo wjumetra :D https://youtu.be/lDDc6PsInoM?list=UUH_aD9FNA3vvYEBpW6F3_MA
Fajnie też że u Ciebie jest więcej ledów. Mam już ATtiny także spróbuje jednak na nich chociaż nigdy ich nie programowałem :)
Kurcze dopiero teraz zauważyłem że nie podałeś jeszcze wartości kondensatorów :P Chyba naprawdę na szybko to wszystko robiłeś :D
Podaj mi: C11, C12, C13, C14
Przy zasilaniu masz podane ale w części analogowej chyba już zapomniałeś :)
Kondensatory sprzęgajace, odcinajace składowa stała mają wartość 100nF, sa to kondensatory C11 i C12. C13 i C14 nie sa konieczne ale lepiej je dać. Mają wartość 47nF. ;-)
Dzięki za odpowiedź. Słuchaj a czemu w eagle’u masz w miejscu C11 i C12 elektrolity a na płytce widzę ceramiczne? Także nie wiem… jakich mam użyć? Coś widzę że naprawdę na szybko to wszystko robiłeś :D
W opisie projektu napisałem ze korzystałem ze schematu podłączenia Lm386 wzietego z noty katalogowej ukladu. Tam są pokazane na wyjściu elektrolity. Ja tez takie miałem w zamiarze zastosować ale po testach dałem ceramiki małe bo zajmują mniej miejsca na płytce a efekt ten sam. Dodam jedynie ze nie warto stosować dużych pojemności bo obciążenie(baza tranzystorów) ma sporą rezystancje i zrobiłby się z tego niezły filtr dla częstości akustycznych. Wiec możesz dać elektrolita 1uF albo ceramika w przedziale 100-1000nF
Aha no rozumiem :) Jeszce tylko powiedz czy dobrze diode prostowniczą zrozumiałem… ma to być 1N4007 lub podobna?
Zmniejszyłem jeszcze trochę płytkę i podopisywałem niepodpisane elementy ;) Sprawdź jeszcze czy wszystko dobrze zrobiłem bo ja początkujący jestem i gdzieś mogłem coś popsuć chociaż mam nadzieje że nie :)
No i możesz podmienić w artykule jeśli jest ok ;)
Pliki EAGLE: https://www.dropbox.com/s/fpfb6iu1sgnfwg6/VU_Meter.rar?dl=0
Wygląda na to że jest ok;) możesz śmiało prasować ;)
Spoko, dzięki :) Dioda też pasi jak rozumiem? :)
Tak, ale mozesz dać jakąś szybszą diodę;)
z szybkich mam tylko 1N4148
Jak najbardziej będą dobre, mają czas rekombinacji liczony w dziesiątkach nanosekund więc przy częstotliwościach akustycznych (ok 20kHz) będa sobie spokojnie działać ;)