Atmega128 не работают таймеры 1 и 3

3d_killer
Offline
Зарегистрирован: 13.06.2018

Столкнулся с проблемой, написал скетч для регулятора мощности, с платой nano все работает, а вот с платой на базе atmega128 не работает вылетает куча ошибок пробовал и таймер 3, но он тоже не работает, работает только второй таймер, но на нем не работает регулятор мощности так как таймер 2 в миллисекундах а нужен период во 40 микросекунд, перерыл весь интернет и ничего путевого не нашел.

C:\Users\USER\Documents\Arduino\libraries\TimerOne-r11\TimerOne.cpp: In member function 'void TimerOne::attachInterrupt(void (*)(), long int)':

C:\Users\USER\Documents\Arduino\libraries\TimerOne-r11\TimerOne.cpp:117:3: error: 'TIMSK1' was not declared in this scope

   TIMSK1 = _BV(TOIE1);                                     // sets the timer overflow interrupt enable bit

   ^

C:\Users\USER\Documents\Arduino\libraries\TimerOne-r11\TimerOne.cpp: In member function 'void TimerOne::detachInterrupt()':

C:\Users\USER\Documents\Arduino\libraries\TimerOne-r11\TimerOne.cpp:125:3: error: 'TIMSK1' was not declared in this scope

   TIMSK1 &= ~_BV(TOIE1);                                   // clears the timer overflow interrupt enable bit 

   ^

C:\Users\USER\Documents\Arduino\libraries\TimerOne-r11\TimerOne.cpp: In member function 'void TimerOne::start()':

C:\Users\USER\Documents\Arduino\libraries\TimerOne-r11\TimerOne.cpp:143:3: error: 'TIMSK1' was not declared in this scope

   TIMSK1 &= ~_BV(TOIE1);        // AR added 

   ^

C:\Users\USER\Documents\Arduino\libraries\TimerOne-r11\TimerOne.cpp:144:3: error: 'GTCCR' was not declared in this scope

   GTCCR |= _BV(PSRSYNC);     // AR added - reset prescaler (NB: shared with all 16 bit timers);

   ^

In file included from c:\program files (x86)\arduino\hardware\tools\avr\avr\include\avr\io.h:99:0,

                 from C:\Users\USER\Documents\Arduino\libraries\TimerOne-r11\TimerOne.h:39,

                 from C:\Users\USER\Documents\Arduino\libraries\TimerOne-r11\TimerOne.cpp:39:

C:\Users\USER\Documents\Arduino\libraries\TimerOne-r11\TimerOne.cpp:144:16: error: 'PSRSYNC' was not declared in this scope

   GTCCR |= _BV(PSRSYNC);     // AR added - reset prescaler (NB: shared with all 16 bit timers);

                ^

exit status 1
Ошибка компиляции для платы ATmega128.

пробовал разные библиотеки, а так же CyberLib.h, но на данной плате не могу запустить этот простейший код, может кто сталкивался, помогите решить проблему.

3d_killer
Offline
Зарегистрирован: 13.06.2018
#include <MsTimer2.h>           //Таймер
#include <avr/wdt.h>            //Библиотека сторожевого таймера

volatile bool charflag=0;                  //Флаг чтения
volatile char char1,char2;                 //Символы чтения
volatile int tic, Dimmer,d;

#include "ports.h"              //Подключение портов
#include "nextion.h"
#include "serialread.h"
#include "TimerOne.h"
//#include <CyberLib.h> // шустрая библиотека для таймера

//***************
//Обработчик прерывания для экрана Для ATMEGA_128 (готово плата 2.0)
//***************
void  timerInterupt()
  {
    SerialRead();   //Чтение порта 
  }
//----------------------ОБРАБОТЧИКИ ПРЕРЫВАНИЙ--------------------------
void timer_interrupt() {       // прерывания таймера срабатывают каждые 40 мкс
  tic++;                       // счетчик
  if (tic > Dimmer)            // если настало время включать ток
    //digitalWrite(9, 1);   // врубить ток
    digitalWrite(44, 1);   // врубить ток
}

void  detect_up() {    // обработка внешнего прерывания на пересекание нуля снизу
  tic = 0;                                  // обнулить счетчик
  //ResumeTimer1();                           // перезапустить таймер
  Timer1.resume();
  attachInterrupt(5, detect_down, RISING);  // перенастроить прерывание
}

void  detect_down() {  // обработка внешнего прерывания на пересекание нуля сверху
  tic = 0;                                  // обнулить счетчик
  Timer1.stop();
  digitalWrite(44, 0);
  attachInterrupt(5, detect_up, FALLING);   // перенастроить прерывание
}
//***************
//Установка Для ATMEGA_128 (готово плата 2.0)
//***************
void setup() {
  //Сторожевой таймер на 2 секунды
  wdt_enable(WDTO_2S);
  //Запуск таймера
  pinMode(44, OUTPUT);
  digitalWrite(44, 0);
  pinMode(5, INPUT);   
  Dimmer=85;
  // настраиваем порт на вход для отслеживания прохождения сигнала через ноль
  attachInterrupt(5, detect_up, FALLING);  // настроить срабатывание прерывания interrupt0 на pin 2 на низкий уровень
  
  MsTimer2::set(10,timerInterupt);
  MsTimer2::start();

  Timer1.initialize(40);
  Timer1.attachInterrupt(timer_interrupt);
  Timer1.stop();
}
//***************
//Основной цикл программы
//***************
void loop()
  {
    delay(500);
    wdt_reset();
  }

 

asam
asam аватар
Offline
Зарегистрирован: 12.12.2018

У Атмеги 128 таймеры устроены немного по другому и библиотека TimerOne не подходит. Либо ищите библиотеку таймеров для вашего контроллера или почитайте даташит и работайте с таймером напрямую без библиотеки. 

3d_killer
Offline
Зарегистрирован: 13.06.2018

Да вот в том то и проблема не могу найти подходящую библиотеку, а работать с таймерами напрямую, знаний не хватает...

Ворота
Ворота аватар
Offline
Зарегистрирован: 10.01.2016

3d_killer пишет:

Да вот в том то и проблема не могу найти подходящую библиотеку, а работать с таймерами напрямую, знаний не хватает...

Решений, как всегда три:

1. прокачать знания (рекомендуется)
2. заказать в коммерческом разделе
3. забить

3d_killer
Offline
Зарегистрирован: 13.06.2018

