Программирование AVR AVR134: часы реального времени на tinyAVR и megaAVR Thu, February 23 2017  

Поделиться

нашли опечатку?

Пожалуйста, сообщите об этом - просто выделите ошибочное слово или фразу и нажмите Shift Enter.

AVR134: часы реального времени на tinyAVR и megaAVR Печать
Добавил(а) microsin   

В даташите AVR134 [1] описывается реализация часов реального времени (Real Time Clock, RTC) со следующими возможностями:

• RTC с очень малым энергопотреблением (4 мкА при напряжении питания 3.3V)
• Очень недорогое решение
• Подстраиваемый прескалер с настраиваемой точностью
• Подсчет времени, даты, месяцев, года с конфигурацией автоматического високосного года
• Формат даты, совместимый с 2000 годом
• Можно использовать на всех микроконтроллерах AVR, оборудованных модулем RTC
• Вместе с апноутом поставляется код на языке C для ATMega128

В этом апноуте показано, как сделать RTC на микроконтроллерах AVR®, у которых есть на борту модуль RTC. Реализация требует подключения только одного внешнего компонента – часовой кварцевый резонатор на 32.768 кГц. Приложение потребляет очень мало энергии, потому что микроконтроллер основную часть времени проводит в режиме пониженного энергопотребления. В этом режиме вычислительное ядро AVR "спит", работает только таймер, тактируемый от подключенного внешнего кварца. При каждом переполнении таймера происходит подсчет времени, даты, месяца и года. Эта реализация RTC написана для ATmega128, и может быть с успехом портирована на другие микроконтроллеры AVR с модулем RTC. Достоинства использования предложенного варианта RTC в сравнении с применением внешнего специального RTC-чипа очевидны:

• Низкая стоимость
• Мало внешних компонентов, простота схемы (только 1 кварц)
• Низкое энергопотребление
• Большая гибкость

Прим. переводчика: на самом деле микроконтроллеров AVR, в которых есть модуль RTC, не так много, и многие из них дешевыми назвать нельзя. Ниже приведен их полный перечень на сегодняшний день 150104.

8-битные AVR c модулем RTC: AT90CAN32, AT90CAN64, AT90CAN128, AT90USB1286, AT90USB1287, AT90USB646, AT90USB647, ATmega128, ATmega128A, ATmega1280, ATmega1281, ATmega1284, ATmega16, ATmega16A, ATmega162, ATmega164, ATmega165, ATmega168, ATmega169, ATmega2560, ATmega2561, ATmega32, ATmega32A, ATmega324, ATmega324A, ATmega325, ATmega325A, ATmega3250, ATmega328, ATmega329, ATmega329A, ATmega3290, ATmega3290A, ATmega406, ATmega48, ATmega48A, ATmega64, ATmega64A, ATmega640, ATmega644, ATmega644A, ATmega645, ATmega645A, ATmega6450, ATmega6450A, ATmega649, ATmega649A, ATmega6490, ATmega6490A, ATmega8, ATmega8A, ATmega8535, ATmega88, ATmega88A, ATtiny1634, ATtiny167, ATtiny828, ATtiny87.

8-битные AVR XMEGA c модулем RTC: ATxmega128A1, ATxmega128A1U, ATxmega128A3, ATxmega128A3U, ATxmega128A4U, ATxmega128B1, ATxmega128B3, ATxmega128C3, ATxmega128D3, ATxmega128D4, ATxmega16A4, ATxmega16A4U, ATxmega16C4, ATxmega16D4, ATxmega16E5, ATxmega192A3, ATxmega192A3U, ATxmega192C3, ATxmega192D3, ATxmega256A3, ATxmega256A3B, ATxmega256A3BU, ATxmega256A3U, ATxmega256C3, ATxmega256D3, ATxmega32A4, ATxmega32A4U, ATxmega32C3, ATxmega32C4, ATxmega32D3, ATxmega32D4, ATxmega32E5, ATxmega384C3, ATxmega64A1, ATxmega64A1U, ATxmega64A3, ATxmega64A3U, ATxmega64A4U, ATxmega64B1, ATxmega64B3, ATxmega64C3, ATxmega64D3, ATxmega64D4, ATxmega8E5.

