ATtiny85 - PWM

Zápisník experimentátora

Hierarchy: ATtiny85

ATtiny85 má 3 PWM výstupy. Sú umiestnené na pinoch 0, 1 a 4. V tomto článku si ukážeme, ako sa PWM používa. PWM (pulse widht modulation) je skratka pre impulzovú šírkovú moduláciu signálu pomocou zmeny striedy (šírka impulzu). Je to efektívna cesta na regulovanie elektrického výkonu, dodávaného do záťaže. Užívatelia Arduina sa s týmto pojmom stretávajú vtedy, keď regulujú jas LED diódy, alebo otáčky ventilátora.

V príkladoch budem používať LED diódu (max 20 mA), ktorá je pripojená cez rezistor priamo na pin mikrokontroléra. Pokiaľ by ste chceli pripojiť výkonnejšiu LED diódu (1 W - 300 mA, 3W - 700 mA), museli by ste použiť ďalšie súčiastky. Dobrý príklad na to, ako to urobiť, nájdete v mojom projekte Osvetlenie RC modelu lietadla. Regulovaniu otáčkam ventilátora sa venovať nebudeme, ale aj v tomto prípade platí, že musíte vedieť, aký maximálny prúd budete dodávať do záťaze a ak prekračuje možnosti mikrokontroléra (približne 20-40 mA), musíte použiť ďalšie súčiastky.

PWM

Napísal som niekoľko príkladov, ktoré ukazujú základnú prácu s PWM. V prvom príklade sa na všetkých dostupných PWM výstupoch mení strieda PWM signálu od 0-255. Využívam makro NUM_DIGITAL_PINS na to, aby som použil všetky digitálne piny. Nie každý pin má PWM výstup a preto používam na kontrolu funkciu digitalPinHasPWM. Ak daný pin podporuje PWM, nastavím na ňom PWM hodnotu pomocou funkcie analogWrite.

Pri tomto príklade si všimnete, že LED dióda svieti nerovnomerne. Máte pocit, že sa strašne rýchlo rozsvieti a potom sa už jas diódy nemení. Je to sposobené tým, že ľudské oko nevníma lineárne zvyšovanie jasu pomocou PWM ako lineárne.

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 korekciou

V druhom príklade používam tabuľku gamma korekcií na to, aby som prispôsoboval jas LED diódy ľudskému oku. Teraz už vaše oko lepšie vníma zmenu PWM ako lineárnu zmenu jasu. Ale nie je to úplne dokonalé. Ak si pozriete tabuľku s gamma korekciami, všimnete si, že na začiatku tabuľky sú hodnoty tak malé, že vďaka zaokrúhľovaniu má veľa položiek v tabuľke rovnakú hodnotu. Je to spôsobené tým, že máme iba 8-bitovú hodnotu a tak nie sme schopní použiť gamma korekcie s dostatočnou presnosťou. V príklade sa to prejavuje tak, že pri nízkych úrovniach jasu má vaše oko pocit, že sa jas mení skokovite.

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 posunom

Posledný príklad je už len hra s tromi PWM výstupmi. Na jednotlivých LED diódach je jas fázovo posunutý a jednotlivé LED diódy vytvárajú dojem, že sa postupne rozsvietia a zhasnú.

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 sa nachádza na serveri GitHub.


07.08.2018


Menu