Оглавление:

Монитор температуры и уровня освещенности с отображением на ЖК-дисплее NOKIA 5110: 4 шага
Монитор температуры и уровня освещенности с отображением на ЖК-дисплее NOKIA 5110: 4 шага

Видео: Монитор температуры и уровня освещенности с отображением на ЖК-дисплее NOKIA 5110: 4 шага

Видео: Монитор температуры и уровня освещенности с отображением на ЖК-дисплее NOKIA 5110: 4 шага
Видео: Подключение дисплея 5110 к ардуино. Вывод температуры на экран дисплея 2024, Ноябрь
Anonim
Image
Image

Всем привет!

В этом разделе мы делаем простое электронное устройство для контроля температуры и уровня освещенности. Измерения этих параметров отображаются на ЖК-дисплее NOKIA 5110. Устройство построено на базе микроконтроллера AVR ATMEGA328P. Устройство контроля оснащено цифровым термометром DS18B20 и фоторезистором для измерения уровня освещенности.

Шаг 1: Описание компонентов

Описание Компоненты
Описание Компоненты
Описание Компоненты
Описание Компоненты

Основные компоненты устройства мониторинга:

  • Микроконтроллер AVR «ATMEGA328P».
  • Монохромный графический ЖК-дисплей «NOKIA 5110»
  • Цифровой термометр 1-Wire с программируемым разрешением «DS18B20»
  • Светозависимый резистор
  • Провода

Микроконтроллер AVR «ATMEGA328P»

Устройство мониторинга использует следующие периферийные функции микроконтроллера:

  1. 16-битное прерывание таймера / счетчика
  2. 8-канальный 10-битный АЦП
  3. Ведущий / ведомый последовательный интерфейс SPI

Монохромный графический ЖК-дисплей «NOKIA 5110»

Характеристики:

  1. ЖК-дисплей 48 x 84 точек
  2. Интерфейс последовательной шины с максимальной скоростью 4 Мбит / с
  3. Внутренний контроллер / драйвер «PCD8544»
  4. Светодиодная подсветка
  5. Работа при напряжении 2,7-5 Вольт
  6. Низкое энергопотребление; подходит для аккумуляторных батарей
  7. Диапазон температур от -25˚C до + 70˚C
  8. Поддержка входного сигнала CMOS

Обработка адреса ЖК-дисплея (адресация):

Расположение адресов памяти, отображаемое на ЖК-дисплее (DDRAM), представляет собой матрицу, состоящую из 6 строк (адрес Y) от Y-адреса 0 до Y-адреса 5 и 84 столбцов (X-адрес) от X-адреса 0 до X- Адрес 83. Если пользователь хочет получить доступ к позиции отображения результата на ЖК-дисплее, необходимо обратиться к взаимосвязи между X-адресом и Y-адресом.

Данные, которые будут отправлены на дисплей, имеют размер 8 бит (1 байт) и будут расположены в виде вертикальной линии; в этом случае бит MSB будет меньше, а бит LSB будет больше, как показано на рисунке.

Цифровой термометр 1-Wire с программируемым разрешением DALLAS «DS18B20»

Функции:

  1. Уникальный интерфейс 1-Wire® требует только одного вывода порта для связи
  2. Сократите количество компонентов с помощью встроенного датчика температуры и EEPROM
  3. Измеряет температуру от -55 ° C до + 125 ° C (от -67 ° F до + 257 ° F)
  4. ± 0,5 ° C Точность от -10 ° C до + 85 ° C
  5. Программируемое разрешение от 9 до 12 бит
  6. Никаких внешних компонентов не требуется
  7. Режим паразитного питания требует только 2 контактов для работы (DQ и GND)
  8. Упрощает распределенные приложения для измерения температуры с возможностью многоточечного подключения
  9. Каждое устройство имеет уникальный 64-битный серийный код, хранящийся во встроенном ПЗУ.
  10. Гибкие определяемые пользователем параметры энергонезависимой (NV) сигнализации с командой поиска сигнализации идентифицируют устройства с температурами за пределами запрограммированных пределов

