В первом материале, рассказывающем об обучающем наборе «Цифровая лаборатория» из серии Азбука Электронщика, мы в общих чертах описали принципы построения, состав набора и плату расширения.
Рассмотрим теперь входящее в состав набора обучающее пособие, и разберем два несложных опыта с применением платы расширения, которые помогут понять, как подсоединяются внешние устройства и как можно использовать встроенные кнопки.
Как мы уже говорили, на плате размещены группы разъемов для подключения различных внешних модулей: датчиков, исполнительных устройств и устройств, использующих некоторые стандартные шины обмена информацией.
В качестве исполнительного устройства на плате предусмотрено место для установки жидкокристаллического символьного двухстрочного LCD-индикатора с подсветкой. На таком индикаторе можно отобразить достаточно информации как в обучающих целях, так и при применении набора в качестве законченного устройства. В обучающем пособии рассказывается, как выводить символьную информацию на дисплей, как заставить дисплей отображать русские и английские буквы одновременно. Индикатор используется практически во всех описанных в брошюре проектах.
Рассмотрим самое простейшее исполнительное устройство – светодиод. В набор входит трехцветный (RGB – Red, Green, Blue) яркий светодиод. Из трех цветов такого светодиода с помощью изменения интенсивности каждого из них, в силу особенностей человеческого глаза можно получить любой цвет. Такой метод получения цвета называется аддитивным смешением цветов и используется, например, в телевизорах и мониторах. Смешав три цвета в равных пропорциях, мы получим белый цвет.
Подключим светодиод к разъему XP15 платы расширения, который дополнительно промаркирован «RGB_LED» с помощью четырех проводов или переходника. Мы применяем светодиод с общим катодом (общим «минусом»), поэтому самый длинный вывод светодиода подсоединяется к контакту GND («Ground»), а остальные выводы светодиода соединяем с контактами RED/D5 (красный), BLUE/D6 (синий), GREEN/D9 (зеленый).
D5, D6 и D9 – это цифровые выводы Ардуино, на которых можно получить широтно-импульсную модуляцию (ШИМ) для управления яркостью светодиода. В обучающем пособии приведен необходимый минимум теории ШИМ и способ реализации этой модуляции в Ардуино.
Приведем код программы (скетча), управляющей яркостью свечения RGB-светодиода:
// Управляем цветом RGB светодиода
//-----------------------------------------------------------------------
//называем выводы соответственно цвету
int redPin = 5;
int greenPin = 9;
int bluePin = 6;
//-----------------------------------------------------------------------
/* Эта функция будет выполнена 1 раз в момент запуска программы Arduino
в нашем случае она пустая*/
void setup()
{
}
//-----------------------------------------------------------------------
/* Эта функция будет выполнена после функции setup и будет бесконечное число раз повторятся после своего окончания.*/
void loop() {
/* Цикл будет повторятся 256 раз. Каждое повторение переменная value будет увеличивать свое значение на 1.*/
for(int value = 0 ; value <= 255; value ++) {
//яркость красного уменьшается от максимума к 0
analogWrite(redPin, 255-value);
//яркость зеленого увеличивается
analogWrite(greenPin, value);
//синий не горит
analogWrite(bluePin, 0);
// Выдержим паузу в 30 миллисекунд
delay(30);
}
/* Цикл будет повторятся 256 раз. Каждое повторение переменная value будет увеличивать свое значение на 1.*/
for(int value = 0 ; value <= 255; value ++) {
//красный не горит
analogWrite(redPin, 0);
//яркость зеленого уменьшается от максимума к 0
analogWrite(greenPin, 255-value);
//яркость синего увеличивается
analogWrite(bluePin, value);
// Выдержим паузу в 30 миллисекунд
delay(30);
}
/* Цикл будет повторятся 256 раз. Каждое повторение переменная value будет увеличивать свое значение на 1.*/
for(int value = 0 ; value <= 255; value ++) {
//яркость красного увеличивается
analogWrite(redPin, value);
//зеленый не горит
analogWrite(greenPin, 0);
//яркость синего уменьшается от максимума к 0
analogWrite(bluePin, 255-value);
// Выдержим паузу в 30 миллисекунд
delay(30);
}
// Функция loop начнет выполняться сначала
}
При выполнении программы светодиод плавно меняет излучаемый цвет с красного на зеленый, потом с зеленого на синий, и далее с синего на красный.
Дополним нашу программу таким образом, чтобы на LCD-индикаторе отображались значения, в каждый момент времени соответствующие яркости каждого цвета от минимума (0) до максимума (255). Модифицированный код:
// Управляем цветом RGB светодиода
//-----------------------------------------------------------------------
//называем выводы соответственно цвету
int redPin = 5;
int greenPin = 9;
int bluePin = 6;
//задаем переменные для значений ШИМ
int pwmRed;
int pwmGreen;
int pwmBlue;
//-----------------------------------------------------------------------
// Подключаем библиотеку LiquidCrystalRus
#include <LiquidCrystalRus.h>
// Подключаем библиотеки, которые использует LiquidCrystalRus
#include <LiquidCrystalExt.h>
#include <LineDriver.h>
//-----------------------------------------------------------------------
/* Инициализируем дисплей, объясняя программе куда подключены линии RS,EN,DB4,DB5,DB6,DB7 */
LiquidCrystalRus lcd(A1, A2, A3, 2, 4, 7);
// Эта функция будет выполнена 1 раз в момент запуска программы Arduino
void setup()
{
// Инициализируем LCD - 16 символов, 2 строки
lcd.begin(16, 2);
// Курсор находится на первой строке (верхней) и первом слева символе
lcd.print(" RED GREEN BLUE");
}
//-----------------------------------------------------------------------
// Эта функция будет выполнена после функции setup и будет бесконечное число раз повторятся после своего окончания.
void loop() {
/* Цикл будет повторятся 256 раз. Каждое повторение переменная value будет увеличивать свое значение на 1.*/
for(int value = 0 ; value <= 255; value ++) {
pwmGreen = value;
pwmRed = 255 - value;
//яркость красного уменьшается от максимума к 0
analogWrite(redPin, pwmRed);
//яркость зеленого увеличивается
analogWrite(greenPin, pwmGreen);
//синий не горит
analogWrite(bluePin, 0);
// Выдержим паузу в 30 миллисекунд
delay(30);
Display();
}
/* Цикл будет повторятся 256 раз. Каждое повторение переменная value будет увеличивать свое значение на 1.*/
for(int value = 0 ; value <= 255; value ++) {
pwmBlue = value;
pwmGreen = 255 - value;
//красный не горит
analogWrite(redPin, 0);
//яркость зеленого уменьшается от максимума к 0
analogWrite(greenPin, pwmGreen);
//яркость синего увеличивается
analogWrite(bluePin, pwmBlue);
// Выдержим паузу в 30 миллисекунд
delay(30);
Display();
}
/* Цикл будет повторятся 256 раз. Каждое повторение переменная value будет увеличивать свое значение на 1.*/
for(int value = 0 ; value <= 255; value ++) {
pwmRed = value;
pwmBlue = 255 - value;
//яркость красного увеличивается
analogWrite(redPin, pwmRed);
//зеленый не горит
analogWrite(greenPin, 0);
//яркость синего уменьшается от максимума к 0
analogWrite(bluePin, pwmBlue);
// Выдержим паузу в 30 миллисекунд
delay(30);
Display();
}
// Функция loop начнет выполняться сначала
}
// функция выводит на индикатор значения переменных, задающих ШИМ
void Display(){
lcd.setCursor(0,1);
lcd.print(" ");
lcd.setCursor(1,1);
lcd.print(pwmRed);
lcd.setCursor(6,1);
lcd.print(pwmGreen);
lcd.setCursor(11,1);
lcd.print(pwmBlue);
}
Теперь рассмотрим пример использования встроенных в плату кнопок.
В общем случае каждая кнопка подключается к отдельному цифровому выводу Ардуино и программа последовательно опрашивает эти выводы для того, чтобы определить, какая кнопка нажата. Для экономии выводов Ардуино, которые необходимо задействовать для определения нажатия кнопки в плате расширения набора «Цифровая лаборатория» используется «аналоговая» клавиатура, подключенная всего к одному аналоговому входу Ардуино. Такой способ часто используются в бытовой технике. Программа измеряет выходное напряжение на выходе делителя напряжения, которое зависит от того, какая кнопка нажата. В обучающем пособии рассмотрена теория такого делителя и способ его применения в клавиатуре. Недостатком такого способа является то, что кнопки можно нажимать только по одной, последовательно.
Загрузим в Ардуино соответствующую программу:
// Подключаем аналоговую клавиатуру и на дисплее выводи номер нажатой кнопки
//-----------------------------------------------------------------------
// Обязательно подключаем стандартную библиотеку LiquidCrystal
#include <LiquidCrystal.h>
// Определяем сколько кнопок у нас подключено
#define NUM_KEYS 5
// Для каждой кнопки заносим калибровочные значения(выведены экспериментально)
int adcKeyVal[NUM_KEYS] = {30, 150, 360, 535, 760};
//-----------------------------------------------------------------------
// Инициализируем дисплей, объясняя программе куда подключены линии RS,EN,DB4,DB5,DB6,DB7
LiquidCrystal lcd(A1, A2, A3, 2, 4, 7);
//-----------------------------------------------------------------------
// Эта функция будет выполнена 1 раз в момент запуска программы Arduino
void setup()
{
// Инициализируем LCD как обычно -16 символов и 2 строки
lcd.begin(16, 2);
// Курсор находится на первой строке (верхней) и первом слева символе
// И напишем на дисплее Keyboard
lcd.print("Keyboard");
// Выдержим паузу в 2000 миллисекунд= 2 секунды
delay(2000);
}
//-----------------------------------------------------------------------
// Эта функция будет выполнена после функции setup и будет бесконечное число раз повторятся после своего окончания.
void loop() {
// Заводим переменную с именем key
int key;
// Записываем в эту переменную номер нажатой кнопки, вызывая на исполнение нижеописанную функцию get_key
key = get_key();
// Очищаем дисплей от всех надписей
lcd.clear();
// Курсор находится на первой строке (верхней) и первом слева символе
// И напишем какую кнопку нажали. О- ни одна кнопка не нажата
lcd.print(key);
// Выдержим паузу в 100 миллисекунд= 0,1 секунду
delay(100);
// Функция loop начнет выполняться сначала
}
//-----------------------------------------------------------------------
// Эта функция будет выполнена только когда ее вызвали из программы
// Функция читает значение с АЦП, куда подключена аналоговая клавиатура
// и сравнивает с калибровочными значениями, определяя номер нажатой кнопки
int get_key()
{
int input = analogRead(A6);
int k;
for(k = 0; k < NUM_KEYS; k++)
if(input < adcKeyVal[k])
return k + 1;
return 0;
}
Для отображения информации о том, какая кнопка нажата, используется LCD-индикатор. Если нажимать кнопки, то на индикаторе будет отображаться номер нажатой кнопки.
Функция get_key возвращает целое число, соответствующее номеру нажатой кнопки, которое может быть использовано в основной программе. Калибровочные значения, с которыми сравнивается напряжение с выхода делителя, определены экспериментальным путем с помощью вот такой программки:
#include <LiquidCrystal.h>
LiquidCrystal lcd(A1, A2, A3, 2, 4, 7);
void setup()
{
lcd.begin(16, 2);
lcd.print("Press keys");
delay(2000);
}
void loop() {
int input = analogRead(A6);
lcd.clear();
lcd.print(input);
delay(100);
}
Попробуйте загрузить ее в Ардуино и посмотреть, какие значения отображаются, и сравнить их с калибровочными.
Попробуем теперь использовать рассмотренные примеры для создания программы, которая реализует управление светодиодом с помощью кнопок. Зададим следующий функционал:
· при нажатии на кнопку 1 (крайнюю слева) загорается красный свет, на кнопку 2– зеленый, 3 – синий. При повторном нажатии на кнопку соответствующий свет гаснет. На индикаторе отображается, какие цвета включены.
· при нажатии на кнопку 4 включенные и выключенные цвета меняются местами
· при нажатии на кнопку 5 все цвета гаснут.
Вот один из возможных вариантов такого скетча:
// Используем аналоговую клавиатуру вместе с RGB-светодиодом
//-----------------------------------------------------------------------
// Обязательно подключаем стандартную библиотеку LiquidCrystal
#include <LiquidCrystal.h>
// Определяем сколько кнопок у нас подключено
#define NUM_KEYS 5
// Для каждой кнопки заносим калибровочные значения(выведены экспериментально)
int adcKeyVal[NUM_KEYS] = {30, 150, 360, 535, 760};
#define redLED 5
#define greenLED 9
#define blueLED 6
//-----------------------------------------------------------------------
// Инициализируем дисплей, объясняя программе куда подключены линии RS,EN,DB4,DB5,DB6,DB7
LiquidCrystal lcd(A1, A2, A3, 2, 4, 7);
int redLEDstate = 0;
int greenLEDstate = 0;
int blueLEDstate = 0;
int flag = 0;
//-----------------------------------------------------------------------
// Эта функция будет выполнена 1 раз в момент запуска программы Arduino
void setup()
{
pinMode(redLED, OUTPUT);
pinMode(greenLED, OUTPUT);
pinMode(blueLED, OUTPUT);
// Инициализируем LCD как обычно -16 символов и 2 строки
lcd.begin(16, 2);
// Курсор находится на первой строке (верхней) и первом слева символе
// И напишем на дисплее текст
lcd.print("Try Keys + LEDs");
// Выдержим паузу в 1000 миллисекунд= 1 секунда
delay(1000);
// и очистим экран индикатора
lcd.clear();
}
//-----------------------------------------------------------------------
// Эта функция будет выполнена после функции setup и будет бесконечное число раз повторятся после своего окончания.
void loop() {
// Заводим переменную с именем key
int key;
// Записываем в эту переменную номер нажатой кнопки, вызывая на исполнение нижеописанную функцию get_key
key = get_key();
// Если нажата кнопка, меняем состояние соответствующего цвета на противоположное
// C помощью переменной flag не допускаем изменения состояния цвета, если кнопка нажата и не отпущена
if(key == 1 && flag == 0) {
digitalWrite(redLED, !digitalRead(redLED));
flag = 1;
}
if(key == 2 && flag == 0) { // можно написать короче: if(key == 2 && !flag)
digitalWrite(greenLED, !digitalRead(greenLED));
flag = 1;
}
if(key == 3 && !flag) {
digitalWrite(blueLED, !digitalRead(blueLED));
flag = 1;
}
if(key == 4 && !flag) {
digitalWrite(redLED, !digitalRead(redLED));
digitalWrite(greenLED, !digitalRead(greenLED));
digitalWrite(blueLED, !digitalRead(blueLED));
flag = 1;
}
if(key == 5 && !flag){
digitalWrite(redLED, LOW);
digitalWrite(greenLED, LOW);
digitalWrite(blueLED, LOW);
flag = 1;
}
// если кнопка была нажата и отпущена, разрешаем изменение состояния цвета
if(!key && flag) // соответствует if(key == 0 && flag == 1)
{
flag = 0;
}
// проверяем состояние каналов светодиода и выводим на индикатор, какой цвет включен
if (digitalRead(redLED)) { // соответсвует if (digitalRead(redLED) == 1)
lcd.setCursor(0,0);
lcd.print("Red");
}
else {
lcd.setCursor(0,0);
lcd.print(" ");
}
if (digitalRead(greenLED)) {
lcd.setCursor(5,0);
lcd.print("Green");
}
else {
lcd.setCursor(5,0);
lcd.print(" ");
}
if (digitalRead(blueLED)) {
lcd.setCursor(11,0);
lcd.print("Blue");
}
else {
lcd.setCursor(11,0);
lcd.print(" ");
}
// Функция loop начнет выполняться сначала
}
//-----------------------------------------------------------------------
// Эта функция будет выполнена только когда ее вызвали из программы
// Функция читает значение с АЦП, куда подключена аналоговая клавиатура
// и сравнивает с калибровочными значениями, определяя номер нажатой кнопки
int get_key()
{
int input = analogRead(A6);
int k;
for(k = 0; k < NUM_KEYS; k++)
if(input < adcKeyVal[k])
return k + 1;
return 0;
}
В заключение приведем небольшой видеоролик, демонстрирующий описанные опыты:
">https://www.youtube.com/watch?v=O49JK0gQkAE" frameborder="0" allowfullscreen="">
Как видим, возможности платы расширения набора «Цифровая лаборатория» позволяют удобно, наглядно и быстро осваивать практику работы с Ардуино и подсоединяемыми дополнительными модулями.
В следующей статье мы рассмотрим взаимодействие Ардуино с Андроид-смартфоном по технологии Bluetooth с использованием платы расширения. Программировать смартфон будем с помощью проекта MIT App Inventor, который разработан и поддерживается Массачусетским Технологическим Интститутом.