ну мало ли кто знает библиотеку еще с свободном доступе, поэтому и спросил

asam
asam аватар
Offline
Зарегистрирован: 12.12.2018

3d_killer пишет:

ну мало ли кто знает библиотеку еще с свободном доступе, поэтому и спросил

Да настроить таймеры, что бы генерили прерывания через нужные промежутки совсем не сложно. В сети полно объяснений как это делается, если лень даташит читать.

ua6em
ua6em аватар
Онлайн
Зарегистрирован: 17.08.2016

Ворота пишет:

3d_killer пишет:

Да вот в том то и проблема не могу найти подходящую библиотеку, а работать с таймерами напрямую, знаний не хватает...

Решений, как всегда три:

1. прокачать знания (рекомендуется)
2. заказать в коммерческом разделе
3. забить

надо прокачать, даже IRINKA прокачивает )))

И воспользоваться готовой библиотекой:
ConstTimers.h

#ifndef  CONSTTIMERS_H
#define CONSTTIMERS_H

///////////////////////////////////////////////////////////////////////////////
//
// Модификация недобиблиотеки от ЕвгенийП.
// Выполнена: Ворота, 11.07.2019.
// Проба: UA6EM 12.07.2019 (Atmega328PB, WAVGAT, LGT8FX8P)
// 
// Основные изменения:
// 1. К работе с частотами добавлена работа с периодами/интервалами;
// 2. Добавлено задание максимальной допустимой погрешности количества тактов;
// 3. Появилась возможность выдавать ошибку компиляции в случае выхода за допустимую погрешность;
// 4. Добавлены суффиксы для работы с временными интервалами (на основе другого кода от ЕвгенийП);
// 5. Добавлена поддержка Мега, Леонардо и ATmega32A
// 6. Все «внутренние» функции спрятаны в своё пространство имён.
// 
// ---------------
// 
// Определяются биты конфигурации делителя частоты таймера и количество тактов с данным делителем для 
// получения нужного интервала срабатывания таймера. Интервал задаётся либо частотой, либо периодом 
// (длительностью, если речь идёт об одиночном сигнале, например, по переполнению). 
// Соответственно, имеются четыре функции:
// 
// uint8_t prescalerBitsByPeriod(int8_t nTimer, uint32_t period);
// uint16_t timerTicksByPeriod(int8_t nTimer, uint32_t period, int8_t error = 0);
// 
// uint8_t prescalerBitsByFrequency(int8_t nTimer, uint32_t frequency);
// uint16_t timerTicksByFrequency(int8_t nTimer, uint32_t frequency, int8_t error = 0);
// 
// Первый параметр у всех функций – номер таймера. Параметры period и frequency – соответственно  
// требуемые период в тактах микроконтроллера (см. ниже о суффиксах) и частота (в герцах).   
// Параметр error задаёт допустимое отклонение от запрошенных характеристик в процентах. 
// Если не удаётся получить решение в пределах допустимого отклонения, то timerTicksByХХХ вернут 0.
// 
// Также имеется функция, возвращающая значение делителя частоты заданного таймера по битам конфигурации, 
// полученным от функций prescalerBitsByХХХ.
// 
// int16_t prescalerValue(uint8_t nTimer, uint8_t bits);
// 
// Для удобства работы с временными интервалами добавлены суффиксы _clk, _us, _ms и _sec. Таким образом, 
// второй параметр функций prescalerBitsByPeriod и timerTicksByPeriod (время в тактах микроконтроллера) 
// можно задавать при помощи суффиксов, например:
//
//    100 или 100_clk – сто тактов микроконтроллера;
//    100_us – сто микросекунд;
//    100_ms – сто миллисекунд;
//    2_sec – две секунды.
//    
// Допускаются также арифметические операции, например, запись
//
//    2_ms + 50_us
//
// вполне допустима и означает 2050 микросекунд.
//
//  ИСПОЛЬЗОВАНИЕ
//
// Для использования необходимо включить файл «ConstTimers.h» и определить константы с
// модификатором constexpr для нужных конфигурационных битов и количества тиков, которым
// присвоить значения, возвращаемые функциям prescalerBitsByХХХ и timerTicksByХХХ соответственно.
//
// Если использовать именно так, то код библиотеки целиком исполняется во время компиляции
// и не оказывает никакого влияния ни на размер занимаемой памяти, ни на код программы.
// В коде программы будут вставлены готовые (вычисленные на этапе компиляции) константы.
//
// Это позволяет организовать проверку полученного на этапе компиляции значения (функции
// timerTicksByХХХ возвращают 0 в случае невозможности соблюсти необходимую точность)
// и прервать компиляцию с соответствующим сообщением об ошибке при помощи static_assert.
//
//  Пример рекомендуемого использования:
//
//    /////////////////////////////////////////////////
//    //
//    //  Получаем меандр с частотой 50Гц на 9-ом пине
//    //  для этого заводим его на СТС и инвертированием
//    //  на частоте 100Гц (как раз 100/2 = 50)
//    //
//    #include <ConstTimers.h>
//
//    #define TIMER 1
//    #define FREQUENCY 100
//
//    static constexpr uint8_t prescalerBits = prescalerBitsByFrequency(TIMER, FREQUENCY);
//    static constexpr uint16_t timerTicks = timerTicksByFrequency(TIMER, FREQUENCY);
//
//    // проверка установилась ли частота (например, при частоте 101 будет ошибка компиляции)
//    static_assert(timerTicks, "The required frequency with a desired accuracy is unattainable for timer/counter");
//
//    void setup() {
//      pinMode(9, OUTPUT);
//      TCCR1A = bit(COM1A0); // Инвертирование пина 9 по сравнению
//      TCCR1B = bit(WGM12) | prescalerBits;  // Установить СТС режим и делитель частоты
//      OCR1A = timerTicks; // установить TOP равным timerTicks
//    }
//
//    void loop() {}
//
//Результат работы будет точно такой же, как если написать константы, вместо вычислений:
//
//    void setup() {
//      pinMode(9, OUTPUT);
//      TCCR1A = bit(COM1A0);
//      TCCR1B = bit(WGM12) | 2;
//      OCR1A = 20000;
//    }
//    void loop() {}
//
// Ни на один байт код не изменится.
//
//  КОНФИГУРАЦИЯ:
//
//  1. расчёт производится для текущей тактовой частоты микроконтроллера. Если нужно
//    считать для какой-то другой частоты, измените константу FCPU.
//
//  2. STimerParameters - массив конфигурации таймеров. Количество элементов массива
//    соответствует количеству таймеров. Нулевой элемент описывает нулевой таймер,
//    первый элемент – первый таймер и т.д. Если требуется расширить недобиблиотеку для других
//    микроконтроллеров, нужно изменить именно этот массив и больше изменять ничего не надо.
//
//  В массиве для каждого таймера указано:
//    1) разрядность таймера в виде максимально возможного значения количества тиков
//      (для 8-разрядных таймеров – 0xFF, для 16-разрядных – 0xFFFF.
//    2) указатель на массив делителей частоты. Делители начинаются с 1 (делитель 0 писать не нужно)
//    3) количество делителей частоты у данного таймера.
//
// ЛИЦЕНЗИЯ
//
// Данный код поставляется по лицензии ПНХ.
//
// 1. Вы можете свободно использовать или не использовать его в коммерческих,
//    некоммерческих, и любых иных, не запрещённых законом, целях.
//
// 2. Автор не несёт решительно никакой ответственности за любые положительные
//    или отрицательные результаты использования или неиспользования данного кода.
//
// 3. Если Вам таки хочется сделать автору предъяву, то Вы знаете, куда
//    Вам следует обратиться. А если не знаете, то см. название лицензии.
//
// 4. Если данный код вдруг Вам пригодился (как учебник или ещё как что) и Вам
//    почему-либо (ну, приболели, может) захотелось отблагодарить автора рублём,
//    то это всегда пожалуйста – WebMoney, кошелёк № R626206676373
//
// 5. Возникновение или невозникновение у Вас желаний, обозначенных в п.4
//     настоящей лицензии никак не связано с п.1, который действует безусловно
//     и независимо от п.4.
//
// 6. Если данный код нужен Вам с какой-либо другой лицензией, например, с
//     сопровождением или Вы нуждаетесь во внесении изменений, свяжитесь с автором
//     на предмет заключения договора гражданско-правового характера.
//
///////////////////////////////////////////////////////////////////////////////