Приложения:

  1. Термостатические регуляторы
  2. Промышленные системы
  3. Потребительские товары
  4. Термометры
  5. Термочувствительные системы

Светозависимый резистор

Светозависимый резистор (LDR) - это преобразователь, который меняет свое сопротивление, когда свет падает на его поверхность.

Обычно LDR будет иметь от одного мегаома до двух мегаомов в полной темноте, от десяти до двадцати кОм при десяти люксах, от двух до пяти кОм при 100 люксах. Сопротивление между двумя контактами датчика уменьшается с увеличением интенсивности света или проводимость между двумя контактами датчика увеличивается.

Используйте схему делителя напряжения для преобразования изменения сопротивления в изменение напряжения.

Шаг 2: Код микропрограммы микроконтроллера

#ifndef F_CPU # define F_CPU 16000000UL // сообщение частоты кристалла контроллера (16 МГц AVR ATMega328P) #endif

// ИНТЕРФЕЙС SPI DEFINES #define MOSI 3 // MOSI it PORT B, PIN 3 #define MISO 4 // MISO it PORT B, PIN 4 #define SCK 5 // SCK it PORT B, PIN 5 #define SS 2 // SS это ПОРТ B, ПИН 2

// СБРОСИТЬ ДИСПЛЕЙ #define RST 0 // СБРОСИТЬ это ПОРТ B, ПИН 0

// ВЫБОР РЕЖИМА ОТОБРАЖЕНИЯ - Вход для выбора либо команды / адреса, либо ввода данных. #define DC 1 // DC это ПОРТ B, PIN 1

// массив кодов отрицательного знака статический const unsigned char neg [4] = {0x30, 0x30, 0x30, 0x30};

// кодирует массив цифр [0..9] static const unsigned char font6x8 [10] [16] = {{0xFC, 0xFE, 0xFE, 0x06, 0x06, 0xFE, 0xFE, 0xFC, 0x01, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x01}, // 0 {0x00, 0x00, 0x18, 0x1C, 0xFE, 0xFE, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x01, 0x00}, // 1 { 0x0C, 0x8E, 0xCE, 0xE6, 0xE6, 0xBE, 0x9E, 0x0C, 0x01, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x01}, // 2 {0x00, 0x04, 0x26, 0x06, 0x06, 0x04, 0x26DE, 0x06, 0x06, 0x8C, 0x00, 0x01, 0x03, 0x03, 0x03, 0x03, 0x03, 0x01}, // 3 {0x3C, 0x3E, 0x7C, 0x60, 0x60, 0xFC, 0xFE, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 0x01, 0x03, 0x01}, // 4 {0x1C, 0x3E, 0x3E, 0x36, 0x36, 0xF6, 0xF6, 0xE4, 0x01, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x01FC, // 5 {0 0xFE, 0xFE, 0x36, 0x36, 0xF6, 0xF6, 0xE4, 0x01, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x01}, // 6 {0x04, 0x06, 0x06, 0x86, 0xE6, 0xE6, 0x86, 0xE6, 0x00, 0x00, 0x00, 0x01, 0x03, 0x01, 0x00, 0x00}, // 7 {0xCC, 0xFE, 0xFE, 0x36, 0x36, 0xFE, 0xFE, 0xCC, 0x01, 0x03, 0x03, 0x03, 0x03, 0x03 0x0 3, 0x01}, // 8 {0x3C, 0x7E, 0x7E, 0x66, 0x66, 0xFE, 0xFE, 0xFC, 0x01, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x01} // 9};

// массив кодов слова "TEMP:" static const unsigned char TEMP_1 [165] = {0x02, 0x06, 0x06, 0xFE, 0xFE, 0xFE, 0x06, 0x06, 0x02, 0x00, 0xFC, 0xFE, 0xFE, 0x26, 0x26, 0x24, 0x00, 0xFC, 0xFE, 0xFE, 0x1C, 0x38, 0x70, 0x38, 0x1C, 0xFE, 0xFE, 0xFC, 0x00, 0xFC, 0xFE, 0xFE, 0x66, 0x66, 0x7E, 0x7E, 0x3C, 0x8C, 0x8C, 0x8C 0x00, 0x00, 0x00, 0x01, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x03, 0x03, 0x03, 0x01, 0x00, 0x01, 0x03, 0x01, 0x00, 0x00, 0x00 0x01, 0x03, 0x01, 0x00, 0x01, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x0C, 0x1E, 0x33, 0x33, 0x1E, 0x0CF, 0x0C, 0x00, 0x 0x9C, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x03, 0x03, 0x01,};