32-битные AVR c модулем RTC: AT32UC3A0128, AT32UC3A0256, AT32UC3A0512, AT32UC3A1128, AT32UC3A1256, AT32UC3A1512, AT32UC3A3128, AT32UC3A3256, AT32UC3A364, AT32UC3A4128, AT32UC3A4256, AT32UC3A464, AT32UC3B0128, AT32UC3B0256, AT32UC3B0512, AT32UC3B064, AT32UC3B1128, AT32UC3B1256, AT32UC3B1512, AT32UC3B164, AT32UC3C0128C, AT32UC3C0256C, AT32UC3C0512C, AT32UC3C064C, AT32UC3C1128C, AT32UC3C1256C, AT32UC3C1512C, AT32UC3C164C, AT32UC3C2128C, AT32UC3C2256C, AT32UC3C2512C, AT32UC3C264C, AT32UC3L0128, AT32UC3L016, AT32UC3L0256, AT32UC3L032, AT32UC3L064, ATUC128D3, ATUC128D4, ATUC128L3U, ATUC128L4U, ATUC256L3U, ATUC256L4U, ATUC64D3, ATUC64D4, ATUC64L3U, ATUC64L4U.

[Немного теории: как это работает]

Реализация RTC задействует асинхронное функционирование модуля RTC. В этом режиме Timer/Counter0 работает независимо от тактовой частоты ядра AVR.

На рис. 2-1 показано, как микроконтроллер AVR работает в обычном режиме от основной тактовой частоты 4 МГц. Когда нужно работать с пониженным потреблением энергии, AVR переключается в режим Power-down, в котором работает только асинхронный таймер от частоты внешнего кристалла 32.768 кГц.

Программно Real Time Clock (RTC) реализован с использованием 8-разрядного таймера/счетчика, работающего в режиме прерывания по переполнению (Timer/Counter Overflow Interrupt). Программа управляет прерыванием переполнения для вычисления времени и переменных календаря. Прерывание Timer Overflow используется для корректного обновления программных переменных second (секунды), minute (минуты), hour (часы), date (дата), month (месяц) и year (год).

AVR134-RTC-oscillator-connection

Рис. 2-1. Подключение генератора к RTC.

Поскольку количество времени, проходящее между переполнениями таймера счетчика одно и то же, каждая из этих переменных будет инкрементироваться на фиксированное число с каждым переполнением таймера. Для этой задачи используется обработчик прерывания переполнения таймера (Interrupt Service Routine, ISR).

Для снижения энергопотребления микроконтроллер AVR входит в режим сохранения энергии (Power-save mode), в котором все модули микроконтроллера запрещены, кроме RTC. Как показано в таблице 2-1, ядро AVR обычно потребляет в этом режиме меньше 4 мкА. Микроконтроллер проснется, когда произойдет прерывание по переполнению таймера (Timer Overflow Interrupt). Запустится код обработчика прерывания в активном режиме ядра, который обновит переменные таймера.

Затем микроконтроллер AVR снова запустит режим сохранения энергии (Power-save mode), и будет оставаться в нем, пока не произойдет следующее прерывание Timer Overflow. На рис. 2-2 и 2-3 показано время, когда AVR работает в режиме сохранения энергии (Power-save mode) в сравнении с активным режимом (Active mode).

Чтобы вычислить общее энергопотребление, нужно сложить потребление энергии Power-save mode с потреблением энергии в Active mode. Время, которое требуется на обновление переменных таймера в обработчике прерывания, составляет менее 100 циклов тактовой частоты ядра, что на частоте 4 МГц составит 25 мкс. Потребление мощности за этот короткий промежуток времени получается несущественным. Гораздо важнее время пробуждения микроконтроллера (wake-up time). Оно может быть запрограммировано на 35 мс при использовании внешнего кварцевого резонатора, или 1 мс для использования внешнего керамического резонатора. Пример схемы, которые пробуждаются каждую секунду для обновления переменных RTC, показывают энергопотребление для двух типов источников тактирования:

AVR134-Current-Crystal-Oscillator

Рис. 2-2. Диаграмма потребляемого тока для кварцевого резонатора, время старта 35 мс (Startup Time).

Общее потребление тока на одну секунду:

= (1 с * 4 мкA) + (35 мс * 6 мА) = 4 мкАс + 210 мкАс = 214 мкАс (микроампер за секунду)

Это показывает, что основная часть потребления тока приходится на Active mode.

