Licznik – tryb PWM


Tematy pokrewne   Podrozdziały
(w budowie)
  Sterowanie analogowe

 

 

Sterowanie analogowe

 
   

Mikrokontroler jest urządzeniem cyfrowym. Oznacza to, że potrafi "produkować" na swoich wyjściach jedynie sygnały cyfrowe o poziomach logicznych 1 (0,83Vcc, dla Vcc=5V równe około 4,2V) i 0 (mniej więcej 0,4V). Czasami jednak zachodzi potrzeba sterowania urządzeniami analogowymi (np. silniczki, żarówki). Urządzenia analogowe wymagają podawania im napięć o różnych wartościach. Aby uzyskać napięcia pośrednie, musimy zastosować pewną sztuczkę, która nosi nazwę Modulacji Szerokości Impulsów (ang. Pulse Width Modulation – PWM). Słowo modulacja oznacza kształtowanie, nadawanie kształtu, formy.

Na czym to polega? Otóż mikrokontroler generuje ciąg impulsów o stałej, lecz dosyć dużej częstotliwości. Impulsy te mogą posiadać różną szerokość (czas trwania) w stosunku do szerokości całego okresu:

obrazek

Stosunek czasu trwania impulsu do czasu trwania okresu nazywamy współczynnikiem wypełnienia lub po prostu wypełnieniem i najczęściej podajemy w %. Wypełnienie 0% oznacza, że impulsy wyjściowe nie występują, 25% oznacza, że impulsy wyjściowe mają długość 1/4 okresu, itd.

Średnie napięcie wyjściowe zależy od współczynnika wypełnienia i wyraża się przybliżonym wzorem:

obrazek
UO  – średnie napięcie wyjściowe
VOL  – napięcie wyjściowe dla stanu 0
VOH  – napięcie wyjściowe dla stanu 1
fPWM  – współczynnik wypełnienia 0...1

Na przykład dla fPWM = 0,5 uzyskamy średnie napięcie wyjściowe:

obrazek

Im większy współczynnik wypełnienia, tym napięcie wyjściowe jest bliższe VOH. Im niższy współczynnik wypełnienia, tym napięcie wyjściowe jest bliższe VOL. Na tej zasadzie opiera się sterowanie cyfrowe urządzeń analogowych. Spotkaliśmy się już  wcześniej z tym rozwiązaniem w programach, które regulowały jasność świecenia diod LED. To samo działanie możemy uzyskać w trybie PWM w sposób sprzętowy, tzn. bez potrzeby pisania skomplikowanego programu sterującego. Co więcej, tryb PWM działa o wiele szybciej od analogicznego trybu programowego i nie angażuje cennego czasu procesora, który może zająć się wykonywaniem czegoś innego. Wszystko opiera się na odpowiednim wykorzystaniu licznika TCNT0 oraz rejestrów porównawczych OCR0A i OCR0B, co opiszemy dokładnie w tym rozdziale.

Przejdźmy do konkretów. Wyróżniamy kilka trybów PWM. Ustawiamy je za pomocą bitów WGM00, WGM01 i WGM02 w znanych nam już rejestrach TCCR0A i TCCR0B.

bit 7 6 5 4 3 2 1 0
nazwa COM0A1 COM0A0 COM0B1 COM0B0 WGM01 WGM00
R/W R/W R/W R/W R/W R R R/W R/W
stan 0 0 0 0 0 0 0 0

Rejestr sterowania licznikiem TCCR0A

bit 7 6 5 4 3 2 1 0
nazwa FOC0A FOC0B WGM02 CS02 CS01 CS00
R/W W W R R R/W R/W R/W R/W
stan 0 0 0 0 0 0 0 0

Rejestr sterowania licznikiem TCCR0B

Bity te należy traktować jak całość, trójkę, pomimo że znajdują się w dwóch osobnych rejestrach mikrokontrolera. Dotychczas używaliśmy ich do ustawiania trybu CTC. Kombinacja trzech bitów daje 8 różnych możliwości, które dla ATTINY13 przedstawia poniższa tabelka.