// кодовый массив слова "LUX:" const unsigned char TEMP_2 [60] = {0xFC, 0xFE, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFE, 0xFC, 0x00, 0x00, 0xFC, 0xFE, 0xFC, 0x00, 0x04, 0x8E, 0xDE, 0xFC, 0xF8, 0xFC, 0xDE, 0x8E, 0x04, 0x00, 0x8C, 0x8C, 0x01, 0x03, 0x03, 0x03, 0x03, 0x03, 0x01, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x01, 0x00, 0x01, 0x03, 0x03, 0x01, 0x00, 0x01, 0x03, 0x03, 0x01, 0x00, 0x01, 0x01};

#включают

#include #include

// Инициализация порта не используется Port_Init () {DDRB = (1 << MOSI) | (1 << SCK) | (1 << SS) | (1 << RST) | (1 << DC); // Установить MOSI, SCK, SS, RST, DC в качестве выхода, все остальные входные PORTB | = (1 << RST); // Установить на выводе RST высокий уровень PORTB | = (1 << SS); // Установить на выходе SS высокий уровень - Дисплей Отключить DDRC = 0xFFu; // Установить все контакты PORTC как выходные. DDRC & = ~ (1 << 0); // Делает первый вывод PORTC как Input PORTC = 0x00u; // Устанавливаем все выводы PORTC на низкий уровень, что выключает его. }

// Инициализация АЦП void ADC_init () {// Включить АЦП, частота дискретизации = osc_freq / 128 устанавливает предделитель на максимальное значение, 128 ADCSRA | = (1 << ADEN) | (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0); ADMUX = (1 << REFS0); // Выбор опорного напряжения для АЦП // Выбор нулевого канала по умолчанию с помощью регистра выбора мультиплексора АЦП (ADC0). }

// Функция для чтения результата аналого-цифрового преобразования uint16_t get_LightLevel () {_delay_ms (10); // Подождите некоторое время, пока канал не будет выбран ADCSRA | = (1 << ADSC); // Запускаем преобразование АЦП, устанавливая бит ADSC. записать 1 в ADSC, а (ADCSRA & (1 << ADSC)); // ждем завершения преобразования // ADSC снова становится 0 до тех пор, непрерывно выполнять цикл _delay_ms (10); возврат (ADC); // Возвращаем 10-битный результат}

// Инициализация SPI void SPI_Init () {SPCR = (1 << SPE) | (1 << MSTR) | (1 << SPR0); // Включить SPI, установить как Master, установить предделитель как Fosc / 16 в управлении SPI регистр }

// инициализируем 16-битный Timer1, прерывание и переменную void TIMER1_init () {// устанавливаем таймер с предварительным делителем = 256 и режимом CTC TCCR1B | = (1 << WGM12) | (1 << CS12); // инициализируем счетчик TCNT1 = 0; // инициализировать значение сравнения - 1 сек OCR1A = 62500; // разрешить прерывание сравнения TIMSK1 | = (1 << OCIE1A); // разрешить глобальные прерывания sei (); }

// Включить отображение void SPI_SS_Enable () {PORTB & = ~ (1 << SS); // Подключаем вывод SS к логике 0}

// Отключение отображения void SPI_SS_Disable () {PORTB | = (1 << SS); // Отключаем вывод SS на логику 1}

// Функция отправки данных в буфер дисплея void SPI_Tranceiver (unsigned char data) {SPDR = data; // Загружаем данные в буфер while (! (SPSR & (1 << SPIF))); // Дождемся завершения передачи}

