Урок 23
Часть 4
Собираем часы на DS1307 и LED индикаторе
В прошлой части нашего занятия мы уже отобразили на нашем индикаторе текущее время, а также. используя выход генератора прямоугольных импульсов в микросхеме DS1301, научили мигать двоеточие на индикаторе, что сделало данные показания более живыми и натуральными.
Небольшое лирическое отступление. Почему я решил собрать именно часы на данном индикаторе? А потому, что здесь пересекаются очень многие технологии и периферии — и динамическая индикация, и ШИМ, и I2C, и АЦП также будет задействовано, вообщем, много чего есть возможность повторить, а также хорошие электронные часы — это всегда интересно!
Теперь к делу. Сегодня мы как раз-то и задействуем модуль АЦП. С помощью АЦП и фоторезистора мы будем измерять интенсивность освещения и на основе результата измерений наш код будет «решать», с какой интенсивностью будет в данный момент светиться наш индикатор.
Вот такой вот я использовал фоторезистор
Вот такой вот у нас резистор. Как мы видим. он подключен через делитель напряжения, одной из частей которого является сам фоторезистор, а второй — обычный постоянный резистор. Среднее сопротивление фоторезистора 10 килоом, а освещение будет измеряться в диапазоне где-то от 1 килоома до 100 килоом, поэтому нам будет делитель напряжения просто необходим.
Посмотрим теперь нашу общую схему с подключенным делителем напряжения на фоторезисторе (нажмите на картинку для увеличения изображения)
Здесь выделен участок делителя. Как видно. делитель фоторезистором подключен к общему проводу, а постоянным резистором на 120 килоом подключен к шине питания, а центральный провод делителя подключен к контакту микроконтроллера, соответствующему нулевому каналу АЦП.
Поэтому чем меньше сопротивление фоторезистора, тем меньшее напряжение мы получим на делителе и чем больше — тем большее напряжение. И когда сопротивление фоторезистора достигнет 120 килоом, то напряжение будет приблизительно 2,5 вольта, что нам, в принципе и нужно. Это почти максимальное напряжение, так как опорное напряжение у нас 2,56 вольт.
Режим 10-битный АЦП я считаю использовать в часах нецелесообразным, потому что зачем нам такая точность для регулирования свечения, 8-битного вполне хватит.
Но для 8-битного режима для удобства считывания 8 бит удобнее всего воспользоваться вторым вариантом комбинирования бит в регистре ADC при бите ADLAR в регистре ADMUX, равном 1. В этом случае нам считывать придётся только старший регистр регистровой пары данных — ADCH. Вернее мы будем запоминать только этот регистр, считывать-то мы их обязаны все, так как будут использоваться прерывания, так как при таком режиме требуется меньше ресуросов, в том числе процессорного времени, а чтобы запустилось следующее преобразование, мы обязаны считать оба регистра, причем в особенной последовательности
Для использования аналого-цифрового преобразователя из проекта урока по АЦП MyADCISRLCD с использованием прерываний мы подключим файлы adc.c и adc.h.
Подключим также данную библиотеку в main.h
#include «PWM.h»
#include «adc.h»
Также здесь же добавим глобальную переменную для результата АЦП и вместе с ней ещё две для усреднения показаний, чтобы не было скачков результата преобразования
#include «led.h»
unsigned int adc_value,adc_counter,adc_tmp;
Также добавим ещё эти переменные в adc.c, первая там уже, соответственно, есть
extern unsigned int adc_value,adc_counter,adc_tmp;
В функции инициализации АЦП включим бит ADLAR
ADMUX |= (1<<ADLAR)|(1<<REFS1)|(1<<REFS0); //Внутренний Источник ОН 2,56в, вход ADC0
Включим большую частоту АЦП, для 8-битного режима медленная не нужна
|(1<<ADPS2)|(0<<ADPS1)|(1<<ADPS0)//Делитель 32 = 256 кГц
Также напишем усреднение показателей в обработчике прерываний АЦП
ISR(ADC_vect)
{
low_adc = ADCL;
high_adc = ADCH;//Верхняя часть регистра ADC должна быть считана последней, иначе не продолжится преобразование
if(adc_counter<20) {adc_tmp+=high_adc;adc_counter++;}
else {adc_value=adc_tmp/20;adc_counter=0;adc_tmp=0;}
}
Как мы видим, используем мы в расчете только старший регистр данных. Усреднение у нас простое, примитивное, без скольжения, да оно сложное и не нужно, у нас же постепенно происходит наступление темноты и света, а не скачкообразно.
Инициализируем АЦП в функции main()
init_PWM_timer();
ADC_Init();
Ну, и теперь, прежде чем придумать расчет ШИМ из показаний АЦП, то мы пока будем отображать результат преобразований АЦП, а когда их посмтотрим, то что-нибудь решим.
Напишем следующий код в бесконечном цикле функции main(), перед этим полностью закомментировав код работы с показаниями часов
//date = RTC_ConvertFromDec(date); //Преобразуем в десятичный формат
ledprint(adc_value);
_delay_ms(50);
}
Прошьём код и попробуем позатемнять фоторезистор. При очень светлом освещение у нас показатель около 7, а в темноте ложится на 255, то есть на максимум.
Ну и на этом основании мы теперь можем поуправлять значением ШИМ. Теперь мы на индикаторе будем показыать значение регистра ШИМ OCR2
ledprint(OCR2);
А также напишем саму зависимость
if(adc_value<120) OCR2=128-adc_value;
else OCR2=7;
ledprint(OCR2);
Вот такая вот зависимость. У нас ведь чем темнее. тем показатель ADCH больше, то есть всё наоборот, поэтому мы будем вычитать показания АЦП из 128, я подобрал такую оптимальную цифру для ШИМ, больше которой индикатор светится слишком ярко, нам это не надо. Вернее не слишком ярко, а больше которой у индикатора уже малоразличима разница интенсивности свечения.
Теперь соберем код, прошьём контроллер и посмотрим как будет это всё работать.
Показывать это в виде картинок нет смысла, да и интереснее будет смотреть когда уже будут ходить часы, а если кому интересно, то всё видно в видеоверсии урока, размещённой внизу страницы.
Вернём теперь весь закомментированный код и отображение времени на индикатор
date = RTC_ConvertFromDec(date); //Преобразуем в десятичный формат
if(adc_value<120) OCR2=128-adc_value;
else OCR2=7;
ledprint(hour*100+min);
Опять соберём код, прошьём контроллер, теперь можно и посмотреть
Вот так вот у нас всё работает. Я думаю, неплохо!
Но работы у нас с часами ещё много. И продолжим мы её в следующей части занятия.
Предыдущая часть Программирование МК AVR Следующая часть
Программатор, модуль RTC DS1307 с микросхемой памяти и индикатор можно приобрести здесь:
Программатор (продавец надёжный) USBASP USBISP 2.0
Модуль RTC DS1307 с микросхемой памяти
Семисегментный чертырехразрядный индикатор красный с общим анодом 10 шт
Смотреть ВИДЕОУРОК (нажмите на картинку)
Добавить комментарий