#define ATtiny85Detected  (defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__))
#define ATmega328Detected (defined(__AVR_ATmega48A__) || defined(__AVR_ATmega48PA__) || defined(__AVR_ATmega88A__) \
  || defined(__AVR_ATmega88PA__) || defined(__AVR_ATmega168A__) || defined(__AVR_ATmega168PA__) \
  || defined(__AVR_ATmega328__) || defined(__AVR_ATmega328P__))
#define ATmega2561Detected  (defined(__AVR_ATmega640__) || defined(__AVR_ATmega640V__) || defined(__AVR_ATmega1280__) \
  || defined(__AVR_ATmega1280V__) || defined(__AVR_ATmega1281__) || defined(__AVR_ATmega1281V__) \
  || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega2560V__) || defined(__AVR_ATmega2561__) || defined(__AVR_ATmega2561V__))
#define ATmega32U4Detected (defined(__AVR_ATmega32U4__))
#define ATmega32ADetected (defined(__AVR_ATmega32A__))
#define ATmega328PBDetected (defined(__AVR_ATmega328PB__))
#define Wavgatlgtx8PDetected (defined(__LGT8FX8P32__)) || (defined(__LGT8FX8P__))

#define FCPU  F_CPU

namespace constTimersNS {

struct STimerParameters {
  const uint32_t maxValue;
  const int16_t * prescalers;
  const uint8_t totalPrescalers;
};

static constexpr uint32_t bits8 = 0x000000FFul;
static constexpr uint32_t bits10 = 0x000003FFul;
static constexpr uint32_t bits16 = 0x0000FFFFul;

#if Wavgatlgtx8PDetected

static constexpr  int16_t prescalers013[] = { 1, 8, 64, 256, 1024 };
static constexpr  int16_t prescalers2[] = { 1, 8, 32, 64, 128, 256, 1024 };

static constexpr STimerParameters timerParameters[] = {
  { bits8, prescalers013, sizeof(prescalers013) / sizeof(prescalers013[0]) },
  { bits16, prescalers013, sizeof(prescalers013) / sizeof(prescalers013[0]) },
  { bits8, prescalers2, sizeof(prescalers2) / sizeof(prescalers2[0]) },
  { bits16, prescalers013, sizeof(prescalers013) / sizeof(prescalers013[0]) }
};

#elif ATmega328PBDetected

static constexpr  int16_t prescalers0134[] = { 1, 8, 64, 256, 1024 };
static constexpr  int16_t prescalers2[] = { 1, 8, 32, 64, 128, 256, 1024 };

static constexpr STimerParameters timerParameters[] = {
  { bits8, prescalers0134, sizeof(prescalers0134) / sizeof(prescalers0134[0]) },
  { bits16, prescalers0134, sizeof(prescalers0134) / sizeof(prescalers0134[0]) },
  { bits8, prescalers2, sizeof(prescalers2) / sizeof(prescalers2[0]) },
  { bits16, prescalers0134, sizeof(prescalers0134) / sizeof(prescalers0134[0]) },
  { bits16, prescalers0134, sizeof(prescalers0134) / sizeof(prescalers0134[0]) }
};

#elif ATmega328Detected || ATmega32ADetected

static constexpr  int16_t prescalers01[] = { 1, 8, 64, 256, 1024 };
static constexpr  int16_t prescalers2[] = { 1, 8, 32, 64, 128, 256, 1024 };
static constexpr  int16_t prescalers3[] = { 1, 8, 64, 256, 1024 };

static constexpr STimerParameters timerParameters[] = {
  { bits8, prescalers01, sizeof(prescalers01) / sizeof(prescalers01[0]) },
  { bits16, prescalers01, sizeof(prescalers01) / sizeof(prescalers01[0]) },
  { bits8, prescalers2, sizeof(prescalers2) / sizeof(prescalers2[0]) },
  { bits16, prescalers3, sizeof(prescalers3) / sizeof(prescalers3[0]) } // для WAVGAT
};

#elif ATmega32U4Detected

static constexpr  int16_t prescalers013[] = { 1, 8, 64, 256, 1024 };
static constexpr  int16_t prescalers2[] = { 1, 8, 32, 64, 128, 256, 1024 };
static constexpr  int16_t prescalers4[] = { 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384 };

static constexpr STimerParameters timerParameters[] = {
  { bits8, prescalers013, sizeof(prescalers013) / sizeof(prescalers013[0]) },
  { bits16, prescalers013, sizeof(prescalers013) / sizeof(prescalers013[0]) },
  { bits8, prescalers2, sizeof(prescalers2) / sizeof(prescalers2[0]) },
  { bits16, prescalers013, sizeof(prescalers013) / sizeof(prescalers013[0]) },
  { bits10, prescalers4, sizeof(prescalers4) / sizeof(prescalers4[0]) }
};

#elif ATmega2561Detected

static constexpr  int16_t prescalers01345[] = { 1, 8, 64, 256, 1024 };
static constexpr  int16_t prescalers2[] = { 1, 8, 32, 64, 128, 256, 1024 };

static constexpr STimerParameters timerParameters[] = {
  { bits8, prescalers01345, sizeof(prescalers01345) / sizeof(prescalers01345[0]) },
  { bits16, prescalers01345, sizeof(prescalers01345) / sizeof(prescalers01345[0]) },
  { bits8, prescalers2, sizeof(prescalers2) / sizeof(prescalers2[0]) },
  { bits16, prescalers01345, sizeof(prescalers01345) / sizeof(prescalers01345[0]) },
  { bits16, prescalers01345, sizeof(prescalers01345) / sizeof(prescalers01345[0]) },
  { bits16, prescalers01345, sizeof(prescalers01345) / sizeof(prescalers01345[0]) }
};

#elif ATtiny85Detected

static constexpr  int16_t prescalers0[] = { 1, 8, 64, 256, 1024 };
static constexpr  int16_t prescalers1[] = { 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384 };

static constexpr STimerParameters timerParameters[] = {
  { bits8, prescalers0, sizeof(prescalers0) / sizeof(prescalers0[0]) },
  { bits8, prescalers1, sizeof(prescalers1) / sizeof(prescalers1[0]) }
};

#else

#error The library does not seem to support your MCU

#endif

constexpr int8_t totalTimers = sizeof(timerParameters) / sizeof(timerParameters[0]);

static constexpr uint32_t getPeriod(const uint32_t frequency) {
  return (FCPU + frequency / 2) / frequency;
}

static constexpr uint16_t prValue(const int8_t prescalerId, const int8_t nTimer) {
  return timerParameters[nTimer].prescalers[prescalerId];
}

static constexpr uint32_t getDesiredTicks(const uint32_t period, const int8_t prescalerId, const int8_t nTimer) {
  return (period + prValue(prescalerId, nTimer) / 2) / prValue(prescalerId, nTimer);
}

static constexpr uint32_t correctTicks(uint32_t dTicks, const uint32_t maxValue) {
  //if (dTicks > maxValue) return maxValue; else return dTicks; // начиная с C++14
  return dTicks > maxValue ? maxValue : dTicks;
}

static constexpr uint32_t getTicks(const uint32_t period, const int8_t prescalerId, const int8_t nTimer) {
  return prescalerId >= timerParameters[nTimer].totalPrescalers ? 0x1FFFFFFF :
  correctTicks(getDesiredTicks(period, prescalerId, nTimer), timerParameters[nTimer].maxValue);
}

static constexpr uint32_t getBits(const int8_t prescalerId, const int8_t nTimer) {
  return prescalerId >= timerParameters[nTimer].totalPrescalers ? timerParameters[nTimer].totalPrescalers : prescalerId + 1;
}


static constexpr int32_t absErrorTicks(const uint32_t period, const uint32_t ticks) {
  return period > ticks ? period - ticks : ticks - period;
}

static constexpr int32_t absError(const uint32_t period, const int8_t prescalerId, const int8_t nTimer) {
  return prescalerId >= timerParameters[nTimer].totalPrescalers ? 0x1FFFFFFF :
  absErrorTicks(period, getTicks(period, prescalerId, nTimer) * prValue(prescalerId, nTimer));
}

static constexpr uint8_t getPrescalerId(const uint32_t error, const uint32_t newError, const uint8_t prId, const uint8_t candidate, const uint32_t period, const int8_t nTimer) {
  return
  (prId >= timerParameters[nTimer].totalPrescalers) ? candidate
  : getPrescalerId(newError, absError(period, prId + 1, nTimer), prId + 1, (error <= newError) ? candidate : prId, period, nTimer);
}

static constexpr double calcErrorPercentage(const double fcpu, const double perc) {
  return (fcpu < perc ? 1.0 - fcpu / perc : fcpu / perc - 1.0) * 100.0;
}

static constexpr uint16_t returnTicksOrZero(const uint32_t left, const uint32_t right, const int8_t allowableError, const uint32_t ticks) {
  return left == right || calcErrorPercentage(left, right) <= allowableError ? ticks : 0;
}

static constexpr uint16_t getTimerTicksIntFTicks(const uint32_t ticks, const int8_t nTimer, const uint32_t freq, uint8_t prescalerId, const int8_t allowableError) {
  return returnTicksOrZero(FCPU, freq * ticks * timerParameters[nTimer].prescalers[prescalerId], allowableError, ticks);
}

static constexpr uint16_t getTimerTicksIntF(const int8_t nTimer, const uint32_t freq, uint8_t prescalerId, const int8_t allowableError) {
  return getTimerTicksIntFTicks(getTicks(getPeriod(freq), prescalerId, nTimer), nTimer, freq, prescalerId, allowableError);
}

static constexpr uint16_t getTimerTicksIntTTicks(const uint32_t ticks, const int8_t nTimer, const uint32_t period, uint8_t prescalerId, const int8_t allowableError) {
  return returnTicksOrZero(period, ticks * timerParameters[nTimer].prescalers[prescalerId], allowableError, ticks);
}

static constexpr uint16_t getTimerTicksIntT(const int8_t nTimer, const uint32_t period, uint8_t prescalerId, const int8_t allowableError) {
  return getTimerTicksIntTTicks(getTicks(period, prescalerId, nTimer), nTimer, period, prescalerId, allowableError);
}


//////////////////////////////////////////////////////////////////
//
//  Суффиксы литералов для задания времени
//    100 или 100_clk - время в тактах контроллера (100 тактов)
//    100_us - время в микросекундах (100 микросекунд)
//    100_ms - время в милисекундах (100 милисекунд)
//    5_sec - время в секундах (5 секунд)
//
static constexpr int8_t __sLen(const char * str, const int8_t candidate = 0) { return (!*str) ? candidate : __sLen(str + 1, candidate + 1); }
static constexpr bool __isFin(const char * str, const int8_t lInd) { return lInd < 0 || !isdigit(str[lInd]); }
static constexpr uint32_t __toDig(const char * str, const uint32_t lg, const int8_t lInd) { return (str[lInd] - '0') * lg; }
static constexpr uint32_t ___s2ul(const char * str, const uint32_t, const int8_t);
static constexpr uint32_t __nextL(const char * str, const uint32_t lg, const int8_t lInd) { return __toDig(str, lg, lInd) + ___s2ul(str, lg * 10, lInd - 1); }
static constexpr uint32_t ___s2ul(const char * str, const uint32_t lg, const int8_t lInd) { return __isFin(str, lInd) ? 0 : __nextL(str, lg, lInd); }
static constexpr uint32_t __s2ul(const char * str) { return ___s2ul(str, 1, __sLen(str) - 1); }

} //  namespace constTimersNS