// Сбрасываем дисплей в начале инициализации void Display_Reset () {PORTB & = ~ (1 << RST); _delay_ms (100); PORTB | = (1 << RST); }

// Функция записи команды void Display_Cmnd (данные символа без знака) {PORTB & = ~ (1 << DC); // устанавливаем вывод постоянного тока на логический 0 для выполнения команды SPI_Tranceiver (data); // отправляем данные в регистр данных PORTB | = (1 << DC); // переводим вывод постоянного тока в высокий логический уровень для работы с данными}

// Инициализация дисплея void Display_init () {Display_Reset (); // сбросить отображение Display_Cmnd (0x21); // набор команд в режиме сложения Display_Cmnd (0xC0); // установить напряжение, отправив C0, означает VOP = 5V Display_Cmnd (0x07); // устанавливаем темп. коэффициент до 3 Display_Cmnd (0x13); // устанавливаем значение системы смещения напряжения Display_Cmnd (0x20); // набор команд в базовом режиме Display_Cmnd (0x0C); // выводим результат в нормальном режиме}

// Очистить дисплей void Display_Clear () {PORTB | = (1 << DC); // сделать вывод постоянного тока на высокий логический уровень для обработки данных for (int k = 0; k <= 503; k ++) {SPI_Tranceiver (0x00);} PORTB & = ~ (1 << DC); // подключаем вывод постоянного тока к логике ноль для командных операций}

// устанавливаем столбец и строку в положение отображения результата на ЖК-дисплее void Display_SetXY (unsigned char x, unsigned char y) {Display_Cmnd (0x80 | x); // столбец (0-83) Display_Cmnd (0x40 | y); // строка (0-5)}

// Функция для отображения отрицательного знака void Display_Neg (unsigned char neg) {Display_SetXY (41, 0); // Устанавливаем адрес позиции на дисплее для (int index = 0; index0) {SPDR = 0x30;} // Загружаем данные в буфер дисплея (отображаем отрицательный знак) else {SPDR = 0x00;} // Загружаем данные в буфер отображения (убрать отрицательный знак) while (! (SPSR & (1 << SPIF))); // Ждем завершения передачи _delay_ms (100); }}

// Функция очистки цифрового знака void Off_Dig (unsigned char x, unsigned char y) {Display_SetXY (x, y); // Устанавливаем адрес позиции на дисплее (верхняя строка) для (int index = 0; index <8; index ++) {SPI_Tranceiver (0);} // Загружаем данные в буфер дисплея (очищаем верхнюю часть цифрового знака) y ++; Display_SetXY (x, y); // Устанавливаем адрес позиции на дисплее (нижняя строка) для (int index = 0; index <8; index ++) {SPI_Tranceiver (0);} // Загружаем данные в буфер отображения (прозрачная нижняя часть цифровой вывески)}

// Функция для отображения цифрового знака void Display_Dig (int dig, unsigned char x, unsigned char y) {Display_SetXY (x, y); // Установить адрес позиции на дисплее (верхняя строка) for (int index = 0; index <16; index ++) {if (index == 8) {y ++; Display_SetXY (x, y);} // Устанавливаем адрес позиции на дисплее (нижняя строка) SPI_Tranceiver (font6x8 [dig] [index]); // Загружаем массив кодов цифр в буфер дисплея _delay_ms (10); }}

// Инициализация DS18B20 unsigned char DS18B20_init () {DDRD | = (1 << 2); // Установить вывод PD2 порта PORTD как вывод PORTD & = ~ (1 << 2); // Устанавливаем вывод PD2 на низкий уровень _delay_us (490); // Время инициализации DDRD & = ~ (1 << 2); // Установить вывод PD2 порта PORTD как input _delay_us (68); // Время OK_Flag = (PIND & (1 << 2)); // получаем импульс датчика _delay_us (422); return OK_Flag; // возвращаем 0-нормально датчик подключен, 1-ошибка датчик отключен}

