Fun Electronic

Электронные поделки, программирование микроконтроллеров, и прочая белиберда|Electronic Basteleien, Mikrokontroller Programmierung und anderes Quatsch

RSS
people

Tips and Tricks: использование Watchdog таймера|Tips and Tricks: Benutzen von Watchdog Timer

[lang_de]Die Übersetzung kommt demnächst [/lang_de]

Поделюсь с вами небольшим, но довольно интересным способом работы с Watchdog таймером микроконтроллера.

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

И по этой причине обычно программисты раскидывают по всей программе и во всех циклах команду сброса таймера wdt_reset (), что не только портит вид всего текста программы но и мешает ее чтению, если вы копаетесь в чужом коде, а так же — самое главное — это лишний десяток байт, который тратится только на простой сброс. Ну и если что-то новое добавляете, то опять же надо постараться не забыть вставить вызов этой функции. В Avr Gcc вызов этой функции заменяется всего одной командой на ASMе, но всей некрасоты этого метода оно не отменяет.

Что же делать?

Мой коллега с первой моей работы подсказал мне довольно элегантное решение этой проблемы, коим я до сих пор и пользуюсь. А именно — сбрасывать watchdog — таймер в обычном хардверном таймере. Да, вы не ослышались, — в обычном таймере, но с небольшой обвязкой. Потому как просто поставив команду сброса в функцию прерывания таймера равносильно самоубийству.

И так — обвязка.

Для начала нам надо объявить одну глобальную переменную размером в байт или бит (в зависимости от архитектуры вашего микроконтроллера).  И еще одну прееменную размером побольше. Скажем

[codesyntax lang="c" lines_start="10" container="div" title="Global variable" ]

u08 SWdtReset;
u32 SWdtTimer;

[/codesyntax]

Затем в функцию прерывания таймера вставляем такой вот кусок кода:

[codesyntax lang="c" lines_start="23" container="div" title="Watchdog-Timer reset" ]

 if (SWdtReset)
 {
   SWdtReset = 0;
   SWdtTimer = SWDT_VALUE;
 }
 if (SWdtTimer)
 {
  SWdtTimer--;
  wdt_reset();
 }

[/codesyntax]

Значение макроса SWDT_VALUE вычисляем на практике, равное примерному количеству срабатываний нашего таймера в течение выполнения основного цикла программы, с учетом основных прерываний.

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

[codesyntax lang="c" lines_start="15" container="div" title="Watchdog-Timer reset" ]

SWdtReset = 1;

[/codesyntax]

И, собственно, все!

Теперь разберем все по порядку.

В функции прерывания таймера мы опрашиваем переменную SWdtReset на предмет наличия в ней какого либо значения, отличного от 0. Если таковое есть, то это значит, что кто-то его туда записал, т.е. жизнь еще теплится в жилах нашего микроконтроллера, и можно спокойно записать в переменную SWdtTimer наше SWDT_VALUE — количество циклов таймера на один проход основного цикла программы, и надо не забыть обнулить переменную SWdtReset. Это обязательно!

Далее мы опрашиваем переменную SWdtTimer на предмет наличия в ней ненулевого значения, и, если такое имеется, то мы сбразываем наш watchdog-таймер, и одновременно уменьшаем значение переменной  SWdtTimer на 1-цу. Это тоже обязательно!

Таким образом, если никто не будет записывать в переменную SWdtReset значение, отличное от 0, то в скором времени мы перестанем сбрасывать watchdog — таймер, и он перезапустит наш микроконтроллер.

Т.е. этим простым трюком мы мониторим сразу все: — основной цикл программы, — и все прерывания, ведь, зависни одно из прерываний — то watchdog — таймер, просто напросто, не сбросится, а если основной цикл зависнет, то watchdog — таймер будет сбрасываться только определенное количество раз и затем перестанет это делать. Что, собственно, нам и надо было получить в результате.

И этот метод нам дает одно преимущество — а именно — чистоту кода — у нас  нет больше раскиданных там и туд команд wdt_reset (), — один раз настроив этот механизм, мы просто забываем о нем.

Есть и небольшой недостаток — если в программе есть циклы, которые требуют много времени — например — чтение сектора флеш-карты, то надо в этот цикл тоже вставить строку

[codesyntax lang="c" lines_start="96" container="div" title="Watchdog-Timer reset" ]

SWdtReset = 1;

[/codesyntax]

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

Приятного кодинга вам сегодня!

2 комментария to “Tips and Tricks: использование Watchdog таймера|Tips and Tricks: Benutzen von Watchdog Timer”

  1. di-halt.livejournal.com/ Says:

    А смысл? Растянуть выдержку вачдога? Так ее же и так можно увеличить. И также будет в одном месте главного цикла одна строка. Получается меняем WDR на LDI. Или я что то недоглядел?

  2. MasterAlexei Says:

    Смысл именно в том, чтобы растянуть выдержку и уменьшить раскиданные по всей программе команды сброса вачдога. Например если в проге много мелких циклов — то, при обычном использовании вачдога, в каждый их них надо ставить команду сброса, а так — и не надо вовсе. А сам вачдог аппаратно вроде как не сильно то и увеличивается. Максимум до 1.9 секунды. А так — и на 10 можно поставить. Ну и один из плюсов — один раз сделал и забыл.

Leave a Reply

You must be logged in to post a comment.