Сдвиговый регистр HC595 и микроконтроллер ATmega8

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

внутренности HC595
Видно, что он состоит из 8 триггеров, которые передают данные вперед друг другу с помощью импульса на SHIFT CLOCK. Импульс на выводе LATCH CLOCK выводит записанные данные на выхода, вывод RESET – сбрасывает выхода в нулевое состояние, а вывод OE разрешает вывод данных, если на нем высокий уровень, то на выходах будет Hi-Z состояние, если низкий – то что записано в регистр.
Посмотрим внимательно на HC595:
распиновка HC595
Выводы VCC и GND – питание, Qa-Qh – выхода (SQh применяется для каскадирования), A – вход данных, SHIFT CLOCK – запись бита на входе, LATCH CLOCK – запись в регистр введенной информации, OUTPUT ENABLE – вывод для разрешения выхода, (если на нем логическая единица, то на выходе будет Hi-Z состояние, если 0 – то то, что записалось), RESET – обнуляет регистр. Теперь словесно опишу работу с данной микросхемой. Выставляем данные на вывод A, далее фронтом импульса на SHIFT CLOCK записываем все 8 бит. Далее даем импульс на вывод LATCH CLOCK чтобы записать введенную информацию. Если вывод OUTPUT ENABLE сидит на земле, то на выходах Qa-Qh можно наблюдать введенные данные. Если вам мало 8 выводов, то сдвиговые регистры можно каскадировать с помощью вывода SQh и получить практически любое конечное количество портов:

Правда с увеличением количества сдвиговых регистров увеличиться время, необходимое, чтобы загнать в них цепочку данных. Итак, с помощью HC595 и 4-х выводов микроконтроллера можно управлять конечным количеством светодиодов. На схеме: резистор R1 – 10кОм, конденсатор С7 – 0,1мкФ. Конденсаторы С3,С5 электролитические, по 200 и 100мкФ, С4,С6 – керамические по 0,1мкФ соответственно. Светодиод D1 сигнализирует подачу питания, резистор R2 на 1кОм. Светодиоды D2-D17 – слаботочные на 20мА, резисторы R3-R18 ограничительные, на 1кОм каждый. Источник тактирования микроконтроллера – внутренний RC генератор на 1 МГц.
Продемонстрируем на сказанное не примере: подключим к ATmega8 2 штуки HC595, а к ним в свою очередь 16 светодиодов. Запрограммируем микроконтроллер, чтобы он что-то выводил на это 16 светодиодов. Пускай это будет переменная типа int, которую будем разлагать на биты и выводить с помощью светодиодов. Чтобы не было скучно, будем ее инкрементировать и наблюдать за происходящей картиной. Вот сам код программы:

  1. #include <avr/io.h>
  2.  
  3. #define DATA 0
  4. #define SCL 1
  5. #define REC 2
  6.  
  7. void pause (unsigned int a)
  8. { unsigned int i;
  9.  
  10. for (i=a;i>0;i--)
  11. ;
  12. }
  13.  
  14. void send_data (unsigned int data)
  15. { unsigned char i;
  16.  
  17. for (i=0;i<16;i++)
  18. {
  19. if ((data&0x8000)==0x00) PORTD&=~_BV(DATA); //Выставляем данные на PD0
  20. else PORTD|=_BV(DATA);
  21. asm("nop");
  22. PORTD|=_BV(SCL); //Импульс на SCL
  23. asm("nop");
  24. PORTD&=~_BV(SCL);
  25. asm("nop");
  26. data=(data<<1);
  27. }
  28. PORTD|=_BV(REC); //Импульс на Latch clock
  29. asm("nop");
  30. PORTD&=~_BV(REC);
  31. }
  32.  
  33. int main(void)
  34. { unsigned int data=0;
  35. PORTD=0x00; //Первоначально выключаем выхода
  36. DDRD=0x07; //PD0-PD2 как выхода
  37.  
  38. while (1)
  39. {
  40. send_data(data); //Отправить данные
  41. data=data+1;
  42. pause(500);
  43. }
  44. return 1;
  45. }

Подключив к микроконтроллеру логический анализатор увидим на мониторе картинку, которую мы выше описали словесно (здесь в регистр забиваются данные 0xA305):
осциллограмма работы с HC595
Все это собрано на макетной платке и работает вот так:

Скачать исходники и бинарники в виде проекта под AVR Studio 4.

А не проще ли использовать дешифраторы?

А не проще ли использовать дешифраторы , такие как 555ИД3 -- 4 вывода на данные и 16 выходов .
это и побыстрее работать будет...

Дешифраторы?

Тогда из 16 светодиодов гореть только один, тот, у которого номер вывода будет равен числу на входе дешифратора. Вроде.

наверно можно подключить к

наверно можно подключить к SPI?

Можно

Можно

Хорошее направление, мне тоже

Хорошее направление, мне тоже нравится
вот аналоги конструкций, может тебе поможет по схемотехнике и софту.
написано только на асме
easyelectronics.ru/3d-led-globus.html
code.google.com/p/povglobe/

Массив данных.

А вот как вывести какой-то заранее определённый массив данных?
Мне очень нравится так называемая "механическая развёртка", но вот никак не могу разобраться со сдвиговыми регистрами. Хотелось бы побольше вертикальных пикселей.
Пока только могу выводить на отдельные порты, как в примере на видео.

Всё! Сам разобрался! :) Ещё добавил примитивный датчик начала движения из двух контактов.

Примеры мехразвёртки.

Вот ещё пара примеров механической развёртки! :)

механическая развертка 1механическая развертка 2механическая развертка 3

В свое время долго не мог

В свое время долго не мог понять, как же работает такая светодиодная палочка :) Оказалось все очень просто.

о выводе на 4 сдвиговых регистра

Добрый вечер не могли бы вы написать пример вывода на 4 сдвиговых регистра с двумя нормально все получалось и раньше а вот на 4 никак не выходит,нужно управлять 32мя светодиодами. Как это правильно реализовать помогите плиз.

Регистры соединяем

Регистры соединяем паровозиком, SDO предыдущего с SDI следующего. LCHCLK и SFTCLK общие. Все RST на +5В, OE на земле. У меня с первого раза правильно соединить не удалось, запутался в бороде проводов.

Насчет кода: 32 бита, это как раз переменная long int. Вывести ее аналогично как и 16 бит int.

  1. void send_data (long int data)
  2. { unsigned char i;
  3.  
  4. for (i=0;i<32;i++)
  5. {
  6. if ((data&0x80000000)==0x00) PORTD&=~_BV(DATA); //Выставляем данные на PD0
  7. else PORTD|=_BV(DATA);
  8. asm("nop");
  9. PORTD|=_BV(SCL); //Импульс на SCL
  10. asm("nop");
  11. PORTD&=~_BV(SCL);
  12. asm("nop");
  13. data=(data<<1);
  14. }
  15. PORTD|=_BV(REC); //Импульс на Latch clock
  16. asm("nop");
  17. PORTD&=~_BV(REC);
  18. }
  19.  
  20. Использовать вот так: send_data (0x12345678);

огромное спасибо работает

огромное спасибо работает отлично а то все знакомые сишники не могли помочь