// Функция для чтения байта из DS18B20 unsigned char read_18b20 () {unsigned char i, data = 0; для (я = 0; я <8; я ++) {DDRD | = (1 << 2); // Установить вывод PD2 порта PORTD как output _delay_us (2); // Синхронизация DDRD & = ~ (1 1; // Следующий бит if (PIND & (1 << 2)) data | = 0x80; // помещаем бит в байт _delay_us (62);} return data;}

// Функция для записи байта в DS18B20 void write_18b20 (unsigned char data) {unsigned char i; для (я = 0; я <8; я ++) {DDRD | = (1 << 2); // Установить вывод PD2 порта PORTD как output _delay_us (2); // Время if (data & 0x01) DDRD & = ~ (1 << 2); // если мы хотим записать 1, освобождаем строку else DDRD | = (1 1; // Следующий бит _delay_us (62); // Синхронизация DDRD & = ~ (1 << 2); // Устанавливаем вывод PD2 PORTD как вход _delay_us (2);}}

// Функция для отображения уровня освещенности void Read_Lux () {uint16_t buffer; беззнаковый int temp_int_1, temp_int_2, temp_int_3, temp_int_0; // одиночные цифры, двойные цифры, тройные цифры, четверть цифры buffer = get_LightLevel (); // считываем результат аналого-цифрового преобразования уровень освещенности temp_int_0 = buffer% 10000/1000; // четверть разряда temp_int_1 = буфер% 1000/100; // трехзначный temp_int_2 = buffer% 100/10; // двузначное число temp_int_3 = buffer% 10; // однозначное число if (temp_int_0> 0) // если результат четвертьзначное число {Display_Dig (temp_int_0, 32, 2); // отображаем 1 цифру уровня освещенности Display_Dig (temp_int_1, 41, 2); // отображаем 2 цифры уровня освещенности Display_Dig (temp_int_2, 50, 2); // отображаем 3 цифры уровня освещенности Display_Dig (temp_int_3, 59, 2); // отображение 4-значного уровня освещенности} else {if (temp_int_1> 0) // если результат - трехзначное число {Off_Dig (32, 2); // очищаем 1 знак числа Display_Dig (temp_int_1, 41, 2); // отображаем 1 цифру уровня освещенности Display_Dig (temp_int_2, 50, 2); // отображаем 2 цифры уровня освещенности Display_Dig (temp_int_3, 59, 2); // отображаем 3 цифры уровня освещенности} else {if (temp_int_2> 0) // если результат - двузначное число {Off_Dig (32, 2); // очищаем 1 знак числа Off_Dig (41, 2); // очистить знак 2 числа Display_Dig (temp_int_2, 50, 2); // отображаем 1 цифру уровня освещенности Display_Dig (temp_int_3, 59, 2); // отображаем 2 цифры уровня освещенности} else // если результат однозначное число {Off_Dig (32, 2); // очищаем 1 знак числа Off_Dig (41, 2); // очистить знак 2 числа Off_Dig (50, 2); // очистить знак 3 числа Display_Dig (temp_int_3, 59, 2); // отображаем 1 цифру уровня освещенности}}}}

// Функция для отображения температуры void Read_Temp () {unsigned int buffer; беззнаковый int temp_int_1, temp_int_2, temp_int_3; // одиночные цифры, двойные цифры, тройные цифры, четверть разряда unsigned char Temp_H, Temp_L, OK_Flag, temp_flag; DS18B20_init (); // Инициализация DS18B20 write_18b20 (0xCC); // Проверка кода датчика write_18b20 (0x44); // Запуск преобразования температуры _delay_ms (1000); // Задержка опроса датчика DS18B20_init (); // Инициализация DS18B20 write_18b20 (0xCC); // Проверка кода датчика write_18b20 (0xBE); // Команда чтения содержимого ОЗУ датчика Temp_L = read_18b20 (); // Считываем первые два байта Temp_H = read_18b20 (); temp_flag = 1; // 1-положительная температура, 0-отрицательная температура // Получение отрицательной температуры if (Temp_H & (1 << 3)) // Проверка битов знака (если бит установлен - отрицательная температура) {signed int temp; temp_flag = 0; // установлен флаг 0 - отрицательная температура temp = (Temp_H << 8) | Temp_L; temp = -temp; // Преобразование дополнительного кода в прямой Temp_L = temp; Temp_H = temp >> 8; } buffer = ((Temp_H 4); temp_int_1 = buffer% 1000/100; // трехзначный temp_int_2 = buffer% 100/10; // двузначный temp_int_3 = buffer% 10; // однозначный

