Часто возникает необходимость выводить данные на дисплей. И к сожалению не всегда есть возможность делать это напрямую. Ведь для управления семисегментным индикатором необходимо ещё больше ног чем для LCD дисплея.
Рассмотрим схему индикатора:
Из схемы видим, что «зажигаение» определённого сегмента происходит коммутацией контактов. Имеется 4 контакта для выбора сегмента и 8 для подачи кода символа (комбинации необходимых сегментов).
Т.е. для работы необходимо 12 пинов контроллера, что не есть хорошо для такой простой функции как вывод числа пользователю.
Из ситуации выходят путём применения сдвиговых регистров типа 74hc595.
Так уж совпало, что их интерфейс есть не что иное как SPI. О котором я уже писал.
Очень хотелось сделать это всё в живую с фото и на STM32, но ехать на радио рынок за регистрами не хотелось больше.
Так что покажу модель в Proteus с использованием ATmega8 . На борту у неё SPI присутствует и смоделировать можно..
Вот результат:
Программа тоже не намного сложнее.
Даже с моими минимальными знаниями программирования AVR написать труда не составило.
Писал в AVR Studio. Вот проект.
Кратко опишу что происходит в коде.
Нужна функция обмена с SPI:
char spi_transfer(volatile char data) { SPDR = data; // Start the transmission while (!(SPSR & (1<<SPIF))) {}; // Wait the end of the transmission return SPDR; // return the received byte }
Спёр её из какойто библиотеки…
Кроме того определил 2 типа:
typedef unsigned char byte;
typedef unsigned long ulong;
Несколько констант:
byte led_table[10]={0b00000011,0b10011111,0b00100101,0b00001101,0b10011001,0b01001001,0b01000001,0b00011111,0b00000001,0b00001001}; ulong show_data=7812; //Отображаемая цифра ulong dig_data=0; byte dig_num=0; //Отображаемый разряд
И функцию для вывода:
void show_dig() { PORTB &= ~(1<<2); if (dig_num==0) { dig_data=show_data; //Если показываем первую цифру обнавляем переменную dig_num++; } spi_transfer(dig_num); //Отправляем байт для отображения разряда spi_transfer(led_table[dig_data%10]); //Получаем разряд из dig_data и отправляем байт с цифрой dig_data/=10; dig_num<<=1; //Смещаем бит для отображения следующего разряда PORTB |= (1<<2); // включаем }
Ну и main функция для порядка:
int main(void) { PORTB=0; DDRB=0x2C; //Настраиваем порт для SPI ACSR=0x80; //Отключаем компаратор //Включаем SPI //Биты будем отправлять LSB-MSB, т.е. от младших к старшим SPCR=0x70; SPSR=0; while (1) show_dig(); //Показываем разряды }
Суть всего этого проста.
Мы посылаем через SPI 2 байта в регистры сдвига.
Первым байтом выбирается номер индикатора.
Вторым — число (код символа).
Из-за того, что регистры 8 разрядные, первый байт сразу же сдвигается во второй регистр, тогда как второй — занимает своё место в выборе символа.
Дальше операция многократно повторяется с выбором другого номера индикатора. Таким образом можно управлять индикаторами с огромным количеством символов.
Забыл упомянуть, что в протусе дисплей не такой как на картинке и схеме выше. Там есть дополнительные сегменты. Мы их просто не используем, а двойной сегмент (средний) соединяем «в кучу».