AVR134-Current-Ceramic-Oscillator

Рис. 2-3. Диаграмма потребляемого тока для керамического резонатора, время старта 1 мс (Startup Time).

Общее потребление тока на одну секунду:

= (1 с * 4 мкА) + (1 мс * 6 mA) = 4 мкАс + 6 мкАс = 10 мкАс

Получается, что уменьшение длительности запуска приведет к уменьшению потребляемого тока с 214 мкАс до 10 мкАс.

Таблица 2-1. Потребление тока микроконтроллером AVR в каждом режиме.

Режим Обычное потребление Max
Active 4 МГц, 3.3V питание 4 мА 6 мА
Idle 4 МГц, 3.3V питание 1.8 мА 2 мА
Power-down 4 МГц, 3.3V питание < 1 мкА 2 мкА
Power-save 4 МГц, 3.3V питание < 4 мкА 6 мкА

[Вычисления]

Зная частоту часового кварца, пользователь может определить время для каждого типа таймера/счетчика выбором нужного коэффициента деления прескалера. Как показано в таблице 3-1, биты CS02, CS01 и CS00 в регистре TCCR0 (Timer/Counter0 Control Register) определяют выбор частоты с выхода прескалера для тактирования таймера/счетчика, где CK равно частоте часового кварца. Например, если CK равно 32768 Гц, то таймер/счетчик получит частоту тактирования 256 Гц, если коэффициент деления прескалера будет CK/128.

Таблица 3-1. Выбор коэффициента деления прескалера для тактовой частоты Timer/Counter0.

CS02 CS01 CS00 Описание(1) Период переполнения
0 0 0 Timer/Counter0 остановлен -
0 0 1 CK 1/128 сек
0 1 0 CK/8 1/16 сек
0 1 1 CK/32 1/4 сек
1 0 0 CK/64 1/2 сек
1 0 1 CK/128 1 сек
1 1 0 CK/256 2 сек
1 1 1 CK/1024 8 сек

Примечание (1): CK = 32.768 кГц.

[Пример конфигурации]

Как показано на рис. 2-1, кварцевый резонатор должен быть напрямую подключен к выводам микроконтроллера TOSC1 и TOSC2. Более новые устройства требуют наличия на этих выводах дополнительных внешних конденсаторов (из-за различий в реализации внутреннего генератора), поэтому обратитесь к даташиту на используемый микроконтроллер, чтобы узнать подробности по поводу подключения внешнего резонатора. Генератор оптимизирован на работу с частой 32.768 кГц от внешнего часового кварца, или от внешнего тактового сигнала в интервале от 0 Гц до 256 кГц. В этом примере реализации 8 светодиодов (LED) подключены к порту B микроконтроллера, и используются для отображения состояния RTC. LED на ножке PB0 будет показывать изменение состояния каждую секунду. Еще 6 LED (PB6..PB1) показывают минуты в двоичном виде, и последний LED, подключенный к PB7, горит в течение часа, и погашен в течение другого часа.

Необходимо учитывать некоторые условия, когда таймер/счетчик тактируется от источника, асинхронного по отношению к системной тактовой частоте. Кварцевый резонатор на 32.768 кГц имеет время стабилизации до одной секунды после включения питания. Таким образом, микроконтроллер не должен входить в режим Power-save раньше, чем после 1 секунды после включения питания. Нужно также позаботиться о переключении режима таймера на асинхронный режим. Подробности по этим вопросам см. в даташите на используемый микроконтроллер. Данные регистра таймера передаются во временный регистр и защелкиваются там после 2 циклов внешних тактов. Регистр статуса асинхронных операций (Asynchronous Status Register, ASSR) содержит флаги состояния, которые можно проверить, чтобы контролировать, когда записанный регистр обновился.

[Реализация]

Программное обеспечение состоит из в основном двух подпрограмм. Процедура counter является обработчиком прерывания переполнения таймера (Timer/Counter Overflow ISR), она обновляет все переменные таймера, когда происходит переполнение счетчика таймера (это событие происходит каждую секунду). Вторая процедура not_leap корректирует дату, учитывая високосные года. Основная программа настраивает все нужные регистры ввода/вывода, чтобы разрешить работу модуля RTC, и управлять последовательностью входа в режим экономии энергии (Power-down).

