595-Регістр потрібен скрізь і всім, замітки на полях

Застосування регістрів зсуву 74HC595 або як управляти всім відразу використовуючи всього 3 ноги МК.

595 Перший - штука широко використовувана коли не вистачає портів виведення мікроконтролера. Для управління регістром потрібно мінімум два висновки контролера (а краще три), а виходів отримуємо теоретично скільки завгодно (у мене максимум було 48), про що далі і піде мова.

В самому кінці опишу досвід захисту від перешкод, наприклад коли блок з регістрами підключений шлейфом до контролера, а адже CMOS-входи, це не старий-добрий- "теплий" TTL, тут струми майже нульові. А ще не шкідливо при таких підключених передбачити і ситуацію, коли з'єднувальний шлейф несподівано згризли грізлі, а порти керують ядерним арсеналом.

Ну і до купи напишу якими командами в Atmel контролерах (ATMEGA, ATTINY) зручно працювати з портами при програмуванні на C (всякі бітові оператори, хитрі #define для підвищення Новомосковскемості коду та ін.). Ніби як такої гайд для зовсім початківців. А чи не початківцям краще відразу на другий пост про перешкоди ...

По-перше як працює зсувний регістр?

Як видно з назви, він щось кудись зрушує. У будь-якого такого регістра є два основні входи:

  • Вхід даних (Data serial input)
  • Вхід імпульсу * зсуву (Shift clock)

* "Імпульс" (або "стрибає"), це послідовна зміна значення входу з "0" на "1" і назад на "0", або інверсний варіант з "1" на "0" і назад в "1". Перехід з "0" в "1" називається переднім фронтом, навпаки - заднім. 74HC595 перемикається по передньому фронту, тобто в момент переходу з "0" в "1".

Строб зсуву ініціює "переписування" значень виходів в наступний вихід: з 1-го по 2-й, з 2-го на 3-й, ..., 7> 8, то що було на 8 втрачається. Виходить зрушення від першого виходу в напрямку останнього. Одночасно на перший вихід записується те, що було на вході даних.

Наприклад: спочатку на виходах були нулі (00000000),

Потім на Data подали 1, після чого зробили 3 стрибає на Shift clock.

В результаті отримаємо на виході: 11100000 (тобто 3 рази все зсовували вправо і писали 1 з Data в перший вихід).

Потім на вхід Data виставили 0 і відправили ще один стрибає:

Вихід: 01110000 (3 одиниці відповзли вправо, а в перший розряд записався 0 з Data)

Ну і нарешті на Data залишили 0 і зробили ще 5 стробов (5 зрушень вправо):

Вихід: 00000011 (зрушили так сильно, що найперша записана одиниця вискочила за 8 розряд і пропала)

Послідовно виставляючи потрібні значення на вхід Data і зрушеннями можна отримати будь-яке поєднання на виходах регістра, тобто перетворити послідовну передачу в паралельну. У 74HC595 виходів 8, виходить що 2 виходи контролера, можна "розвести" на 8 виконавчих пристроїв. А якщо на останній вихід регістра причепити вхід Data іншого регістра і запараллелить його Shift clock на Shift clock першого, то "тікає 8 розряд" буде стає першим у наступного регістра і ми отримаємо вже не 8, а 16 розрядів, керуючи як і раніше з двох ніг контролера (нарощувати розрядність доп.регістрамі можна і далі, отримуючи 24, 32 і т.д.).

Трохи кодування.

Найпростіший приклад (годиться для індикації і повільних пристроїв типу реле).

Послідовно видаємо кожен біт на порт контролера куди підключений вхід Data і смикаємо туди-назад порт, куди підключений вхід Shift регістра.

Взагалі такий код на рідкість страшний (і до речі не перевірений, тому що я так не пишу), краще ввести кілька #define:

* Можна піти далі і зробити вкладені #define, що б позбавиться від прямого PORT B. DDR B. P B ..., але у мене поки немає настільки універсальних бібліотек, що б це стало критичним.

Тепер перейдемо до схемотехнике і нюансам.

В якості жертви виберемо Attiny13, якого бог сильно образив ногами, зате нагородив вкрай низькою ціною. На скиди Reset і MR не забуваємо вішати підтягує резистори, інакше можна отримати вічне обнулення і довго розбиратися чомусь же завжди 8 :).

