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