static constexpr uint32_t operator "" _clk(const char * s) { return constTimersNS::__s2ul(s); }
static constexpr uint32_t operator "" _us(const char * s) { return operator "" _clk(s) * (FCPU / 1000000ul); }
static constexpr uint32_t operator "" _ms(const char * s) { return operator "" _us(s) * 1000ul; }
static constexpr uint32_t operator "" _sec(const char * s) { return operator "" _ms(s) * 1000ul; }
//
//////////////////////////////////////////////////////////////////


static constexpr uint8_t prescalerBitsByPeriod(const int8_t nTimer, const uint32_t period) {
  return constTimersNS::getBits(constTimersNS::getPrescalerId(0x1FFFFFul, constTimersNS::absError(period, 0, nTimer), 0, 0, period, nTimer), nTimer);
}

static constexpr uint16_t timerTicksByPeriod(const int8_t nTimer, const uint32_t period, const int8_t allowableError = 0) {
  return constTimersNS::getTimerTicksIntT(nTimer, period, constTimersNS::getPrescalerId(0x1FFFFFul, constTimersNS::absError(period, 0, nTimer), 0, 0, period, nTimer), allowableError);
}

static constexpr uint8_t prescalerBitsByFrequency(const int8_t nTimer, const uint32_t freq) {
  return prescalerBitsByPeriod(nTimer, constTimersNS::getPeriod(freq));
}

