Доработаем программу «Бегущие огни», изменив процедуру формирования задержки. Чтобы не загружать процессор новая процедура задержки должна использовать один из внутренних таймеров/счетчиков и не использовать прерывания.

В микроконтроллере Atmega8 имеются 3 таймера: 2 восьмиразрядных и 1 шестнадцатиразрядный. Для формирования временных интервалов таймер просто подсчитывает тактовые импульсы от системного генератора.

В нашем случае частота равна 4 MHz, а период импульсов 1/4MHz=0,25мкс. Для того чтобы получить на выходе 200мс, необходимо иметь коэффициент деления равный 200мс/0,25мкс= 800000. Восьмиразрядный таймер имеет максимальный коэффициент пересчета 28=256, а шестнадцатиразрядный 216=65536. То есть даже шестнадцатиразрядного таймера нам не хватит для формирования требуемой задержки. Тогда воспользуемся предварительным делителем. Этот делитель производит предварительное деление тактового сигнала перед тем как он поступит на вход таймера.

Выберем самый большой коэффициент предделителя 1024. Тогда на его выходе получим сигнал с частотой 4MHz/1024=3906Hz . Период тактового сигнала будет равен 1/3906Hz=0,256мс. Посчитаем коэффициент деления, который наш таймер должен нам обеспечить: 200мс/0,256мс=780. Такой коэффициент пересчета нам может обеспечить только шестнадцатиразрядный таймер Т1.

Доработка программы сводится к созданию новой функции задержки.

Наша новая функция задержки получила название wait1. Описание этой функции в нашей программе расположено раньше, чем описание функции main.

В языке Си действует правило: любая функция должна быть прежде описана и лишь затем в первый раз применена.

Так как функция main использует функцию wait1 в качестве процедуры задержки, то описание wait1 должно располагаться перед описанием main.

В модуль инициализации добавляем настройки таймера

TCCR1A = 0x00;

TCCR1B = (1 << CS12)|(0 << CS11)|(1 << CS10);

Нулевое значение в регистр TCCR1A можно не записывать т. к. там и так ноль по умолчанию. Для TCCR1B из даташита на микроконтроллер Atmega8 выбираем коэффициент предделителя 1024, и устанавливаем нужные биты CS в единицу.

Добавляем функцию задержки с использованием таймера:

void wait1 (void)
{
TCNT1 = 0;
while (TCNT1 < 780){};
} 

Функция wait1 формирует задержку с использованием таймера. Где первая строка – это заголовок описания функции. Из него видно, что функция wait1 не использует параметров и не возвращает ни каких значений. Счетному таймеру TCNT1 присваивается нулевое значение. Дальше расположен цикл проверки. Это пустой цикл, в качестве условия которого выступает выражение TCNT1<780. Цикл проверки будет выполняться до тех пор, пока значение счетного регистра не будет превышать 780. Как только окажется, что это не так, цикл завершится, а с завершением цикла завершится и вся функция wait1. Полный код программы ниже:

/***Занятие 5. Бегущие огни с использованием таймера***/
#include <avr/io.h>
/***функция задержки***/
void wait1 (void)
{
TCNT1 = 0;
while (TCNT1 < 780){};
}
int main(void)
{
unsigned char temp;
DDRC = 0x00; // Порт C вход
PORTC |= (1 << PC0); // Подключаем внутренний резистор к PC0
DDRD = 0xFF; // Порт D выход
PORTD = 0x00; // Лог. 0 на выходе
// Настройка таймера
TCCR1A = 0x00;
TCCR1B = (1 << CS12)|(0 << CS11)|(1 << CS10); //выбор коэффициента предделителя clk/1024
while(1)
{
if ((PINC&(1 << PC0)) == 0) //проверяем нажатие кнопки
{//сдвиг вправо
temp = 0x80; //записываем начальное значение
while (temp != 0) // Пока temp не равно 0 
{
PORTD = temp; //запишем temp в порт D
temp = temp >> 1; //сдвигаем разряды
wait1(); // Задержка
}
}
else
{ //сдвиг влево
temp = 0x01; //записываем начальное значение
while (temp != 0) // Пока temp не равно 0
{
PORTD = temp; //запишем temp в порт D
temp = temp << 1; //сдвиг вправо
wait1(); // Задержка
}
}
}
} 

В статье были использованы материалы из книги Белова А.В. "Самоучитель разработчика устройств на AVR"

Комментарии  

0 #1 Dmitriy 17.11.2013 08:45
можете на электронку ответить я сколько форумов перечитал мало что понял задача запустить на 162 АТмеге мигание светодиода с частотой наверно 2 герца не по нажатию кнопки а по ходу выполнения записанного алгоритма использую CVAVR xtal 16Mh
Сообщить модератору
+4 #2 Disgbor8 22.12.2013 16:18
Бред получается - задача разгрузить процессор от функции _delay_ms(200) дабы в момент задержки он мог выполнять другие задачи, а вместо этого мы его послали в ожидание покуда натикает таймер в 200ms
Сообщить модератору
+1 #3 boogyman 22.12.2013 19:09
Цитирую Disgbor8:
Бред получается - задача разгрузить процессор от функции _delay_ms(200) дабы в момент задержки он мог выполнять другие задачи, а вместо этого мы его послали в ожидание покуда натикает таймер в 200ms

Что делает функция util/delay.h? Правильно, выполняет пустые цыклы, что загружает процессор. Мы используем таймер, тем самым разгружаем процессор, и он может выполнять другую работу. Не вводите людей в заблуждение.
Сообщить модератору
+1 #4 voldemarishe 25.04.2015 12:32
Вы его действительно заставляете ждать, вы ведь ввели функцию wait(1). Правильнее поместить в прерывание опрос кнопки и выполнение кода по нажатию кнопки.
Сообщить модератору
0 #5 Евгений89 27.08.2015 03:47
Приветствую уважаемого автора и читателей сайта! Работаю электроником и изучаю атмеги по вашим примерам, очень доволен. Но всё не могу понять как задаётся тактовая частота генератора(поче му именно 4 а не 8 или 1 МГц?). В Eclipse при создании проекта указывается рабочая частота, это она и есть? и как быть при использовании внешнего кварца? С уважением из Иркутска.
Сообщить модератору
0 #6 AntonChip 27.08.2015 15:20
Можно использовать любую удобную Вам тактовую частоту и 1МГц и 8МГц, просто потом надо будет пересчитать предделители и коэффициенты для обеспечения задержки в 200мс. Рабочую частоту можно установить в AVRstudio в настройках проекта или записью в самом начале программы строчки Код:
#define F_CPU 8000000L
Сообщить модератору
0 #7 Юрий Шевчук 23.03.2021 20:34
Автор сам вводит в заблуждение людей. нету разницы для задержек что мы используем для этого таймер или пустой цикл delay, таймер и delay делают нагрузку на процессор. Автору советую прочесть литературу а потом писать статейки! :D
Сообщить модератору