Делаем простой термометр на Attiny13 и LM35.
Подключение семисегментных индикаторов с помощью сдвигового регистра 74HC595.
Сдвиговый регистр 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.Контроллер используем наиболее подходящий - Attiny13, который работает от внутреннего генератора частотой 4,8 MHz. Семисегментные индикаторы используются любые с общим катодом, они подключаются к регистрам через токоограничительные ризисторы сопротивлением 220 Ом.
Функция write_display отвечает за передачу данных в регистры, в переменную data заносятся передаваемые данные, переменная nbytes определяет количество регистров, в нашем примере их 3 штуки.
Измерение сигнала с датчика происходит по окончанию преобразования АЦП, затем это значение конвертируется, усредняется и передается в регистры, в общем ничего сложного. Ниже исходный текст программы c подробным описанием:001.
// Подключение семисегментных индикаторов с помощью сдвигового регистра 74HC595.
002.
// Делаем простой термометр на Attiny13 и LM35.
003.
#include <avr/io.h>
004.
#include <util/delay.h>
005.
#include <avr/interrupt.h>
006.
007.
volatile
unsigned
int
adc_counter, temperature, value;
008.
009.
// Прерывание по окончанию преобразования АЦП
010.
ISR(SIG_ADC)
011.
{
012.
// Vref = 5V, выход с датчика от 0 до 1,5V
013.
// max напряжение на входе 4,99V
014.
// k = 499/1023 = 0,487 или 26/53
015.
value = value + ((ADC*26)/53);
016.
adc_counter++;
017.
}
018.
019.
// Массив значениий для семисегментного индикатора
020.
//------------------0-----1-----2-----3-----4-----5
021.
char
SEGMENTE[] = {0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D,
022.
//------------------6-----7-----8-----9----пусто
023.
0x7D, 0x07, 0x7F, 0x6F, 0x00};
024.
025.
// Функция вывода данных через регистр
026.
void
write_display(unsigned
char
*data, unsigned
char
nbytes)
027.
{
028.
unsigned
char
mask,i;
029.
030.
for
(i = 0; i < nbytes; i++)
031.
{
032.
mask = 0x80;
033.
034.
for
(
char
k = 0; k < 8; k++)
035.
{
036.
// сравниваем каждый бит с единицей
037.
if
(data[i] & mask)
038.
{
039.
PORTB |= (1 << PB0);
// DATA 1
040.
PORTB |= (1 << PB2);
// CLK 1
041.
PORTB &= ~(1 << PB2);
// CLK 0
042.
}
043.
else
044.
{
045.
PORTB &= ~(1 << PB0);
// DATA 0
046.
PORTB |= (1 << PB2);
// CLK 1
047.
PORTB &= ~(1 << PB2);
// CLK 0
048.
}
049.
mask = mask >> 1;
// сдвигаем биты
050.
}
051.
}
052.
// защелкиваем регистр
053.
PORTB |= (1 << PB1);
054.
PORTB &= ~(1 << PB1);
055.
}
056.
057.
int
main(
void
)
058.
{
059.
DDRB = 0b00000111;
060.
PORTB = 0b00000000;
061.
062.
ADMUX |= (1 << MUX1)|(1 << MUX0);
// Вход ADC3
063.
ADCSRA |= (1 << ADEN)
// Разрешение АЦП
064.
|(1 << ADPS2)|(1 << ADPS1)
// Предделитель на 64
065.
|(1 << ADIE);
// разрешаем прерывание по окончанию преобразования
066.
067.
ACSR |= (1 << ACD);
// Выключаем аналаговый компаратор
068.
DIDR0 |= (1 << ADC3D);
// Отключаем неиспользуемые цифровые входы
069.
070.
sei();
// Глобально разрешаем прерывания
071.
072.
unsigned
char
display[3];
073.
074.
while
(1)
075.
{
076.
ADCSRA |= (1 << ADSC);
// Начинаем преобразование
077.
078.
if
(adc_counter > 300)
// вычисляем среднее значение АЦП
079.
{
080.
temperature = value/adc_counter;
081.
adc_counter = 0;
082.
value = 0;
083.
_delay_ms(50);
084.
}
085.
086.
// Если температура меньше 100 градусов гасим незначащий ноль
087.
if
(temperature < 100)
088.
{
089.
display[0] = SEGMENTE[temperature % 10];
090.
display[1] = SEGMENTE[(temperature / 10) % 10];
091.
display[2] = SEGMENTE[10];
092.
}
093.
// Иначе показываем все разряды
094.
else
095.
{
096.
display[0] = SEGMENTE[temperature % 10];
097.
display[1] = SEGMENTE[(temperature / 10) % 10];
098.
display[2] = SEGMENTE[(temperature / 100) % 10];
099.
}
100.
// Отправляем данные на индикатор
101.
write_display(display,3);
102.
}