static constexpr uint16_t timerTicksByFrequency(const int8_t nTimer, const uint32_t freq, const int8_t allowableError = 0) {
  return constTimersNS::getTimerTicksIntF(nTimer, freq, 
      constTimersNS::getPrescalerId(0x1FFFFFul, constTimersNS::absError(constTimersNS::getPeriod(freq), 0, nTimer), 0, 0, 
      constTimersNS::getPeriod(freq), nTimer), allowableError);
}

static constexpr int16_t prescalerValue(const uint8_t nTimer, const uint8_t bits) {
  return constTimersNS::timerParameters[nTimer].prescalers[bits-1];
}

#endif  //  CONSTTIMERS_H

 

asam
asam аватар
Offline
Зарегистрирован: 12.12.2018

Вот, например

 

 //настройка таймера1
void setup()
{
   TCCR1B |= (1 << WGM12); // Configure timer 1 for CTC mode

   TIMSK |= (1 << OCIE1A); // Enable CTC interrupt

   OCR1A   = 15624; // Set CTC compare value to 1Hz at 1MHz AVR clock, with a prescaler of 64

   TCCR1B |= ((1 << CS10) | (1 << CS11)); // Start timer at Fcpu/64
}

//прерывание по таймеру

ISR(TIMER1_COMPA_vect)
{
   // do something
}

 

3d_killer
Offline
Зарегистрирован: 13.06.2018

Сейчас пробую переписать библиотеку первого таймера, скопировав ее и переименовав и с помощью даташита на мегу 128 пытаюсь переписать, хоть и много всего не понятного мне.

ua6em
ua6em аватар
Онлайн
Зарегистрирован: 17.08.2016

3d_killer пишет:

Сейчас пробую переписать библиотеку первого таймера, скопировав ее и переименовав и с помощью даташита на мегу 128 пытаюсь переписать, хоть и много всего не понятного мне.

А использовать библиотеку от ЕвгенийП религия не позволила?

3d_killer
Offline
Зарегистрирован: 13.06.2018

я не находил такой библиотеки

3d_killer
Offline
Зарегистрирован: 13.06.2018

Спасибо, код рабочий, кажется что в русской документации много не прописано. Вот например хочу установить делитель как в таймере TimerOne смотрю код установки:

void TimerOne::setPeriod(long microseconds)		// AR modified for atomic access
{
  
  long cycles = (F_CPU / 2000000) * microseconds;                                // the counter runs backwards after TOP, interrupt is at BOTTOM so divide microseconds by 2
  if(cycles < RESOLUTION)              clockSelectBits = _BV(CS10);              // no prescale, full xtal
  else if((cycles >>= 3) < RESOLUTION) clockSelectBits = _BV(CS11);              // prescale by /8
  else if((cycles >>= 3) < RESOLUTION) clockSelectBits = _BV(CS11) | _BV(CS10);  // prescale by /64
  else if((cycles >>= 2) < RESOLUTION) clockSelectBits = _BV(CS12);              // prescale by /256
  else if((cycles >>= 2) < RESOLUTION) clockSelectBits = _BV(CS12) | _BV(CS10);  // prescale by /1024
  else        cycles = RESOLUTION - 1, clockSelectBits = _BV(CS12) | _BV(CS10);  // request was out of bounds, set as maximum
  
  oldSREG = SREG;				
  cli();							// Disable interrupts for 16 bit register access
  ICR1 = pwmPeriod = cycles;                                          // ICR1 is TOP in p & f correct pwm mode
  SREG = oldSREG;
  
  TCCR1B &= ~(_BV(CS10) | _BV(CS11) | _BV(CS12));
  TCCR1B |= clockSelectBits;                                          // reset clock select register, and starts the clock
}

Чем отличается 6 от 7 строки (условия одни и те же, действия разные) или

8 от 9 строки (тоже самое).

Откуда вот это число - 15624

b707
Онлайн
Зарегистрирован: 26.05.2017

3d_killer пишет:

Спасибо, код рабочий, кажется что в русской документации много не прописано.

зачем нужна "русская документация" ? ее почти ни на одну библиотеку нет. Даже русские программисты часто пишут доки по английски, чтобы два раза не писать. Смотрите комменты в исходнике.

