ten artykuł jest kontynuacją poprzedniego postu PWM. Dowiedz się, jak zaprogramować timery do pracy w trybie PWM! Więc zaczynajmy!
Witajcie! Kopę lat! 🙂
w poprzednim poście omówiliśmy podstawowe pojęcia PWM. Podsumujmy to najpierw:
- PWM oznacza modulację Szerokości Impulsu.
- można go wygenerować przez porównanie z góry określonego kształtu fali z poziomem napięcia odniesienia lub przez wykonanie prostych obwodów analogowych.
- Cykl pracy przebiegu PWM jest podany w następującej relacji.
- istnieją trzy tryby pracy PWM-szybkie PWM, poprawne fazowo PWM i częstotliwość i poprawne fazowo PWM
- jak wybrać timer, tryb pracy i porównać Tryb wyjściowy do generowania żądanego PWM.
weźmy Oświadczenie o problemie. Musimy wygenerować sygnał PWM 50 Hz o 45% cyklu pracy.
Analiza
biorąc pod uwagę, że
Frequency = 50 Hz
innymi słowy, okres czasu, T
T = T(on) + T(off) = 1/50 = 0.02 s = 20 ms
również, biorąc pod uwagę, że
Duty Cycle = 45%
tak więc, rozwiązując zgodnie z równaniem podanym powyżej, otrzymujemy
T(on) = 9 msT(off) = 11 ms
teraz, może to być osiągane na dwa sposoby:
- użyj timera w trybie CTC
- użyj timera w trybie PWM
Metodologia – tryb CTC
Ok, więc nie będę tutaj pisał żadnego kodu (tylko pseudo kodu). Zakładam, że po przeczytaniu moich poprzednich postów, jesteś na tyle mądry, aby napisać jeden sam! Omówimy tylko koncepcje.
po pierwsze, wybierz odpowiedni timer. Do tej aplikacji możemy wybrać dowolny z trzech timerów dostępnych w ATMEGA32. Wybierz odpowiedni przedszkolak. Następnie Ustaw timer i kontynuuj jak zwykle. Haczyk polega na tym, że musisz aktualizować wartość porównania rejestru OCRx za każdym razem. Jeden z takich sposobów jest omówiony w podanym poniżej pseudo kodzie.
jest to analogiczne do tradycyjnego migacza LED, z wyjątkiem faktu, że czasy włączania i wyłączania są różne.
Pseudo kod
#include <avr/io.h>#include <avr/interrupt.h> uint8_t count = 0; // global counter // initialize timer, interrupt and variablevoid timerX_init(){ // set up timerX with suitable prescaler and CTC mode // initialize counter // initialize compare value // enable compare interrupt // enable global interrupts} // process the ISR that is firedISR (TIMERx_COMPA_vect){ // do whatever you want to do here // say, increment the global counter count++; // check for the global counter // if count == odd, delay required = 11 ms // if count == even, delay required = 9 ms // thus, the value of the OCRx should be constantly updated if (count % 2 == 0) OCRx = 9999; // calculate and substitute appropriate value else OCRx = 10999; // calculate and substitute appropriate value} int main(void){ // initialize the output pin, say PC0 DDRC |= (1 << 0); // initialize timerX timerX_init(); // loop forever while(1) { // do nothing }}
Teraz jest to jedna z metod. I to jest bardzo nieefektywne. Możesz zwiększyć jego wydajność, pisząc lepszy kod C (pod względem składni), jednak koncepcja pozostaje taka sama. Jeśli masz inną metodę / koncepcję, zapraszamy do podzielenia się nią tutaj! 🙂
UPDATE: jeden z czytelników maxEmbedded,” coolpales ” napisał ten kod i zadziałał dla niego.
pamiętaj, że ten kod nie jest jeszcze testowany! Tak więc, jeśli ktoś z was próbuje go, czy opublikować swoje wyniki tutaj, byłbym szczęśliwy, aby je zobaczyć! 🙂
Metodologia – tryb PWM
Ok, więc teraz dowiedzmy się o trybie PWM. Tryb PWM w AVR jest sterowany sprzętowo. Oznacza to, że wszystko, przez co mam na myśli „wszystko”, jest wykonywane przez procesor AVR. Wszystko, co musisz zrobić, to zainicjować i uruchomić timer oraz ustawić cykl pracy! Fajnie, co?! Dowiedzmy się jak!
tutaj użyłem Timer0 ATMEGA32 do demonstracji. Możesz również wybrać dowolny inny timer lub mikrokontroler AVR. Teraz rzućmy okiem na rejestry.
rejestr kontrolny Tccr0 – Timer/Counter0
natrafiliśmy na ten rejestr w moim samouczku Timer0. Tutaj dowiemy się, jak ustawić odpowiednie bity, aby uruchomić timer w trybie PWM.
Tccr0 Zarejestruj
omówimy tylko te bity, które są dla nas interesujące.
- Bit 6,3 – WGM01:0 – tryb generowania przebiegów – Te bity mogą być ustawione na „00” lub „01” w zależności od typu PWM, który chcesz wygenerować. Tu jest stolik.
opis bitów trybu generowania przebiegu
- Bit 5,4-COM01: 0-Compare Match output Mode-te bity są ustawiane w celu kontrolowania zachowania Pina porównania wyjścia (OC0, pin 4 w ATMEGA32) zgodnie z bitami WGM01:0. Poniższa tabela look up określa operacje pinów OC0 dla trybu Fast PWM.
Porównaj Tryb wyjściowy, szybki tryb PWM
teraz spójrzmy na szybkie przebiegi PWM. Szczegółowe wyjaśnienie znajdziesz w moim poprzednim tutorialu.
szybkie PWM
teraz przypomnę, że AVR PWM jest w pełni sterowany sprzętowo, co oznacza, że nawet operacja porównania timera jest wykonywana przez procesor AVR. Wszystko, co musimy zrobić, to powiedzieć CPU, co zrobić, gdy dojdzie do dopasowania. Piny COM01: 0 wchodzą tutaj w grę. Widzimy, że ustawiając go na „10” lub „11”, pin wyjściowy OC0 jest ustawiony lub wyczyszczony (innymi słowy, określa, czy PWM jest w trybie odwróconym, czy w trybie nieodwracalnym).
podobnie w przypadku poprawnego PWM, tabela look up i przebiegi idą w ten sposób.
Porównaj Tryb wyjściowy, poprawny fazowo tryb PWM
Phase Correct PWM
nawet tutaj, ustawienie COM01:0 na „10” lub „11” określa zachowanie pinu OC0. Jak pokazano w kształtach, istnieją dwie instancje – jedna podczas liczenia w górę, a druga podczas liczenia w dół. Zachowanie jest wyraźnie opisane w tabeli look up.
zwróć uwagę, że OC0 jest pinem wyjściowym. Tak więc efekty WGM I COM nie wejdą w grę, chyba że rejestr DDRx jest prawidłowo ustawiony. Zobacz ten samouczek, aby uzyskać więcej informacji.
- Bit 2:0 – CS02:0 – Bit Select zegara – te bity są już omówione w samouczku Timer0.
OCR0 – Output Compare Register
natknęliśmy się nawet na ten rejestr w moim samouczku Timer0. Używamy tego rejestru do przechowywania wartości porównania. Ale kiedy używamy Timer0 w trybie PWM, zapisana w nim wartość działa jak cykl pracy (oczywiście!). W oświadczeniu o problemie, jego biorąc pod uwagę, że cykl pracy wynosi 45%, co oznacza
OCR0 = 45% of 255 = 114.75 = 115
i to wszystko! Teraz jesteśmy gotowi do napisania kodu dla niego! 🙂
Edycja: Uwaga
poniższy kod omawia sposób tworzenia sygnału PWM o żądanym cyklu pracy. Jeśli chcesz zmienić jego częstotliwość, musisz zmienić górną wartość, co można zrobić za pomocą rejestru ICRx (który nie jest obsługiwany przez 8-bitowe timery). W przypadku 16-bitowego Timer1 można go zmieniać za pomocą ICR1A. omówię o tym wkrótce, gdy omówimy kontrolę serwo.
Kod
więc oto kod. Aby dowiedzieć się więcej o operacjach portów we/wy w programie AVR, zobacz to. Aby dowiedzieć się o nieco manipulacji, zobacz to. Aby dowiedzieć się, jak korzystać z AVR Studio 5, zapoznaj się z tym. Aby dowiedzieć się, jak ten kod jest zorganizowany, Zobacz poprzedni post TIMER0.
#include <avr/io.h>#include <util/delay.h>void pwm_init(){ // initialize TCCR0 as per requirement, say as follows TCCR0 |= (1<<WGM00)|(1<<COM01)|(1<<WGM01)|(1<<CS00); // make sure to make OC0 pin (pin PB3 for atmega32) as output pin DDRB |= (1<<PB3);} void main(){ uint8_t duty; duty = 115; // duty cycle = 45% of 255 = 114.75 = 115 // initialize timer in PWM mode pwm_init(); // run forever while(1) { OCR0 = duty; }}
Oświadczenie o problemie
więc teraz weźmy inne Oświadczenie o problemie. Ten będzie bardziej praktyczny w przeciwieństwie do poprzedniego!
weźmy tradycyjny flasher LED, w którym musimy migać DIODĄ LED o określonej częstotliwości. Ale hej, czekaj, czy nie omawialiśmy tego długo w tym poście (przewiń w dół pod koniec)? Hmm, więc zmodyfikujmy to tak, aby włączyć PWM. W przeciwieństwie do tradycyjnego migacza LED (gdzie Diody LED są włączone lub wyłączone), pozwala go świecić przy maksymalnej jasności, a następnie powoli zmniejszać jego jasność, aż osiągnie zero, a następnie ponownie zwiększać jego jasność powoli, aż osiągnie maksimum.
Analiza i Kod
więc jak to zrobić? Tak, dobrze zgadłeś! Powoli zmniejszaj cykl pracy z 255 do zera, a następnie zwiększaj go z zera do 255. W zależności od cyklu pracy napięcie przyłożone do DIODY LED zmienia się, a tym samym jasność. Poniższy wzór podaje zależność między napięciem a cyklem pracy.
więc oto kod. Nie wyjaśnię tego, sam możesz to odkodować. Aby dowiedzieć się więcej o operacjach portów we/wy w programie AVR, zobacz to. Aby dowiedzieć się o nieco manipulacji, zobacz to. Aby dowiedzieć się, jak korzystać z AVR Studio 5, zapoznaj się z tym. Aby dowiedzieć się, jak ten kod jest zorganizowany, Zobacz poprzedni post TIMER0.
// program to change brightness of an LED// demonstration of PWM #include <avr/io.h>#include <util/delay.h> // initialize PWMvoid pwm_init(){ // initialize timer0 in PWM mode TCCR0 |= (1<<WGM00)|(1<<COM01)|(1<<WGM01)|(1<<CS00); // make sure to make OC0 pin (pin PB3 for atmega32) as output pin DDRB |= (1<<PB3);} void main(){ uint8_t brightness; // initialize timer0 in PWM mode pwm_init(); // run forever while(1) { // increasing brightness for (brightness = 0; brightness < 255; ++brightness) { // set the brightness as duty cycle OCR0 = brightness; // delay so as to make the user "see" the change in brightness _delay_ms(10); } // decreasing brightness for (brightness = 255; brightness > 0; --brightness) { // set the brightness as duty cycle OCR0 = brightness; // delay so as to make the user "see" the change in brightness _delay_ms(10); } // repeat this forever }}
więc tutaj kończy się mój kolejny długo oczekiwany tutorial! Następny.. Komunikacja Szeregowa! Do zobaczenia!! 🙂
i tak, jeśli masz jakieś sugestie, wątpliwości, konstruktywną krytykę itp., zapraszam do wrzucenia notki poniżej! Subskrybuj mój blog lub pobieraj kanały RSS, aby być na bieżąco!