- Co to jest sygnał PWM?
- Programowanie PIC do generowania PWM na pinach GPIO
- Schemat obwodu
- Symulacja
- Konfiguracja sprzętu do sterowania serwomotorem za pomocą mikrokontrolera PIC
Generowanie sygnału PWM jest istotnym narzędziem w każdym arsenale inżynierów wbudowanych, są one bardzo przydatne w wielu zastosowaniach, takich jak sterowanie pozycją serwomotoru, przełączanie kilku układów scalonych mocy w przetwornikach / falownikach, a nawet do prostego sterowania jasnością diod LED. W mikrokontrolerach PIC sygnały PWM można generować za pomocą modułów Compare, Capture i PWM (CCP), ustawiając wymagane rejestry, dowiedzieliśmy się już, jak to zrobić w samouczku PIC PWM. Ta metoda ma jednak jedną istotną wadę.
PIC16F877A może generować sygnały PWM tylko na szpilki RC1 i RC2, jeśli używamy modułów CCP. Ale możemy napotkać sytuacje, w których potrzebujemy więcej pinów, aby mieć funkcjonalność PWM. Na przykład w moim przypadku chcę sterować 6 serwosilnikami RC dla mojego projektu ramienia robota, dla którego moduł CCP jest beznadziejny. W tych scenariuszach możemy zaprogramować piny GPIO do wytwarzania sygnałów PWM za pomocą modułów czasowych. W ten sposób możemy wygenerować dowolną liczbę sygnałów PWM z dowolnym wymaganym pinem. Istnieją również inne hacki sprzętowe, takie jak używanie multipleksera IC, ale po co inwestować w sprzęt, skoro to samo można osiągnąć poprzez programowanie. W tym samouczku nauczymy się, jak przekonwertować pin PIC GPIO na pin PWM i aby go przetestować, zasymulujemy go na proteusie za pomocą oscyloskopu cyfrowego, a takżesterować położeniem serwomotoru za pomocą sygnału PWM i zmieniać jego cykl pracy poprzez zmianę potencjometru.
Co to jest sygnał PWM?
Zanim przejdziemy do szczegółów, odświeżmy trochę, czym są Sygnały PWM. Modulacja szerokości impulsu (PWM) to sygnał cyfrowy, który jest najczęściej używany w obwodach sterujących. Ten sygnał jest ustawiony na wysoki (5 V) i niski (0 V) w określonym czasie i prędkości. Czas, w którym sygnał pozostaje wysoki, nazywany jest „czasem włączenia”, a czas, w którym sygnał pozostaje niski, nazywany jest „czasem wyłączenia”. Istnieją dwa ważne parametry PWM, jak omówiono poniżej:
Cykl pracy PWM
Procent czasu, w którym sygnał PWM pozostaje WYSOKI (w czasie) jest nazywany cyklem pracy. Jeśli sygnał jest zawsze włączony, to jest w 100% cyklu pracy, a jeśli jest zawsze wyłączony, to cykl pracy 0%.
Cykl pracy = czas włączenia / (czas włączenia + czas wyłączenia)
Nazwa zmiennej |
Odnosi się do |
PWM_Frequency |
Częstotliwość sygnału PWM |
T_TOTAL |
Całkowity czas potrzebny na jeden pełny cykl PWM |
TONA |
Na czas sygnału PWM |
ELEGANT |
Czas wyłączenia sygnału PWM |
Duty_cycle |
Cykl pracy sygnału PWM |
A teraz zróbmy matematykę.
To standardowe formuły, w których częstotliwość jest po prostu odwrotnością czasu. Wartość częstotliwości musi zostać określona i ustawiona przez użytkownika w oparciu o wymagania aplikacji.
T_TOTAL = (1 / PWM_Frequency)
Gdy użytkownik zmieni wartość cyklu pracy, nasz program powinien automatycznie dostosować czas T_ON i czas T_OFF zgodnie z tym. Zatem powyższe wzory mogą być użyte do obliczenia T_ON na podstawie wartości Duty_Cycle i T_TOTAL.
T_ON = (cykl pracy * T_TOTAL) / 100
Ponieważ Całkowity czas sygnału PWM dla jednego pełnego cyklu będzie sumą czasu włączenia i wyłączenia. Możemy obliczyć czas wyłączenia T_OFF, jak pokazano powyżej.
T_OFF = T_TOTAL - T_ON
Mając na uwadze te wzory, możemy rozpocząć programowanie mikrokontrolera PIC. Program obejmuje moduł czasowy PIC i moduł PIC ADC do tworzenia sygnału PWM w oparciu o zmienny cykl pracy zgodnie z wartością ADC z POT. Jeśli jesteś nowym użytkownikiem tych modułów, zdecydowanie zalecamy przeczytanie odpowiedniego samouczka, klikając hiperłącza.
Programowanie PIC do generowania PWM na pinach GPIO
Kompletny program na tym kursie można znaleźć na dole strony jak zawsze. W tej sekcji przyjrzyjmy się, jak program jest faktycznie napisany. Jak wszystkie programy, zaczynamy od ustawienia bitów konfiguracji. Użyłem opcji widoków pamięci, aby ustawić to za mnie.
// CONFIG #pragma config FOSC = HS // Bity wyboru oscylatora (oscylator HS) #pragma config WDTE = OFF // Watchdog Timer Enable bit (WDT wyłączony) #pragma config PWRTE = OFF // Power-up Timer Enable bit (PWRT wyłączone) #pragma config BOREN = ON // Brown-out Reset Bit Enable (włączony BOR) #pragma config LVP = OFF // Niskonapięciowe (pojedyncze zasilanie) In-Circuit Serial Programming Bit Enable (RB3 to cyfrowe we / wy, HV na MCLR musi być używany do programowania) #pragma config CPD = OFF // Bit ochrony kodu pamięci EEPROM danych (wyłączona ochrona kodu EEPROM danych) #pragma config WRT = OFF // Zapisywanie pamięci programu Flash Włącz bity (ochrona przed zapisem wyłączona; cała pamięć programu może być zapisywana przez sterowanie EECON) #pragma config CP = OFF // Bit ochrony kodu pamięci programu Flash (ochrona kodu wyłączona) // Instrukcje konfiguracyjne #pragma powinny poprzedzać dołączenie pliku projektu. // Użyj wyliczeń projektu zamiast #define do włączania i wyłączania. #zawierać
Następnie wspominamy o częstotliwości zegara używanej w sprzęcie, tutaj mój sprzęt używa kryształu 20 MHz, możesz wprowadzić wartość na podstawie twojego sprzętu. Po niej następuje wartość częstotliwości sygnału PWM. Ponieważ moim celem jest tutaj sterowanie hobbystycznym serwomotorem RC, który wymaga częstotliwości PWM 50 Hz, ustawiłem 0,05 kHz jako wartość częstotliwości, możesz ją również zmienić w zależności od wymagań aplikacji.
# zdefiniować _XTAL_FREQ 20000000 # zdefiniować PWM_Frequency 0,05 // w KHz (50Hz)
Teraz, gdy mamy wartość Częstotliwości, możemy obliczyć T_TOTAL przy użyciu wyżej omówionych wzorów. Wynik jest zmniejszany o 10, aby uzyskać wartość czasu w milisekundach. W moim przypadku wartość T_TOTAL wyniesie 2 miliardy sekund.
int T_TOTAL = (1 / PWM_Frequency) / 10; // oblicz całkowity czas na podstawie częstotliwości (w milisekundach)) // 2 ms
Następnie inicjalizujemy moduły ADC do odczytu pozycji potencjometru, jak omówiono w naszym samouczku ADC PIC. Następnie mamy procedurę obsługi przerwań, która będzie wywoływana za każdym razem, przepełnienie licznika czasu, wrócimy do tego później, na razie sprawdźmy główną funkcję.
W funkcji głównej konfigurujemy moduł timera. Tutaj skonfigurowałem moduł Timer do przepełnienia co 0,1 ms. Wartość czasu można obliczyć za pomocą poniższych wzorów
RegValue = 256 - ((Delay * Fosc) / (Prescalar * 4)) opóźnienie w sekundach i Fosc w Hz
W moim przypadku dla opóźnienia 0,0001 sekundy (0,1ms) z preskalarem 64 i Fosc 20MHz wartość mojego rejestru (TMR0) powinna wynosić 248. Tak więc konfiguracja wygląda następująco
/ ***** Konfiguracja portu dla timera ****** / OPTION_REG = 0b00000101; // Timer0 z zewnętrznym freq i 64 jako prescalar // Umożliwia również PULL UPs TMR0 = 248; // Załaduj wartość czasu dla 0.0001s; delayValue może zawierać się w przedziale 0-256, tylko TMR0IE = 1; // Włącz bit przerwania timera w rejestrze PIE1 GIE = 1; // Włącz globalne przerwanie PEIE = 1; // Włącz przerwanie peryferyjne / *********** ______ *********** /
Następnie musimy ustawić konfigurację wejścia i wyjścia. Tutaj używamy pin AN0 do odczytu wartości ADC i pinów PORTD do wyprowadzania sygnałów PWM. Więc zainicjuj je jako piny wyjściowe i zmniejsz je, używając poniższych linii kodu.
/ ***** Konfiguracja portu dla I / O ****** / TRISD = 0x00; // Poinstruuj MCU, że wszystkie piny na PORT D są wyprowadzane PORTD = 0x00; // Zainicjuj wszystkie piny na 0 / *********** ______ *********** /
Wewnątrz nieskończonej podczas pętli, musimy obliczyć wartość na czas (T_ON) z cyklu pracy. Na czas i obowiązek cyklu zmienia się w zależności od położenia POT tak robimy go wielokrotnie wewnątrz while pętli, jak pokazano poniżej. 0,0976 to wartość, którą należy pomnożyć przez 1024, aby otrzymać 100, a aby obliczyć T_ON, pomnożyliśmy ją przez 10, aby uzyskać wartość w milisekundach.
while (1) { POT_val = (ADC_Read (0)); // Odczytaj wartość POT używając ADC Duty_cycle = (POT_val * 0.0976); // Odwzoruj od 0 do 1024 do 0 do 100 T_ON = ((Duty_cycle * T_TOTAL) * 10/100); // Obliczanie czasu przy użyciu formuł w milisekundach __delay_ms (100); }
Ponieważ licznik czasu jest ustawiony na przepełnienie co 0,1 ms, procedura obsługi przerwania timera ISR będzie wywoływana co 0,1 ms. W ramach procedury serwisowej używamy zmiennej o nazwie count i zwiększamy ją co 0,1 ms. W ten sposób możemy śledzić czas. Aby dowiedzieć się więcej o przerwaniach w mikrokontrolerze PIC, skorzystaj z łączy
if (TMR0IF == 1) // Flaga timera została wyzwolona z powodu przepełnienia timera -> ustawiona na przepełnienie co 0,1 ms { TMR0 = 248; // Załaduj licznik czasu Wartość TMR0IF = 0; // Wyczyść licznik przerwania licznika czasu ++; // Zliczanie przyrostów co 0,1 ms -> count / 10 da wartość count w ms }
Wreszcie nadszedł czas, aby przełączyć pin GPIO na podstawie wartości T_ON i T_OFF. Mamy zmienną count , która śledzi czas w milisekundach. Więc używamy tej zmiennej, aby sprawdzić, czy czas jest krótszy niż w czasie , jeśli tak, to trzymamy pin GPIO włączony, w przeciwnym razie go wyłączamy i trzymamy wyłączony, aż rozpocznie się nowy cykl. Można to zrobić porównując go z całkowitym czasem jednego cyklu PWM. Kod umożliwiający to samo pokazano poniżej
if (count <= (T_ON)) // Jeśli czas jest krótszy niż w czasie RD1 = 1; // Włącz GPIO else RD1 = 0; // W przeciwnym razie wyłącz GPIO if (count> = (T_TOTAL * 10)) // Pozostaw wyłączone, dopóki nie rozpocznie się nowy cykl count = 0;
Schemat obwodu
Schemat obwodu do generowania PWM z pinem GPIO mikrokontrolera PIC jest naprawdę prosty, wystarczy zasilić PIC z oscylatorem i podłączyć potencjometr do pinu AN0, a silnik serwo do pinu RD1, możemy użyć pinu GPIO, aby uzyskać sygnał PWM, wybrałem RD1 po prostu nie przypadkowo. Zarówno potencjometr, jak i silnik serwo są zasilane napięciem 5 V, które jest regulowane z 7805, jak pokazano poniżej na schemacie obwodu.
Symulacja
Aby zasymulować projekt, użyłem mojego oprogramowania proteus. Zbuduj obwód pokazany poniżej, połącz kod ze swoją symulacją i uruchom ją. Powinieneś otrzymać sygnał PWM na pinie RD1 GPIO zgodnie z naszym programem, a cykl pracy PWM powinien być kontrolowany w oparciu o położenie potencjometru. Poniższy GIF pokazuje, jak reagują sygnał PWM i serwomotor, gdy wartość ADC jest zmieniana za pomocą potencjometru.
Konfiguracja sprzętu do sterowania serwomotorem za pomocą mikrokontrolera PIC
Moja kompletna konfiguracja sprzętu jest pokazana poniżej, dla osób, które śledzą moje samouczki, ta płyta powinna wyglądać znajomo, jest to ta sama płyta, której użyłem we wszystkich moich dotychczasowych tutorialach. Możesz skorzystać z samouczka Migająca dioda LED, jeśli chcesz wiedzieć, jak go zbudowałem. W przeciwnym razie postępuj zgodnie ze schematem obwodu powyżej i wszystko powinno działać dobrze.
Załaduj program i zmieniaj potencjometr, a powinieneś zobaczyć, jak serwo zmienia pozycję w zależności od pozycji potencjometru. Cała praca nad projektem jest pokazana na wideo zamieszczonym na końcu tej strony. Mam nadzieję, że zrozumiałeś projekt i spodobał Ci się projekt. Jeśli masz pytania, możesz je opublikować na forum, a ja postaram się odpowiedzieć.
Planuję kontynuować ten projekt, dodając opcje sterowania wieloma serwomotorami, a tym samym budując z niego ramię robota, podobne do ramienia robota Arduino, które już zbudowaliśmy. Więc do tego czasu do zobaczenia !!