Цитата:
Чем отличается 6 от 7 строки (условия одни и те же, действия разные) или

это не просто условия, в момень вычисления выражения в скобках значение cycles меняется

3d_killer
Offline
Зарегистрирован: 13.06.2018

что то реально не то что ли делаю, попробовал пример, начал подставлять свои значения из таблицы описания микроконтроллера, но на скорость это никак не повлияло (каждую по отдельности пробовал).

TCCR1B |= ((1 << CS10) | (1 << CS11)); 
TCCR1B |= ((1 << CS10) ||(0 << CS11) || (1 << CS12)); 
TCCR1B |= ((1 << CS10));

 

3d_killer
Offline
Зарегистрирован: 13.06.2018

b707 пишет:

это не просто условия, в момень вычисления выражения в скобках значение cycles меняется

то есть знак подчеркивания играет роль плейсхолдера?

b707
Онлайн
Зарегистрирован: 26.05.2017

3d_killer пишет:

то есть знак подчеркивания играет роль плейсхолдера?

при чем тут знак подчеркивания? Вы знаете, что означает выражение x-=3; ?

- а теперь попробуйте прочитать cycles>>=3

 

у меня такое ощущения, что вы многие контструкции Си впервые видите. Может для начала свой уровень прокачать, как уже выше советовали? тогда и подчеркивания перестанут казаться чем-то мистическим :)

 

3d_killer
Offline
Зарегистрирован: 13.06.2018

Многие да, в первый раз, сейчас начал исправлять таймер, он начинает потихоньку работать (используя документацию и ошибки которые выдает компилятор), например

//TIMSK1 &= ~_BV(TOIE1);        // AR added 
   TIMSK &= ~_BV(TOIE1);        // AR added

первое было второе стало.

А вот это по описанию, я нашел что это главный регистр счетчиков и таймеров, но ничего пододного в документации на мегу128 я не нашел, пока закомментировал, компилятор перестал ругаться, но на сколько это критично?

//GTCCR |= _BV(PSRSYNC);   		// AR added - reset prescaler (NB: shared with all 16 bit timers);

 

ua6em
ua6em аватар
Онлайн
Зарегистрирован: 17.08.2016

 GTCCR=0; // Запускаем синхронно все таймера

3d_killer
Offline
Зарегистрирован: 13.06.2018

Компилятор не знает об этой переменной

C:\Users\USER\Documents\Arduino\libraries\TimerMy\TimerMy.cpp:146:3: error: 'GTCCR' was not declared in this scope

   GTCCR |= _BV(PSRSYNC);     // AR added - reset prescaler (NB: shared with all 16 bit timers);

 

ua6em
ua6em аватар
Онлайн
Зарегистрирован: 17.08.2016

для 328 чипа знает, аддон MegaCore?

3d_killer
Offline
Зарегистрирован: 13.06.2018

Верно, ничего другого не нашлось

По таймеру он нормально заработал и диммирование заработало

ua6em
ua6em аватар
Онлайн
Зарегистрирован: 17.08.2016

3d_killer пишет:

Верно, ничего другого не нашлось

По таймеру он нормально заработал и диммирование заработало

 и чего бы ему не заработать )))

3d_killer
Offline
Зарегистрирован: 13.06.2018

Сейчас опять вернулся к данному коду, начал проводить разные тесты, работать он заработал, но работает как то не так, во первых, если запустить 2 таймера в такой последовательности:

 MsTimer2::set(10,timerInterupt);
 MsTimer2::start();
TimerNew.initialize(10);
TimerNew.attachInterrupt(timer_interrupt);

То таймер 2 не работает, а если поменять местами, то они работают оба но как то, как будто мешают друг другу, на MsTimer2 сидит обработка Serial.available() (а там сенсорный экран), и если запущен TimerNew, то нажатия на экран отрабатывают редко (но отрабатывают), если отключить TimerNew, то все работает как часы, не пойму в чем дело.

TimerNew это таймер 3 у которого исправлены 2 строки c TIMSK1 на TIMSK


 

3d_killer
Offline
Зарегистрирован: 13.06.2018

Думал может дело в приоритете прерываний, попробовал TimerNew.initialize(1000); но ничего не изменилось, не пойму куда копать

b707
Онлайн
Зарегистрирован: 26.05.2017

3d_killer пишет:

 ничего не изменилось, не пойму куда копать

это вы верно заметили, вам давно советовали прокачать знания - но "ничего не изменилось" - вы продолжаете использовать настройки таймеров как египетские заклинания. не понимая что к чему

nik182
Offline
Зарегистрирован: 04.05.2015

В авр нет приоритета прерываний. Кто первый взял тот и в прерывании. И уже не отнимешь. Можно только отдать.

3d_killer
Offline
Зарегистрирован: 13.06.2018

меня интересует пока не сам код, а хотя бы, то что при одновременной работе таймеров с прерываниями будут ли они друг другу мешать, как происходит сейчас или такого не должно быть, в прерывании для Serial там чтение порта и отсылка в порт, крошечного объема, и то только при нажатии на экран, а во втором прерывании вобще ничего нет, глюк проявляется только когда запущен именно этот таймер

3d_killer
Offline
Зарегистрирован: 13.06.2018

посмотрел одну и вторую библиотеку и увидел что при использовании Atmega128 Timer2 использует TIMSK так же как и другая библиотека, в документации указано что у нее 2 16-разрядных таймера, но название второго не могу найти в официальной документации.

sadman41
Онлайн
Зарегистрирован: 19.10.2016

16-bit Timer/Counter (Timer/Counter1 and Timer/Counter3 )

The 16-bit Timer/Counter unit allows accurate program execution timing (event management), wave generation, and signal timing measurement. The main features are:
• True 16-bit Design (i.e.,Allows 16-bit PWM)
• Three Independent Output Compare Units
• Double Buffered Output Compare Registers
• One Input Capture Unit • Input Capture Noise Canceler
• Clear Timer on Compare Match (Auto Reload)
• Glitch-free, Phase Correct Pulse width Modulator (PWM)
• Variable PWM Period
• Frequency Generator
• External Event Counter
• Ten Independent Interrupt Sources (TOV1, OCF1A, OCF1B, OCF1C, ICF1, TOV3, OCF3A, OCF3B, OCF3C, and ICF3)

Jeka_M
Jeka_M аватар
Offline
Зарегистрирован: 06.07.2014

