Библиотека TimerOne

Adno
Offline
Зарегистрирован: 21.09.2012

Существует такая библиотека 16-ти разрядного таймера

http://www.pjrc.com/teensy/td_libs_TimerOne.html

Использовал, работает хорошо

Обнаружил в ней функцию pwm ( pin, duty, microseconds)

Пытался запустить, результатов не обнаружил, а главное не понял почему

P.S. для сторонников analogWrite() сразу сообщаю, что надеюсь получить 16-ти разрядный PWM

Adno
Offline
Зарегистрирован: 21.09.2012

P.S.
Обращаю внимание, функция pwm работает с пинами 1,2 или 9,10

Adno
Offline
Зарегистрирован: 21.09.2012

Нашел такой вот пример у испанцев кажется

#include 

/*
    PWM Pin 10
*/

void setup () {
 
 Timer1.initialize (10000); // inizialize period
 Timer1.pwm(10,512);
 pinMode(10, OUTPUT);
 
}

void loop() {
 Timer1.start();
 delay(2000);
 Timer1.stop();
 digitalWrite(10, LOW);
 delay(500);
}

не работает

Adno
Offline
Зарегистрирован: 21.09.2012

Нашел ещё такую фигню.

Each timer controls PWM pins. While uses these libraries,
analogWrite() to those pins will not work normally, but you can use the library pwm() function.

Board                     TimerOne      TimerThree
                            PWM Pins      PWM Pins	

Teensy 3.1             3, 4               25, 32
Teensy 3.0             3, 4	
Teensy 2.0             4, 14, 15          9
Teensy++ 2.0           25, 26, 27       14, 15, 16
Arduino Uno            9, 10	
Arduino Leonardo       9, 10, 11         5
Arduino Mega           11, 12, 13        2, 3, 5
Wiring-S               4, 5	
Sanguino              12, 13	
leshak
Offline
Зарегистрирован: 29.09.2011

Если очень нужно, то можно и на других пинах получить PWM этой либой, только уже программно.

Делаете attachInterrupt на интервал поменьше, и уже в обработчике, делаете что-то типа

static volatile byte pwmCnt;
byte level=100; // уровень заполнения шима. 255 - 100%
void handler(){
  pwmCnt++;
  
  digitalWrite(PIN,pwmCnt<level);
  
}

Для скорости-точности можно digitalWrite заменить прямым управление портом.

Strangeman
Offline
Зарегистрирован: 28.11.2014

Adno пишет:
Нашел ещё такую фигню. Each timer controls PWM pins. While uses these libraries, analogWrite() to those pins will not work normally, but you can use the library pwm() function.

Board                     TimerOne      TimerThree
                            PWM Pins      PWM Pins	

Teensy 3.1             3, 4               25, 32
Teensy 3.0             3, 4	
Teensy 2.0             4, 14, 15          9
Teensy++ 2.0           25, 26, 27       14, 15, 16
Arduino Uno            9, 10	
Arduino Leonardo       9, 10, 11         5
Arduino Mega           11, 12, 13        2, 3, 5
Wiring-S               4, 5	
Sanguino              12, 13	

Возможно, давно неактуально, но не смог запустить на Arduino Mega2560, начал разбираться.

Ещё один момент — можно указывать в качестве номера пина 1 и 2 вместо 9 и 10, но здесь тоже нужно быть внимательным: если указать 1 или 2, то это сработает и на Arduino Mega (пины 11 и 12), и на простой Arduino (пины 9 и 10), но если указать 9 или 10, то сработает только на Arduino… Брр, и что только автор библиотеки курил?

Казалось бы, все ясно, но не тут то было. Я нигде не увидел, что для использования библиотекой пины нужно предварительно инициализировать на выход.

В общем, заработало так:
 

  pinMode(11, OUTPUT);
  Timer1.initialize(20);
  Timer1.pwm(1, 512);

Запустить на 13м выводе не удалось.

Для выводов 11 и 12 их нужно инициализировать на выход, а библиотеке передавать 1 или 2 соответственно.

Maverik
Offline
Зарегистрирован: 12.09.2012

