PICSim.js - широтно-импульсная модуляция

В предыдущем примере светодиод либо горит либо нет т.е. работает в т.н. ключевом (цифровом) режиме. Широтно-импульсная модуляция (ШИМ) в микроконтроллерах - очень простой и эффективный способ преобразования цифрового сигнала в аналоговый с очень высоким КПД. Задавая скважность программно можно менять среднее напряжение на выходе ШИМ и тем самым формировать аналоговый сигнал любой формы. Высокий КПД ШИМ также позволяет эффективно управлять и мощной нагрузкой - моторами, нагревательными элементами. К недостаткам ШИМ стоит в первую очередь высокий уровень помех, для устранения которых можно использовать даже самую простую интегрирующую RC-цепочку.

Наиболее простой реализацией ШИМ на микроконтроллере является программная реализация, однако также программный метод получения ШИМ сигнала очень требователен к частоте работы микроконтроллера и занимает достаточно много процессорного времени. В связи с этим большинство современных микроконтроллеров имеет на борту отдельный периферийных модуль аппаратного ШИМ, работающего параллельно с основной программой, но обо всём по порядку.

hex | picsim.js

/*
  xc8 --chip=16f648A pwm.c
*/

#include <xc.h>

#pragma config WDTE = OFF

#define DUTY_MAX 12

#define _DUTY_CYCLE_RB0(value)                      \
  do {                                              \
    for (unsigned char i = 0; i < DUTY_MAX; i++) {  \
      RB0 = i < value;                              \
    }                                               \
  } while(0)

int main() {

  PORTB = TRISB = 0;

  while(1) {
    if (!RA1) {
      _DUTY_CYCLE_RB0(DUTY_MAX/4);
    } else if (!RA2) {
      _DUTY_CYCLE_RB0(DUTY_MAX/3);
    } else if (!RA3) {
      _DUTY_CYCLE_RB0(DUTY_MAX/2);
    } else if (!RA4) {
      _DUTY_CYCLE_RB0(DUTY_MAX*2/3);
    }
    // Do something useful
    // for (unsigned char i=0; --i;);
  }

  return 0;
}

Каждая кнопка RA1-RA4 при нажатии устанавливает свою яркость светодиода RB0. Поскольку частота переключения RB0 достаточно большая, человеческий глаз видит среднее значение яркости. Точно расчитать частоту переключения RB0 затруднительно т.к. тут многое зависит от компилятора - нужно смотреть в ассемблерный листинг. Также очевидно что любая дополнительная логика в // Do something useful окажет сильное влияние на итоговую скважность импульсов на выходе RB0. Аппаратный ШИМ лишен всех этих недостатков.

screenshot

Для работы модуля ШИМ требуется один таймер и модуль CCP1. На блок-схеме PIC16f648 аппаратный модуль CCP1 на ноге RB3 поэтому там и будет гореть светодиод.

hex | picsim.js

/*
  xc8 --chip=16f648A pwm.c
*/

#include <xc.h>

#pragma config WDTE = OFF

// ignore two least significant bits PWMxDCL 
#define _DUTY_CYCLE(value) \
  CCPR1L = (4*(249+1)*value)>>2

int main() {

  // http://microchip.wikidot.com/8bit:10bitpwm

  // 0b01 Prescaler is 4; 0b1xx TMR2 on
  T2CON = 0b00000101;

  // Desired PWM frequency 250Hz
  // PR2=[(Fosc)/(4∗TMR2Prescale∗PWMFrequency)]−1
  // PR2=(1Mhz/(4*4*250Hz))-1=249
  PR2 = 249;

  // 0b11xx - PWM mode;
  // assert log(1e6/249)/log(2) > 8 bit

  CCP1CON = 0b00001100;

  PORTB = TRISB = 0;

  while(1) {
    if (!RA1) {
      _DUTY_CYCLE(1/4);
    } else if (!RA2) {
      _DUTY_CYCLE(1/3);
    } else if (!RA3) {
      _DUTY_CYCLE(1/2);
    } else if (!RA4) {
      _DUTY_CYCLE(2/3);
    }
    // Do something useful
    for (unsigned char i=0; --i;);
  }

  return 0;
}

Аппаратный ШИМ не расходует ресурсы процессора и логика // Do something useful никак не влияет на яркость свечения светодиодов. Для уменьшения энергопотребления можно спокойно уменьшить тактовую частоту микроконтроллера, просто пересчитав значения регистров ШИМ.

screenshot

К тому же частоту аппаратного ШИМ в отличие от программного можно совершенно точно рассчитать на этапе проектирования системы.

Далее прерывания.

links

social