GOLOS
RU
EN
UA
evgenij-byvshev
3 года назад

Программирование микроконтроллеров. Часть 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).

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

Перейдем к коду: сначала необходимо будет настроить выводы портов. Все выводы 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:

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


Если есть вопросы и предложения по этому уроку, пишите комментарии буду рад ответить на ваши вопросы.


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

3
487.943 GOLOS
На Golos с February 2017
Комментарии (2)
Сортировать по:
Сначала старые