2014-01-27 6 views
3

Я экспериментировал с режимами генерации формы PWM на ATMega328P. Я получаю некоторые странные результаты, и я не могу понять, есть ли проблема с тем, как я пишу прошивку или как я интерпретирую datasheet.Arduino Uno PWM - Странные результаты

Вот первый кусок кода, который я написал для эмуляции функции analogWrite():

// Waveform Generation Mode 0 
// Table 15-4 of the datasheet 

void setup() 
{ 
    DDRB = (1<<PB1); // set pin 9 as output 

    TCCR1A |= (1<<COM1A1); 
    OCR1A = 125; 
} 

void loop() 
{ 
} 

Приведенный выше код производит в среднем выходное напряжение около 2,5В (49% рабочего цикла) из штифта 9 Странная вещь (для меня) заключается в том, что согласно техническому описанию TIMER1 является 16-битным таймером, поэтому он должен переполняться на 65536 тиков. Насколько я понимаю, установка OCR1A между 0 и 65535 изменит рабочий цикл импульса. Итак, установив OCR1A на 125, не должен ли я получать выход около 0,01 В вместо 2,5 В? Результаты, похоже, подразумевают, что часы переполнены на 255.

Для моего второго набега на землю PWM, я хотел попробовать создать сигнал 2.5V с использованием режима быстрой PWM ATMega. Вот что я получил:

// Waveform Generation Mode 14 
// Table 15-4 of the datasheet 

void setup() 
{ 
    DDRB = (1<<PB1); 

    TCCR1A |= (1<<COM1A1) | (1<<WGM11); 
    TCCR1B |= (1<<WGM13) | (1<<WGM12) | (1<<CS10); 

    ICR1 = 19999; 
    OCR1A = 10000; 
} 

void loop() 
{ 
} 

Я поставил ICR1 (значение переполнения) произвольно 20000 тиков затем установите OCR1A (сравниваемое значение) примерно в два раза меньше. Я установил канал A в режим без инвертирования, но (я думаю), если бы я установил его в режим инвертирования, это не имело бы значения. Когда я высветил это на Arduino, я получил постоянное напряжение в среднем 5 В (100% -ный рабочий цикл) из штыря 9, и я не могу на всю жизнь понять, почему.

Я хотел бы получить любое понимание, которое вы можете предложить.

ответ

2

Ответил joeymorin на AVRfreaks:

Обратите внимание, что на Uno, в Arduino иницилизации код, который работает до вашей установки() конфигурирует много вещей, в том числе всех трех таймеров на 328P.

От wiring.c:

sbi(TCCR0A, WGM01); 
    sbi(TCCR0A, WGM00); 
    sbi(TCCR0B, CS01); 
    sbi(TCCR0B, CS00); 
    sbi(TIMSK0, TOIE0); 

    sbi(TCCR1B, CS11); 
    sbi(TCCR1B, CS10); 
    sbi(TCCR1A, WGM10); 

    sbi(TCCR2B, CS22); 
    sbi(TCCR2A, WGM20); 

Это начинает все три таймера с делителем 64.

TIMER0 помещается в режим 3 (быстрый ШИМ) с переливом прерывания включена в службу поддержки функции синхронизации (millis(), micros() и delay()).

TIMER1 помещается в режим 1 (фиксированный 8-битный фазоинверторный PWM).

TIMER2 помещается в режим 1 (с фазоинвертором PWM).

void setup() 
{ 
    DDRB = (1<<PB1); // set pin 9 as output 

    TCCR1A |= (1<<COM1A1); 
    OCR1A = 125; 
} 

void loop() 
{ 
} 

Поскольку WGM10 в TCCR1A уже установлен, установка COM1A1 включит выход ШИМ в режиме неинвертирующим, так же, как analogWrite() будет.

