Сдвиговый регистр 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 подробным описанием:
// Подключение семисегментных индикаторов с помощью сдвигового регистра 74HC595. // Делаем простой термометр на Attiny13 и LM35. #include <avr/io.h> #include <util/delay.h> #include <avr/interrupt.h> volatile unsigned char adc_counter; volatile unsigned long adc_buffer; unsigned int temperature; unsigned char display[3]; // Массив значениий для семисегментного индикатора unsigned char SEGMENTE[] = { 0x3F, // 0 0x06, // 1 0x5B, // 2 0x4F, // 3 0x66, // 4 0x6D, // 5 0x7D, // 6 0x07, // 7 0x7F, // 8 0x6F, // 9 0x00 // blank }; // Прерывание по окончанию преобразования АЦП ISR(ADC_vect) { adc_buffer += ADC; // Накапливаем в буфер значения АЦП adc_counter++; // Увеличиваем счетчик измерений } // Функция вывода данных через регистр 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 << ADSC) // Начинаем преобразование |(1 << ADATE) // Непрерывный режим работы АЦП |(1 << ADPS2)|(1 << ADPS1) // Предделитель на 64 |(1 << ADIE); // разрешаем прерывание по окончанию преобразования ACSR |= (1 << ACD); // Выключаем аналаговый компаратор DIDR0 |= (1 << ADC3D); // Отключаем неиспользуемые цифровые входы sei(); // Глобально разрешаем прерывания while(1) { if(adc_counter > 250) { // Усредняем и преобразуем в мВ, U = ADC*Uref/1024 temperature = ((adc_buffer*5*100)/1024)/adc_counter; adc_counter = 0; adc_buffer = 0; } display[0] = SEGMENTE[temperature%10]; display[1] = SEGMENTE[temperature/10%10]; // Если температура меньше 100 гасим незначащий ноль if(temperature < 100) display[2] = SEGMENTE[10]; else display[2] = SEGMENTE[temperature/100%10]; write_display(display,3); // Отправляем данные на индикатор } }
Файлы к статье "Подключение семисегментных индикаторов с помощью сдвигового регистра 74HC595. Делаем простой термометр на Attiny13 и LM35" | |
Описание:
Проект AVRStudio4 |
|
Размер файла: 35.33 KB Количество загрузок: 584 | Скачать |
Комментарии
добавить к этому термометру функцию термостата , 2 кнопки (+) и (-) для установки температуры и выход исполнительного устройства?
в итоге получилось бы очень дешевое термореле
Я понимаю что нужна еще одна функция в которую надо отправить, к примеру
Код:
func(24, 1)
где 24 номер светодиода, а 1 или 0 - вкл или выкл светодиода, но сам не могу это написать.... Помогите чем смогите
Просто отсылай на индикатор только те биты, которые должны засвечивать светодиоды. В примере используются 7-сегментные индикаторы, которые из черточек должны отображать конкретные цифры - образы этих цифр собрвны в массив SEGMENTE[]. Сделай массив SEGMENTE[] = {0х01, 0х02, 0х04, 0х08, 0х10, 0х20, 0х40, 0х80}; В нем каждый элемент зажигает один светодиод. Массив создан для одного регистра.
Перебирая в цикле - можно создать бегущую точку на каждом регистре.
Если нужна одна точка (а не 3), то выхода два: или в массиве прописать все возможные варианты для 26 светодиодов или условиями выделять с какой момент в какой регистр что писать.
А какие-то другие варианты можно получить объединяя элементы массива операцией ИЛИ (например так display[0] = SEGMENTE[0] | SEGMENTE[2])
пожалуйста, попрошу проверить программу в железе, если все нормально выложу код в статье
Добавил в архив примерчик