Симуляция светофора, или первые шаги в использовании GPIO
-
Собираем на макетной плате и реализуем на "Си" симулятор светофора с кнопкой - простой пример для начала изучения работы с GPIO.
Вместо вступления
В этой записи я хочу рассказать об одном из первых моих проектов, который объясняет основы работы с GPIO выводами Raspberry Pi. Этот проект не является простейшей мигалкой, которую писал, наверное, каждый обладатель Малины, и также не является супер-сложным проектом, который новичку просто не потянуть.Сразу оговорюсь, что идея проекта принадлежит не мне, а одному английскому разработчику - Гордону Хендерсону, который, кстати, написал и библиотеку для Си, которая была использована в проекте. Запись, в принципе, является описанием проекта с моей стороны. Писалась она для новичков, с целью показать основы программирования для работы с GPIO. Теперь, когда все дисклеймеры написаны, приступим к делу.
Идея
Идея заключается в сборке макета (симуляции) светофора с кнопкой, а точнее даже двух светофоров - автомобильного и пешеходного, которые связаны той самой кнопкой. Суть таких светофоров в том, что зеленый свет для пешеходов включается по требованию (читай - по нажатию кнопки). Такой тип светофоров очень распространен в США, где пешеходов в небольших городах довольно мало. Принцип работы таков: Во время простоя автомобилям все время горит зеленый, а пешеходам - красный. По нажатию на кнопку автомобильный светофор останавливает движение, после чего пешеходный светофор зажигает зеленый свет, тем самым разрешая пешеходам перейти улицу. Через некоторое время (не будем его уточнять, это не столь важно) светофоры снова возвращаются в исходное положение: зеленый для машин и красный для пешеходов.
Реализация
Реализацию этого проекта, как и любого другого с использованием GPIO, можно разделить на два этапа: сборка электрической схемы и написание программы, которая будет управлять элементами этой схемы.
Сборка схемы
Для сборки схемы данного проекта нам понадобится:
-
Пластиковая макетная плата. Подойдет любая, я использовал похожую на эту .
-
Светодиоды. Нужно пять штук, два зеленых, два красных и один желтый. Подойдут и любые другие, но для наглядности проекта лучше подобрать именно такие цвета. .
-
Резисторы. Я использовал резисторы в 330 Ом, но можно использовать и большего номинала. Однако не советую использовать номинал выше 1,5 кОм. Резисторов нужно шесть - пять для светодиодов, и один для кнопки.
-
Кнопка. Тут уточнять нечего, кроме того, что она должна быть замыкающей, а не размыкающей.
Также вам понадобится что-то, чтобы соединять нашу макетную плату и выводы GPIO на Малине. Тут уже выбор за вами, скажу лишь что я для этих целей использовал обрезанный IDE шлейф, второй конец которого распаял на 26 DLS-штырьков, который вставляются прямиком в макетку. Как это примерно будет выглядеть в собранном виде и визуальная схема сборки приведена ниже. Советую пользоваться именно графической схемой для сборки.
Обратите внимание на полярность светодиодов. На схеме оранжевым цветом обозначен "+" светодиода (длинная ножка). Многие, должно быть, заметили, что нумерация пинов GPIO выглядит не совсем стандартной. Об этом позднее, а пока, если со сборкой закончили, приступим к следующему шагу.
Пишем программу.
Писать будем на "Си", с использованием библиотеки wiringPi, автором которой является все тот же Гордон Хендерсон. Эта библиотека имеет упрощенный синтаксис и очень схожа с библиотекой для написание скетчей для Arduino. Мне, как новичку, было намного приятнее и удобнее работать с ней, чем со стандартной библиотекой, синтаксис которой читается и воспринимается сложнее. Для начала установим библиотеку. Это сделаем в два шага, выполнять которые нужно в консоли RaspberryPi. Если у Вас уже установлен пакет GIT-core, то первый шаг можно смело пропускать.
Шаг 1: Устанавливаем GIT:
sudo apt-get install git-core sudo apt-get update sudo apt-get upgrade
Шаг 2: Скачиваем и компилируем wiringPi:
git clone git://git.drogon.net/wiringPi cd wiringPi git pull origin ./build
После выполнения этих действий библиотека будет установлена и готова к использованию.Для удобства пользования автор изменил нумерацию пинов GPIO. Распиновку для этой библиотеки вы уже видели выше, на всякий случай ознакомьтесь с "чистой" картинкой распиновки:
Теперь создадим в удобном для вас месте файл walk.c:
touch walk.c
Откроем его:
nano walk.c
И заполним следующим кодом. Этот код и есть кодом для нашей программы, то как он работает я попытался максимально объяснить в комментариях:
//**********Подключаем необходимые библиотеки************ #include "wiringPi.h" //Библиотека для работы с GPIO #include "stdio.h" #include "stdlib.h" //**********Назначаем буквенные метки номерам пинов****** #define RED 0 //Красный автомобильный #define YEL 1 //Желтый автомобильный #define GRE 2 //Зеленый автомобильный #define P_RED 3 //Красный пешеходный #define P_GRE 4 //Зеленый пешеходный #define BUT 8 //Кнопка //------------------------------------------------------- void init() { if (wiringPiSetup () == -1) //Инициализация wiringPi exit (1); //**********Устанавливаем пины светодиодов в режим вывода pinMode (RED, OUTPUT); pinMode (YEL, OUTPUT); pinMode (GRE, OUTPUT); pinMode (P_RED, OUTPUT); pinMode (P_GRE, OUTPUT); //------------------------------------------------------- pinMode (BUT, INPUT); // Пин кнопки ставим в режим ВВОДА //**********Устанавливаем изначальную комбинацию ******** // Функция записи значения имеет следующий синтаксис: // digitalWrite(номер_пина, состояние) //Состояния: LOW - светодиод не горит, HIGH - светодиод горит digitalWrite(RED, LOW); digitalWrite(YEL, LOW); digitalWrite(GRE, HIGH); digitalWrite(P_RED, HIGH); digitalWrite(P_GRE, LOW); //------------------------------------------------------- printf("Okay..\n"); //Выводим в консоль как знак завершения инициализации } //********Функция ожидания нажатия кнопки**************** void button_wait() { printf("Ожидание нажатия...\n"); //Пока состояние кнопки = HIGH (логическая единица) - ждем одну милисекунду while(digitalRead(BUT)==HIGH) { delay(1); } //Как только состояние изменится цикл прервется и в консоль будет выведена надпись printf("Нажато!\n"); } //------------------------------------------------------- //********Функция остановки трафика********************** void stop_traff() { int i; printf("Останавливаем движение...\n"); // Трижды мигаем зеленым светом для автомобилей for(i=0; i<3; i++){ digitalWrite(GRE, LOW); delay(500); digitalWrite(GRE, HIGH); delay(500); } // Выключаем зеленый для автомобилей, включаем желтый digitalWrite(GRE, LOW); digitalWrite(YEL, HIGH); //Ожидаем три секунды, выключаем желтый и включаем красный для автомобилей delay(3000); digitalWrite(YEL, LOW); digitalWrite(RED, HIGH); } //------------------------------------------------------- //********Функция запуска пешеходов********************** void p_start() { //Выключаем пешеходный красный, затем включаем зеленый. Выводим в консоль надпись. digitalWrite(P_RED, LOW); digitalWrite(P_GRE, HIGH); printf("Можно идти!\n"); } //------------------------------------------------------- //********Функция восстановления режимов***************** // Запускается по истечению времени движения пешеходов. void change_time() { printf("Окончание перехода..!\n"); int i; // Выключаем красный для автомобилей и зеленый для пешеходов digitalWrite(RED, LOW); digitalWrite(P_GRE, LOW); //Трижды мигаем одновременно зеленым для пешеходов и желтым for(i=0; i<3; i++){ digitalWrite(P_GRE, HIGH); digitalWrite(YEL, HIGH); delay(500); digitalWrite(P_GRE, LOW); digitalWrite(YEL, LOW); delay(500); } } //------------------------------------------------------- //********Функция запуска автомобилей******************** void start_traff() { printf("Движение автомобилей восстановлено.\n\n"); //Включаем зеленый для автомобилей и красный для пешеходов digitalWrite(GRE, HIGH); digitalWrite(P_RED, HIGH); } //------------------------------------------------------- //*****Главная функция, в которой будут вызваны остальные int main() { printf("__________________Симулятор светофора_________________\n"); init(); for( ; ; ){ //Повторяем бесконечное число раз button_wait(); // Ожидаем нажатие кнопки, код снизу будет выполнен только после нажатия stop_traff(); // Останавливаем автомобили delay(1000); // Ждем секунду, прежде чем запустить пешеходов p_start(); // Запускаем пешеходов delay(5000); //Время для движения пешеходов - 5 секунд change_time(); // Режим восстановления движения start_traff(); // Движение восстановлено } // Чтобы завершить программу нужно нажать Ctrl+C return(0); }
Теперь сохраним наш файл комбинациейCtrl+O и закроем его комбинацией Ctrl+X (комбинации актуальны при использовании текстового редактора nano). Для запуска нашей программы нам нужно её скомпилировать. Делается это следующей командой в консоли:
gcc -Wall -o walk walk.c -lwiringPi
Теперь запускаем:
sudo ./walk
Если вы все сделали правильно - загорится зеленый светодиод на "светофоре" для автомобилей и красный на "светофоре" для пешеходов.По нажатию на кнопку выполнится программа. То, как эта программа работает можно посмотреть на видео - http://youtu.be/R_jUUYhD0BU Если что-то работает неправильно - значит на каком-то из этапов вы допустили ошибку. Проверьте все очень внимательно и попробуйте еще раз.
Заключение.
Собрав и запустив этот проект Вы получили базовые знания в работе с GPIO выводами. Если что-то из проделанного вам показалось сложным или не понятным - пишите об этом в комментарии, с радостью помогу вам разобраться. Надеюсь этот проект не будет вашим последнем, и в следующий раз вы уже соберете что-то свое. Если эта запись будет кому-то полезна, то в будущем я могу написать еще несколько инструкций для новичков. Хорошего дня и удачи в ваших начинаниях
-