Варіант 1 (найпростіший) - управління 7 поділок вказує з ATTINY13 по 2-м проводам:

595-Регістр потрібен скрізь і всім, замітки на полях
Прийшла пора сказати про ще один важливий вхід 595-го - це Latch Clock (за схемою ST_CP), який "защелкивает" інформацію на виходах.

Схема 595-го зроблена так, що між виходами регістра зсуву (віртуальні 1..8) і собсно виходами мікросхеми (Qa-Qh) захований ще й паралельний регістр. Це означає, що ми можемо писати і рухати скільки завгодно, але стан фізичних виходів (Qa-Qh) зміниться тільки по появі стрибає по входу Latch Clock (запис в паралельний регістр). Його можна просто з'єднати з Shift Сlock і продовжувати керувати по 2-м лініях, що тут і показано.

А нюанс в тому, що і зрушення (SH_CP або Shift Clock), і "защелкивание" виходів (ST_CP або Latch Сlock) робляться по передньому фронту стрибає. І виходить, що на виходи замикається стан регістра до подачі зсуву, тому що поточне не встигає дістатися до засувок.

Якби інженери зробили один з входів по "заднім фронтом", жити було б сильно легше, а так щоб обійти проблему, в коді потрібно прописати додатковий стрибає після циклу виведення (жирним):

Ну і наостанок про особливість невикористання Latch Clock за призначенням. Ми виводимо на індикатор кожен зрушення регістра, а не тільки останнє "правильне стан виходів". І перед тим як засвітиться правильний сегмент підключений до Q6, ми побачимо як "вогник" послідовно пробіжить по всім іншим сегментам, їсть-но при тактовій частоті в 9.6МГц це станеться дуже швидко, але може бути помітно.

І, звичайно, так не можна робити, якщо у нас на виходах не прості світлодіоди, а щось більш розумне і швидке, наприклад контролер LCD-екранчика. А тому:

Варіант 2 (3 лінії):

595-Регістр потрібен скрізь і всім, замітки на полях
Тут жодного проміжного висновку на індикатор не відбудеться, поки не відправимо імпульс по лінії PB2 - ST_CP (Latch Сlock). Код тепер правимо трохи по-іншому (цей варіант або його асемблерний еквівалент я використовую зараз):

Той же варіант, але з двома розрядами статичної індикації.

595-Регістр потрібен скрізь і всім, замітки на полях

Тут пора трохи розповісти про каскадирование декількох регістрів. Зрозуміло, що сигнал поданий на DS послідовно пробігає по усіх виходах регістра, але відображає регістр стан виходів тільки по Latch Clock (ST_CP), але є "секретна" нога Q7 '- яка виведена з регістра безпосередньо, тобто минаючи засувку (і соотв. не залежить від Latch Clock). Минуло 8 стробов по Shift Clock, отримаєте стан DS на Q7 ', не залежно дозволяли ми висновок на Q0-Q7. Тобто Data (DS) кожного наступного регістра потрібно підключити до Q7 'попереднього і таким чином буде нарощуватися розрядність. На даній схемі, перший відправлений байт відобразитися на нижньому індикаторі, а другий байт на верхньому.

Код для цієї схеми трохи відрізняється стилістикою, тому що я його витягнув його з старого проекту з використанням 7-сегментної індикації. У нього є невеликий недолік - його роботу складніше розглядати осциллографом, тому що в попередньому варіанті зручно вішати синхронізацію на спад PCLatch і спостерігати куди що передається, а тут Latch проходить коли вже все закінчилося. Ну і висновок байта побитно через старший розряд (лівим зрушенням) на асемблері реалізується оптимальніше, а тут через молодший (правим зрушенням), тому що на C так "природніше". Але все це я зрозумів значно пізніше наведеного проекту :) Зате цей код наочніше і повніше в практичному сенсі:

Про всяк випадок трохи про використовуваний Сі синтаксис:

Скорочена запис data = 2; еквівалентна data = data 2;

Широко використовуються оператори роботи з бітами:

Схожі статті