3d_killer пишет:

но название второго не могу найти в официальной документации.

http://ww1.microchip.com/downloads/en/DeviceDoc/doc2467.pdf

стр.111, 16-bit Timer/Counter (Timer/Counter1 and Timer/Counter3)
стр.132, 16-bit Timer/Counter Register Description
3d_killer
Offline
Зарегистрирован: 13.06.2018

Так вот я совсем запутался, в MsTimer2 библиотеке для Atmega128 идет регистр управления TCCR2, во второй библиотеке TCCR1A, в документации указано 2 регистра: TCCR1A, TCCR3A

Но таймер MsTimer2 прекрасно работает, это как такое получается, там в таймере того кода... ничего лишнего.

3d_killer
Offline
Зарегистрирован: 13.06.2018
  TCCR1B |= (1 << WGM12); // Configure timer 1 for CTC mode
  TIMSK |= (1 << OCIE1A); // Enable CTC interrupt
  OCR1A   = 15624; // Set CTC compare value to 1Hz at 1MHz AVR clock, with a prescaler of 64
  TCCR1B |= ((1 << CS10) | (1 << CS11)); // Start timer at Fcpu/64
  
  TCCR3B |= (1 << WGM32); // Configure timer 1 for CTC mode
  TIMSK |= (1 << OCIE1A); // Enable CTC interrupt
  OCR3A   = 15624; // Set CTC compare value to 1Hz at 1MHz AVR clock, with a prescaler of 64
  TCCR3B |= ((1 << CS30) | (1 << CS11)); // Start timer at Fcpu/64

Вот попытался запустить 2 таймера, первый работает второй нет, в чем причина, вроде все с документации

3d_killer
Offline
Зарегистрирован: 13.06.2018

ETIMSK |= (1 << OCIE1A); // Enable CTC interrupt

Разобрался

3d_killer
Offline
Зарегистрирован: 13.06.2018

Только так и не понял, почему в библиотеке MsTimer2, все не соответствует документации, но при этом он работает???

Кусок из кода:

#elif defined (__AVR_ATmega128__)
	TIMSK &= ~(1<<TOIE2);
	TCCR2 &= ~((1<<WGM21) | (1<<WGM20));
	TIMSK &= ~(1<<OCIE2);
	
	if ((F_CPU >= 1000000UL) && (F_CPU <= 16000000UL)) {	// prescaler set to 64
		TCCR2 |= ((1<<CS21) | (1<<CS20));
		TCCR2 &= ~(1<<CS22);
		prescaler = 64.0;
	} else if (F_CPU < 1000000UL) {	// prescaler set to 8
		TCCR2 |= (1<<CS21);
		TCCR2 &= ~((1<<CS22) | (1<<CS20));
		prescaler = 8.0;
	} else { // F_CPU > 16Mhz, prescaler set to 256
		TCCR2 |= (1<<CS22);
		TCCR2 &= ~((1<<CS21) | (1<<CS20));
		prescaler = 256.0;
	}
#endif

 

3d_killer
Offline
Зарегистрирован: 13.06.2018

И еще в этом коде:

void TimerMy::setPeriod(long microseconds)		// AR modified for atomic access
{
  
  long cycles = (F_CPU / 2000000) * microseconds;                                // the counter runs backwards after TOP, interrupt is at BOTTOM so divide microseconds by 2
  if(cycles < RESOLUTION)              clockSelectBits = _BV(CS10);              // no prescale, full xtal
  else if((cycles >>= 3) < RESOLUTION) clockSelectBits = _BV(CS11);              // prescale by /8
  else if((cycles >>= 3) < RESOLUTION) clockSelectBits = _BV(CS11) | _BV(CS10);  // prescale by /64
  else if((cycles >>= 2) < RESOLUTION) clockSelectBits = _BV(CS12);              // prescale by /256
  else if((cycles >>= 2) < RESOLUTION) clockSelectBits = _BV(CS12) | _BV(CS10);  // prescale by /1024
  else        cycles = RESOLUTION - 1, clockSelectBits = _BV(CS12) | _BV(CS10);  // request was out of bounds, set as maximum
  
  oldSREG = SREG;				
  cli();							// Disable interrupts for 16 bit register access
  ICR1 = pwmPeriod = cycles;                                          // ICR1 is TOP in p & f correct pwm mode
  SREG = oldSREG;
  
  TCCR1B &= ~(_BV(CS10) | _BV(CS11) | _BV(CS12));
  TCCR1B |= clockSelectBits;                                          // reset clock select register, and starts the clock
}

Разве не ошибка делить на 2000000? Это получается что заданный интервал вырастет в двое или я не прав?

 

3d_killer
Offline
Зарегистрирован: 13.06.2018

asam пишет:

Вот, например

 

 //настройка таймера1
void setup()
{
   TCCR1B |= (1 << WGM12); // Configure timer 1 for CTC mode

   TIMSK |= (1 << OCIE1A); // Enable CTC interrupt

   OCR1A   = 15624; // Set CTC compare value to 1Hz at 1MHz AVR clock, with a prescaler of 64

   TCCR1B |= ((1 << CS10) | (1 << CS11)); // Start timer at Fcpu/64
}

//прерывание по таймеру

ISR(TIMER1_COMPA_vect)
{
   // do something
}

Скажите пожалуйста как понять эту запись, какой это интервал срабатывания? как его посчитать?

3d_killer
Offline
Зарегистрирован: 13.06.2018
  TCCR1B |= (1 << WGM12);   // Вызвывает сброс счетного регистра при совпадении
  TIMSK |= (1 << OCIE1A);   // разрешаем прерывания при совпадении
  //TCNT1 = 0;              //СБРОС СЧЕТЧИКА
  OCR1A   = 31250;          // 8000000/256 Частота разделить на делитель
  TCCR1B |= (1 << CS12);    // Запись делителя

я так понимаю сделал прерывание по 1мкс, как теперь сделать 50, 100 и т.д.? и правильно ли я понял что сделал?

3d_killer
Offline
Зарегистрирован: 13.06.2018
  TIMSK |= (1 << OCIE1A); // //устанавливаем бит разрешения прерывания 1ого счетчика по совпадению с OCR1A(H и L)
  TCCR1A = 0;// clear control register A 
  OCR1A   = 31250; // Set CTC compare value to 1Hz at 1MHz AVR clock, with a prescaler of 64
  TCCR1B =0b00001100;

