ATtiny85 - PWM

Zápisník experimentátora

Hierarchy: ATtiny85

ATtiny85 má 3 PWM výstupy. Jsou umístěny na pinech 0, 1 a 4. V tomto článku si ukážeme, jak se PWM používá. PWM (pulse widht modulation) je zkratka pro pulzně šířkovou modulaci signálu pomocí změny střídy (šířka impulzu). Je to efektivní cesta k regulaci elektrického výkonu, dodávaného do zátěže. Uživatelé Arduina se s tímto pojmem setkávají když regulují jas LED diody, nebo otáčky ventilátoru.

V příkladech budu používat LED diodu (max 20 mA), která je připojena přes rezistor přímo na pin mikrokontroléru. Pokud byste chtěli připojit výkonnější LED diodu (1 W - 300 mA, 3W - 700 mA), museli byste použít další součástky. Dobrý příklad na to, jak to udělat, najdete v mém projektu Osvětlení RC modelu letadla. Regulování otáčkám ventilátoru se věnovat nebudeme, ale i v tomto případě platí, že musíte vědět, jaký maximální proud budete dodávat do zátěže a pokud překračuje možnosti mikrokontroléru (přibližně 20-40 mA), musíte použít další součástky.

PWM

Napsal jsem několik příkladů, které ukazují základní práci s PWM. V prvním příkladu se na všech dostupných PWM výstupech mění střídá PWM signálu od 0-255. Využívám makro NUM_DIGITAL_PINS na to, abych použil všechny digitální piny. Ne každý pin má PWM výstup a proto používám na kontrolu funkci digitalPinHasPWM. Pokud daný pin podporuje PWM, nastavím na něm PWM hodnotu pomocí funkce analogWrite.

Při tomto příkladu si všimnete, že LED dioda svítí nerovnoměrně. Máte pocit, že se strašně rychle rozsvítí a potom se už jas diody nemění. Je to způsobené tím, že lidské oko nevnímá lineární zvyšování jasu pomocí PWM jako lineární.

int pwm_value = 0;
int dms = 20;

void setup() {
  for (int i = 0; i < NUM_DIGITAL_PINS; i++)
    pinMode(i, OUTPUT);
}

void loop() {
  for (int i = 0; i < NUM_DIGITAL_PINS; i++) {
    if (digitalPinHasPWM(i))
      analogWrite(i, pwm_value);
  }

  pwm_value = (pwm_value + 1) % 255;
  delay(dms);
}

PWM s gamma korekcí

Ve druhém příkladu používám tabulku gamma korekcí na to, abych přizpůsoboval jas LED diody lidskému oku. Nyní už vaše oko lépe vnímá změnu PWM jako lineární změnu jasu. Ale není to úplně dokonalé. Pokud si prohlédnete tabulku s gamma korekcemi, všimnete si, že na začátku tabulky jsou hodnoty tak malé, že díky zaokrouhlování má mnoho položek v tabulce stejnou hodnotu. Je to způsobeno tím, že máme pouze 8-bitovou hodnotu a tak nejsme schopni použít gamma korekce s dostatečnou přesností. V příkladu se to projevuje tak, že při nízkých úrovních jasu má vaše oko pocit, že se jas mění skokově.

int pwm_value = 0;
int dms = 20;

