В этом уроке мы научимся визуализировать данные аналоговых датчиков используя дисплей LCD1602 I2C. Алгоритм работы данного устройства можно применять как для тестирования различных аналоговых датчиков, так и в готовых проектах, один из которых был показан в видеообзоре датчиков газа.
Нам понадобится:
- Arduino Uno х 1шт.
- Любой аналоговый датчик x 1шт.
- Дисплей LCD1602 I2C зелёный или синий x 1шт.
- Trema Shield x 1шт.
Для реализации проекта нам необходимо установить библиотеки:
- LiquidCrystal_I2C - для работы с символьными ЖК дисплеями.
- Wire - для работы с аппаратной шиной I2C (библиотека входит в стандартный набор Arduino IDE).
Схема подключения:
Дисплей LCD1602 I2C подключается к аппаратной шине I2C. Аналоговый датчик подключается к любому аналоговому входу Arduino Uno (в примере используется вывод A0).
Код программы:
#include <Wire.h> // Подключаем библиотеку для работы с шиной I2C #include <LiquidCrystal_I2C.h> // Подключаем библиотеку для работы с LCD дисплеем по шине I2C LiquidCrystal_I2C lcd(0x27,16,2); // Объявляем объект библиотеки, указывая параметры дисплея (адрес I2C = 0x27, количество столбцов = 16, количество строк = 2) Если дисплей не отвечает, то измените адрес на 0x3F uint8_t symbol[8] = {31,31,31,31,31,31,31,31}; // Определяем массив который содержит полностью закрашенный символ const uint8_t pinSensor = A0; // Определяем константу для хранения номера аналогового входа с которого будут браться данные uint16_t valSensor; // Объявляем переменную для хранения данных с аналогового входа pinSensor // void setup(){ // lcd.init(); // Инициируем работу с LCD дисплеем lcd.backlight(); // Включаем подсветку LCD дисплея lcd.createChar(1, symbol); // Загружаем символ из массива symbol в первую ячейку ОЗУ дисплея } // Так как символ был загружен в 1 ячейку, то для его отображения на дисплее нужно вывести символ с кодом 1 // Если бы мы загрузили символ во 2 ячейку, то для его отображения на дисплее нужно было бы вывести символ с кодом 2 void loop(){ // valSensor = analogRead(pinSensor); // Читаем данные с аналогового входа pinSensor в переменную valSensor lcd.setCursor(6, 1); lcd.print(" "); // Устанавливаем курсор дисплея на 6 символ 1 строки и выводим 4 пробела начиная с той позиции, куда ранее был установлен курсор. lcd.setCursor(6, 1); lcd.print(valSensor); // Устанавливаем курсор дисплея на 6 символ 1 строки и выводим значение переменной valSensor на дисплей (начиная с той позиции, куда ранее был установлен курсор) lcd.setCursor(0, 0); // Устанавливаем курсор дисплея на 0 символ 0 строки для вывода шкалы, дальнейший вывод символов начнётся именно с этой позиции uint8_t j=map(valSensor,0,1023,0,17); // Определяем переменную j которой присваиваем значение valSensor преобразованное от диапазона 0...1023 к диапазону 0...17 for(uint8_t i=0; i<16; i++){ // Выполняем цикл 16 раз для вывода шкалы из 16 символов начиная с позиции в которую ранее был установлен курсор lcd.write(j>i? 1:32); // Выводим на дисплей символ по его коду, либо 1 (символ из 1 ячейки ОЗУ дисплея), либо 32 (символ пробела) } // После вывода каждого символа, курсор дисплея сдвигается автоматически }
Алгоритм работы:
До кода «Setup» подключаются библиотеки, объявляются объекты, переменные и константы. Формируется массив «symbol», данные которого являются символом для закрашивания шкалы визуализации.
В коде «Setup» инициируется работа с дисплеем, включается его подсветка, а в 1 ячейку его ОЗУ записывается символ из ранее созданного массива «symbol», после чего начинает постоянно выполняться код «loop».
Данные с аналогового входа читаются в переменную «valSensor» и выводятся по центру нижней строки дисплея. Перед тем как новые данные переменной «valSensor» выводятся на дисплей, в ту же позицию записывается строка из 4 пробелов, стирая предыдущие данные.
Те же данные (из переменной «valSensor») присваиваются переменной «j», только преобразуются функцией «map» от диапазона 0...1023 к диапазону 0...17. Диапазон 0...1023 охватывает все возможные значения переменной «valSensor», которые читаются с аналогового входа Arduino Uno. Диапазон 0...17 охватывает все возможные значения для переменной «j» и позволяет рассчитать сколько символов, из 16 символов шкалы, требуется закрасить, а сколько оставить. Почему выбран диапазон 0...17, а не 0...16 - рассказано ниже, в разделе «примечание».
Шкала визуализации выводится посимвольно в цикле «for». При каждом проходе этого цикла увеличивается значение переменной «i» (от 0 до 15 включительно), которое внутри цикла сравнивается в условии оператора «?» со значением переменной «j». Единственная строка внутри цикла предназначена для вывода одного символа на экран дисплея. Если значение переменной «j» больше значения переменной «i» (как это описано в условии оператора «?»), то будет выведен символ с кодом 1, иначе символ с кодом 32. Символ с кодом 1 - это символ который находится в 1 ячейке ОЗУ дисплея, а символ с кодом 32 - это пробел. Таким образом, при j=0 - все символы шкалы будут состоять из пробелов, а при j>=16 - все символы шкалы будут состоять из символов с кодом 1.
Примечание:
Как было сказано ранее, переменной «j» присваивается значение переменной «valSensor» преобразованное от диапазона 0...1023 к диапазону 0...17, это значит:
- при значении «valSensor» от 0 до 60 - значение «j» будет равно 0
- при значении «valSensor» от 61 до 120 - значение «j» будет равно 1
- ...
- при значении «valSensor» от 963 до 1022 - значение «j» будет равно 16
- при значении «valSensor» равном 1023 - значение «j» будет равно 17
Значит что «j» может принимать значение 17 не в диапазоне значений «valSensor», а только если значение «valSensor» точно равно 1023, вот почему выбран диапазон от 0 до 17, а не от 0 до 16. Иначе последний символ шкалы никогда бы не закрашивался символом с кодом 1.
Обсуждение