Делаем простой термометр на 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.volatileunsignedintadc_counter, temperature, value;008.009.// Прерывание по окончанию преобразования АЦП010.ISR(SIG_ADC)011.{012.// Vref = 5V, выход с датчика от 0 до 1,5V013.// max напряжение на входе 4,99V014.// k = 499/1023 = 0,487 или 26/53015.value = value + ((ADC*26)/53);016.adc_counter++;017.}018.019.// Массив значениий для семисегментного индикатора020.//------------------0-----1-----2-----3-----4-----5021.charSEGMENTE[] = {0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D,022.//------------------6-----7-----8-----9----пусто023.0x7D, 0x07, 0x7F, 0x6F, 0x00};024.025.// Функция вывода данных через регистр026.voidwrite_display(unsignedchar*data, unsignedcharnbytes)027.{028.unsignedcharmask,i;029.030.for(i = 0; i < nbytes; i++)031.{032.mask = 0x80;033.034.for(chark = 0; k < 8; k++)035.{036.// сравниваем каждый бит с единицей037.if(data[i] & mask)038.{039.PORTB |= (1 << PB0);// DATA 1040.PORTB |= (1 << PB2);// CLK 1041.PORTB &= ~(1 << PB2);// CLK 0042.}043.else044.{045.PORTB &= ~(1 << PB0);// DATA 0046.PORTB |= (1 << PB2);// CLK 1047.PORTB &= ~(1 << PB2);// CLK 0048.}049.mask = mask >> 1;// сдвигаем биты050.}051.}052.// защелкиваем регистр053.PORTB |= (1 << PB1);054.PORTB &= ~(1 << PB1);055.}056.057.intmain(void)058.{059.DDRB = 0b00000111;060.PORTB = 0b00000000;061.062.ADMUX |= (1 << MUX1)|(1 << MUX0);// Вход ADC3063.ADCSRA |= (1 << ADEN)// Разрешение АЦП064.|(1 << ADPS2)|(1 << ADPS1)// Предделитель на 64065.|(1 << ADIE);// разрешаем прерывание по окончанию преобразования066.067.ACSR |= (1 << ACD);// Выключаем аналаговый компаратор068.DIDR0 |= (1 << ADC3D);// Отключаем неиспользуемые цифровые входы069.070.sei();// Глобально разрешаем прерывания071.072.unsignedchardisplay[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.else095.{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.}