attiny pwm

Mikrokontrolery ATtiny (tinyAVR-0/1/2) – PWM

Wpis dotyczy programowania układów z serii tinyAVR-0 wzwyż.

PWM (Pulse Width Modulation) to metoda generowania sygnału przez zmianę jego wypełnienia, czyli czasu trwania stanu wysokiego w jednym cyklu. Stosuje się ją do sterowania silnikami (regulacja prędkości obrotowej), diodami LED (jasność) oraz tranzystorami MOSFET (np. w przetwornicach lub układach grzewczych).

Zasada działania jest prosta: jeśli ustawimy długość impulsu na 50% okresu, to w przybliżeniu przekazujemy urządzeniu zasilanemu tym sygnałem połowę mocy dostępnej przy ciągłym napięciu o tej samej amplitudzie.

ATtiny PWM

Układy z serii tinyAVR-0+ mają zazwyczaj 4 dedykowane kanały pwm. Trzy kanały obsługuje timer TCA i jeden kanał TCB, aczkolwiek istnieje możliwość podziału 16-bitowego timera TCA, na dwa 8-bitowe co umożliwia skonfigurowanie aż sześciu kanałów pwm, tylko dla tego timera. W przypadku programowania attiny w Arudino IDE z megaTinyCore, jeden z timerów (domyślnie TCB) jest używany do obsługi funkcji micros() i millis(). Możemy to zmienić, lub całkowicie wyłączyć z rubryki „Narzędzia” w menu kontekstowym.

W przykładach poniżej używam układu attiny1614, w innych mikrokontrolerach attiny sprawa wygląda w zasadzie identycznie.

Podstawowa konfiguracja pwm (TCA0, single-slope)

Skonfigurujmy więc najpierw jeden kanał pwm posługując się timerem TCA (bez podziału), pwm w trybie single-slope.

Kod nr. 1

PORTB.DIRSET = PIN0_bm;
TCA0.SINGLE.CTRLB = TCA_SINGLE_WGMODE_SINGLESLOPE_gc | TCA_SINGLE_CMP0EN_bm;
TCA0.SINGLE.PER = 0xff;

Na samym początku, należy ustawić odpowiednie wyprowadzenie procesora jako wyjście, ja ustawiam PB0, gdyż właśnie takie wybieram niżej w konfiguracji rejestru CTRLB (CMP0EN).

attiny konfiguracja pwm ctrlb

Powyżej zawartość rejestru CTRLB, jak widać, do wyboru są trzy wyprowadzenia, by sprawdzić do jakich fizycznie pinów attiny one korespondują musimy zajrzeć do tabeli z początkowych stron noty katalogowej mikrokontrolera.

https://mcinm.pl/pliki/DS/ATtiny1614-16-17-DataSheet.pdf#_OPENTOPIC_TOC_PROCESSING_d139e8852

Zaglądamy w kolumnę od timera jaki konfigurujemy, a więc TCA0. W tej kolumnie zobaczyć możemy kilka znaczników WOn. WO, oznacza „Waveform Output”, ja wybieram pierwsze z brzegu – WO0. Jak możesz zauważyć, tych znaczników jest więcej niż 3 sztuki jak mamy do wyboru w rejestrze CTRLB. Pamiętaj, że możemy podwoić ilość wyjść PWM, poprzez wcześniej wspomniany podział timera TCA0.
Natomiast znaczniki z przyrostkiem „(3)” to alternatywne pozycje tych wyprowadzeń. Można je wprowadzić korzystając z komponentu PORTMUX.

Ostatnia linijka kodu (kod nr. 1) odpowiada za ustawienie zakresu w jakim działa nasz pwm. Ja skonfigurowałem 0-255.

I to byłoby w sumie na tyle, tak wygląda najprostsza implementacja pwm dla mikrokontrolerów attiny. Pozostaje nam wybrać preskaler zegara, włączyć timer i załadować żądaną wartością wypełnienia cyklu rejestr CMPn.