Tryb WGM02 WGM01 WGM00 Zakres TCNT0 Opis
0 0 0 0 0..0xFF Tryb normalny
1 0 0 1 0...0xFF PWM poprawny fazowo
2 0 1 0 0...OCRA CTC
3 0 1 1 0...0xFF PWM szybki
4 1 0 0   Nieużywany w ATTiny13
5 1 0 1 0...OCRA PWM poprawny fazowo
6 1 1 0   Nieużywany w ATTiny13
7 1 1 1 0...OCRA PWM szybki

Trybów PWM mamy cztery (1, 3, 5 i 7). Tryby 1 i 5 nazywamy trybami PWM poprawnymi fazowo (ang. phase-correct PWM mode), a tryby 3 i 7 nazywamy trybami PWM szybkimi (ang. fast PWM mode).

 

Tryb PWM szybki

Tryb ten uzyskujemy w trybach PWM nr 3 i 7. Licznik TCNT0 liczy od 0 w górę do 255 (dla trybu nr 3) lub do wartości w rejestrze OCR0A (dla trybu 7). W trybie 3 uzyskujemy stałą częstotliwość zależną od źródła impulsów zegarowych zliczanych przez licznik (ustawienia preskalera lub źródło zewnętrzne). W trybie 7 częstotliwość może być zmieniana przez zmianę zawartości rejestru OCR0A, podobnie jak robiliśmy przy generacji dźwięków. Impulsy wyjściowe z regulowanym wypełnieniem mogą pojawiać się na wyjściach PB0 i PB1 (tryb 3) lub tylko PB1 (tryb 7). Sposób kształtowania impulsów określają bity COM0x1:0 rejestru TCCR0A:

COM0A1 COM0A0 Opis
1 0 Gdy licznik zostaje wyzerowany, wyjście OC0A (PB0) przybiera stan 1. Gdy licznik osiągnie wartość równą zawartości rejestru OCR0A, na wyjściu OC0A pojawia się stan 0.
1 1 Gdy licznik zostaje wyzerowany, wyjście OC0A (PB0) przybiera stan 0. Gdy licznik osiągnie wartość równą zawartości rejestru OCR0A, na wyjściu OC0A pojawia się stan 1. Jest to tzw. odwrócony tryb PWM.

 

COM0B1 COM0B0 Opis
1 0 Gdy licznik zostaje wyzerowany, wyjście OC0B (PB1) przybiera stan 1. Gdy licznik osiągnie wartość równą zawartości rejestru OCR0B, na wyjściu OC0B pojawia się stan 0.
1 1 Gdy licznik zostaje wyzerowany, wyjście OC0B (PB1) przybiera stan 0. Gdy licznik osiągnie wartość równą zawartości rejestru OCR0B, na wyjściu OC0B pojawia się stan 1. Jest to tzw. odwrócony tryb PWM.

Napiszmy prosty program, który zademonstruje działanie szybkiego trybu PWM nr 3. Do płytki bazowej podłącz płytkę aplikacyjną APP001. Zworki ustaw na górne położenie. Następnie prześlij do kontrolera następujący program:

/*
 * main.c
 *
 *  Created on: 14 gru 2015
 *      Author: Jerzy
 *  Opis:
 *  Program steruje jasnością świecenia diod D0 i D1
 *  za pomocą trybu PWM 3.
 *  Konfiguracja jumperów płytki APP001:
 *  J0: góra
 *  J1: góra
 */

#include <avr/io.h>
#include <util/delay.h>

