Настраиваем выводы микроконтроллера ATmega8 и управляем светодиодами

В этом уроке настроим выводы микроконтроллера ATmega8 на выход и подключим к ним пять светодиодов. Светодиоды будут включаться по очереди, а длительность задержки между переключениями будет изменяться с помощью генератора псевдослучайных чисел.

Подключение светодиодов

Используем пять выводов порта D: PD0, PD1, PD2, PD3 и PD4. Каждый светодиод подключается к отдельному выводу микроконтроллера через токоограничивающий резистор.

Схема подключения светодиодов к микроконтроллеру ATmega8
Схема подключения светодиодов к ATmega8
Важно: номинал токоограничивающих резисторов зависит от используемых светодиодов и напряжения питания. Ток через вывод микроконтроллера не должен превышать допустимое значение, указанное в документации ATmega8. Для данной учебной схемы обычно можно использовать резисторы порядка 470 Ом – 1 кОм.

Регистр DDRx

В микроконтроллерах AVR направление работы выводов задаётся регистрами DDRx.

Если соответствующий бит регистра DDR установлен в логическую 1, вывод работает как выход. Если записан логический 0, вывод работает как вход.

Например, для настройки вывода PB0 на выход можно записать:

DDRB = 0b00000001;

В нашей программе на выход настраиваются сразу пять выводов порта D:

DDRD = 0b00011111;
В результате биты PD0–PD4 установлены в 1 и соответствующие выводы работают как выходы.

Регистр PORTx

После настройки вывода на выход логический уровень задаётся через регистр PORTx.

Например, установить логическую 1 на выводе PB0 можно записью:

PORTB = 0b00000001;

Но на практике удобнее изменять только нужный бит, не затрагивая остальные выводы порта.

Установить логическую 1:

PORTB |= (1 << PB0);

Установить логический 0:

PORTB &= ~(1 << PB0);
Такая запись особенно удобна, когда к одному порту подключено сразу несколько устройств: можно изменить состояние одного вывода, не изменяя остальные биты регистра.

Генератор псевдослучайных чисел

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

Функция находится в стандартной библиотеке stdlib.h и генерирует псевдослучайное число.

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

Основная программа

Сначала подключаем необходимые заголовочные файлы, выполняем инициализацию выводов, после чего в бесконечном цикле вызываем функцию последовательного переключения светодиодов.

#include <avr/io.h>
#include "led.h"
#include <stdlib.h>

#define F_CPU 1000000UL

unsigned int k;

void init(void);
void delay(unsigned int y);
void miganie(unsigned int t);


int main(void)
{
    init();

    while (1)
    {
        k = 1000 * (unsigned int)rand();

        miganie(k);
    }
}


void init(void)
{
    /* PD0-PD4 работают как выходы */
    DDRD = 0b00011111;

    /* На PD0-PD4 устанавливаем логический 0 */
    PORTD = 0b00000000;
}


void delay(unsigned int y)
{
    unsigned int i = 0;
    unsigned int w = 0;

    for (w = 0; w <= 4; w++)
    {
        for (i = 0; i <= y; i++)
        {
            ;
        }
    }
}


void miganie(unsigned int t)
{
    HL1_on;
    HL2_off;
    HL3_off;
    HL4_off;
    HL5_off;

    delay(t);


    HL1_off;
    HL2_on;
    HL3_off;
    HL4_off;
    HL5_off;

    delay(t);


    HL1_off;
    HL2_off;
    HL3_on;
    HL4_off;
    HL5_off;

    delay(t);


    HL1_off;
    HL2_off;
    HL3_off;
    HL4_on;
    HL5_off;

    delay(t);


    HL1_off;
    HL2_off;
    HL3_off;
    HL4_off;
    HL5_on;

    delay(t);
}

Заголовочный файл led.h

Чтобы основной файл программы оставался более читаемым, операции включения и выключения светодиодов вынесем в отдельный заголовочный файл led.h.

Для каждого светодиода создаём два макроса: включение и выключение.

#ifndef LED_H_
#define LED_H_

/* Светодиод HL1 */
#define HL1_on     PORTD |=  (1 << PD0)
#define HL1_off    PORTD &= ~(1 << PD0)

/* Светодиод HL2 */
#define HL2_on     PORTD |=  (1 << PD1)
#define HL2_off    PORTD &= ~(1 << PD1)

/* Светодиод HL3 */
#define HL3_on     PORTD |=  (1 << PD2)
#define HL3_off    PORTD &= ~(1 << PD2)

/* Светодиод HL4 */
#define HL4_on     PORTD |=  (1 << PD3)
#define HL4_off    PORTD &= ~(1 << PD3)

/* Светодиод HL5 */
#define HL5_on     PORTD |=  (1 << PD4)
#define HL5_off    PORTD &= ~(1 << PD4)

#endif /* LED_H_ */

Как работает программа

После запуска микроконтроллера функция init() настраивает PD0–PD4 на выход. Затем в бесконечном цикле формируется значение задержки и вызывается функция miganie(). В ней последовательно включается один светодиод, а остальные четыре выключаются. После задержки управление переходит к следующему светодиоду.