Много таймеров из одного. Блинк без delay() и millis()

Тема в разделе "Arduino & Shields", создана пользователем DetSimen, 4 апр 2017.

  1. DetSimen

    DetSimen Guest

    Alex19, Tomasina и arkadyf нравится это.
  2. Tomasina

    Tomasina Сушитель лампочек Модератор

    а можно попросить оформить это как библиотеку? Чтобы не копировать каждый раз в файл проекта.
     
  3. DetSimen

    DetSimen Guest

    Я прошу прощения, но это настолько маленькая вещь, что 2 файла скопировать, я думаю, труда не составит.
    Я сделаю библиотеку, но несколько позже, когда отлажу очередь сообщений, и то, что я выложил сейчас, будет лишь ее маленькая часть.
     
    arkadyf нравится это.
  4. serg_admin

    serg_admin Гик

    Желательно, что бы ссылка на функцию
    Код (C++):
    using    PVoidFunc = void(*)(void);
    Принимала указатель на область памяти. Тогда будет возможность одну функцию вешать на несколько таймеров.

    И использовать в библиотечных функциях явную конструкцию

    Код (C++):
    cli();
    ...
    ...
    sei();
    Не желательно - потому, что если вы зайдете в функцию с выключенным флагом прерывания то функцию в любом случае прерывания включит (в step у Вас так и происходит). Часто приводит к очень не хорошим глюкам.
    Лучше сохранять значение флага прерываний, а потом восстанавливать.
     
  5. serg_admin

    serg_admin Гик

    Ни кто не гарантирует, что функции всех таймеров выполнятся в течении цикла таймера (вроде у Вас 1 милисекунда). Поэтому вызов
    Код (Text):
    Items[i].CallingFunc();
    Просто необходимо вынести из прерывания.
    Я обычно делаю примерно так:
    Код (C++):

    void loop(void) {
    ...
      for (THandle i = 0; i < MAXTIMERSCOUNT; i++)
      {
        if (Items[i].WorkingCounter == 1)
        {
           Items[i].WorkingCounter = 0; // Таймер выключен (если передавать ссылку на
                                        //таймер в функцию вызова, она сможет его включить)
           Items[i].CallingFunc();
        }
      }
    }
     
     
  6. DetSimen

    DetSimen Guest

    Никто не мешает и сейчас вешать одну функцию на несколько таймеров с разными интервалами

    по второму замечанию (по прерываниям) - ничо не понял. Они запрещаются на время изменения массива, и вызова нужной функции, да, ну так и функция отклика должна быть короткой (как мне кажется). У меня она используется например для проверки датчиков, и если показания изменились - положить сообщение в очередь сообщений.
    16 МГц процессор за 1 миллисекунду выполнит более 10000 команд, думаю, никто такие раздутые функции отклика писать не будет

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

    примерно так
    Код (C++):
       
    for (THandle i = 0; i < MAXTIMERSCOUNT; i++)
        {
            cli();                                        
            if (Items[i].CallingFunc == NULL)  continue;
            if (NOT Items[i].Active)               continue;
            if (--Items[i].WorkingCounter > 0) continue;
            Items[i].WorkingCounter = Items[i].InitCounter;  
            sei();
            Items[i].CallingFunc();                    
    }
     
     
  7. DetSimen

    DetSimen Guest

    И это... Если прерывания были запрещены до этого, мы в функцию перебора таймеров не попадем, ибо Step() вызывается именно из аппаратного прерывания таймера. А на выходе из аппаратного прерывания, они всё равно разрешаются командой reti.
     
  8. serg_admin

    serg_admin Гик

    Согласен никто не мешает.
    Я имею ввиду следующее:
    В упрощенном случае можно представить, что одна и та же функция используется для зажигания разных диодов в разное время. Тогда в качестве параметра нужно передавать номер пина и порт. А в более общем случае указатель на некоторый объем данных.

    Раздутые и не нужно писать - вывод в RS232 одного символа при скорости 9600 займет ровно одну мили секунду, конечно там два байта ложатся в буфер, но таймеров то 8. Три байта в порт и время истекло. Точно не проверял но мне кажется Serial.print не асинхронная функция.
    Менее явный вариант, если кто-нибудь в прерывание начнет выполнять операции деления например.

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

    DetSimen Guest

    Воот, и вот тут мы плавненько подходим к следующему этапу, который я выложу скоро, к очереди сообщений. Как в виндовсе, проверил по таймеру, например, датчик температуры, не изменилась - на выход , изменилась - кладем в очередь команду с параметрами (в общем случае - указатель на данные) перерисовать экран, например, или включить/выключить реле и т.д и опять же на выход.
    Тогда loop() будет состоять из выборки сообщений и управления исполнительными механизмами. И ничего лишнего, никаких if millis()-prevmillis , есть событие, приходящее асинхронно, есть отклик, выполняющийся последовательно, на следующей итерации loop(). Пока тестирую, но уже получается красиво. :)
     
  10. DetSimen

    DetSimen Guest

    Ничего не займет, ибо тоже работает по прерываниям опустошения/переполнения буфера. Иначе бы проц только этим и занималса. С точки зрения процессорного времени, передача одного символа через Serial - это примерно как для нас промежуток времени от аванса до зарплаты, мы же не сидим всё это время сложа руки. Вот и у него есть специальные прерывания UART, их даже несколько :)

    Про софт сериал такого не скажу.
     
  11. DetSimen

    DetSimen Guest

    Единственное, что портит картину - analogRead(), который выполняется достаточно долго, сссскатина. Над этим я тоже счас думаю.
     
  12. serg_admin

    serg_admin Гик

    работы ADC тоже можно сделать через прерывания.
    На первом цикле запросил данные на втором забрал.
     
  13. Alex19

    Alex19 Гуру

    Как один из вариантов решения - http://forum.amperka.ru/threads/Простые-примеры-adc-1-wire.6438/. Это без библиотеки, где-то на работе была библиотека.

    В сети очень много примеров, библиотек выбирайте на свой вкус.
     
  14. DetSimen

    DetSimen Guest

    Да, спасибо, почитаю, разберусь