// table of exponential values
// generated for values of i from 0 to 255 -> x=round( pow( 2.0, i/32.0) - 1);
const byte table[] PROGMEM = {
  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
  0,   0,   0,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,
  1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   2,   2,   2,   2,   2,
  2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   3,   3,   3,   3,   3,   3,
  3,   3,   3,   3,   3,   3,   4,   4,   4,   4,   4,   4,   4,   4,   4,   5,
  5,   5,   5,   5,   5,   5,   5,   6,   6,   6,   6,   6,   6,   6,   7,   7,
  7,   7,   7,   8,   8,   8,   8,   8,   9,   9,   9,   9,   9,  10,  10,  10,
 10,  11,  11,  11,  11,  12,  12,  12,  12,  13,  13,  13,  14,  14,  14,  15,
 15,  15,  16,  16,  16,  17,  17,  18,  18,  18,  19,  19,  20,  20,  21,  21,
 22,  22,  23,  23,  24,  24,  25,  25,  26,  26,  27,  28,  28,  29,  30,  30,
 31,  32,  32,  33,  34,  35,  35,  36,  37,  38,  39,  40,  40,  41,  42,  43,
 44,  45,  46,  47,  48,  49,  51,  52,  53,  54,  55,  56,  58,  59,  60,  62,
 63,  64,  66,  67,  69,  70,  72,  73,  75,  77,  78,  80,  82,  84,  86,  88,
 90,  91,  94,  96,  98, 100, 102, 104, 107, 109, 111, 114, 116, 119, 122, 124,
127, 130, 133, 136, 139, 142, 145, 148, 151, 155, 158, 161, 165, 169, 172, 176,
180, 184, 188, 192, 196, 201, 205, 210, 214, 219, 224, 229, 234, 239, 244, 250
};

void setup() {
  for (int i = 0; i < NUM_DIGITAL_PINS; i++)
    pinMode(i, OUTPUT);
}

void loop() {
  for (int i = 0; i < NUM_DIGITAL_PINS; i++) {
    if (digitalPinHasPWM(i))
      analogWrite(i, pgm_read_byte(&table[pwm_value]));
  }

  pwm_value = (pwm_value + 1) % 255;
  delay(dms);
}

PWM s posunem

Poslední příklad je už jen hra se třemi PWM výstupy. Na jednotlivých LED diodách je jas fázově posunutý a jednotlivé LED diody vytvářejí dojem, že se postupně rozsvítí a zhasnou.

int pwm_value = 0;
const int dms = 20;
const int pwm_shift = 255/3;

// table of exponential values
// generated for values of i from 0 to 255 -> x=round( pow( 2.0, i/32.0) - 1);
const byte table[] PROGMEM = {
  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
  0,   0,   0,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,
  1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   2,   2,   2,   2,   2,
  2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   3,   3,   3,   3,   3,   3,
  3,   3,   3,   3,   3,   3,   4,   4,   4,   4,   4,   4,   4,   4,   4,   5,
  5,   5,   5,   5,   5,   5,   5,   6,   6,   6,   6,   6,   6,   6,   7,   7,
  7,   7,   7,   8,   8,   8,   8,   8,   9,   9,   9,   9,   9,  10,  10,  10,
 10,  11,  11,  11,  11,  12,  12,  12,  12,  13,  13,  13,  14,  14,  14,  15,
 15,  15,  16,  16,  16,  17,  17,  18,  18,  18,  19,  19,  20,  20,  21,  21,
 22,  22,  23,  23,  24,  24,  25,  25,  26,  26,  27,  28,  28,  29,  30,  30,
 31,  32,  32,  33,  34,  35,  35,  36,  37,  38,  39,  40,  40,  41,  42,  43,
 44,  45,  46,  47,  48,  49,  51,  52,  53,  54,  55,  56,  58,  59,  60,  62,
 63,  64,  66,  67,  69,  70,  72,  73,  75,  77,  78,  80,  82,  84,  86,  88,
 90,  91,  94,  96,  98, 100, 102, 104, 107, 109, 111, 114, 116, 119, 122, 124,
127, 130, 133, 136, 139, 142, 145, 148, 151, 155, 158, 161, 165, 169, 172, 176,
180, 184, 188, 192, 196, 201, 205, 210, 214, 219, 224, 229, 234, 239, 244, 250
};

void setup() {
  for (int i = 0; i < NUM_DIGITAL_PINS; i++)
    pinMode(i, OUTPUT);
}

void loop() {
  int ii = 0;
  for (int i = 0; i < NUM_DIGITAL_PINS; i++) {
    if (digitalPinHasPWM(i)) {
      int value = pwm_value + pwm_shift*ii;
      value = (value + 1) % 255;
      analogWrite(i, pgm_read_byte(&table[value]));
      ii++;
    }
  }

  pwm_value = (pwm_value + 1) % 255;
  delay(dms);
}

Zdrojový kód

Zdrojový kód se nachází na serveru GitHub.


07.08.2018


Menu