Так работает, 1с интервал, а как считать 1мкс или 1мс?

ua6em
ua6em аватар
Онлайн
Зарегистрирован: 17.08.2016

3d_killer пишет:

  TIMSK |= (1 << OCIE1A); // //устанавливаем бит разрешения прерывания 1ого счетчика по совпадению с OCR1A(H и L)
  TCCR1A = 0;// clear control register A 
  OCR1A   = 31250; // Set CTC compare value to 1Hz at 1MHz AVR clock, with a prescaler of 64
  TCCR1B =0b00001100;

Так работает, 1с интервал, а как считать 1мкс или 1мс?

для 1 мс OCR1A = 31; видимо

asam
asam аватар
Offline
Зарегистрирован: 12.12.2018

nik182 пишет:
В авр нет приоритета прерываний. Кто первый взял тот и в прерывании. И уже не отнимешь. Можно только отдать.

Ну, вообще-то, приоритеты есть. Если одновременно (в течении одного такта процессора) случится несколько прерываний, то они будут вызываться в порядке приоритета. А так да, если обработчик начал работать, то пока он не закочится или внутри него явно не разрешить прерывания, то его прерывать не будут.  

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

asam пишет:

Если одновременно (в течении одного такта процессора) случится несколько прерываний, то они будут вызываться в порядке приоритета. 

Где про это прочитать?  А какое из одновременных прерываний будет главнее, PCINT, IRQ0 или CTC от таймера 1? Как это узнать? 

asam
asam аватар
Offline
Зарегистрирован: 12.12.2018

DetSimen пишет:

asam пишет:

Если одновременно (в течении одного такта процессора) случится несколько прерываний, то они будут вызываться в порядке приоритета. 

Где про это прочитать?  А какое из одновременных прерываний будет главнее, PCINT, IRQ0 или CTC от таймера 1? Как это узнать? 

Хорош тролить дед! Буд-то сам не знаешь где. В даташите вестимо :

 The complete list of vectors is shown in “Interrupts” on page 59. The list also determines the priority levels of the different interrupts. The lower the address the higher is the priority level. RESET has the highest priority, and next is INT0 – the External Interrupt Request 0.

 

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

asam пишет:

 The complete list of vectors is shown in “Interrupts” on page 59. The list also determines the priority levels of the different interrupts. The lower the address the higher is the priority level. RESET has the highest priority, and next is INT0 – the External Interrupt Request 0.

Блаадарю. Не знал.  Видимо, не дочитал до этого, потому думал, что у AVR все прерывания равнозначны, кроме Reset, естессна. 

nik182
Offline
Зарегистрирован: 04.05.2015

asam пишет:

nik182 пишет:
В авр нет приоритета прерываний. Кто первый взял тот и в прерывании. И уже не отнимешь. Можно только отдать.

Ну, вообще-то, приоритеты есть. Если одновременно (в течении одного такта процессора) случится несколько прерываний, то они будут вызываться в порядке приоритета. А так да, если обработчик начал работать, то пока он не закочится или внутри него явно не разрешить прерывания, то его прерывать не будут.  


Абсолютно согласен. Именно в течении одного такта процессора есть. Но событие настолько маловероятное, что я держу в памяти его наличие, а стараюсь писать так, чтобы в остальных случаях работало без приоритетов.

asam
asam аватар
Offline
Зарегистрирован: 12.12.2018

nik182 пишет:
Абсолютно согласен. Именно в течении одного такта процессора есть. Но событие настолько маловероятное, что я держу в памяти его наличие, а стараюсь писать так, чтобы в остальных случаях работало без приоритетов.

На самом деле не настолько маловероятное. В один такт если при нормальном исполнении программы. А вот если прерывания были запрещены, например потому, что обрабатывается какое-то другое, и за это время произошли события, которые должны были вызвать другие прерывания, то после разрешения прерываний (выходе из обработчика) "накопившиеся" прерывания будут вызываться один за другим в порядке приоритета.

sadman41
Онлайн
Зарегистрирован: 19.10.2016

Интересно, там счётчик бежит по регистру флагов каждый раз сначала или нет? Если, допустим, во время выполнения обработчика "высокоприоритетного" прерывания опять оно произойдёт, то следующим будет обрабатываться опять оно или нижележащее? 

Логично, конечно, предположить, что "высокоприоритетное" будет постоянно блочить остальные - иначе зачем ему приоритетность...

asam
asam аватар
Offline
Зарегистрирован: 12.12.2018

sadman41 пишет:

Интересно, там счётчик бежит по регистру флагов каждый раз сначала или нет? Если, допустим, во время выполнения обработчика "высокоприоритетного" прерывания опять оно произойдёт, то следующим будет обрабатываться опять оно или нижележащее? 

Логично, конечно, предположить, что "высокоприоритетное" будет постоянно блочить остальные - иначе зачем ему приоритетность...

Насколько я понимаю, то с начала, хотя не проверял. Но по выходу из прерывания выполняется, как минимум, одна команда основной программы. То есть выполнение основной программы полностью не блокируется при непрерывных прерываниях, хоть и здорово тормозится.

nik182
Offline
Зарегистрирован: 04.05.2015

И снова согласен. Но имел в виду только одновременное срабатывание. Очереди прерываний нет. Если выставлено несколько, то после того как после выхода из прерывания выполнится одна команда программы механизм прерываний будет работать с "чистого листа" , делая переход на обработку прерывания с наивысшим приоритетом. Если он выставляется чаще низкоприоритетного то у низкоприритетного могут быть проблемы с вызовом.

asam
asam аватар
Offline
Зарегистрирован: 12.12.2018

Ну, в общем да. Но такая ситуация возможна только если более высокоуровневое прерывание случается в момент обработки его же непрерывно. А такой расклад это и так почти полная ж.. тут у же не до заботы о других прерываниях. 

-NMi-
Offline
Зарегистрирован: 20.08.2018

Чото я самниваютя и немогу согласиццо с некоторыми вищщами...

С INTх ладно, вроде согласен, но с остальным не очень. И по поводу ОДНОЙ (заветной) команды между векторами - а чем докажете??? Кто может побырику наваять скетч(328Р), шоб работали все таймеры (9 векторов) + два INT0,1 от собственного ногодрыга + АЦП в Free... ну и ещё что там осталось кроме PCINTx, они не интересны.   В протеусе можно потактно логировать события, приходящие от процессора, вот и посмотрим на вашу теорию.