TIMER1 - это таймер 16 бит, поэтому он должен переполняться на 65536 тиков. От я понимаю, что настройка OCR1A между 0 и 65535 изменит рабочий цикл импульса . Итак, установив OCR1A на 125, не должен ли я получать 0.на выходе около 0,01 В вместо 2,5 В? Результаты , кажется, подразумевают, что часы переполнены на 255.

В режиме 1 она ведет себя как 8-разрядный таймер.

void setup() 
{ 
    DDRB = (1<<PB1); 

    TCCR1A |= (1<<COM1A1) | (1<<WGM11); 
    TCCR1B |= (1<<WGM13) | (1<<WGM12) | (1<<CS10); 

    ICR1 = 19999; 
    OCR1A = 10000; 
} 

void loop() 
{ 
} 

Поскольку WGM10 в TCCR1A уже установлен, установка WGM11, WGM13 и WGM12 будет режим 15, а не в режиме 14. Режим 15 быстрый ШИМ с TOP = OCR1A (не ICR1) выбора. Поскольку вы также используете настройку вывода OC1A для PWM с COM1A1, это приведет к тому, что OC1A останется высоким.

Как уже упоминалось, если вы хотите настроить таймеры в среде Arduino, вы должны сделать это с нуля с помощью = вместо | =.

theusch писал:

И, насколько я знаю, еще может быть запущен после установки()

От main.cpp Arduino в: Код:

#include <Arduino.h> 

int main(void) 
{ 
    init(); 

#if defined(USBCON) 
    USB.attach(); 
#endif 

    setup(); 

    for (;;) { 
     loop(); 
     if (serialEventRun) serialEventRun(); 
    } 

    return 0; 
} 

JJ

1

OCR1A контроль частоты (переполнение перезапускает таймер), в то время как OCR1B управления долгом Cicle (переполнение изменения состояния выходного штырьковый)

во втором примере я не могу uderstand почему вы используете ICR1 и как возможно, вы получаете 8V в качестве выхода, поскольку arduino работает на 5V ... или вы обманываете его, или ваше чтение является неточным.

, пожалуйста, посмотрите здесь, это объяснит много вещей о PWM, быстрой PWM и многом другом.

http://arduino.cc/en/Tutorial/SecretsOfArduinoPWM

редактировать: я скучал вы используете ICR1 в ТОП и OCR1A в счетчике. Тогда проблема заключается в следующем: по умолчанию, регистры инициализируются некоторым значением библиотеками arduino. TCCR1A = 1 -> (WMG10 ON, это плохо) TCCR1B = 11 -> (предделитель = 64)

вы НЕ отвергая это значение, но просто положить 1 некоторые битном; таким образом, вместо того, чтобы activatid булавку WGM11, WMG12 и WMG13, вы также будете иметь немного WMG10 дальше, заставляя упасть на режим 15.

Также окончательный предделитель все равно будет 16 вместо 8.

Решение заключается в изменении | = с =, поэтому вы переопределите значение по умолчанию.

+0

Я согласен с тем, что 8V, вероятно, является ошибкой измерения. Но дело не в этом. Дело в том, что я получал 100% сигнал рабочего цикла, когда ожидал 50% -ный сигнал рабочего цикла. Я обновил свой пост с измеренными рабочими циклами, которые мой друг измерил с помощью его осциллографа. ICR1 - это значение переполнения (TOP) в режиме 14 таблицы 15-4 в руководстве пользователя ATMega328P, поэтому я его использовал. –

+0

editet мой ответ. Также выполняется быстрый тест, печатающий значение регистра. с вашим кодом: 4.97V, конечное значение TCCR1A 10000011 и TCCR1B = 11011 (режим предварительного предсказателя 15, 16) с коррекцией: 2,47 В, конечное значение TCCR1A 10000010 и TCCR1B = 11001 (режим 14, 8 предделитель) – Lesto

+0

Я думаю, что вы правы на этом один. Ребята на уроках AVR также участвуют в одном решении. Вы знаете, есть ли список значений по умолчанию, которые библиотеки Arduino инициализируют регистры? Я проверю это, как только у меня появится шанс. –