Wzór na częstotliwość zegara zliczającego PWM. N – wartość dzielnika preskalera.

Kod nr. 2

TCA0.SINGLE.CTRLA = TCA_SINGLE_CLKSEL_DIV16_gc | TCA_SINGLE_ENABLE_bm;
TCA0.SINGLE.CMP0 = 128; // Wypełnienie 50%

Na poniższym gifie możesz zauważyć przykład użycia sygnału PWM do sterowania jasnością diod LED. Dla „hecy” dodałem jeszcze drugi kanał pwm i otrzymałem w ten sposób ładny efekt policyjnego stroboskopu.

attiny pwm police strobo

Cały kod powyższego przykładu:

Kod nr. 3

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

void setup() {
  PORTB.DIRSET |= PIN0_bm | PIN1_bm;

  TCA0.SINGLE.CTRLB = TCA_SINGLE_WGMODE_SINGLESLOPE_gc | TCA_SINGLE_CMP0EN_bm | TCA_SINGLE_CMP1EN_bm;
  TCA0.SINGLE.PER = 0xff; 
  TCA0.SINGLE.CTRLA = TCA_SINGLE_CLKSEL_DIV16_gc | TCA_SINGLE_ENABLE_bm;
}

void loop() {
  for (uint8_t i=0; i<254; i++) {
    TCA0.SINGLE.CMP0 = i;
    TCA0.SINGLE.CMP1 = 254-i;
    _delay_ms(1);
  }
  for (uint8_t i=254; i>0; i--) {
    TCA0.SINGLE.CMP0 = i;
    TCA0.SINGLE.CMP1 = 254-i;
    _delay_ms(1);
  }
}

ATtiny PWM Dual-Slope (Phase Correct PWM)

Istnieje możliwość ustawienia generatora pwm w tryb działania „dual-slope” (podwójne zbocze). Jak nazwa sama wskazuje, mamy wtedy do czynienia z sygnałem dwuzboczowym.
Na poniższej grafice wyraźnie widać na czym polega sygnał o dwóch zboczach. Oba syngały finalnie generują sygnał o wypełnieniu 50%.

attiny pwm single-slope vs dual-slope

W trybie single-slope licznik timera generującego sygnał PWM zlicza w górę od 0 do wartości TOP (rejestr PER), po czym się resetuje i cykl się powtarza.
Jeżeli chodzi o dual-slope to licznik nie ulega resetowi, gdy osiągnie wartość maksymalną to zaczyna zliczać w dół (do zera). W efekcie zadana przez nas wartość rejestru CMPn wystąpi dwa razy w czasie trwania jednego cyklu.

Tryb dual-slope PWM używany jest w bardziej wymagających zastosowaniach gdzie istotna jest dokładna symetria, oraz stabilność sygnału. np. zagadnienia audio, obsługa silników. Do mniej dokładnych zastosowań single-slope będzie całkowicie wystarczające.

Poniżej prosta implementacja dual-slope.

Kod nr. 4

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

void setup() {
  PORTB.DIRSET |= PIN0_bm;

  TCA0.SINGLE.CTRLB = TCA_SINGLE_WGMODE_DSBOTTOM_gc | TCA_SINGLE_CMP0EN_bm;

  TCA0.SINGLE.PERBUF  = 0xff;    
  TCA0.SINGLE.CMP0BUF = 128;

  TCA0.SINGLE.CTRLA = TCA_SINGLE_CLKSEL_DIV16_gc | TCA_SINGLE_ENABLE_bm;
}

void loop(){
}

W powyższym przykładzie użyłem rejestrów „PERBUF” oraz „CMP0BUF”. Są to rejestry buforowe gdzie zapisujemy wartości, które zostaną automatycznie przeniesione do rejestrów właściwych po zakończeniu aktualnie trwającego cyklu.
Takie podejście nie będzie zaburzać cyklu i generować gliczy, które w przypadku bardziej krytycznych zastosowań (gdzie najpewniej użyjemy dual-slope) byłyby problematyczne.

Zamieść komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *