Идеальный таймер

Joiner
Offline
Зарегистрирован: 04.09.2014

Иногда в наших самодельных устройствах требуется контролировать время (сколько прошло....сколько осталось). Лучший вариант это RTC часы реального времени. Но многие простенькие самоделки не стоят того, и можно применить какой-нибудь простенький програмный таймер. Я неоднократно применял таймер в своих поделках, например для разрядки аккумуляторов с подсчетом их емкости. Мой таймер успевал выполнить свою работу по подсчету времени и выводу на экран, но еслиб программа была бы более насыщенной то для моего таймера просто бы не хватало времени и результатом его работы была бы полная фигня.

Всвязи с выше изложенным я написал "Идеальный таймер" :), вернее даже 2 варианта. Этот таймер не может быть поврежден ни какой программой (если не ковырять очень глубоко). С этим таймером я пробовал все, даже пиликать мелодию. Таймер работает изумительно, конечно в пределах точности кварца ардуинки, и ни что не может сбить его ход.

Обращаюсь к мастерам. Подскажите, пожалуйста, какой из вариантов идеальней?

Вариант1

#include <MsTimer2.h>//Библиотека прерываний по таймеру2
long totalSek=0;//Здесь мы будем хранить секунды с момента запуска программы
//Этого счетчика хватит на 68 лет :)  (это просто размышления...68 лет нам не нужно)
void setup() {
Serial.begin(9600);
 MsTimer2::set(1000, to_Timer); // Здесь задаем период 1 секунда
 MsTimer2::start();//Стартуем, теперь таймер запущен
}

void loop() {
//Здесь будет какая-то программа
//у которой теперь есть свой таймер
//и которая не сможет этиму таймеру навредить
}

void to_Timer()//Функция Таймер, он считает и пишет на экран время которое прошло
{
  totalSek++;//Сюда попадаем каждую секунду и приплюсовываем одну секунду
    //Далее рассчитываем часы минуты секунды и записываем на экран
    Serial.println(totalSek/3600);//Пишем в сериал часы
    Serial.println((totalSek%3600)/60);//Далее минуты
    Serial.println((totalSek%3600)%60);//Далее секунды
    Serial.println(" ");//Делаем разрывчик (совсем необязательно) 

}    

Вариант2

#include <MsTimer2.h>//Библиотека прерываний по таймеру2
unsigned long currentMillis = millis();//Делаем глобальную переменную
void setup() {
Serial.begin(9600);
 MsTimer2::set(1000, to_Timer); // Здесь задаем период 1 секунда
 MsTimer2::start();//Стартуем, теперь таймер запущен
}

void loop() {
//Здесь будет какая-то программа
//у которой теперь есть свой таймер
//и которая не сможет этиму таймеру навредить
}

void to_Timer()//Функция Таймер, он считает и пишет на экран время которое прошло
{
    currentMillis=millis();
    Serial.println(currentMillis/3600000);//Пишем в сериал часы
    Serial.println((currentMillis%3600000)/60000);//Далее минуты
    Serial.println((currentMillis%3600000)%60000/1000);//Далее секунды
    Serial.println(" ");//Делаем разрывчик (совсем необязательно)
}    

Спасибо

Tomasina
Tomasina аватар
Offline
Зарегистрирован: 09.03.2013

а ШИМ при этом работает?

Ведь библиотека MsTimer2 использует timer2

Joiner
Offline
Зарегистрирован: 04.09.2014

Tomasina пишет:

а ШИМ при этом работает?

Ведь библиотека MsTimer2 использует timer2

Не помню точно...таймер2 шимит какие-то 2 вывода ардуинки, и скорее всего шим на них работать не будет. И функция Tone будет конфликтовать, там тоже, вроде бы таймер2.

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

Joiner
Offline
Зарегистрирован: 04.09.2014

На прощание фотка как это выглядит на дисплейчике Nokia5110. Скетчик моргает светиком 13, измеряет температуру, пишет в Serial и поет песенки. На таймере это не отражается ни как......прерывания однако

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

Давайте завтра .. сегодня под, да после вчерашней ночи .. да под пиво .. увольте. :)

Сходу - первая предпочтительней. Но надо смотреть что там в библиотеке.

faeton
faeton аватар
Offline
Зарегистрирован: 21.03.2016

Ничего не может сбить его ход? Да запросто: cli на пару секунд и опаньки. :) Прерывания тоже не всегда и все могут быть обработаны и запросто могут быть потеряны. Любое прерывание со старшим приоритетом может помешать.

Joiner
Offline
Зарегистрирован: 04.09.2014

faeton пишет:

Ничего не может сбить его ход? Да запросто: cli на пару секунд и опаньки. :) Прерывания тоже не всегда и все могут быть обработаны и запросто могут быть потеряны. Любое прерывание со старшим приоритетом может помешать.

Я же писал-

" Этот таймер не может быть поврежден ни какой программой (если не ковырять очень глубоко). "

А что такое cli на пару секунд? Я пока не знаю что такое cli....:(

dhog1
Offline
Зарегистрирован: 01.03.2016

Честно говоря оба варианта ни в козу ни в Красную Армию.

"Бабушка" millis() осёдлывает Timer0 и дергает его одну тысячу раз в секунду. Это одна тысяча прерываний в секунду. Вход в прерывание, операция с чудовищным по разрядности числом (32 бита), выход из прерывания. Это "бесплатный" таймер платформы ардуино, ну чем он вам не угодил? Может быть вы не умеете структурировать код своего приложения, если такой роскоши (без кавычек) недостаточно? Так тут на форуме "пришпилено" одно из решений, хук на таймер (возможность привязать свою функцию), что при всей спорности подхода мЕньшее зло, чем то, о чем вы пишете.

Вы сторонней библиотекой вводите второй миллисекундный таймер, Timer2. Это еще одна тысяча (вдобавок) дергания МК в секунду. Оба таймера (в смысле Timer0 и Timer2) трудятся, не покладая рук или что у них там. Еще операции с 32 битными числами на 8 битном МК.

В результате вы теряете 2 счетчика/таймера из 3, беря взамен... А что вы берете взамен? Об "неубиваемости" уже написали. Вежливо могу дополнить, что _любая_ сторонняя "библиотека", использующая Timer2, скорее всего (наверняка) подерется за ресурс с MsTimer2.

Ну и судя по вашим примерам, характерное время для вас - секунды (часы обновить интервалом времени, не временем). И что бы не использовать для этого Timer1, 16-ти битный счетчик, способный отсчитывать секунды?

Все хотят идеальный таймер (я тоже хочу). Но так таймер, не идеальный, просто таймер, делать не принято.

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

Если нужны секунды, то можно использовать watchdog таймер с делителем. Он, как-бы никому не нужен и судя по даташиту, как раз и предназначен для таких целей (RTOS), кроме задачи "будить МК".

По этим решениям - в целом одинаково, что первое что второе. Сильно зависит от использования ресурсов, вам верно отписали: если понадобится один из таймеров для конкретной цели, а вы его заняли .. придется "кого-то переселять": или вам свой таймер или библиотеку, которой он нужен. В этом плане timer0 (millis) предпочтительней - шансов "переселять" существенно меньше.

Joiner
Offline
Зарегистрирован: 04.09.2014

dhog1, Arhat109-2, спасибо за ответы. Самый первый конфликт, с которым я столкнулся, это функция Tone(). Она тоже использует таймер2. Когда начинает играть музыка, показания секунд наглухо останавливаются. Но если пиликать музыку без этой функции, то все нормально, прерывания почти, можно сказать совсем не портят музыку.

 Я пока ковырялся с этим таймером, понял, что все можно высчитать из millis(), ...........previosMillis и прочая. Но подскажите, пожалуйста, как сделать, чтобы показания таймера на экране обновлялись ровно один раз в секунду, независимо от хода основной программы, как рационально использовать имеющиеся таймеры?

Подскажите идеальное решение.

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

Так не бывает "идеального". :)

Joiner
Offline
Зарегистрирован: 04.09.2014

Arhat109-2 пишет:

Так не бывает "идеального". :)

Бывает.......ну..почти идеальный... Уверен, что вариант получше существует, но т.к. я не спец в программировании, то мне он пока не виден.

Т.к. мой таймер оформлен в виде функции, то легко встраивается в любую программу. Попробовал ради интереса воткнуть ее в скетч примеров из библиотеки LCD5110_Graph. Пример называется Graph_Demo. Там какбэ бенчмарк экрана, ресуются всякие линии квадратики, выводится рисунок. Без встраивания функции таймера в конце теста показывает 47ххх миллисекунд, со встроенной функцией таймера, который выводит в сериал секунды, минуты часы, получилось тоже 47ххх миллисекунд. Абсолютно не заметно, что таймер мучает этот пример своими прерываниями.

 

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

Так это верно для любой "функции", особенно если она проста и локально-замкнута (не портит что-то извне себя).

На самом деле вас зазря несколько напугали. Обработчик таймера (что 0, что ваш) отработает за примерно 2-3микросекунды .. какова доля занимаемого им процессорного времени на протяжении 1 миллисекунды (1 вызов)? :)

Верно 2-3 / 1000. или 0.25% -- четверть от одного процента. Вы такое способны заметить на глаз? :)

faeton
faeton аватар
Offline
Зарегистрирован: 21.03.2016

Вот Вы не поверите - в PC всего один таймер и на нём всё вмещается. :) Суть такая: запускаем таймер на максимально требуемую скрость. В прерывании таймера делаем софтовые делители, по которым вызываем процедуры.

const byte cSecFlag = 1;
const byte cMinFlag = 2;
volatile int SecDiv  = 0, MinDiv =0;
volatile byte IntFlags = 0;
volatile * OldInt;

void Interrupt() {    // вызывается 1000 раз в секунду
   assembler {
      pushf
      call    OldInt
      sti
   };
   if (SecDiv==1000) {
      SecDiv=0;                   // запускается каждое 1000-е срабатывание таймера раз в секунду
      if (IntFlags and  cSecFlag)!=0) {
         IntFlags=IntFlags or cSecFlag;
         EverySecond();      // можно тут висеть хоть сутки - kheubt прерывания будут работать
         IntFlags=IntFlags and not(cSecFlag);
      }
   } else {
      SecDiv++;
   };
   if (MinDiv==1000*60) {
      MinDiv=0;
      if (IntFlags and  cMinFlag)!=0) {
         IntFlags=IntFlags or cMinFlag;
         EveryMin();                 // запускается ещё реже - раз в минуту
         IntFlags=IntFlags and not(cMinFlag);
      }
   } else {
      MinDiv++;
   };
};


void setup() {
   OldInt= //адрес прежнего обработчика прерываний
   SetInt(Timer1Int, Interrupt);
}

Это называлось перехват прерывания. :) Код не нативный, это шаблон, простите паттерн. :) Такаыя схема позволяет работать прерываниям без конфликтов, не трогает то, что было в обработчике прерываний. В каждом отдельном обработчике прерываний можно зависнуть сколь угодно долго, это не повлияет на другие обработчики. Я думаю, понятно.

Клапауций 232
Offline
Зарегистрирован: 05.04.2016

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

курим http://microcontrollerov.net/microcontrolleri/mega/AVR134-Chasy-Realnogo-Vremeni-na-osnove-Asinhronnogo-Tajmera

для ATMEGA16, ATMEGA8 юзаю так



// ATMEGA16, ATMEGA8

volatile unsigned long t = 0;

ISR (TIMER2_OVF_vect) {++t;} // обработка событий по прерыванию счётчика

void setup() {
///////////////////////////////////////////////////////////////////
cli(); // запрет прерываний глобально
TIMSK &= ~(_BV(TOIE2) | _BV(OCIE2)); // отключение прерывания Таймера 2
ASSR |= _BV(AS2); // перевод Таймера 2 в асинхронный режим тактирования от кварцевого резонатора 32768Гц
TCNT2 = 0x00; // начальная инициализация счётчика
TCCR2 = 0x05; // установка коэффициента деления 128
OCR2  = 0x00; // совпадение с частотой 1 Гц
while (ASSR & (_BV(TCN2UB) | _BV(OCR2UB) | _BV(TCR2UB))); // ждём готовности таймера
TIMSK |= _BV(TOIE2); // разрешаем прерывание от Таймера 2
sei(); // разрешаем прерывания глобально
///////////////////////////////////////////////////////////////////

}

void loop() {}

 

Joiner
Offline
Зарегистрирован: 04.09.2014

Спасибо faeton,

Спасибо Клапауций 232.

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

Попробую оба, предложенные, варианта. О впечатлениях отпишусь.

Спасибо.

P.S. Попробовал копипастом оба скетча откомпилировать. Скетч faeton_а выдает ошибку,

скетч Клапауция компилируется, если выбрать Атмегу8...

Клапауций 232
Offline
Зарегистрирован: 05.04.2016

Joiner пишет:

скетч Клапауция компилируется, если выбрать Атмегу8...

я дал пример для М8 и М16 для того, что бы ты его компиллировал для контроллеров отличных от М8 и М16?

Joiner
Offline
Зарегистрирован: 04.09.2014

Клапауций 232 пишет:

Joiner пишет:

скетч Клапауция компилируется, если выбрать Атмегу8...

я дал пример для М8 и М16 для того, что бы ты его компиллировал для контроллеров отличных от М8 и М16?

Видел я коментарий сверху, где написано про атмегу 16 и атмегу 8,  поэтому не запаниковал, когда выдало ошибку на атмеге 328, а просто поменял на микропроцессор из комментария.

У меня есть чип атмега8, припаяю на платку, попробую.

Клапауций 232
Offline
Зарегистрирован: 05.04.2016

Joiner пишет:

У меня есть чип атмега8, припаяю на платку, попробую.

зачем? - у меня RTC на m8 работает, я уже сделал - тебе не нужно ничего пробовать.

Logik
Offline
Зарегистрирован: 05.08.2014

Клапауций 232 пишет:

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

Все ещё печальней, там даже не кварц, так - керамический резонатор. Т.е. он еще и температурно нестабилен. Но для некоторых применений, для которых 3-5% некритично, то сойдет. Толькож шо за хрень, они пишут... 

dhog1 пишет:

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

+1. Целиком разделяю..

Joiner
Offline
Зарегистрирован: 04.09.2014

Logik пишет:

Все ещё печальней, там даже не кварц, так - керамический резонатор. Т.е. он еще и температурно нестабилен. Но для некоторых применений, для которых 3-5% некритично, то сойдет. Толькож шо за хрень, они пишут... 

dhog1 пишет:

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

+1. Целиком разделяю..

Мне нужно контролировать процесс, который занимает по времени не более 3-х часов. За это время без какой-либо коррекции (ставлю в программе просто 1000) мой таймер уходит на 4-5 секунд. Эти 5 секунд не имеют для меня ни какого значения. Еслиб это было критично, то поставил бы DS3231, за которыми наблюдаю уже больше месяца. Уход от атомных за это время менее 2-х секунд.

Просто хотелось посмотреть более красивые решения.

Мне нравится, когда говорят: "Это плохо!",

но еще больше нравятся, когда говорят:"Это плохо, лучше будет вот так..."

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

Если 328 без спец. обвеса (кварца), то шибко лучше не будет. Можно поиграться с калибрующим регистром, таковой есть на 2560, не знаю есть ли на 328 .. но думаю что "существенно" он тоже ничего не улучшит, поэтому и не стал советовать. Код от Клапауция - рабочий .. но только там, где есть таковая аппаратная возможность, что им и озвучено. Поэтому и не стал постить разного рода "частные случаи", догадываясь что речь про УНО или аналоги (95% постов форума).

Пример faeton, работать не будет, и я уже где-то тут это указывал. Не все то золото, что блестит. Код, пригодный на писюках, а равно как и методики и советы по программированию, здесь по большей или просто вредны (один из таких ляпов - даже прибит гвоздиком про оптимизации от ЕвгенияП, второй ляп про переписывание виртуальных рюшек в потоках ввода-вывода уже утонул) или вовсе не рабочие (как этот пример с прерываниями).

Ещё раз: не всё то золото, что блестит.

 

dhog1
Offline
Зарегистрирован: 01.03.2016

2 Joiner

Ну когда страсти поутихли, давайте отвечу за свои слова. Почему то, что вы написали - "плохо" (в кавычках. Работает же). Первая причина в том, что вы вдобавок к имеющемуся миллисекундному таймеру (millis(), чтоб она здорова была) добавили еще один миллисекундный таймер через библиотеку MsTimer2. Для работы с интервалами с характерным временем 1 сек это не лучшее решение. Непроизводительные потери от использования "неоптимального" счетчика составляют в _лучшем_ случае 0.5% от производительности МК. Эту цифру я даю не оценочно, эта цифра считается по выполняемым инструкциям МК. Немного, да, но как-то ... неаккуратненько для ИТ (идеального таймера).

Вторая причина в том, _как_ вы используете прерывания таймера. Вы их используете "хуком" из прерывания таймера (Timer2). Посмотрел текст MsTimer2. В момент срабатывания таймера, управление передается функции пользователя в контексте текущего прерывания, т.е. с глобально запрещенными прерываниями. Это небезопасный метод. Он описан на этом же форуме и доступен по ссылке  http://arduino.ru/forum/programmirovanie/etyudy-dlya-nachinayushchikh-metronom-ne-zagruzhaya-taimer  , там же и обсуждение.

И последнее из "плохого". Вы пишете, что на масштабе 3 часов ваш таймер уходит на 4-5 сек. Это тревожный сигнал. То, что такое поведение для вас не критично, не говорит в пользу ИТ. 4-5 сек за 3 часа - это _очень_ необычный результат для ИТ.

Теперь о том, как _можно_ сделать программный таймер для ваших характерных времён. Ниже код, который _не нужно_ компилировать, который нужно посмотреть. Этот код демонстрирует часто используемый прием - структуризацию приложения, когда исполняется та его ветка, которая должна исполняться. Некоторые такую организацию называют State Machine, некоторые по-другому. В контексте нашего разговора такая организация хорошо подходит для секундного таймера. Составляя этот пример, старался не скупиться на комментарии.

                             // удобные названия для бит переменной StFlag
#define one_sec_bit            0
#define read_buttons_bit       1
#define get_temperature_bit    2
#define turn_on_radio_bit      3

volatile byte StFlag = 0;    // значения бит этого байта управляют ходом приложения


#define DHT22_DELAY     15   // например опрашивать темп-ру каждые 15 сек


... // в loop()

byte temperature_delay = DHT22_DELAY;  // предполагаемая задержка между опросами датчика температуры
uint16_t some_delay;  // какая-то задержка от 1 до 65535 сек; перед использованием ее нужно задать

                             // конструкция, дробящая приложение на участки исполняемого кода

switch (get_bit(StFlag)) {   // получить бит события

    case one_sec_bit:          // сюда попадаем от срабатывания секундного таймера
        update_my_watch();     // секунда прошла, обновить визуальные часы (например)
                               // если уже пора, выставить бит для последующего опроса температуры
        if (!temperature_delay--) {temperature_delay = DHT22_DELAY; StFlag |= (1<<get_temperature_bit);};
                              // проверить какую-то задержку; будет проверена на "0", затем уменьшена на единицу
        if (!some_delay--) {... что-то сделать и переопределить задержку; обычно выставляют бит события в StFlag}
        StFlag &= ~(1<<one_sec_bit);  // сбросить бит обрабатываемого события
    break;
    
    case read_buttons_bit:   // например обработчик прерываний от кнопок определил нажатую
                             // кнопку как radio_btn_pressed
                             // в принципе "кнопочный" обработчик мог бы и напрямую выставить бит turn_on_radio_bit
        ...
        if (radio_btn_pressed) StFlag |= (1<<turn_on_radio_bit);  // например нажата кнопка включения радио
        ...
        StFlag &= ~(1<<read_buttons_bit);  // сбросить бит обрабатываемого события
    break;
    
    case get_temperature_bit:
        temperature = read_DHT22();
        StFlag &= ~(1<<get_temperature_bit);   // сбросить бит обрабатываемого события
    break;
    
    case turn_on_radio_bit:
        ... // включить что-то, например радио
        StFlag &= ~(1<<turn_on_radio_bit);  // сбросить бит обрабатываемого события
    break;

} // end switch

... // end loop()

... // ну и считывать номер установленного бита в управляющей переменной StFlag
    // например справа-налево, бит справа будет иметь приоритет перед "более левым" битом

byte get_bit(byte flag) {
byte i = 0;
    while ( !(flag & (1<<i)) && (i<8) ) i++;
    return i;
}

    // запустить секундный таймер
    // собственно инициализация таймера с комментариями
    // Clock source: System Clock
    // Clock value: 62,500 kHz @ 16 MHz MCU
    // Mode: Normal top=0xFFFF
    // Timer Period: 1 s
    // Timer1 Overflow Interrupt: On

     TCCR1A = 0;
     TCCR1B = (1<<CS12);         // все это (как инициализировать таймер) есть в документации на МК
     TCNT1H=0x0B;                // это начальное значение счетчика
     TCNT1L=0xDC;                // для выбранного времени счета 1 сек и 16 МГц МК
 
     TIMSK1 = (1<<TOIE1);        // разрешаем прерывание по переполнению
    
    // и не забыть обработчик прерывания таймера по переполнению
    // в этом примере он будет таким
    // и количество секунд подсчитывать в прерывании совсем не обязательно
    
    interrupt [TIM1_OVF] void timer1_ovf_isr(void)
{
                // вновь выставить значения для начала счета
    TCNT1H = 0xBDC >> 8;
    TCNT1L = 0xBDC & 0xff;
                // и отметить факт срабатывания таймера
                // т.е. выставить соответствующий бит в управляющей переменной StFlag
    StFlag |= (1<<one_sec_bit);
}

Как сломать такой таймер? Сделать так, чтобы он пропустил счет. Пропустить счет он может, если какой-то участок кода будет выполняться _дольше_ 1 сек. IMHO 1 сек для 16 МГц МК - это достаточно много, и если не удается с чем-то управиться за 1 сек, то скорее всего это признак неправильной работы с этим "чем-то".

ИТ это, конечно, считаться не может, просто аккуратный секундный программный таймер, как вы и заказывали. И еще - используемый в примере ресурс 16 бит Timer1 - дорогой ресурс, у младших AVR он если есть, то один.

Последнее. Для моих интересов ИТ (секундный) представляет собой внешний "часовой" 32.768 кГц кварц +-5ppm (если верить продавцам, сам проверить не могу). Для ATMega328P это означает рабочие 8 МГц (вместо 16-ти) и потерю для других целей асинхронного Timer2. Для каких-то задач это нормально.
 

Joiner
Offline
Зарегистрирован: 04.09.2014

dhog1 пишет:

2 Joiner

Ну когда страсти поутихли, давайте отвечу ............

Во-первых, спасибо что откликнулись на мой вопрос, спасибо за обстоятельный ответ. Прочитал, пока понял не все. Буду вникать, разбираться. Благодаря этуму форуму многие вещи становятся для меня более-менее понятными.

Спасибо.

dhog1
Offline
Зарегистрирован: 01.03.2016

И вам спасибо за ваше спасибо.  Вы не представляете как это приятно - общаться с адекватным человеком, без понтов с любой стороны.

Потом прийдут другие и поправят (это интересная тема) или выскажут свое мнение. Надеюсь что пример поведения (а не идеальный таймер) брать будут у вас.

faeton
faeton аватар
Offline
Зарегистрирован: 21.03.2016

Arhat109-2 пишет:

Пример faeton, работать не будет, и я уже где-то тут это указывал. Не все то золото, что блестит. Код, пригодный на писюках, а равно как и методики и советы по программированию, здесь по большей или просто вредны (один из таких ляпов - даже прибит гвоздиком про оптимизации от ЕвгенияП, второй ляп про переписывание виртуальных рюшек в потоках ввода-вывода уже утонул) или вовсе не рабочие (как этот пример с прерываниями).

Ещё раз: не всё то золото, что блестит.

Чем приведённый мной алгоритм неприменим на на МК? Компилиповаться не будет, разумеется, я не знаю ассемблер меги и привёл писюковую нотацию. И не знаю как в С перехватить прерывание. :)

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

Тут этот подход как-бы "принципиально" невозможен. Я уже писал где-то ранее, если не вам, то на похожее предложение.

У МК - "гарвардская архитектура", и вектора прерывания находятся во флеше, а не ОЗУ. То есть адрес обработчика прерывания фиксирован этапом компиляции программы. Можно, конечно, используя команды lpm,spm его изменить "по ходу исполнения", но есть серъезные ограничения. Писать во флеш можно только из ДРУГОГО куска флеша .. а там сидит типовой загрузчик. То есть, ваш подход предполагает изменения как в системе компоновке программы (перенастройка сценария линковщика), так и изменение в загрузчике, чтобы он имел методы, вызывая которые можно переписыать таблицу векторов.

То есть, по сути изменить ВЕСЬ подход от компиляции, до загрузки прогаммы.

Второй способ предполагает единый обработчик, который будет косвенно вызывать реальную программу по таблице, которая лежит в ОЗУ. Это очень медленный и расточительный способ, поэтому применяется только частично в wiring: attachInterrupt() и только для основных векторов прерываний.

В общем, во всех отношениях - гемморой и немалый.

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

dhog1, а что там "править"? Вполне нормальный и верный разбор ситуации. Спасибо.

Joiner
Offline
Зарегистрирован: 04.09.2014

Поставил в начале и в конце функции таймера строчки   Serial.println(micros()); Выводит показания микросекунд в начале исполнения функции и в конце. Разница между ними 1052 микросекунды. И в этом времени в том числе еще запись в сериал и вывод показаний таймера на LCD Nokia. Так что совсем не много времени расходует таймер.

dhog1
Offline
Зарегистрирован: 01.03.2016

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

1. Функция таймера - зарегистрировать истечение заданного количества отсчетов. В вашем случае это число "1000", которое вы передаете в строке MsTimer2::set(1000, to_Timer).

2. Когда _вы_ говорите "функция таймера", вы имеете в виду что-то свое, указатель на что вы передаете вторым параметром, to_Timer. Эта функция к собственно таймеру отношения не имеет. В ваших примерах вы пишете в Serial и, видимо, обновляете Nokia 5110. Другие включают насос, например. Один физический таймер может управлять многими процессами, оформленными в коде в виде функций.

3. Ранее вы писали, что "встраивали функцию таймера" в графический бенчмарк 5110, и время выполнения бенчмарка в миллисекундах не изменилось, от слова совсем. Теперь вы пытаетесь замерить количество микросекунд от начала до окончания выполнения "функции таймера" и получаете очень наглядный результат. На основании этого результата вы делаете вывод. Дальше будете экспериментировать? Например включив в "функцию таймера" маленькую задержку. Или в миллисекундах померить.

4. В том, что ваш таймер уходит на 4-5 секунд за 3 часа вы не видите ничего тревожного. А ведь это очевидно указывает, что Timer2 теряет счет, что ваша "функция таймера" отрабатывает больше 1 миллисекунды.

На этом результат использования библиотеки MsTimer2 закончил. Занудству тоже есть предел. Работает же.

2 Arhat109-2

Да все там править, раз не сумел внятно написать. Если в контексте прерывания время измеряют. Кстати, можно, но не так же.

Joiner
Offline
Зарегистрирован: 04.09.2014

dhog1 пишет:

Только мое занудство пишет этот пост........................................

Ни чего не понял.... Видимо я что-то не правильно делаю..... Скажите что. Может делаю глупость, измеряя неправильно время...может быть. Думаю, мне простительно, т.к. моя профессия столяр. Ошибок по деревяшкам себе бы не простил, а в программировании вполне допустимо :)

dhog1
Offline
Зарегистрирован: 01.03.2016

2 Joiner

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

Весь этот флуд в поисках идеального таймера. Пока не нашли. В этой фразе уже ирония.

Вы измеряете время, когда э-ээ... остановился ход времён. Ваша "функция таймера" его отключила. millis() не работает, micros() выдает одну (примерно) миллисекунду по флагу переполнения Timer0. Обработчики по переполнению таймеров что millis(), что MsTimer2 отключены во время работы вашей "функции таймера". Это результат _такого_ использования событий таймера.

И заканчивайте с извинениями, тут нет кисейных барышень и вы не из числа, да и с такой достойной профессией.

Joiner
Offline
Зарегистрирован: 04.09.2014

dhog1 пишет:

2 Joiner....

OK :)

faeton
faeton аватар
Offline
Зарегистрирован: 21.03.2016

Arhat109-2 пишет:

Тут этот подход как-бы "принципиально" невозможен. Я уже писал где-то ранее, если не вам, то на похожее предложение.

У МК - "гарвардская архитектура", и вектора прерывания находятся во флеше, а не ОЗУ. То есть адрес обработчика прерывания фиксирован этапом компиляции программы. Можно, конечно, используя команды lpm,spm его изменить "по ходу исполнения", но есть серъезные ограничения. Писать во флеш можно только из ДРУГОГО куска флеша .. а там сидит типовой загрузчик. То есть, ваш подход предполагает изменения как в системе компоновке программы (перенастройка сценария линковщика), так и изменение в загрузчике, чтобы он имел методы, вызывая которые можно переписыать таблицу векторов.

То есть, по сути изменить ВЕСЬ подход от компиляции, до загрузки прогаммы.

Второй способ предполагает единый обработчик, который будет косвенно вызывать реальную программу по таблице, которая лежит в ОЗУ. Это очень медленный и расточительный способ, поэтому применяется только частично в wiring: attachInterrupt() и только для основных векторов прерываний.

В общем, во всех отношениях - гемморой и немалый.

Я, наверное, что-то не понимаю, но чем Вам не нравится таблица векторов прерываний по адресу 0x0000? Что мешает утащить из неё адрес обработчика, который библиотекой среды назначен, и подставить туда свой?

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

Мешает процесс записи во флеш из исполняемой в том же участке программы. Атмел запрещает .. :)

Logik
Offline
Зарегистрирован: 05.08.2014

Joiner пишет:

Logik пишет:

Все ещё печальней, там даже не кварц, так - керамический резонатор. Т.е. он еще и температурно нестабилен. Но для некоторых применений, для которых 3-5% некритично, то сойдет. Толькож шо за хрень, они пишут... 

dhog1 пишет:

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

+1. Целиком разделяю..

Мне нужно контролировать процесс, который занимает по времени не более 3-х часов. За это время без какой-либо коррекции (ставлю в программе просто 1000) мой таймер уходит на 4-5 секунд. Эти 5 секунд не имеют для меня ни какого значения.

Так так и пишите. Уход за сутки на столе около 1 минуты. На жаре и холоде - ХЗ. 

А слово идеальный выкиньте. Потому как это дерьмовенький показатель даже для дешевых китайских тикалок.

А уж фраза "Этот таймер не может быть поврежден ни какой программой"?! Это чё? А на спор?

А что за словесной пургой - обычный делитель тактовой частоты на таймере 2 да еще не самой лучшей организации. С таймером напрямую чего не работаем? Понимаете, такое делал пошти каждый, кто авр в руках держал, и я делал, но только Вы решили что он "идеальный" и "не может быть поврежден ни какой программой". Остальные считали что это бюджетное, компромисное решение с очень ограничеными возможностями. Но про ограничения Вы не написали, по крайнерь о всех и сразу.

Как бы Вы отнеслись  к продавцу гнилой картошки нахваливающего товар как "идеальный"?! Вот и к Вашей теме так.

 

Joiner пишет:

 Еслиб это было критично, то поставил бы DS3231, за которыми наблюдаю уже больше месяца. Уход от атомных за это время менее 2-х секунд.

Просто хотелось посмотреть более красивые решения.

Так поставьте далос и смотрите! Уж точно красивее предложенного и цена бросовая. 

ПС. Такое впечетление, что делали тему из ничего на спор. 

faeton
faeton аватар
Offline
Зарегистрирован: 21.03.2016

Arhat109-2 пишет:

Мешает процесс записи во флеш из исполняемой в том же участке программы. Атмел запрещает .. :)

Вот засада... Разве не в RAM таблица векторов прерываний? Каким образом тогда работают установщики обработчиков attachInterrupt()?

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

faeton, ну перечитайте мой пост внимателней, я уже вам отписал ответ на ваше "как" :)

Joiner
Offline
Зарегистрирован: 04.09.2014

Logik пишет:

Так так и пишите. Уход за сутки на столе около 1 минуты...........

..............Это чё? А на спор?

А что за словесной пургой................

Как бы Вы отнеслись  к продавцу гнилой картошки ..................................

Так поставьте далос и смотрите! ..............................................

ПС. Такое впечетление, что делали тему из ничего на спор. 

Ну вот..........пришел АСС и отшлепал мою непрофессиональную задницу.

Попробую объясниться. Сейчас вижу, что "Идеальный" надо было поставить в кавычки, чтобы не злить АССов программирования. Посто делаю сейчас простенькое устройство, "контроллер" температуры (контроллер пишу в кавычках, чтобы потом не отругали, т.к. контроллер совсем и не контроллер, а электронный термометр, который при достижении определенной температуры на разных этапах подает звуковой сигнал и требует ручного вмешательства). В программе будет предусмотрено измерение времени прохождения этапов (используется именно этот таймер), весь процесс займет не более 2х часов и ошибка в 5 сек не заставит меня застрелиться. Еще будет простенькое меню, включить-выключить подсветку экрана и задать параметры, если будет в этом надобность и записать их в EEPROM для использование на будущее.

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

По вопросу продавца гнилой картошки.......Я не заметил, что я кому-то здесь что-то продавал :)

По вопросу даласа........У меня стоит DS3231 в самодельных часиках со стрелочками. Они негромко тикают у меня в комнате уже давным-давно и очень радуют меня своей точностью и несбиваемостью при отключении электроэнергии. И еще.....в них осталось еще много памяти для всяких улучшений, но пока некогда.

По вопросу темы из ни чего..... Для новичков, может кому и пригодится....и еще надеялся что спецы что-то подскажут.

Ну вот и все..

Извините, очень много букв.

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

Logik был "груб, но прав". однако. А вот Вы обиделись на него зря и забоялись АССов .. не стоит, они такие же как и Вы и тоже когда-то были новичками и без кавычек. Молодсть - тот недостаток, который с каждым днем проходит, однако. :)

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

Спецы уже вам наподсказывали .. делайте выводы. "идеальных балалаек" - нет в природе. Все хорошо для своего, конкретного применению (попадалову). :)

Logik
Offline
Зарегистрирован: 05.08.2014

Joiner пишет:

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

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

Это контроллер самогонного аппарата?

Клапауций 232
Offline
Зарегистрирован: 05.04.2016

кароче тема переименовывается из 

Идеальный таймер

в

Пуленепробиваемый картофель #35

Joiner
Offline
Зарегистрирован: 04.09.2014

Logik пишет:

Это контроллер самогонного аппарата?

Да............для самогона из гнилого картофеля :)))))

Logik
Offline
Зарегистрирован: 05.08.2014

Из гнилого получается только гнилое. Зачем там вобще время? Разве чтоб потом вывести отчет, типа процесс длился стокото... И чего было вобще лезть к таймеру2, на пересчете миллис получится ну ничем не хуже. Зато проще.  .... Хотя дайте угадаю, Вы приципили термометр, обнаружили что в его либе блокирующий вызов пошти секунда, и это вызвало пропуски при подсчете секунд. ))))

Joiner
Offline
Зарегистрирован: 04.09.2014

Logik пишет:

.........Зачем там вобще время? Разве чтоб потом вывести отчет, типа процесс длился стокото......

Точно, угадали на 100%.  И в моей программе все временные помежутки расчитываются из millis(). А Timer2 применяется лишь для красивого, неполамаемого посекундного вывода времени на экран. Может совершенно ненужная фишка, но я же говорил, что этот скетч - этюд по программированию, тренировка мозга и приобретение навыков.

Пока мне нравится то, что у меня получается. Скоро закончу скетч и выложу видео работы на макетке.

А самогон делаю не из гнилой картошки, а из " для городского жителя из чистейшего сахару рафинада"(из какого-то фильма).

Logik
Offline
Зарегистрирован: 05.08.2014

Так если с датчиками работать правильным путем, то и время на millis() отрисовыватся будет верно.

Как раз доделываю сильно похожее (ко крайней мере по функциональному назначению) устройство. Потому и угадываю легко )))

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

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

Фото-видео тож могу запостить, как на днях испытания сделаю.

Joiner пишет:

мне нравится то, что у меня получается. Скоро закончу скетч и выложу видео работы на макетке.

А самогон делаю не из гнилой картошки, а из " для городского жителя из чистейшего сахару рафинада"(из какого-то фильма).

Целеком разделяю и горяче одобряю подход.

Joiner
Offline
Зарегистрирован: 04.09.2014

Logik пишет:

.....................................

Фото-видео тож могу запостить, как на днях испытания сделаю.

................................

Было бы интересно посмотреть. Буду ждать.

И про динамику изменения температуры - интересная мысль! Надо бы осмыслить и попробовать.

Logik
Offline
Зарегистрирован: 05.08.2014

Joiner пишет:

И про динамику изменения температуры - интересная мысль! Надо бы осмыслить и попробовать.

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

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

Joiner
Offline
Зарегистрирован: 04.09.2014

Logik пишет:

........................

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

А мне еще показалось, что температура на всех этапах процесса еще зависит и от атмосферного давления. Заказал в Китае 2 барометрических датчика, ждал 60 дней, так и не пришли, пришлось забрать деньги. Но время-то упущено! Придется снова заказывать датчики. В своей конструкции оставлю место под барометр.

Logik
Offline
Зарегистрирован: 05.08.2014

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

bwn
Offline
Зарегистрирован: 25.08.2014

Logik пишет:

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

Истинная правда. Хотя на ректификации ловим стабилизацию относительной температуры и по ней работаем.