Печать

Подключение семисегментных индикаторов с помощью сдвигового регистра 74HC595. Делаем простой термометр на Attiny13 и LM35

Автор: AntonChip Опубликовано . Опубликовано в Программирование на Си

Рейтинг:   / 16
ПлохоОтлично 

Сдвиговый регистр 74HC595 находит то же применение что и регистр 74HC164, но у первого больше функций и возможностей. У него есть так называемая "защелка", которая управляет выходами регистра, т.е. как только все биты поступят в регистр их надо "защелкнуть", зафиксировать, чтобы данные появились на его выходе, данные на выходах не изменятся пока мы вновь не "защёлкнем" их. Выходы регистра можно установить в высокоомное состояние(HI-Z), т. е. они будут висеть в воздухе, нагрузка полностью отключается. Также как и 74HC164, регистры 74HC595 можно соединять последовательно цепочками, это применяется например в матричных светодиодных индикаторах.

Описание выводов регистра:

- Q0…Q7 – выходы;
- GND – земля;
- 'Q7 – выход предназначенный для последовательного соединения регистров;
- MR – сброс регистра;
- SH_CP – вход для тактовых импульсов;
- ST_CP – вход «защёлкивающий» данные;
- OE – вход переводящий выходы из HI-Z в рабочее состояние;
- DS – вход данных;
- VCC – питание 5 вольт.

Для управления регистром в обычной ситуации достаточно всего лишь трёх  выводов : SH_CP, ST_CP, DS. Рассмотрим работу регистра на примере цифрового термометра с датчиком LM35. LM35 - прецизионный датчик температуры с аналоговым выходом. В нашем примере будет измеряет температуру от 0 до 150 градусов Цельсия. При подаче двухполярного питания может измерять отрицательную температуру.

Характеристики датчика LM35:

- отображение в градусах Цельсия;
- линейная зависимость 10 мВ/°С;
- точность измерения 0,5°С;
- предел измерения температуры от -55°С до +150°С;
- напряжение питания 4-30В;
- выпускаются в корпусах TO-46, SO-8, TO-92, TO-220.

Подключение семисегментных индикаторов с помощью сдвигового регистра 74HC595. Делаем простой термометр на Attiny13 и LM35

Контроллер используем наиболее подходящий - Attiny13, который работает от внутреннего генератора частотой 4,8 MHz. Семисегментные индикаторы используются любые с общим катодом, они подключаются к регистрам через токоограничительные ризисторы сопротивлением 220 Ом.

Функция write_display отвечает за передачу данных в регистры, в переменную data заносятся передаваемые данные, переменная nbytes определяет количество регистров, в нашем примере их 3 штуки.
Измерение сигнала с датчика происходит по окончанию преобразования АЦП, затем это значение конвертируется, усредняется и передается в регистры, в общем ничего сложного. Ниже исходный текст программы c подробным описанием:

// Подключение семисегментных индикаторов с помощью сдвигового регистра 74HC595.
// Делаем простой термометр на Attiny13 и LM35.
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h> 

volatile unsigned int adc_counter, temperature, value;

// Прерывание по окончанию преобразования АЦП
ISR(SIG_ADC)
{
// Vref = 5V, выход с датчика от 0 до 1,5V
// max напряжение на входе 4,99V
// k = 499/1023 = 0,487 или 26/53
value = value + ((ADC*26)/53);
adc_counter++;
}

// Массив значениий для семисегментного индикатора
//------------------0-----1-----2-----3-----4-----5                      
char SEGMENTE[] = {0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D,
//------------------6-----7-----8-----9----пусто
                   0x7D, 0x07, 0x7F, 0x6F, 0x00};

// Функция вывода данных через регистр
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); // DATA 1
PORTB |= (1 << PB2); // CLK 1
PORTB &= ~(1 << PB2); // CLK 0
}
else
{
PORTB &= ~(1 << PB0); // DATA 0
PORTB |= (1 << PB2); // CLK 1
PORTB &= ~(1 << PB2); // CLK 0
}
mask = mask >> 1; // сдвигаем биты
}
}
// защелкиваем регистр
PORTB |= (1 << PB1); 
PORTB &= ~(1 << PB1);
}

int main(void)
{
DDRB = 0b00000111;
PORTB = 0b00000000;

ADMUX |= (1 << MUX1)|(1 << MUX0);  // Вход ADC3
ADCSRA |= (1 << ADEN) // Разрешение АЦП
       |(1 << ADPS2)|(1 << ADPS1) // Предделитель на 64
	   |(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);
}

// Если температура меньше 100 градусов гасим незначащий ноль
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);
}
}

Комментарии  

0 #1 Alex1708 11.05.2015 08:44
можно ли расширить функционал ?
добавить к этому термометру функцию термостата , 2 кнопки (+) и (-) для установки температуры и выход исполнительного устройства?
в итоге получилось бы очень дешевое термореле
Сообщить модератору

Рекомендуем посмотреть