Вопрос только один - а зачем весь этот огород ?

Strangeman
Offline
Зарегистрирован: 28.11.2014

Какой?

Maverik
Offline
Зарегистрирован: 12.09.2012

ну, зачем добиваться того, что аппаратно не поддерживается изначально, ведь всё равно это будет только эмуляция 16 разрядов,  зато это уже есть в arduino due ?

Strangeman
Offline
Зарегистрирован: 28.11.2014

Аппаратно не поддерживается что? 16 разрядный таймер-счетчик? Т.е. документация на контроллеры врет? Даже в Atmega8 заявлено:

One 16-bit Timer/Counter with Separate Prescaler, Compare Mode, and Capture
Mode

И что делать? Всем срочно переходить на arduino due ?

Что касается самой библиотеки - да, с ней проблем хватает, во всяком случае у меня таймер нормально не заработал. При установке тика на 100мс получил тик в 120мс.

Maverik
Offline
Зарегистрирован: 12.09.2012

а, точно, 16 разрядов.

s1292oia
Offline
Зарегистрирован: 04.09.2015

Не могу разобраться с библиотекой TimerOne. Я новичок в Arduino. Собрал самодельную плату на Atmega 8. Установил Arduino IDE 1.6.5 (OS XP). Прошил bootloader, загружал скетчи, все работает. Столкнулся с необходимостью использования библиотеки TimerOne. Скачал последнюю версию, распаковал в папку libraries. Запустил IDE, проверил, библиотека добавилась. Решил посмотреть работу библиотеки из примеров. Открыл ISRBlink из папки. Запустил компилятор и получил в ответ ошибку.  Нашел более старую версию библиотеки, заменил - результат тот же. вычитал, что может глючить новый компилятор. откатился на версию Arduino IDE 1.5.5 - результат ошибка.

Текст ошибки: Arduino: 1.5.5-r2 (Windows XP), Board: "Arduino NG or older, ATmega8"

 
C:\Program Files\Arduino\libraries\TimerOne\TimerOne.cpp: In member function 'void TimerOne::attachInterrupt(void (*)(), long int)':
C:\Program Files\Arduino\libraries\TimerOne\TimerOne.cpp:117: error: 'TIMSK1' was not declared in this scope
C:\Program Files\Arduino\libraries\TimerOne\TimerOne.cpp: In member function 'void TimerOne::detachInterrupt()':
C:\Program Files\Arduino\libraries\TimerOne\TimerOne.cpp:125: error: 'TIMSK1' was not declared in this scope
C:\Program Files\Arduino\libraries\TimerOne\TimerOne.cpp: In member function 'void TimerOne::start()':
C:\Program Files\Arduino\libraries\TimerOne\TimerOne.cpp:143: error: 'TIMSK1' was not declared in this scope
C:\Program Files\Arduino\libraries\TimerOne\TimerOne.cpp:144: error: 'GTCCR' was not declared in this scope
C:\Program Files\Arduino\libraries\TimerOne\TimerOne.cpp:144: error: 'PSRSYNC' was not declared in this scope
 
  This report would have more information with
  "Show verbose output during compilation"
  enabled in File > Preferences.
Не знаю, где копать! Остается грешить на OS, т.к. вычитал на буржуйском сайте, что была подобная проблема на MAC.
dimax
dimax аватар
Онлайн
Зарегистрирован: 25.12.2013

s1292oia, этой библой не пользуюсь, но могу прокмментировать по ошибкам - в меге8 нет перечисленных регистров. Там есть аналогичные, но они по другому называются. Соответссно можно предположить что библа не поддерживает мегу8.

s1292oia
Offline
Зарегистрирован: 04.09.2015

Спасибо за подсказку. Для проверки поменял плату в Arduino IDE на Arduino UNO и все скомпилировалось! Сейчас начну крючить библиотеку под atmega 8.

s1292oia
Offline
Зарегистрирован: 04.09.2015

Запустил библиотеку для atmega 8 добавив в файл TimerOne.cpp строки:

// enable support for ATMEGA8
#if defined(__AVR_ATmega8__)
#define TIMSK1 TIMSK
#define GTCCR SFIOR
#define PSRSYNC PSR10
#endif

Источник:http://forum.arduino.cc/index.php?topic=244553.0

Arafrael
Offline
Зарегистрирован: 12.01.2016

Уважаемые форумчена подскажите. Нужно реализовать нормальный ШИМ на Arduino, решил сделать на данной библиотеке. Покопавшись в интерете, почитал форумы статьи, вроде бы все просто. Но не тут то было, набросал тестовую програмку и понял что ничего не понял

#include <TimerOne.h>


const int shim = 11;

void setup ()
{
  Timer1.initialize (20);  // обьясните если не сложно зачем число в скобках и как оно влияет на работу, так и не разобрался
  Timer1.pwm (1, 512); //тут вроде все понятно
  pinMode (shim, OUTPUT);
  }

  void loop()

  {
    Timer1.start(); //я так понимаю когда явызвал ШИМ  он должен работать до STOP 100мс? 
    delay(100);
    Timer1.stop();
    //digitalWrite (shim, LOW); //с этой строкой светодиод вновь не загорается
    delay(1000);
    Timer1.resume();    //тут я так понимаю старт ШИМа перезапускается
    }
 
но беда в следующем, при увеличении скважности светодиод или не полностью тухнет  или горит дольше 100мс или подергается потухнет и т.д.
что не так в коде
 
ПС и если не затруднит еще одно  все это у меня должно работать по нажатию на кнопку (нажал кнопку ШИМ проработал n-времени и остановился, но эта фигня также не заработала)
 
ПСПС Спасибо всем кто отпишется
Blackhock
Offline
Зарегистрирован: 09.02.2018

Подскажите, пожалуйста, как переделать в библиотеку TimerOne так, чтобы на его выходных выходах (Ардуино МЕГА) можно было менять вместо скважинных импульсов, фазных импульсов в пределах 0-1023 значения должны быть не изменены 50%. Ввод TimerOne.h, но сам не могу мало опыта.

  Что сдесь нужно изменить?

/ *
 * Утилиты прерывания и ШИМ для 16-битного Таймера1 на ATmega168 / 328
 * Оригинальный код Джесси Тейна для http://labs.ideo.com Август 2008
 * Изменено в марте 2009 года Жеромом Деспати и Джесси Таном для поддержки ATmega328
 * Изменено в июне 2009 года Майклом Полли и Джесси Тейном для исправления ошибки в setPeriod (), которая приводила к остановке таймера
 * Изменено в апреле 2012 года Полом Стоффрегеном - перенос на другие чипы AVR, использует встроенные функции
 * Изменено снова, июнь 2014 года Полом Стоффрегеном - поддержка Teensy 3.x и даже больше чипов AVR
 *  
 *
 * Это бесплатное программное обеспечение. Вы можете распространять его и / или изменять его в разделе
 * условия лицензии Creative Commons Attribution 3.0 United States. 
 * Чтобы просмотреть копию этой лицензии, посетите http://creativecommons.org/licenses/by/3.0/us/ 
 * или отправьте письмо в Creative Commons, 171 Second Street, Suite 300, Сан-Франциско, Калифорния, 94105, США.
 *
 * /

#ifndef TimerOne_h_
#define TimerOne_h_

#iffined (ARDUINO) && ARDUINO> = 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif

#include "config / known_16bit_timers.h"

#define TIMER1_RESOLUTION 65536UL // Таймер1 16-битный


// Размещение почти всего кода в этом .h файле позволяет функциям быть
// встроено компилятором. В очень распространенном случае с постоянными значениями
// компилятор выполнит все вычисления и просто напишет константы
// к аппаратным регистрам (например, setPeriod).