// Если температура отрицательная, отобразить знак температуры, иначе очистить

if (temp_flag == 0) {Display_Neg (1);} else {Display_Neg (0);} if (temp_int_1> 0) // если результат - трехзначное число {Display_Dig (temp_int_1, 45, 0); // отображение 1 цифры температуры Display_Dig (temp_int_2, 54, 0); // отображаем 2 цифры температуры Display_Dig (temp_int_3, 63, 0); // отображаем 3 цифры температуры} else {if (temp_int_2> 0) // если результат двузначное число {Off_Dig (45, 0); // очищаем 1 знак числа Display_Dig (temp_int_2, 54, 0); // отображение 1 цифры температуры Display_Dig (temp_int_3, 63, 0); // отображаем 2 цифры температуры} else // если результат однозначное число {Off_Dig (45, 0); // очищаем 1 знак числа Off_Dig (54, 0); // очистить знак 2 числа Display_Dig (temp_int_3, 63, 0); // отображаем 1 цифру температуры}}}

// Эта ISR запускается всякий раз, когда происходит совпадение счетчика таймера со значением сравнения (каждую 1 секунду) ISR (TIMER1_COMPA_vect) {// Чтение, отображение температуры и уровня освещенности Read_Temp (); Read_Lux (); }

// Функция для отображения слов «TEMP» и «LUX» void Display_label () {// Слово «TEMP» Display_SetXY (0, 0); // Устанавливаем адрес позиции на дисплее (верхняя строка) for (int index = 0; index <105; index ++) {if (index == 40) {Display_SetXY (0, 1);} // Устанавливаем адрес позиции на дисплее (нижняя строка) if (index == 80) {Display_SetXY (72, 0);} // Устанавливаем адрес позиции на дисплее (верхняя строка) if (index == 92) {Display_SetXY (72, 1); } // Устанавливаем адрес позиции на дисплее (нижняя строка) SPDR = TEMP_1 [index]; // Загружаем данные массива кодов в буфер отображения while (! (SPSR & (1 << SPIF))); // Дождемся завершения передачи _delay_ms (10); } // Слово "ЛЮКС" Display_SetXY (0, 2); // Устанавливаем адрес позиции на дисплее (верхняя строка) for (int index = 0; index <60; index ++) {if (index == 30) {Display_SetXY (0, 3);} // Устанавливаем адрес позиции на дисплее (нижняя строка) SPDR = TEMP_2 [индекс]; // Загружаем данные массива кодов в буфер отображения while (! (SPSR & (1 << SPIF))); // Дождемся завершения передачи _delay_ms (10); }}

int main (пусто)

{Port_Init (); // Инициализация порта ADC_init (); // Инициализация АЦП SPI_Init (); // Инициализация SPI SPI_SS_Enable (); // Включить отображение DS18B20_init (); // Инициализация DS18B20 Display_init (); // Инициализация дисплея Display_Clear (); // Отображение очистки Display_label (); // Отображение слов «ТЕМП» и «ЛЮКС» TIMER1_init (); // Инициализация Timer1. Начать мониторинг. Получение параметров каждую секунду. // бесконечный цикл while (1) {}}

Шаг 3. Прошивка микроконтроллера

Загрузка файла HEX во флеш-память микроконтроллера. Посмотрите видео с подробным описанием записи флеш-памяти микроконтроллера: Запись флеш-памяти микроконтроллера…

Шаг 4: Сборка схемы устройства мониторинга

Сборка схемы устройства мониторинга
Сборка схемы устройства мониторинга
Сборка схемы устройства мониторинга
Сборка схемы устройства мониторинга

Подключайте компоненты в соответствии с принципиальной схемой.

Подключите питание, и он работает!

Рекомендуемые: