Почему я всегда получаю нулевой выход ШИМ?

Я хочу вывести два разных аналоговых значения с разрешением 10 бит, то есть dac_value в диапазоне от 0 до 1023. Я использую ATmega16 с внешним кристаллом 4 МГц. Я также пробовал подключить RC-фильтр на выходе, но ничего не изменилось. У меня постоянно нулевой выход, может кто-нибудь поможет ??

#include <avr/io.h>
#include <avr/interrupt.h>

void initPWM()
{
  TCCR1A |= (1<<WGM11) | (1<<WGM10) | (1<<COM1A1) | (1<<COM1A0) | (1<<COM1B1) | (1<<COM1B0) ;
  TCCR1B |= (1<<WGM12) | (1<<CS10);
}


    uint16_t dac_value1 = 100, dac_value2 = 200;
int main(void)
{
    initPWM();
      while(1) {
      OCR1A = dac_value1;
      OCR1B = dac_value2;
          }
     for (;;) {}

 }

person Yash    schedule 04.06.2015    source источник
comment
Есть еще одна проблема: выходные данные OCR1A и OCR1B будут одинаковыми независимо от того, что dac_value1 и dac_value2 различны.   -  person Yash    schedule 05.06.2015


Ответы (1)


Вы назначаете неправильные биты неправильным регистрам. Чтобы уточнить: ШИМ - это НЕ аналоговый выход. Быстро изменяется высокое или низкое состояние выхода. Значение PWM определяет, как долго выход будет находиться в каждом состоянии (высоком или низком) в течение периода таймера.

Если вы хотите сделать «аналоговый» выход, вам нужно отфильтровать выходной сигнал, например, пропустив его через RC-фильтр, также вам нужно сделать вывод как можно быстрее, это означает, что вам нужно выбрать нижний предделитель и выбрать Режим Fast-PWM. В вашей текущей конфигурации вы получите pwm с предварительным делителем 1024. Т.е. менее 4 периодов таймера в секунду.

Итак, если вы назначите быстрый ШИМ с предварительным делителем 1 (который даст нам выходную частоту 3906 Гц) с инвертированным выходом (т.е. более высокое значение OCR1x приводит к более низкому выходному значению), это будет примерно так:

void initPWM()
{
    TCCR1A = (1<<WGM11) | (1<<WGM10) | (1<<COM1A1) | (1<<COM1A0) | (1<<COM1B1) | (1<<COM1B0); 
    // here bits WGM10 WGM11 (with WGM12 in TCCR1B) will select the Fast PWM mode with 10 bit resolution; 
    // COM1A1 COM1A0 COM1B1 COM1B0 select an inverted PWM output on pins OC1A OC1B
    TCCR1B = (1<<WGM12) | (1<<CS10);
    // CS10 will select  1:1 prescaler (i.e. 4000000/1024 timer periods per second)

    // Also, your PWM output will not be visible on corresponding pins, unless you will configure an DDR bits for these pins to output. Those pins are PD5 and PD4 on ATmega16
    DDRD |= (1 << 4) | (1 << 5);
}

Следующее, что вам нужно учитывать: когда выполнение функции main () вашего приложения достигает своего конца, оно переходит к сбросу вектора. Итак, поместите пустой цикл в конец main ():

int main(void)
{
    uint16_t dac_value1, dac_value2;
    dac_value1 = 123; // do not forget to init variables!!!
    dac_value2 = 987; 
    initPWM();
    OCR1A = dac_value1;
    OCR1B = dac_value2;
    for(;;) {
        // main loop. Now it's empty
    } 
}
person AterLux    schedule 04.06.2015
comment
Спасибо, установив правильное значение R и C, я обнаружил правильный вывод, хотя через несколько секунд времени установления. - person Yash; 05.06.2015
comment
Но вывод с обоих каналов, то есть PD4 и PD5, выходит одинаковым. - person Yash; 05.06.2015