Бит AS0 в регистре ASSR (Asynchronous Status Register) устанавливается для конфигурирования Timer/Counter0 для тактирования от внешнего источника. Только после этого таймер может работать асинхронно. Таймер сбрасывается, и для него устанавливается нужный коэффициент деления прескалера (чтобы частота тактирования была 256 Гц, и таймер переполнялся после каждого 256-го импульса, т. е. каждую секунду). Для синхронизации с внешним тактовым сигналом программа ждет, пока обновится регистр ASSR. Затем устанавливается бит TOIE0 в регистре TIMSK (Timer/Counter Interrupt Mask Register), чтобы разрешить прерывание Timer/Counter0 Overflow. Также устанавливается бит общего разрешения прерываний (Global Interrupt Enable) в регистре SREG (Status Register) - чтобы разрешить работу всех прерываний. Биты SM1 и SM0 в регистре MCUCR (MCU Control Register) устанавливаются для выбора режима пониженного энергопотребления (Power-save mode). Затем инструкция SLEEP переводит микроконтроллер в режим сна. Главный бесконечный цикл основной программы периодически выполняет инструкцию SLEEP.

Подпрограмма counter. Это обработчик прерывания переполнения таймера, он выполняется каждый раз, когда происходит событие Timer Overflow. Это прерывание пробуждает ядро микроконтроллера, чтобы обновить переменные таймера. Процедура обработчика прерывания не принимает какие-либо входные параметры, и не возвращает из себя данные, как может делать обычная функция. Вместо этого она работает с глобальными переменными. Для этого декларируется глобальная структура, используемая для хранения времени, с полями second, minute, hour, date, month и year. Поскольку известно время, которое прошло между прерываниями таймера (1 секунда), то поле second будет каждый раз инкрементироваться на 1. Как только поле second достигнет 60, то поле minute будет инкрементировано на 1, и поле second установится в 0.

AVR134-ISR-Counter

Рис. 5-1. Алгоритм работы подпрограммы обработчика прерывания Counter.

//Обработчик прерывания по переполнению таймера 0. Здесь отслеживается
// изменение счетчиков времени, даты, месяца и года.
ISR(TIMER0_OVF_vect)
{
   if (++t.second==60)
   {
      t.second=0;
      if (++t.minute==60)
      {
         t.minute=0;
         if (++t.hour==24)
         {
            t.hour=0;
            if (++t.date==32)
            {
               t.month++;
               t.date=1;
            }
            else if (t.date==31)
            {
               if ((t.month==4) || (t.month==6) || (t.month==9) || (t.month==11))
               {
                  t.month++;
                  t.date=1;
               }
            }
            else if (t.date==30)
            {
               if(t.month==2)
               {
                  t.month++;
                  t.date=1;
               }
            }
            else if (t.date==29)
            {
               if((t.month==2) && (not_leap()))
               {
                  t.month++;
                  t.date=1;
               }
            }
            if (t.month==13)
            {
               t.month=1;
               t.year++;
            }
         }
      }
   }
   PORTB=~(((t.second & 0x01)|t.minute << 1)|t.hour << 7);
}

Подпрограмма not_leap. Эта подпрограмма проверяет, есть или нет сейчас високосный год. Она возвращает true, если год не високосный, и false, если високосный. Считается, что год високосный, если удовлетворяются оба условия:

1. Число года делится нацело на 4.
2. Если год делится нацело на 100, то он также делится нацело на 400.

AVR134-not leap

Рис. 5-2. Алгоритм работы функции not_leap.

//Эта функция проверяет, високосный год или нет.
static char not_leap(void)
{
   if (!(t.year%100))
   {
      return (char)(t.year%400);
   }
   else
   {
      return (char)(t.year%4);
   }
}

Инициализация. Функция init() производит все необходимые действия по настройке RTC, портов ввода/вывода, тактирования таймера.