int main(void)
{
    // ustawiamy PB0 i PB1 jako wyjścia
    DDRB   = (1<<PB1)|(1<<PB0);
    // ustawiamy tryb PWM 3
    // wyjście PB0 pracuje w trybie normalnym
    // wyjście PB1 pracuje w trybie odwróconym
    TCCR0A = (1<<COM0A1)|(1<<COM0B1)|(1<<COM0B0)|(1<<WGM01)|(1<<WGM00);
    // Ustawiamy rejestry porównań
    OCR0A = 255; // Maksymalna jasność diody D0
    OCR0B = 255; // Maksymalna jasność diody D1
    // Uruchamiamy licznik z maksymalną częstotliwością 1MHz
    TCCR0B = (1<<CS00);
    uint8_t d = 0;
    while (1)
    {
	if(d)
	{
	    OCR0A++; OCR0B++;
	}
	else
	{
	    OCR0A--; OCR0B--;
	}
	_delay_ms(5);
	if((OCR0A == 255)||(OCR0A == 0)) d = 1 - d;
    }
}

Program ustawia szybki tryb PWM nr 3. Licznik zlicza impulsy zegarowe o częstotliwości 1MHz. Licznik liczy od 0 do 255, po czym się przewija i liczy ponownie od 0 do 255. I tak w kółko. W programie ustawiamy rejestry porównawcze OCR0A i OCR0B. Pierwszy steruje generacją impulsów na wyjściu PB0. Drugi steruje generacją impulsów na wyjściu PB1. Na obu wyjściach częstotliwość sygnału będzie taka sama, jednakże wypełnienia tych sygnałów są niezależne od siebie. Wyjście PB0 pracuje w trybie normalnym, a wyjście PB1 pracuje w trybie odwróconym. W trybie normalnym wyjście PB0 jest ustawiane na 1, gdy licznik się zeruje. Stan ten utrzymuje się na tym wyjściu do czasu, aż licznik osiągnie wartość zapisaną w rejestrze OCR0A. Wtedy do końca okresu wyjście PB0 zostaje wyzerowane. Wyjście PB1 działa odwrotnie. Gdy licznik jest zerowany, zostaje ustawione na 0 aż do momentu, gdy licznik osiągnie wartość zapisaną w rejestrze OCR0B. Wtedy do końca okresu wyjście PB1 znajduje się w stanie 1. Ponieważ w programie zmieniamy zawartość rejestrów porównawczych OCR0A i OCR0B, powoduje to zmianę wypełnienia impulsów generowanych na wyjściach PB0 i PB1. Diody naprzemiennie płynnie zapalają się i gasną.

obrazek

Dwa rejestry porównawcze pozwalają niezależnie sterować dwoma kanałami PWM (PB0–OCR0A i PB1–OCR0B). Daje to nam możliwość sterowania dwoma urządzeniami analogowymi (np. dwoma silnikami napędzającymi koła robota). Częstotliwość wyjściowa impulsów jest równa:
obrazek

f – częstotliwość impulsów na wyjściu PBx
N – współczynnik prescalera (1, 8, 64, 256 lub 1024)

Tryb PWM 7 różni się tym, iż licznik zlicza do wartości w OCR0A, po czym się zeruje. Umożliwia to zmianę częstotliwości generowanych impulsów. Do sterowania wypełnieniem wykorzystujemy rejestr OCR0B oraz wyjście PB1. Należy jednak mieć na uwadze, że w trybie tym maleje rozdzielczość szerokości generowanych impulsów. Wyjaśnienie tego faktu jest następujące:

W trybie 3 licznik może przyjmować 256 różnych wartości od 0 do 255. Pozwala to generować impulsy o szerokości co 1/256 okresu. W trybie 7 licznik zlicza od 0 do OCR0A. Zatem może przyjmować wartości od 0 do OCR0A wartości. Rozdzielczość wynosi:

1/(OCR0A + 1)

Dla OCR0A < 255 jest ona mniejsza niż w trybie 3.

Przykład:

Dla OCR0A = 4 licznik zlicza od 0 do 4, co daje 5 różnych wartości. Przy częstotliwości impulsów zegarowych 1000000Hz uzyskamy częstotliwość impulsów PWM równą:

obrazek