класс TimerOne
{


#iffined (__ AVR__)
  общественности:
    // ****************************
    // Конфигурация
    // ****************************
    void initialize (unsigned long microseconds = 1000000) __attribute __ ((always_inline)) {
	TCCR1B = _BV (WGM13); // установить режим как фазу и частоту правильного ШИМ, остановить таймер
	TCCR1A = 0; // очистить регистр управления A
	setPeriod (микросекунды);
    }
    void setPeriod (беззнаковые длинные микросекунды) __attribute __ ((always_inline)) {
	const беззнаковые длинные циклы = (F_CPU / 2000000) * микросекунды;
	if (циклы <TIMER1_RESOLUTION) {
		clockSelectBits = _BV (CS10);
		pwmPeriod = циклы;
	} еще
	if (циклы <TIMER1_RESOLUTION * 8) {
		clockSelectBits = _BV (CS11);
		pwmPeriod = циклов / 8;
	} еще
	if (циклы <TIMER1_RESOLUTION * 64) {
		clockSelectBits = _BV (CS11) | _BV (CS10);
		pwmPeriod = циклов / 64;
	} еще
	if (циклы <TIMER1_RESOLUTION * 256) {
		clockSelectBits = _BV (CS12);
		pwmPeriod = циклов / 256;
	} еще
	if (циклы <TIMER1_RESOLUTION * 1024) {
		clockSelectBits = _BV (CS12) | _BV (CS10);
		pwmPeriod = циклов / 1024;
	} еще {
		clockSelectBits = _BV (CS12) | _BV (CS10);
		pwmPeriod = TIMER1_RESOLUTION - 1;
	}
	ICR1 = pwmPeriod;
	TCCR1B = _BV (WGM13) | clockSelectBits;
    }

    // ****************************
    // Запуск управления
    // ****************************
    void start () __attribute __ ((always_inline)) {
	TCCR1B = 0;
	TCNT1 = 0; // TODO: это вызывает нежелательное прерывание?
	продолжить();
    }
    void stop () __attribute __ ((always_inline)) {
	TCCR1B = _BV (WGM13);
    }
    void restart () __attribute __ ((always_inline)) {
	Начните();
    }
    void resume () __attribute __ ((always_inline)) {
	TCCR1B = _BV (WGM13) | clockSelectBits;
    }

    // ****************************
    // ШИМ-выходы
    // ****************************
    void setPwmDuty (символьный штифт, беззнаковая int обязанность) __attribute __ ((always_inline)) {
	unsigned long dutyCycle = pwmPeriod;
	dutyCycle * = обязанность;
	dutyCycle >> = 10;
	if (pin == TIMER1_A_PIN) OCR1A = dutyCycle;
	#ifdef TIMER1_B_PIN
	иначе if (pin == TIMER1_B_PIN) OCR1B = dutyCycle;
	#endif
	#ifdef TIMER1_C_PIN
	иначе if (pin == TIMER1_C_PIN) OCR1C = dutyCycle;
	#endif
    }
    void pwm (char pin, unsigned int обязанности) __atribute __ ((always_inline)) {
	if (pin == TIMER1_A_PIN) {pinMode (TIMER1_A_PIN, OUTPUT); TCCR1A | = _BV (COM1A1); }
	#ifdef TIMER1_B_PIN
	иначе if (pin == TIMER1_B_PIN) {pinMode (TIMER1_B_PIN, OUTPUT); TCCR1A | = _BV (COM1B1); }
	#endif
	#ifdef TIMER1_C_PIN
	иначе if (pin == TIMER1_C_PIN) {pinMode (TIMER1_C_PIN, OUTPUT); TCCR1A | = _BV (COM1C1); }
	#endif
	setPwmDuty (pin, duty);
	TCCR1B = _BV (WGM13) | clockSelectBits;
    }
    void pwm (символьная булавка, беззнаковая int обязанность, беззнаковые длинные микросекунды) __attribute __ ((always_inline)) {
	if (микросекунды> 0) setPeriod (микросекунды);
	ШИМ (штифт, долг);
    }
    void disablePwm (char pin) __attribute __ ((always_inline)) {
	if (pin == TIMER1_A_PIN) TCCR1A & = ~ _BV (COM1A1);
	#ifdef TIMER1_B_PIN
	иначе if (pin == TIMER1_B_PIN) TCCR1A & = ~ _BV (COM1B1);
	#endif
	#ifdef TIMER1_C_PIN
	иначе if (pin == TIMER1_C_PIN) TCCR1A & = ~ _BV (COM1C1);
	#endif
    }

    // ****************************
    // Функция прерывания
    // ****************************
    void attachInterrupt (void (* isr) ()) __attribute __ ((always_inline)) {
	isrCallback = isr;
	TIMSK1 = _BV (TOIE1);
    }
    void attachInterrupt (void (* isr) (), длинные микросекунды без знака) __atribute __ ((always_inline)) {
	if (микросекунды> 0) setPeriod (микросекунды);
	attachInterrupt (ISR);
    }
    void detachInterrupt () __attribute __ ((always_inline)) {
	TIMSK1 = 0;
    }
    static void (* isrCallback) ();
    static void isrDefaultUnused ();

  частный:
    // свойства
    static unsigned short pwmPeriod;
    статический символ без знака clockSelectBits;






#elif определен (__ arm__) && определен (CORE_TEENSY)

#iffined (KINETISK)
#define F_TIMER F_BUS
#eliffined (KINETISL)
#define F_TIMER (F_PLL / 2)
#endif

  общественности:
    // ****************************
    // Конфигурация
    // ****************************
    void initialize (unsigned long microseconds = 1000000) __attribute __ ((always_inline)) {
	setPeriod (микросекунды);
    }
    void setPeriod (беззнаковые длинные микросекунды) __attribute __ ((always_inline)) {
	const беззнаковые длинные циклы = (F_TIMER / 2000000) * микросекунды;
  // намного быстрее if-else
  // Это похоже на бинарное дерево поиска и оценивается не более 3 условий.
  // Я не проверял, становится ли это значительно длиннее ASM, чем простая лестница.
  // Это выглядит очень похоже на лестницу tho: same # of if's and else's
 
  / *
  // Этот код работает не во всех случаях :(
  // https://github.com/PaulStoffregen/TimerOne/issues/17 
  if (циклы <TIMER1_RESOLUTION * 16) {
    if (циклы <TIMER1_RESOLUTION * 4) {
      if (циклы <TIMER1_RESOLUTION) {
        clockSelectBits = 0;
        pwmPeriod = циклы;
      } Еще {
        clockSelectBits = 1;
        pwmPeriod = циклы >> 1;
      }
    } Еще {
      if (циклы <TIMER1_RESOLUTION * 8) {
        clockSelectBits = 3;
        pwmPeriod = циклы >> 3;
      } Еще {
        clockSelectBits = 4;
        pwmPeriod = циклы >> 4;
      }
    }
  } Еще {
    if (циклы> TIMER1_RESOLUTION * 64) {
      if (циклы> TIMER1_RESOLUTION * 128) {
        clockSelectBits = 7;
        pwmPeriod = TIMER1_RESOLUTION - 1;
      } Еще {
        clockSelectBits = 7;
        pwmPeriod = циклы >> 7;
      }
    }
    еще {
      if (циклы> TIMER1_RESOLUTION * 32) {
        clockSelectBits = 6;
        pwmPeriod = циклы >> 6;
      } Еще {
        clockSelectBits = 5;
        pwmPeriod = циклы >> 5;
      }
    }
  }
  * /
	if (циклы <TIMER1_RESOLUTION) {
		clockSelectBits = 0;
		pwmPeriod = циклы;
	} еще
	if (циклы <TIMER1_RESOLUTION * 2) {
		clockSelectBits = 1;
		pwmPeriod = циклы >> 1;
	} еще
	if (циклы <TIMER1_RESOLUTION * 4) {
		clockSelectBits = 2;
		pwmPeriod = циклы >> 2;
	} еще
	if (циклы <TIMER1_RESOLUTION * 8) {
		clockSelectBits = 3;
		pwmPeriod = циклы >> 3;
	} еще
	if (циклы <TIMER1_RESOLUTION * 16) {
		clockSelectBits = 4;
		pwmPeriod = циклы >> 4;
	} еще
	if (циклы <TIMER1_RESOLUTION * 32) {
		clockSelectBits = 5;
		pwmPeriod = циклы >> 5;
	} еще
	if (циклы <TIMER1_RESOLUTION * 64) {
		clockSelectBits = 6;
		pwmPeriod = циклы >> 6;
	} еще
	if (циклы <TIMER1_RESOLUTION * 128) {
		clockSelectBits = 7;
		pwmPeriod = циклы >> 7;
	} еще {
		clockSelectBits = 7;
		pwmPeriod = TIMER1_RESOLUTION - 1;
	}

	uint32_t sc = FTM1_SC;
	FTM1_SC = 0;
	FTM1_MOD = pwmPeriod;
	FTM1_SC = FTM_SC_CLKS (1) | FTM_SC_CPWMS | clockSelectBits | (sc & FTM_SC_TOIE);
    }

    // ****************************
    // Запуск управления
    // ****************************
    void start () __attribute __ ((always_inline)) {
	стоп();
	FTM1_CNT = 0;
	продолжить();
    }
    void stop () __attribute __ ((always_inline)) {
	FTM1_SC = FTM1_SC & (FTM_SC_TOIE | FTM_SC_CPWMS | FTM_SC_PS (7));
    }
    void restart () __attribute __ ((always_inline)) {
	Начните();
    }
    void resume () __attribute __ ((always_inline)) {
	FTM1_SC = (FTM1_SC & (FTM_SC_TOIE | FTM_SC_PS (7))) | FTM_SC_CPWMS | FTM_SC_CLKS (1);
    }

    // ****************************
    // ШИМ-выходы
    // ****************************
    void setPwmDuty (символьный штифт, беззнаковая int обязанность) __attribute __ ((always_inline)) {
	unsigned long dutyCycle = pwmPeriod;
	dutyCycle * = обязанность;
	dutyCycle >> = 10;
	if (pin == TIMER1_A_PIN) {
		FTM1_C0V = dutyCycle;
	} else if (pin == TIMER1_B_PIN) {
		FTM1_C1V = dutyCycle;
	}
    }
    void pwm (char pin, unsigned int обязанности) __atribute __ ((always_inline)) {
	setPwmDuty (pin, duty);
	if (pin == TIMER1_A_PIN) {
		* portConfigRegister (TIMER1_A_PIN) = PORT_PCR_MUX (3) | PORT_PCR_DSE | PORT_PCR_SRE;
	} else if (pin == TIMER1_B_PIN) {
		* portConfigRegister (TIMER1_B_PIN) = PORT_PCR_MUX (3) | PORT_PCR_DSE | PORT_PCR_SRE;
	}
    }
    void pwm (символьная булавка, беззнаковая int обязанность, беззнаковые длинные микросекунды) __attribute __ ((always_inline)) {
	if (микросекунды> 0) setPeriod (микросекунды);
	ШИМ (штифт, долг);
    }
    void disablePwm (char pin) __attribute __ ((always_inline)) {
	if (pin == TIMER1_A_PIN) {
		* portConfigRegister (TIMER1_A_PIN) = 0;
	} else if (pin == TIMER1_B_PIN) {
		* portConfigRegister (TIMER1_B_PIN) = 0;
	}
    }

    // ****************************
    // Функция прерывания
    // ****************************
    void attachInterrupt (void (* isr) ()) __attribute __ ((always_inline)) {
	isrCallback = isr;
	FTM1_SC | = FTM_SC_TOIE;
	NVIC_ENABLE_IRQ (IRQ_FTM1);
    }
    void attachInterrupt (void (* isr) (), длинные микросекунды без знака) __atribute __ ((always_inline)) {
	if (микросекунды> 0) setPeriod (микросекунды);
	attachInterrupt (ISR);
    }
    void detachInterrupt () __attribute __ ((always_inline)) {
	FTM1_SC & = ~ FTM_SC_TOIE;
	NVIC_DISABLE_IRQ (IRQ_FTM1);
    }
    static void (* isrCallback) ();
    static void isrDefaultUnused ();

  частный:
    // свойства
    static unsigned short pwmPeriod;
    статический символ без знака clockSelectBits;

#undef F_TIMER

#endif
};

внешний таймер один таймер1;

#endif