static void init(void)
{
   //Ожидание завершения стабилизации внешнего
   // кварцевого генератора часов RTC:
   for (uint8_t i=0; i < 0x40; i++)
   {
      for (int j=0; j < 0xFFFF; j++);
   }
   //Конфигурирование всех 8 выводов порта B как выходов:
   DDRB = 0xFF;
   //Гарантируем, что все прерывания TC0 запрещены:
   TIMSK &= ~((1 << TOIE0)|(1 << OCIE0));
   //Настройка Timer/counter0 на работу асинхронно по отношению
   // к тактированию ядра, от внешнего кварцевого резонатора
   // 32768 Гц:
   ASSR |= (1 << AS0);
   //Сброс таймера:
   TCNT0 =0;
   //Настройка прескалера таймера, чтобы получить частоту
   // деления на 128, и получить 1-секундный интервал
   // между прерываниями по переполнению таймера:
   TCCR0 =(1 << CS00)|(1 << CS02);
   //Ожидание завершения обновления TC0:
   while (ASSR & ((1 << TCN0UB)|(1 << OCR0UB)|(1 << TCR0UB)))
   {}
   //Разрешение прерывания по переполнению 8-разрядного 
   // Timer/Counter0 (Overflow Interrupt Enable):
   TIMSK |= (1 << TOIE0);
   //Общее разрешение прерываний:
   sei();
   //Выбор режиме энергопотребления (power save mode),
   // когда микроконтроллер переходит в режим сна (sleep mode):
   set_sleep_mode(SLEEP_MODE_PWR_SAVE);
   //Разрешение входа в режим сна:
   sleep_enable();
}

Основная программа (функция main). Эта функция запускается сразу после включения питания (сброса), и в ней находится бесконечный цикл системы. Перед запуском бесконечного цикла происходит инициализация вызовом подпрограммы init(), а в основном цикле происходит постоянный вход в режим сна, и при выходе из режима сна происходит ожидание обновления регистров Timer/Counter0.

int main(void)
{
   //Инициализация регистров и конфигурирование RTC:
   init();
 
   while(1)
   {
      //Вход в режим сна (пробуждение наступит после
      // возникновения прерывания timer overflow interrupt):
      sleep_mode();
      //Запись пустого значения в регистр управления:
      TCCR0=(1 << CS00)|(1 << CS02);
      //Ожидание завершения обновления TC0:
      while(ASSR & ((1 << TCN0UB)|(1 << OCR0UB)|(1 << TCR0UB)));
   }
}

[Точность]

RTC, реализованные на AVR, работают настолько точно, насколько точна генерируемая кварцевым генератором частота. Асинхронное функционирование позволяет таймеру работать без каких-либо задержек, связанных с работой ядра - оно может выполнять (или не выполнять) любые даже самые сложные вычисления, на работу асинхронного таймера это никак не повлияет. Однако в действительности есть незначительное несоответствие считываемого основной программой времени из-за того, что переменные таймера не могут быть обновлены параллельно. Время, за которое обновление завершается, изменяется очень незначительно в зависимости от состояния таймера/счетчика. Самое большое отличие возникает, когда переполняются все переменные таймера. В этот момент поле second = 59, minute = 59, hour = 23, и так далее. Это займет 94 цикла времени ядра для завершения обновления. На тактовой частоте ядра 4 МГц ошибочное расхождение между RTC и часовым кварцем не превысит 23.5 мкс (вычислено как 94/(4 * 10^6)). Обычно ошибка составит 6 мкс, потому что на обновление поля second требуется 24 цикла. Эта ошибка не накапливается, потому что таймер всегда синхронен с частотой часового кварца, и не останавливает счет.

[Затраты ресурсов]

Таблица 7-1. Затраты тактов процессорного времени и затраты памяти AVR.

Функция Размер кода
(в байтах)
Циклы Регистры в примере Прерывание Описание
main 104 - R16 Timer0 Overflow Код устанавливает требуемую конфигурацию
counter 356 - R16, R17, R30, R31 - Обновление переменных часов
not_leap 48 10 (обычно) R16, R17, R30, R31 - Проверка года - високосный или нет
Всего 508 - -

Таблица 7-2. Использование периферийных устройств AVR.

Периферийное устройство Описание Разрешенные прерывания
TOSC1, TOSC2 Вход и выход генератора, подключено к внешнему кварцевому резонатору. -
Timer/Counter0 Используется для часов реального времени (RTC). Timer/Counter0 Overflow
8 выводов GPIO порта B Для индикации работы часов светодиодами (только для демонстрационных целей). -

[Ссылки]

1. AVR134: Real-Time Clock using the Asynchronous Timer on tinyAVR and megaAVR devices site:atmel.com.

 

Добавить комментарий


Защитный код
Обновить

Top of Page