Найти в Дзене
Евгений Бывшев

Программирование микроконтроллеров. Часть 11-2

Последовательный интерфейс SPI подключение семисегментного LED индикатора В прошлой части я рассказал про интерфейс SPI, сегодня я покажу как можно подключить семисегментный LED индикатор к микроконтроллеру по трем проводам. Для этого нам понадобиться сдвиговой регистр 74HC595. Сдвиговый регистр - это набор последовательно соединённых триггеров (обычно их 8 штук). В отличии от стандартных регистров, сдвиговые поддерживают функцию сдвига вправо и влево. (т. е. переписывание данных с каждого предыдущего триггера на следующий по счёту). - Выводы DS, ST_CP, SH_CP - это шины управления. Соответственно: шина данных(MOSI), защёлка(SS) и тактовая линия(SCK). - Выводы Q0, Q1, ..., Q7 - это выходы регистра (разряды). - Выводы VCC и GND - это питание. Подключаем к +5v и GND. - Вывод Q7` предназначен для последовательного соединения таких регистров - Вывод MR - это сброс. Подключаем к +5v (сброс не активен). - Вывод OE притягиваем к земле (подключаем к контакту GND). Получается вот, такая схема
Оглавление

Последовательный интерфейс SPI

подключение семисегментного LED индикатора

В прошлой части я рассказал про интерфейс SPI, сегодня я покажу как можно подключить семисегментный LED индикатор к микроконтроллеру по трем проводам.

Для этого нам понадобиться сдвиговой регистр 74HC595.

-2

Сдвиговый регистр - это набор последовательно соединённых триггеров (обычно их 8 штук). В отличии от стандартных регистров, сдвиговые поддерживают функцию сдвига вправо и влево. (т. е. переписывание данных с каждого предыдущего триггера на следующий по счёту).

- Выводы DS, ST_CP, SH_CP - это шины управления. Соответственно: шина данных(MOSI), защёлка(SS) и тактовая линия(SCK).

- Выводы Q0, Q1, ..., Q7 - это выходы регистра (разряды).

- Выводы VCC и GND - это питание. Подключаем к +5v и GND.

- Вывод Q7` предназначен для последовательного соединения таких регистров

- Вывод MR - это сброс. Подключаем к +5v (сброс не активен).

- Вывод OE притягиваем к земле (подключаем к контакту GND).

Получается вот, такая схема, для разнообразия я решил на этот раз взять микроконтроллер ATMEGA8:

-3

Перейдем к коду: сначала необходимо будет настроить выводы портов. Все выводы SPI будут настроены на выход, так как MISO не используем, а также на них установим низкий логический уровень:

DDRB |= ((1<<PORTB2)|(1<<PORTB3)|(1<<PORTB5)); //выводы SPI на выход
PORTB &= ~((1<<PORTB2)|(1<<PORTB3)|(1<<PORTB5)); //низкий уровень


Теперь настроим саму шину SPI:

SPCR = ((1<<SPE)|(1<<MSTR));//Включим шину, объявим ведущим

Делитель и умножитель не включаем, так как частота на микросхеме поддерживается большая. Также включили SPI и настроили микроконтроллерведущим устройством.

Занесем в регистр данных нули.

SPDR = 0b00000000; //заносим в регистр данных нули

Ну теперь попробуем передать эти данные микросхеме:

while(!(SPSR & (1<<SPIF)));//подождем пока данные передадутся

То есть как только занесли в регистр данных значение, контроллер начнёт их пытаться передавать. После этого в цикле ждём того момента, когда включится бит SPIF в регистре SPSR. Как только он включится, это будет означать, что весь полный байт передался на ведомое устройство.

После этого, чтобы данные в регистре сдвига перешли в нижний регистр хранения, необходимо сформировать там отрицательный фронт. Но, так как данная вывод SS уже находится в низком логическом уровне, то сначала включим ей высокий уровень, а затем низкий уровень, тем самым формируя отрицательный фронт или нисходящий:

PORTB |= (1<<PORTB2); //высокий уровень
PORTB &= ~(1<<PORTB2); //низкий уровень

Тем самым в данном коде сформировали на всех ножках параллельного выхода микросхемы низкий логический уровень и светодиоды у нас должны будут погаснуть, если вдруг они загорелись как-то при старте.

Теперь можно написать код в бесконечный цикл, который будет отправлять в шину SPI числа от 0 до 9:

for(i=0;i<10;i++)
{
SPDR = codes[i]; //Передаем в регистр число
while (!(SPSR&(1<<SPIF))); //ждем пока данные передадутся

//сгенерируем отрицательный фронт для записи в STORAGE REGISTER
PORTB |= (1<<PORTB2); //высокий уровень
PORTB &= ~(1<<PORTB2); //низкий уровень


_delay_ms(300);
}
i=0;

Весь код файла main.c:

#define F_CPU 8000000UL //Рабочая частота МК (8МГц)
#include <avr/io.h>
#include <util/delay.h> //подключение библиотеки для генерации задержек

// 0 1 2 3 4 5 6 7 8 9 .
const unsigned char codes[11]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x80};

int main(void)
{
unsigned char i=0;

DDRB |= ((1<<PORTB2)|(1<<PORTB3)|(1<<PORTB5)); //выводы SPI на выход
PORTB &= ~((1<<PORTB2)|(1<<PORTB3)|(1<<PORTB5)); //устанавливаем низкий уровень

SPCR = ((1<<SPE)|(1<<MSTR)); //Включим шину, объявим ведущим

SPDR = 0x00; //заносим в регистр данных нули
while (!(SPSR&(1<<SPIF))); //ждем пока данные передадутся

while(1)
{
for(i=0;i<10;i++)
{
SPDR = codes[i]; //Передаем в регистр число
while (!(SPSR&(1<<SPIF))); //ждем пока данные передадутся

//сгенерируем отрицательный фронт для записи в STORAGE REGISTER
PORTB |= (1<<PORTB2); //высокий уровень
PORTB &= ~(1<<PORTB2); //низкий уровень


_delay_ms(300);
}
i=0;
}
}

Как видите, код получился компактным. Результат работы этого кода в Proteus:

-4

Таким способом можно подключать большое количество устройств по интерфейсу SPI освобождая выводы микроконтроллера для других нужд.

Программирование микроконтроллеров:

Часть 1 Часть 2-2 Часть 2-2 Часть 3-1 Часть 3-2 Часть 4-1 Часть 4-2 Часть 5 Часть 6-1 Часть 6-2 Часть 7 Часть 8-1 Часть 8-2 Часть 9 Часть 10 Часть 11-1