Регистр сдвига – это набор триггеров, которые записывают и хранят биты информации последовательно при каждом тактовом импульсе. Таким образом, чтобы записать в сдвиговый регистр восемь бит информации, необходимо подавать бит (логический ноль или единицу) одновременно с тактовым импульсом восемь раз один за другим.
Микросхема 74HC595
Представляет собой восьмибитный регистр сдвига с возможностью "защелкивания" (фиксирования) данных по отдельному управляющему сигналу. Работает микросхема с последовательным интерфейсом SPI (Serial Peripheral Interface, обязательно требуется синхронизация данных с тактовым сигналом).
Корпус микросхемы может быть планарным (кодировка 74HC595D) или стандарта DIP16 (в этом случае кодировка 74HC595N).
Принципиальная схема регистра выглядит следующим образом.
Рис. 1. Принципиальная схема регистра
(сверху 8-битный регистр сдвига, в середине регистр хранения, ниже – выходной регистр)
Рис. 2. Микросхема 74HC595
Данные подаются на вход DS. Снимаются с выводов Q0-Q7.
GRD – "земля", VCC – питание +5 В (не более 6 В).
SH_CP – контакт для подачи тактовых сигналов (должны быть синхронизированы с битами данных).
MR – позволяет сбросить (обнулить) регистр.
ST_CP – "защелка" введенных данных.
OE – отвечает за переключение между Z-состоянием и рабочим режимом.
Через контакт Q7’ можно соединять последовательно между собой несколько микросхем 74HC595.
Семисегментный индикатор
Это наиболее распространенный элемент, позволяющий наглядно отобразить цифровую информацию (а иногда и буквенную). Типовой светодиодный или жидкокристаллический элемент выглядит следующим образом.
Рис. 3. Светодиодный или жидкокристаллический элемент
С помощью семи сегментов можно показать пользователю 128 (27) различных комбинаций свечения.
Рис. 4. Комбинации свечения
Использование регистра и индикатора вместе
Как видно из функционала сдвигового регистра, его восемь параллельных выводов могут отлично подойти для управления семисегментным индикатором (один вывод может быть не задействован в зависимости от логики подключения – он управляет точкой).
Используя 74HC595 можно включить в схему не один индикатор, а несколько (в зависимости от того, сколько разрядов индикации требуется).
Самый простой пример (можно даже собрать в программе Proteus) соединения 74HC595 с индикатором ниже.
Рис. 5. Схема соединения 74HC595 с индикатором
Управлять логикой работы индикатора будет следующий листинг:
#include <inttypes.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>
#include <util/delay.h>
#define CLK PB5 // часы
#define DS PB3 // данные
#define E PB2 // ввод
#define PORT PORTB
#define DDR DDRB
void SPI_MasterTransmit(uint8_t Data);
int main()
{
//установка формата SPI
DDR|=(1<<CLK)|(1<<DS)|(1<<E); // вывод
SPCR=(1<<SPE)|(1<<MSTR)|(1<<SPR0); // включение SPI, режим MASTER, делитель частоты 1/16
while (1)
{
char i;
for(i=0;i<10;i++)
{
PORT &= ~(1<<E);
SPI_MasterTransmit(i);
PORT|=(1<<E);
_delay_ms(1000);
}
};
return 0;
}
void SPI_MasterTransmit(uint8_t Data) {
static const uint8_t seg[10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};
SPDR=(Data < 10)? seg[Data] : Data;
while(!(SPSR & (1<<SPIF)));
};
На выходе вы получите циклично изменяющиеся цифры от нуля до девяти через определенный интервал времени.
Логику можно переработать под себя, но здесь важно понять, как именно управляются светодиоды в панели. Смысл заключается в том, что для того, чтобы зажечь требуемые плашки, нужно отправить правильную комбинацию управляющих нулей и единиц на входы индикатора.
Чтобы было понятнее, приведем кодировку команд сопоставленную с десятичными цифрами.
Цифра | HEX |
0 | 0x3F |
1 | 0x06 |
2 | 0x5B |
3 | 0x4F |
4 | 0x66 |
5 | 0x6D |
6 | 0x7D |
7 | 0x07 |
8 | 0x7F |
9 | 0x6F |
h | 0x80 |
Возможно так будет нагляднее (в двоичном коде на контактах светодиодного индикатора).
Обозначения А-H – это светодиоды на панели (смотри обозначения ниже).
Рис. 6. Светодиоды на панели
То есть, чтобы индикатор показал нам цифру 1, нужно отправить код (00000110 или в шестнадцатеричном формате 0x06), тогда загорятся светодиоды c и b. Обратите внимание, здесь массив данных для отображения никак не соотносится с реальными числами, то есть 0x06 – это 6 в десятеричной системе счисления, а светодиоды отобразят 1.
Перейдем к более практическим задачам.
В качестве наглядного примера с использованием последовательного подключения нескольких регистров сдвига 74HC595, управляющих каждый своим разрядом дисплея, может подойти схема термометра на программируемой микросхеме Attiny13.
Сама схема.
Рис. 7. Схема устройства
Генератор тактовой частоты в Attiny13 встроенный. Данные температуры в контроллер передаются с датчика LM35. И после реализации логики в программируемой микросхеме данные для отображения последовательно передаются в 74HC595, которые в свою очередь накопленные 8 бит информации передают на семисегментные светодиоды.
Листинг программы будет выглядеть так:
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
volatile unsigned int adc_counter, temperature, value;
ISR(SIG_ADC)
{
value = value + ((ADC*26)/53);
adc_counter++;
}
char SEGMENTE[] = {0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D,
void write_display(unsigned char *data, unsigned char nbytes)
{
unsigned char mask,i;
for(i = 0; i < nbytes; i++)
{
mask = 0x80;
for(char k = 0; k < 8; k++)
{
if(data[i] & mask)
{
PORTB |= (1 << PB0);
PORTB |= (1 << PB2);
PORTB &= ~(1 << PB2);
}
else
{
PORTB &= ~(1 << PB0);
PORTB |= (1 << PB2);
PORTB &= ~(1 << PB2);
}
mask = mask >> 1;
}
}
PORTB |= (1 << PB1);
PORTB &= ~(1 << PB1);
}
int main(void)
{
DDRB = 0b00000111;
PORTB = 0b00000000;
ADMUX |= (1 << MUX1)|(1 << MUX0);
ADCSRA |= (1 << ADEN)
|(1 << ADPS2)|(1 << ADPS1)
|(1 << ADIE);
ACSR |= (1 << ACD);
DIDR0 |= (1 << ADC3D);
sei();
unsigned char display[3];
while(1)
{
ADCSRA |= (1 << ADSC);
if(adc_counter > 300)
{
temperature = value/adc_counter;
adc_counter = 0;
value = 0;
_delay_ms(50);
}
if(temperature < 100)
{
display[0] = SEGMENTE[temperature % 10];
display[1] = SEGMENTE[(temperature / 10) % 10];
display[2] = SEGMENTE[10];
}
else
{
display[0] = SEGMENTE[temperature % 10];
display[1] = SEGMENTE[(temperature / 10) % 10];
display[2] = SEGMENTE[(temperature / 100) % 10];
}
write_display(display,3);
}
}
Автор: RadioRadar