Jednakże rejestr OCR0B może oddziaływać na wypełnienie impulsów tylko dla wartości od 0 do 4. Wyższe wartości nie spowodują zmiany wypełnienia, ponieważ licznik nie osiąga tych wartości. Zatem impulsy mogą mieć wypełnienie: 20%, 40%, 60%, 80% lub 100%. Dla OCR0B = 0 wypełnienie wynosi 20%. Dla OCR0B = 4 wypełnienie wynosi 100%.

 

Poniższy program jest przykładem użycia trybu nr 7. Na płytce aplikacyjnej APP001 przełącz w dół zworkę J0, aby do mikrokontrolera był podpięty przycisk na linii PB0. Prześlij do mikrokontrolera poniższy program:

/*
 * main.c
 *
 *  Created on: 14 gru 2015
 *      Author: Jerzy
 *  Opis:
 *  Program steruje jasnością świecenia diody D1
 *  w szybkim trybie PWM 7
 *  Konfiguracja jumperów płytki APP001:
 *  J0: dół
 *  J1: góra
 */

#include <avr/io.h>
#include <util/delay.h>

int main(void)
{
    // ustawiamy PB4...PB1 jako wyjścia
    DDRB   = 0b11110;
    // do PB0 podłączamy opornik podciągający
    PORTB  = 0b00001;
    // ustawiamy tryb 7 PWM
    // wyjście PB1 pracuje w trybie normalnym
    TCCR0A = (1<<COM0B1)|(1<<WGM01)|(1<<WGM00);
    // Ustawiamy rejestry porównań
    OCR0A = 7;
    OCR0B = 0;
    // Uruchamiamy licznik z maksymalną częstotliwością
    TCCR0B = (1<<WGM02)|(1 << CS00);
    while (1)
    {
	while(PINB & 1);    // czekamy na klawisz
	_delay_ms(5);       // czekamy na zaprzestanie drgań styków
	while(!(PINB & 1)); // czekamy na zwolnienie klawisza
	_delay_ms(5);       // czekamy na zaprzestanie drgań styków
	if(OCR0B == OCR0A) OCR0B = 0; // modyfikujemy wypełnienie
	else               OCR0B++;
	// na bitach PB2...PB4 ustawiamy stan rejestru OCR0B;
	PORTB = (PORTB & 0b00011)|(OCR0B << 2);
    }
}

 

Tryb PWM poprawny fazowo

W szybkim trybie PWM zmiana wypełnienia  powoduje również przesunięcie fazy sygnału (czerwona kreska na środku impulsu):

obrazek

Niektóre urządzenia (np. silniki elektryczne większej mocy) źle tolerują takie sygnały. Dlatego mikrokontrolery obsługują dodatkowy tryb, zwany trybem PWM poprawnym fazowo. W trybie tym zmiana wypełnienia zachowuje fazę sygnału:

obrazek

W trybie nr 1 licznik liczy od 0 do 255, po czym zmienia kierunek i liczy w dół do 0. Wartość maksymalna utrzymuje się przez jeden okres zliczanego sygnału. To samo odnosi się do wartości minimalnej. Zatem licznik będzie posiadał w kolejnych taktach zegarowych następujące stany:

0 1 2 ... 254 255 254 253 ... 2 1 0 1 2 ...

W trybie 5 licznik liczy od 0 do wartości w OCR0A, po czym zmienia kierunek i liczy do 0. W zależności od bitów COM0A1:0 i COM0B1:0 wyjścia PB0 i PB1 mogą być odpowiednio zmieniane, jeśli stan licznika osiągnie zawartość rejestru porównawczego:

