Это версия страницы http://controllersystems.com/books/praktika_programmirovaniya_atmel_avr/ispolzovanie-storozhevogo-tajmera.html из кэша Google. Она представляет собой снимок страницы по состоянию на 14 янв 2013 09:41:35 GMT. Текущая страница за прошедшее время могла измениться. Подробнее
Совет. Чтобы искать на странице, нажмите Ctrl+F или ?-F (для MacOS) и введите запрос в поле поиска.

Текстовая версия
 
Использование сторожевого таймера » Controllersystems.com

Использование сторожевого таймера

 (голосов: 1)

Сторожевой таймер (Watchdog Timer, WDT) — одно из самых полезных устройств в составе микроконтроллеров. Причем его полезность неочевидна: в нормальном режиме работы, когда все настроено идеально, он вовсе не нужен. Но представьте себе такую ситуацию: МК настроен на прием данных с компьютера с непрерывным опросом бита UDRE. К примеру, он ожидает шесть байтов, как в нашей программе из главы 13, но на пятом байте ПК внезапно ломается (кто-то прошел и ногой выдернул провод из СОМ-порта). Что будет с контроллером? Естественно, он повиснет в ожидании байта, и из этого состояния его не удастся вывести никаким способом, кроме полного сброса. Другой пример: часы реального времени, описанные в главе 12, от которых зависит работоспособность всей системы, по сути также представляют собой контроллер, и подобные устройства могут "зависать" ничуть не хуже любых других, вследствие ошибок в функционировании или из-за помех. В таком случае вся система требует переинициализации путем сброса и запуска с нуля.

Вот для предотвращения таких ситуаций и нужен WDT, который сбросит МК по истечении некоторого срока, если его вовремя не остановить. Он подключается к автономному RC-генератору с частотой примерно 1 МГц при питании 5 В (в старых моделях эта частота могла уменьшаться пропорционально снижению питания МК, в Mega ее стабильность несколько повышена). Заметим кстати, что начальная задержка при включении МК (та, что определяется ячейками SUT1. .0, см. главу 2), точнее, ее постоянная составляющая, определяется именно генератором сторожевого таймера. Другая функция WDT была упомянута в главе 4: МК, находящийся в любом из режимов энергосбережения, можно принудительно "разбудить," сторожевым таймером, если "пробуждающее" событие не наступило. В отличие от выхода из "сна" через внешнее событие, при этом выполнится не прерывание, а начальная процедура reset, как при включении. Отметим, что включенный WDT потребляет ток примерно 70 мкА.

Для того чтобы вследствие какой-нибудь помехи WDT не запустился и, главное, не выключился случайно, и для запуска и для выключения его предусмотрена довольно "навороченная" процедура, которая к тому же довольно "мутно" описана в документации. Причем процедура эта различается для МК семейств Tiny, Classic и Mega, что дало зачем-то авторам техдокументации основание для ввода специальных "уровней управления" режимом WDT. На самом деле все гораздо проще: во-первых, в некоторых моделях Tiny и во всех Mega есть fuse-бит WDTON, который устанавливает, включен ли изначально WDT или выключен. По умолчанию WDTON находится в незапрограммированном состоянии (лог. 1), означающее, что WDT выключен, и для приведения в действие его следует специально инициализировать.

Наличие WDTON — довольно удобное свойство для того, чтобы не возиться с включением WDT самостоятельно, но оно в значительной мере обесценивается тем фактом, что по умолчанию сторожевой таймер запрограммирован на минимальный интервал (~15 мс), который все равно, как правило, приходится увеличивать. А эта процедура ничуть не проще, чем просто включить таймер, одновременно установив его на нужный интервал, потому далее мы будем считать, что WDTON мы не трогали.

Тогда вариантов процедур включения/выключения окажется всего два: попроще для семейств Tiny и Classic (и для Mega в режиме совместимости с Classic при соответствующем установленном fuse-бите, для ATmega8535 это S8535C) и посложнее для Mega. Управляют режимом включения/выключения два разряда регистра WDTCR: бит разрешения изменений WDCE (в некоторых моделях он называется WDTOE) и бит включения WDE. Для семейства Classic и Tiny для включения достаточно установить бит WDE в единичное состояние, одновременно, если надо, устанавливается и период таймера битами WDP2. .0 того же регистра, задающими коэффициент деления генератора (состояние 000 соответствует минимальному периоду ~15 мс, 110 — примерно 1 с, 111 задает максимальный период немного менее 2 с). Перед такими операциями всегда рекомендуется сбрасывать WDT командой wdr (иначе таймер может начать отсчет не с начала, и произойдет непроизвольный сброс МК), как показано в листинге 14.6.

Листинг 14.6
cli wdr
ldi tmp, (1<<WDE) | (1<<WDP2) | (1<<WDP1) | (1<<WDP0)
out WDTCR,tmp
sei

Для семейства Mega процедура несколько сложнее: сначала нужно установить биты WDCE и WDE одновременно, потом повторно разрешить работу установкой WDE и одновременно установить коэффициент деления, но при сброшенном WDCE: (листинг 14.7).

