Фанат науки

 
  • Увеличить размер шрифта
  • Размер шрифта по умолчанию
  • Уменьшить размер шрифта
Таймеры в микроконтроллерах. Управление несколькими пинами порта.
________________________________________________________________________________________________________
    Независимое управление несколькими пинами микроконтроллера ATmega8515 с помощью встроенного таймера. Четыре светодиода моргают каждый со своей частотой независимо от другого.
    Используемый таймер - T0. Режим таймера - прерывание по переполнению. Задействованы пины порта С (С0, С1, С2, С3).
______________________________________________________________________________________

    Описание программы: при старте программы счётный регистр TCNT0 таймера T0 начинает заполняться (по импульсам от тактового генератора). Когда счётный регистр таймера переполняется, программа выходит в прерывание, где программные счётчики Svet увеличиваются на 1. Счётный регистр при этом обнуляется и начинает заполняться опять, до следующего переполнения. Цикл повторяется.

    В основной программе в бесконечном цикле просматривается содержимое программных счётчиков Svet. Если содержимое программного счётчика больше требуемого, программный счётчик обнуляется, а привязанный к счётчику пин микроконтроллера инвертируется.

    Чтобы замедлить скорость переполнения счётного регистра, импульсы от тактового генератора (идущие на счётный регистр) пропускаются через предделитель (1/1024), пропускающие каждый 1024-й импульс. Предделитель настраивается регистром TCCR0.

  • Частота тактового генератора в нашем случае: 1000000 Гц.
  • Скорость подачи импульсов на счётный регистр при делителе 1/1024: 1000000 / 1024 = 976.56 Гц
  • Разрядность счётного регитста T0 - 8 бит (256 состояний вместе с нулём).
  • Скорость переполнения счётного регистра (и скорость инвертирования пина C0): 976.56 / 256 = 3,81 Гц (около четырёх изменений в секунду, что хорошо заметно).
  • Итого: 3.81 / 2 = 1.9 полных импульсов в секунду.




Программа на CodeVisionAVR:

#include <mega8515.h>

int Svet0, Svet1, Svet2, Svet3;  // Резервируем программные счётчики для пинов С0, С1, С2, С3.

interrupt [8] void timer0_overflow(void)  // Обработчик прерывания от таймера T0 по переполнению его счётного регистра.
  {
    Svet0++ ;  // При каждом переполнении счётного регистра увеличиваем каждый программый счётчик на единицу.
    Svet1++ ;
    Svet2++ ;
    Svet3++ ;
  }

void main(void)
{
  DDRC = 0b11111111;  // Настройка всех пинов порта С на вывод.
 
  TCCR0 |= 0b00000101 /* Включаем предделитель 1/1024. Три первых бита регистра управления таймером T0 (TCCR0 - Timer-Counter Control Register 0) устанавливают, на сколько будут делиться импульсы, идущие от тактового генератора к таймеру.
                                              00000101 - 1/1024 ; 
00000100 - 1/256 ;  00000011 - 1/64 ;  00000010 - 1/8 ;
                                             
00000001 - 1/1 (чистые импульсы) ;  00000000 - выключить таймер. */

  SREG |= 0b10000000// Записываем единичку в 7 бит регистра состояния (SREG - Status Regster) и разрешаем общие прерывания.


  TIMSK |= 0b00000010 // Записываем единичку в первый бит регистра маскирования прерываний от таймеров (TIMSK - Timer Interrupt Mask Register), и разрешаем прерывания по переполнению таймера T0.

 

  SFIOR = 0b00000001// Записываем единичку в первый бит регистра особых условий ввода-вывода (SFIOR - Special Function Input-Output Register) и сбрасываем предделитель (не обязательно).



  TCNT0 = 0;  // Обнуляем счётный регистр таймера T0 (TCNT0 - Timer-Counter 0) перед началом цикла опроса программных счётчиков (на всякий случай).

  while (1)  // Бесконечный цикл опроса программных счетчиков, их обнулений и инвертирования пинов порта.
    {
      if (Svet0 >= 1)  // При КАЖДОМ переполнении счётного регистра инвертируем пин С0 и обнуляем счётчик Svet0.
        {
          PORTC ^= 0b00000001;
          Svet0=0;
        }

      if (Svet1 >= 2)  // При каждом ВТОРОМ переполнении счётного регистра инвертируем пин С1 и обнуляем счётчик Svet1.
        {
          PORTC ^= 0b00000010;
          Svet1=0
        }

      if (Svet2 >= 4)  // При каждом ЧЕТВЁРТОМ переполнении счётного регистра инвертируем пин С2 и обнуляем счётчик Svet2.
        {
          PORTC ^= 0b00000100;
          Svet2=0;  
        }

      if (Svet3 >= 8)  // При каждом ВОСЬМОМ переполнении счётного регистра инвертируем пин С3 и обнуляем счётчик Svet3.
        {
          PORTC ^= 0b00001000;
          Svet3=0;
        }
    }
}


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

Та же задача же для микроконтроллера ATmega8.


Программа на CodeVisionAVR:

#include <mega8.h>

int Svet0, Svet1, Svet2, Svet3;

interrupt [10void timer0_overflow(void
  {
    Svet0++ ;
    Svet1++ ;
    Svet2++ ;
    Svet3++ ;
  }

void main(void)
{
  DDRD0b11111111;  
 
  TCCR0 |= 0b00000101 // 00000101 - 1/1024 ;  00000100 - 1/256 ;  00000011 - 1/64 ;  00000010 - 1/8 ;
                                             // 
00000001 - 1/1 (чистые импульсы) ;  00000000 - выключить таймер.

  SREG |= 0b10000000;
  TIMSK |= 0b00000001;  // Записываем единичку в нулевой бит регистра маскирования прерываний от таймеров (TIMSK - Timer Interrupt Mask Register), и разрешаем прерывания по переполнению таймера T0.
  SFIOR = 0b00000001;
 
  TCNT0 = 0; 

  while (1
    {
      if (Svet0 >= 1)  
        {
          PORTD ^= 0b00000001;
          Svet0=0;
        }

      if (Svet1 >= 2)  
        {
          PORTD ^= 0b00000010;
          Svet1=0
        }

      if (Svet2 >= 4)  
        {
          PORTD ^= 0b00000100;
          Svet2=0;  
        }

      if (Svet3 >= 8)  
        {
          PORTD ^= 0b00001000;
          Svet3=0;
        }
    }
}


    Красным указаны отличия программы для ATmega8 от программы для ATmega8515. 
1) Заголовочный файл меняем на Mega8.h
2) Вектор прерывания по переполнению T0 для ATmega8 равен 10, а не 8.
3) У ATmega8 в регистре TIMSK разрешением прерывания по переполнению T0 управляет нулевой бит, а не первый.
4) Используем порт D, пины D0 , D1 , D2 , D3 (№№2-6 по левой стороне сверху).
5) В конфигурации проекта меняем тип кристалла с Меги8515 на Мегу8   Project >> Configure >> C Compiler >> Chip >> ATmega8.

 
   © Фанат науки 2010 - 2022.  Все права защищены.  При использовании материалов обязательна ссылка на сайт  www.fanatnauki.ru