COM0A1 COM0A0 Opis
0 0 Linia PB0 pracuje w normalny sposób.
0 1 Jeśli bit WGM02 jest ustawiony na 0, to linia PB0 pracuje w normalny sposób.
Jeśli bit WGM02 jest ustawiony na 1, to stan linii PB0 zmienia się na przeciwny zawsze, gdy licznik osiąga zawartość rejestru OCR0A.
1 0 Gdy licznik liczy w górę, to osiągnięcie zawartości OCR0A zeruje linię PB0.
Gdy licznik liczy w dół, to osiągnięcie zawartości OCR0A ustawia PB0 na 1.
1 1 Jest to tryb odwrotny do poprzedniego. Gdy licznik liczy w górę, to osiągnięcie zawartości OCR0A ustawia linię PB0 na 1.
Gdy licznik liczy w dół, to osiągnięcie zawartości OCR0A zeruje PB0.

 

COM0B1 COM0B0 Opis
0 0 Linia PB1 pracuje w normalny sposób.
0 1 Jeśli bit WGM02 jest ustawiony na 0, to linia PB1 pracuje w normalny sposób.
Jeśli bit WGM02 jest ustawiony na 1, to stan linii PB1 zmienia się na przeciwny zawsze, gdy licznik osiąga zawartość rejestru OCR0B.
1 0 Gdy licznik liczy w górę, to osiągnięcie zawartości OCR0B zeruje linię PB1.
Gdy licznik liczy w dół, to osiągnięcie zawartości OCR0B ustawia PB1 na 1.
1 1 Jest to tryb odwrotny do poprzedniego. Gdy licznik liczy w górę, to osiągnięcie zawartości OCR0B ustawia linię PB1 na 1.
Gdy licznik liczy w dół, to osiągnięcie zawartości OCR0B zeruje PB1.

Ponieważ licznik liczy w dwóch kierunkach przy jednym okresie PWM, maksymalna częstotliwość sygnału wyjściowego jest mniejsza niż w trybie PWM szybkim i wyraża się wzorem:

obrazek

f – częstotliwość impulsów na wyjściu PBx
N – współczynnik prescalera (1, 8, 64, 256 lub 1024)

Poniższy program jest modyfikacją podanego wcześniej programu dla trybu PWM szybkiego. Zmiana polega jedynie na ustawieniu trybu PWM nr 1 zamiast trybu nr 3.

/*
 * main.c
 *
 *  Created on: 14 gru 2015
 *      Author: Jerzy
 *  Opis:
 *  Program steruje jasnością świecenia diod D0 i D1
 *  Konfiguracja jumperów płytki APP001:
 *  J0: góra
 *  J1: góra
 */

#include <avr/io.h>
#include <util/delay.h>

int main(void)
{
    // ustawiamy PB0 i PB1 jako wyjścia
    DDRB   = (1<<PB1)|(1<<PB0);
    // ustawiamy tryb 1 PWM poprawny fazowo
    // wyjście PB0 pracuje w trybie normalnym
    // wyjście PB1 pracuje w trybie odwróconym
    TCCR0A = (1<<COM0A1)|(1<<COM0B1)|(1<<COM0B0)|(1<<WGM00);
    // Ustawiamy rejestry porównań
    OCR0A = 255;
    OCR0B = 255;
    // Uruchamiamy licznik z maksymalną częstotliwością 1MHz
    TCCR0B = (1 << CS00);
    uint8_t d = 0;
    while (1)
    {
	if(d)
	{
	    OCR0A++; OCR0B++;
	}
	else
	{
	    OCR0A--; OCR0B--;
	}
	_delay_ms(5);
	if((OCR0A == 255)||(OCR0A == 0)) d = 1 - d;
    }
}

 

 

 


   I Liceum Ogólnokształcące   
im. Kazimierza Brodzińskiego
w Tarnowie

©2024 mgr Jerzy Wałaszek

Dokument ten rozpowszechniany jest zgodnie z zasadami licencji
GNU Free Documentation License.

Pytania proszę przesyłać na adres email: i-lo@eduinf.waw.pl

W artykułach serwisu są używane cookies. Jeśli nie chcesz ich otrzymywać,
zablokuj je w swojej przeglądarce.
Informacje dodatkowe