Листинг 14.7
cli wdr
ldi tmp, (1<<WDCE) | (1<<WDE)
out WDTCR,tmp
ldi tmp, (1<<WDE) | (1<<WDP2) | (1<<WDP1) | (1<<WDP0)
out WDTCR,tmp
sei

Процедура выключения одинакова для всех моделей и аналогична включению в предыдущем случае (листинг 14.8).

Листинг 14.8
cli wdr
ldi tmp, (1<<WDCE) | (1<<WDE)
out WDTCR,tmp
ldi tmp, (0<<WDE)
out WDTCR,tmp
sei

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

Листинг 14.9
wdr ;Reset WDT
in temp, WDTCR
ori temp, (1<<WDCE) | (1<<WDE)
out WDTCR, temp
ldi temp, (0<<WDE) ; выключить WDT
out WDTCR, temp

Кажется, что раз в регистре WDTCR больше нет никаких разрядов, кроме WDCE, WDE и WDPx (старшие три бита WDTCR не задействованы), применение инструкции ori, чтобы не трогать биты, кроме необходимых, довольно бессмысленно. На самом деле это не совсем так: нашей операцией мы обнуляем коэффициент деления, и если WDT был близок к срабатыванию, то теоретически не исключена ситуация, что он успеет сбросить систему до окончательного выключения. На практике это, однако, чистая перестраховка.

При включенном постоянно таймере через fuse-бит WDTON (в инструкциях это именуется режимом 2) все операции аналогичны, только нулевое состояние бита WDE не выключает таймер — фактически здесь доступно только изменение коэффициента деления, хотя внешне все выглядит так же, как при обычном включении.

Интересный случай представляет ATtiny2313 (именно он, а не его "классический" аналог), где WDT может работать в двух режимах: установкой бита WDIE в регистре управления (здесь он называется WDTCSR) можно вместо сброса по истечении заданного периода получить специальное прерывание WDT Overflow. Эта возможность несколько усложняет процедуру инициализации и выключения WDT, т. к. приходится заботиться о состоянии флага прерывания WDRF в регистре MCUSR, сбрасывая его перед каждой операцией. Это также рекомендуется осуществлять при начальном включении (как и для регистров прерываний TIFR и GIFR):
in temp, MCUSR
andi temp, (0xff& (0<<WDRF) )
out MCUSR,temp

После того как мы разобрались с включением, WDT начинает постоянно "молотить" (в том числе и в режиме энергосбережения), и чтобы избежать сброса МК в нормальном режиме работы программы, таймер следует периодически сбрасывать командой wdr — раньше, чем истечет заданный период. Обычно это делается по какому-либо прерыванию. Например, в описанной ранее программе с часами DS1307 это можно делать по каждому прерыванию INT0:
EXT_INT0:
wdr ;сброс сторожевого таймера
. . . . . .

Предполагается, что мы установили WDT на период 2 с. Так как прерывание должно возникать каждую секунду, то мы сбрасываем таймер заведомо раньше, чем он сработает, и тогда он начнет отсчет выдержки сначала. Если же что-то (часы или программа) "повиснет", то произойдет общий сброс МК, в том числе и инициализация часов. Причем после чтения данных из flash- памяти мы сможем это обнаружить: если помните, мы в кадр времени записывали байт сбоев (см. главу 12), в котором установленный бит 3 означал, что сброс произошел именно от сторожевого таймера.

Если встречаются процедуры, которые запрещают прерывания на длительный срок (у нас это была описанная в главах 12 и 13 операция чтения данных ReadFullFlash), то перед их выполнением таймер нужно запрещать, а потом опять разрешать (листинг 14.10).

Листинг 14.10
proc_F2: ;F2 читать данные из памяти
cli ;запрещаем прерывания

;выключить WD:
wdr ; Reset WDT
in temp, WDTCR
ori temp, (1<<WDCE) | (1<<WDE)
out WDTCR, temp
ldi temp, (0<<WDE) ; выключить WDT
out WDTCR, temp
rcall ReadFullFlash ;читаем данные
rcall RclockIni ;восстанавливаем часы

;запускаем WDT обратно, 2 с
wdr ;команда на сброс
ldi temp, (1<<WDCE) | (1<<WDE)
out WDTCR,temp
ldi temp, (1<<WDP0) | (1<<WDP1) | (1<<WDP2) | (0<<WDCE) | (1<<WDE)
out WDTCR,temp
sei ;разрешаем прерывания — необязательно, уже есть
;в ReadFullFlash
rjmp Gcykle

Заметьте, что после такой длительной процедуры, как чтение массива внешней памяти, при использовании WDT можно вообще не разрешать прерывания (для этого придется убрать разрешение и из самой процедуры ReadFullFlash) — а вдруг мы что-то нарушили в работе? Тогда контроллер просто перезапустится с нуля, и работа восстановится (то же самое относится к обновлению значений времени в часах, см. главу 13). Универсальный способ принудительного перезапуска МК заключается в том, что после включения WDT запускают пустой бесконечный цикл.


Похожие новости:

Информация


Посетители, находящиеся в группе Гости, не могут оставлять комментарии в данной новости.