
Czasem znajdujemy się w takiej sytuacji gdy nasze założenia projektowe nie pokrywają się z elementami elektronicznymi jakie posiadamy. Może zaistnieć konieczność zwiększenia wyjść logicznych mikroprocesora jaki wykorzystujemy. Ten krótki poradnik dla początkujących pokaże wszystkim zainteresowanym jak sterować 16 wyjściami logicznymi w tym wypadku wykorzystanymi do zapalania diod LED przy użyciu jedynie 3 wyjść mikroprocesora.
Aby tego dokonać będziemy potrzebowali 8-bitowego rejestru przesuwnego. Informacje są zapisywane seryjnie do rejestru przesuwnego, a później utrwalone w rejestrze pamięci. Rejestr pamięci kontroluje 8 wyjść logicznych.

Obrazek pokazuje piny rejestru. Gdy stan pinu 11 (SH_CP lub SRCLK oznaczane zależnie od producenta) zmienia się z niskiego na wysoki to wartość DS (zależnie od podanego stanu logicznego na pinie 14) zapisywana jest w rejestrze przesuwnym a wartości rejestru przesuwane zostają o jeden bit tak aby zrobić miejsce na następną porcję informacji.
Pin 12 (ST_CP lub RCLK oznaczane zależnie od producenta) jest w stanie niskim podczas gdy informacje są zapisywane do rejestru. Stan wysoki powoduje zapisanie danych do rejestru pamięci, po czym stan wyjściowy pojawia się na pinach Q0-Q7.

Prezentowany schemat pokazuje przebieg sygnałowy potrzebny do ustawienia wyjść logicznych (Q0-Q7) tak aby pokazywały wartość 11000011, zakładając że ich pierwotny stan równy był 00000000.

Możemy poznać praktyczne zastosowanie rejestru przesuwnego na przykładzie mikrokontrolera Atmega8, 2 rejestry 74HC595 oraz 16 diod LED. Elementy należy podłączyć według wskazanego schematu. Ten przykład pokazuje sterowanie 16 diodami LED jednak poprzez połączenie kaskadowe kolejnych rejestrów możemy uzyskać niemal nieskończona ilość wyjść logicznych.
Poniższy kod spowoduje migotanie diod LED w układzie ‘knight rider’.
#include <avr/io.h>
#include <util/delay.h>
#define DS_PORT PORTC
#define DS_PIN 0
#define ST_CP_PORT PORTC
#define ST_CP_PIN 1
#define SH_CP_PORT PORTC
#define SH_CP_PIN 2
#define DS_low() DS_PORT&=~_BV(DS_PIN)
#define DS_high() DS_PORT|=_BV(DS_PIN)
#define ST_CP_low() ST_CP_PORT&=~_BV(ST_CP_PIN)
#define ST_CP_high() ST_CP_PORT|=_BV(ST_CP_PIN)
#define SH_CP_low() SH_CP_PORT&=~_BV(SH_CP_PIN)
#define SH_CP_high() SH_CP_PORT|=_BV(SH_CP_PIN)
//Define functions
//===============================================
void ioinit(void);
void output_led_state(unsigned int __led_state);
//===============================================
int main (void)
{
ioinit(); //Setup IO pins and defaults
while(1)
{
// Output a knight rider pattern
for (int i=15;i>=0;i--)
{
output_led_state(_BV(i));
_delay_ms(50);
}
for (int i=1;i<15;i++)
{
output_led_state(_BV(i));
_delay_ms(50);
}
}
}
void ioinit (void)
{
DDRC = 0b00000111; //1 = output, 0 = input
PORTC = 0b00000000;
}
void output_led_state(unsigned int __led_state)
{
SH_CP_low();
ST_CP_low();
for (int i=0;i<16;i++)
{
if ((_BV(i) & __led_state) == _BV(i)) //bit_is_set doesn’t work on unsigned int so we do this instead
DS_high();
else
DS_low();
SH_CP_high();
SH_CP_low();
}
ST_CP_high();
}
Źródło: http://www.protostack.com/forum/blog.php?u=2&b=35&sid=50384afa8d72f982e6ce2b736934eefc