В основе сегодняшнего проекта лежит ЖК-дисплей Nokia 5110. Nokia 5110 LCD является одним из самых популярных ЖК-дисплеев среди производителей. Первоначально он был разработан для использования в качестве экрана для мобильных телефонов и использовался во многих мобильных телефонах в 90-х годах. Дисплей использует низкопотребляющий контроллер/драйвер PCD8544, который управляет графическим дисплеем 84×48px. В нормальном состоянии дисплей потребляет от 6 до 7 мА, что делает его идеальным для устройств с низким энергопотреблением.
Чтобы продемонстрировать, как создать меню на дисплее с Arduino, мы построим простое демо-меню с тремя страницами. Для навигации по меню мы будем использовать 3 кнопки. Первую для прокрутки вверх, вторую для прокрутки вниз и третью для выбора выделенного пункта. Первый экран меню будет служить домашней страницей и будет содержать параметры, которые открывают следующие две страницы. Вторая страница откроется после выбора первой опции меню на главной странице. Пользователи смогут изменить контрастность дисплея с помощью кнопок вверх и вниз, чтобы увеличить или уменьшить контраст. Нажав кнопку Select, пользователи смогут вернуться на главную страницу. Второй вариант на главной странице отображает третью страницу, где пользователи смогут включить/выключить подсветку дисплея, нажав кнопку Select.
Выбор последней опции на главной странице очищает все предыдущие настройки для контраста и подсветки. Это интересный проект может быть очень полезен любому, независимо от уровня вашего технического профессионализма.
Необходимые компоненты
Для построения этого проекта требуются следующие компоненты:
- Arduino Uno или аналогичная плата
- Nokia 5110 LCD
- Макетная плата
- Кнопки
- Перемычки
- Провода
Схема подключения LCD Nokia 5110 к Ардуино
Схема подключения довольно проста, соедините все компоненты как показано на рисунке ниже:
Для удобства ниже показана распинвка соединения между Arduino Uno и Nokia 5110.
LCD - Arduino
RST - D12
CE - D11
DC - D10
DIN - D9
CLK - D8
VCC - VCC
LIGHT - D7
GND - GND
Глядя на схему, вы увидите, что кнопки подключены к Arduino без подтягивающих резисторов. Это потому, что мы будем использовать внутренние подтягивающие резисторы Arduino. После всех подключений мы можем перейти к программированию.
Код
Честно говоря, код для этого проекта немного сложный, и сильно зависит от двух основных библиотек: The Adafruit GFX library and the Adafruit Nokia 5110 LCD Library. Библиотека Adafruit GFX позволяет легко отображать графику и выполнять простые анимации на поддерживаемых дисплеях. С другой стороны, библиотека Nokia 5110 LCD уменьшает объем работы и код, необходимый для взаимодействия с ЖК-дисплеем.
Сначала мы подключаем библиотеки, необходимые для проекта, в данном случае это Adafruit GFX и Nokia 5110 LCD.
#include <Adafruit_GFX.h>
#include <Adafruit_PCD8544.h>
Затем мы объявляем контакты, к которым подключены кнопки, а также объявляем все переменные, которые мы будем использовать для проекта. Имя переменной обеспечивает достаточное представление о том, что означает каждая переменная.
boolean backlight = true;
int contrast=50;
int menuitem = 1;
int page = 1;
volatile boolean up = false;
volatile boolean down = false;
volatile boolean middle = false;
int downButtonState = 0;
int upButtonState = 0;
int selectButtonState = 0;
int lastDownButtonState = 0;
int lastSelectButtonState = 0;
int lastUpButtonState = 0;
Далее пишем функцию void setup. Здесь мы объявляем все контакты, к которым кнопки подключены в качестве входов и установливаем контакт 7 в качестве выхода, так как контакт полсветки ЖК-дисплея подключен к нему. Этот контакт позже будет использоваться для включения/выключения подсветки.
void setup() {
pinMode(2, INPUT_PULLUP);
pinMode(1, INPUT_PULLUP);
pinMode(0, INPUT_PULLUP);
pinMode(7,OUTPUT);
После установки режимов выводов мы инициализируем последовательную связь, инициализируем экран и устанавливаем контраст экрана 50, который служит значением по умолчанию (которое будет изменяться позже с помощью кнопок меню), и используем дисплей.функция display () для применения изменений.
Serial.begin(9600);
display.begin();
display.setContrast(contrast); //Set contrast to 50
display.clearDisplay();
display.display();
Затем мы пишем функцию void loop. Мы запускаем функцию void loop, вызывая функцию drawmenu (), которая содержит код для создания объектов меню на экране.
void loop()
{
drawMenu();
Затем мы читаем кнопки, чтобы проверить, нажата ли какая-либо из них.
downButtonState = digitalRead(2);
selectButtonState = digitalRead(1);
upButtonState = digitalRead(0);
checkIfDownButtonIsPressed();
checkIfUpButtonIsPressed();
checkIfSelectButtonIsPressed();
Затем состояние кнопок подается в серию операторов if-else, которые проверяют, какая кнопка была нажата и какой из экранов в настоящее время отображается, чтобы определить, какое действие будет сделано дальше. Например, первая инструкция if проверяет, находится ли меню на странице 1 и нажата ли кнопка вверх. Если это так, он проверяет положение курсора меню и соответствующим образом настраивает его.
if (up && page == 1 ) {
up = false;
menuitem--;
if (menuitem==0)
{
menuitem=3;
}
}else if (up && page == 2 ) {
up = false;
contrast--;
setContrast();
}
if (down && page == 1) {
down = false;
menuitem++;
if (menuitem==4)
{
menuitem=1;
}
}else if (down && page == 2 ) {
down = false;
contrast++;
setContrast();
}
if (middle) {
middle = false;
if (page == 1 && menuitem==2)
{
if (backlight)
{
backlight = false;
turnBacklightOff();
}
else
{
backlight = true;
turnBacklightOn();
}
}
if(page == 1 && menuitem ==3)
{
resetDefaults();
}
else if (page == 1 && menuitem==1) {
page=2;
}
else if (page == 2) {
page=1;
}
}
}
Оставшаяся часть эскиза-это функции, вызываемые внутри функции цикла.
void drawMenu()
{
if (page==1)
{
display.setTextSize(1);
display.clearDisplay();
display.setTextColor(BLACK, WHITE);
display.setCursor(15, 0);
display.print("MAIN MENU");
display.drawFastHLine(0,10,83,BLACK);
display.setCursor(0, 15);
if (menuitem==1)
{
display.setTextColor(WHITE, BLACK);
}
else
{
display.setTextColor(BLACK, WHITE);
}
display.print(">Contrast");
display.setCursor(0, 25);
if (menuitem==2)
{
display.setTextColor(WHITE, BLACK);
}
else
{
display.setTextColor(BLACK, WHITE);
}
display.print(">Light: ");
if (backlight)
{
display.print("ON");
}
else
{
display.print("OFF");
}
display.display();
if (menuitem==3)
{
display.setTextColor(WHITE, BLACK);
}
else
{
display.setTextColor(BLACK, WHITE);
}
display.setCursor(0, 35);
display.print(">Reset");
display.display();
}
else if (page==2)
{
display.setTextSize(1);
display.clearDisplay();
display.setTextColor(BLACK, WHITE);
display.setCursor(15, 0);
display.print("CONTRAST");
display.drawFastHLine(0,10,83,BLACK);
display.setCursor(5, 15);
display.print("Value");
display.setTextSize(2);
display.setCursor(5, 25);
display.print(contrast);
display.setTextSize(2);
display.display();
}
}
void resetDefaults()
{
contrast = 50;
setContrast();
backlight = true;
turnBacklightOn();
}
void setContrast()
{
display.setContrast(contrast);
display.display();
}
void turnBacklightOn()
{
digitalWrite(7,LOW);
}
void turnBacklightOff()
{
digitalWrite(7,HIGH);
}
Полный код для проекта показан ниже и прилагается для загрузки в конце статьи.
#include <Adafruit_GFX.h>
#include <Adafruit_PCD8544.h>
boolean backlight = true;
int contrast=50;
int menuitem = 1;
int page = 1;
volatile boolean up = false;
volatile boolean down = false;
volatile boolean middle = false;
int downButtonState = 0;
int upButtonState = 0;
int selectButtonState = 0;
int lastDownButtonState = 0;
int lastSelectButtonState = 0;
int lastUpButtonState = 0;
Adafruit_PCD8544 display = Adafruit_PCD8544( 5, 4, 3);
void setup() {
pinMode(2, INPUT_PULLUP);
pinMode(1, INPUT_PULLUP);
pinMode(0, INPUT_PULLUP);
pinMode(7,OUTPUT);
digitalWrite(7,LOW); //Turn Backlight ON
Serial.begin(9600);
display.begin();
display.setContrast(contrast); //Set contrast to 50
display.clearDisplay();
display.display();
}
void loop() {
drawMenu();
downButtonState = digitalRead(2);
selectButtonState = digitalRead(1);
upButtonState = digitalRead(0);
checkIfDownButtonIsPressed();
checkIfUpButtonIsPressed();
checkIfSelectButtonIsPressed();
if (up && page == 1 ) {
up = false;
menuitem--;
if (menuitem==0)
{
menuitem=3;
}
}else if (up && page == 2 ) {
up = false;
contrast--;
setContrast();
}
if (down && page == 1) {
down = false;
menuitem++;
if (menuitem==4)
{
menuitem=1;
}
}else if (down && page == 2 ) {
down = false;
contrast++;
setContrast();
}
if (middle) {
middle = false;
if (page == 1 && menuitem==2)
{
if (backlight)
{
backlight = false;
turnBacklightOff();
}
else
{
backlight = true;
turnBacklightOn();
}
}
if(page == 1 && menuitem ==3)
{
resetDefaults();
}
else if (page == 1 && menuitem==1) {
page=2;
}
else if (page == 2) {
page=1;
}
}
}
void checkIfDownButtonIsPressed()
{
if (downButtonState != lastDownButtonState)
{
if (downButtonState == 0)
{
down=true;
}
delay(50);
}
lastDownButtonState = downButtonState;
}
void checkIfUpButtonIsPressed()
{
if (upButtonState != lastUpButtonState)
{
if (upButtonState == 0) {
up=true;
}
delay(50);
}
lastUpButtonState = upButtonState;
}
void checkIfSelectButtonIsPressed()
{
if (selectButtonState != lastSelectButtonState)
{
if (selectButtonState == 0) {
middle=true;
}
delay(50);
}
lastSelectButtonState = selectButtonState;
}
void drawMenu()
{
if (page==1)
{
display.setTextSize(1);
display.clearDisplay();
display.setTextColor(BLACK, WHITE);
display.setCursor(15, 0);
display.print("MAIN MENU");
display.drawFastHLine(0,10,83,BLACK);
display.setCursor(0, 15);
if (menuitem==1)
{
display.setTextColor(WHITE, BLACK);
}
else
{
display.setTextColor(BLACK, WHITE);
}
display.print(">Contrast");
display.setCursor(0, 25);
if (menuitem==2)
{
display.setTextColor(WHITE, BLACK);
}
else
{
display.setTextColor(BLACK, WHITE);
}
display.print(">Light: ");
if (backlight)
{
display.print("ON");
}
else
{
display.print("OFF");
}
display.display();
if (menuitem==3)
{
display.setTextColor(WHITE, BLACK);
}
else
{
display.setTextColor(BLACK, WHITE);
}
display.setCursor(0, 35);
display.print(">Reset");
display.display();
}
else if (page==2)
{
display.setTextSize(1);
display.clearDisplay();
display.setTextColor(BLACK, WHITE);
display.setCursor(15, 0);
display.print("CONTRAST");
display.drawFastHLine(0,10,83,BLACK);
display.setCursor(5, 15);
display.print("Value");
display.setTextSize(2);
display.setCursor(5, 25);
display.print(contrast);
display.setTextSize(2);
display.display();
}
}
void resetDefaults()
{
contrast = 50;
setContrast();
backlight = true;
turnBacklightOn();
}
void setContrast()
{
display.setContrast(contrast);
display.display();
}
void turnBacklightOn()
{
digitalWrite(7,LOW);
}
void turnBacklightOff()
{
digitalWrite(7,HIGH);
}