Файл: С чего начинаются роботы. О проекте Arduino для школьников (В.Н. Гололобов, 2011).pdf
ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 16.06.2025
Просмотров: 1230
Скачиваний: 3
Глава 9. Паровозик из Ромашково, продолжение
Рис. 9.26. Работа программы осциллографа в openSUSE
Напомню, что фотоприёмник TSOP в отсутствии несущей частоты на выходе поддерживает высокий уровень, а при наличии несущей переходит в состояние низкого логического уровня.
Осциллограмма похожа на то, что я ожидал бы, если бы не два момента: я не вижу первой пачки импульсов; времена вдвое меньше ожидаемых.
Я могу предположить, что осциллограф запускается несколько позже, чем при приходе первой пачки импульсов. Так ли это? Ответ я могу получить, изменив программу излучения так, чтобы интервалы между кодами были меньше, не 1 секунда, а, скажем, 10 миллисекунд. Посмотрим, как выглядит такой вариант.
Рис. 9.27. Проверка приёма пачек импульсов сигнала фотоприёмником
Теперь все пачки импульсов на месте, а времена… я не калибровал осциллограф Xoscill. Можно, конечно, это сделать сейчас, но можно отложить до того времени, когда возникнут проблемы с работой приёмного устройства. Если они возникнут.
105
Глава 10. С чего начинаются роботы?
Глава 10. С чего начинаются роботы?
Пришло время написать программу для семафора, который будет работать под управлением модуля Arduino.
Как должна работать программа? В самом общем виде: если семафор «видит» ИК-код, он включает зелёный свет, который выключает через несколько секунд, включая красный.
Видеть ИК-код семафор будет с помощью фотоприёмника TSOP. Но не просто видеть какойлибо инфракрасный сигнал, а «прочитывать» придуманный нами код. Если код совпадает, то семафор переключается.
У осциллографа мы подключали фотоприёмник к аналоговому входу. Но на выходе фотоприёмника сигнал, который удобно читать цифровым входом. Как вы помните, а если забыли, то посмотрите программу ещё раз, похожую работу выполняет программа для модуля Arduino, которая называется «Button, кнопка». Мы вполне можем себе представить работу фотоприёмника, как работу кнопки, которую нажимают на определённые промежутки времени. Поэтому, взяв программу за основу, мы модифицируем её. Вот эта программа на языке Arduino.
// |
set pin numbers: |
||||||||
const |
int |
buttonPin |
= 2; |
// номер |
вывода |
подключѐнной кнопки |
|||
const |
int |
ledPin = |
13; |
// |
номер |
вывода |
светодиода |
||
// |
variables will |
change: |
|||||||
int buttonState = |
0; |
// |
переменная для чтения состояния кнопки |
||||||
void setup() {
//инициализация вывода светодиода, как выхода pinMode(ledPin, OUTPUT);
//инициализация вывода кнопки, как входа pinMode(buttonPin, INPUT);
}
void loop(){
//читаем состояние кнопки, как значение buttonState = digitalRead(buttonPin);
//проверяем, нажата ли кнопка
//если да, то buttonState имеет значение HIGH: if (buttonState == HIGH) {
//включаем LED
digitalWrite(ledPin, HIGH);
}
else {
// выключаем LED digitalWrite(ledPin, LOW);
}
}
В первую очередь изменим задание выводов.
// установка выводов
const int photoPin = 2; // номер вывода, к которому подключѐн фотоприѐмник const int ledPinGreen = 13; // номер вывода зелѐного светодиода
const int ledPinRed = 12; // номер вывода красного светодиода
Зададим переменную для приёма состояния цифрового входа D2.
106
Глава 10. С чего начинаются роботы?
// переменная для хранения состояния входа
int photoState = HIGH; |
// переменная для чтения состояния |
фотоприѐмника |
В разделе инициализации запишем:
void setup() {
//инициализируем выходы для светодиодов pinMode(ledPinGreen, OUTPUT); pinMode(ledPinRed, OUTPUT);
//инициализируем вход для фотоприѐмника pinMode(photoPin, INPUT);
}
Основная программа будет похожа на оригинал — мы постоянно читаем вход, когда он переходит в состояние с низким логическим уровнем, мы будем читать код.
void loop(){
// включаем красный свет digitalWrite(ledPinRed, HIGH);
//читаем состояние входа photoState = digitalRead(photoPin);
//проверяем есть ли пачка импульсов
//если есть, то photoState становится LOW if (photoState == LOW) {
//начинаем читать код и переключать светодиоды, если код «свой»
}
Теперь, как мы будем читать код? Мы получили переход на цифровом входе в низкое состояние, а с правильным кодом это состояние продлится 4 мС. Затем последует пауза (нет несущей частоты), когда вход перейдёт в высокое состояние. Пауза длится 1 мС. Для проверки нашего кода достаточно сделать паузу в 4.5 мС и проверить, перешёл ли вход в высокое состояние?
Затем будем проверять состояние, стараясь попадать в «середину» состояний после переходов (нашего кода), если это не так, то возвращаемся в начало программы.
if (photoState == LOW) {
// начинаем читать код и переключать светодиоды, если код «свой»
delayMicroseconds(4500); |
// ждѐм 4.5 мС |
|||
photoState = digitalRead(photoPin); |
||||
if (photoState == HIGH){ |
||||
delay(1); |
// ждѐм 1 мС |
|||
photoState = digitalRead(photoPin); |
||||
if (photoState == LOW){ |
||||
delay(1); |
// ждѐм 1 мС |
|||
photoState = digitalRead(photoPin); |
||||
if (photoState == HIGH){ |
||||
delay(1); |
// ждѐм 1 мС |
|||
photoState = digitalRead(photoPin); |
||||
if (photoState == LOW){ |
||||
delayMicroseconds(3500); |
// ждѐм 3.5 мС |
|||
if (photoState == HIGH){ |
||||
digitalWrite(ledPinRed, LOW); // выключаем красный digitalWrite(ledPinGreen, HIGH);//включаем зелѐный delay(2000); // зелѐный 2 секунды digitalWrite(ledPinGreen, LOW);//выключаем зелѐный
}
}
}
}
}
}// иначе ничего не делаем
107
Глава 10. С чего начинаются роботы?
И теперь соберём всю программу вместе (в тексте программы есть ошибка, о которой мы поговорим позже!).
// установка выводов
const int |
photoPin = 2; |
// номер вывода, к которому подключѐн фотоприѐмник |
||
const |
int |
ledPinGreen = |
13; |
// номер вывода зелѐного светодиода |
const |
int ledPinRed = |
12; |
// номер вывода красного светодиода |
|
int photoState = HIGH; |
// переменная для чтения состояния фотоприѐмника |
|||
void setup() {
//инициализируем выходы для светодиодов pinMode(ledPinGreen, OUTPUT); pinMode(ledPinRed, OUTPUT);
//инициализируем вход для фотоприѐмника pinMode(photoPin, INPUT);
}
void loop(){
//включаем красный свет digitalWrite(ledPinRed, HIGH);
//читаем состояние входа photoState = digitalRead(photoPin);
//проверяем есть ли пачка импульсов
//если есть, то photoState становится LOW if (photoState == LOW) {
//начинаем читать код и переключать светодиоды, если код «свой» delayMicroseconds(4500); // ждѐм 4.5 мС
photoState = digitalRead(photoPin); if (photoState == HIGH){
delay(1); |
// ждѐм 1 |
мС |
|
photoState = digitalRead(photoPin); |
|||
if (photoState == LOW){ |
|||
delay(1); |
// ждѐм 1 мС |
||
photoState = digitalRead(photoPin); |
|||
if (photoState == HIGH){ |
|||
delay(1); |
// ждѐм 1 мС |
||
photoState = digitalRead(photoPin); if (photoState == LOW){
delayMicroseconds(3500); // ждѐм 3.5 мС if (photoState == HIGH){
digitalWrite(ledPinRed, LOW); // выключаем красный digitalWrite(ledPinGreen, HIGH);//включаем зелѐный delay(2000); // зелѐный 2 секунды digitalWrite(ledPinGreen, LOW);//выключаем зелѐный
}
}
}
}
}
}// иначе ничего не делаем
}
Думаю, проверить её на макетной плате будет сложнее, чем за компьютером. Поэтому до загрузки программы в модуль Arduino попробуем проверить всё в программе VirtualBreadboard.
Генератора, способного формировать нужный сигнал, который имитировал бы работу фотоприёмника, я не надеюсь найти, но хочу использовать в качестве такого генератора обычную кнопку. А для отладочных операций, кроме светодиодов семафора, я добавлю (и в программу, и на макетную плату) ещё один светодиод. В результате макет выглядит следующим образом.
108
Глава 10. С чего начинаются роботы?
Рис. 10.1. Подготовка к проверке программы в VBB
В программу добавлена строка в определение переменных и констант:
const int ledPinDebug = 11; // отладочный LED
И в начале основного цикла:
digitalWrite(ledPinDebug, LOW);
Для кнопки (в её свойствах после выделения на макете), щёлкнув по клавише рядом «Contact Type», я выбираю режим, при котором нажатая кнопка даёт низкий логический уровень.
Рис. 10.2. Окно свойств виртуальной кнопки
А в качестве первого шага проверки я добавляю в программу, проверяя вход расшифровки ИКкода, несколько строк:
if (photoState == LOW) {
delayMicroseconds(4500);
digitalWrite(ledPinDebug, HIGH); // first test
Запустив программу, щёлкаю несколько раз кнопкой, чтобы убедиться, что при низком логическом уровне на цифровом входе я попадаю в блок программы расшифровки кода.
109
Глава 10. С чего начинаются роботы?
Рис. 10.3. Первая проверка программы
Удалив строку проверки (закомментировав её), я переношу её в следующую проверку состояния цифрового входа: я не успею щёлкнуть кнопкой, а, значит, отладочный светодиод не должен загораться. Запустив программу, щёлкая кнопкой несколько раз, я убеждаюсь, что это так. К сожалению, такие отладочные средства, как точка останова и пошаговое прохождение программы, у меня не работают. Но можно проявить выдумку?!
Я добавляю ещё один светодиод на следующий выход. И добавляю паузы по 3 секунды после каждого тестового включения светодиода отладки (или светодиодов). После этой хитрости я успеваю щёлкать кнопкой после каждого изменения состояния отладочных светодиодов и могу проверить расшифровку кода (конечно, только логику работы программы) до самого конца.
Рис. 10.4. Модификация эксперимента Отладочная программа выглядит так:
class Class0 extends com.muvium.compatibility.arduino.Arduino{//Automatically Added VBB Framework Code - do not remove
const int photoPin = 2; const int ledPinGreen = 13; const int ledPinRed = 12;
const int ledPinDebug1 = 11; // debuging LED 1 const int ledPinDebug2 = 10; // debuging LED 2
110
Глава 10. С чего начинаются роботы?
int photoState = HIGH;
void setup() {
pinMode(ledPinGreen, OUTPUT); pinMode(ledPinRed, OUTPUT); pinMode(ledPinDebug1, OUTPUT); pinMode(ledPinDebug2, OUTPUT); pinMode(photoPin, INPUT);
}
void loop(){
digitalWrite(ledPinRed, HIGH); digitalWrite(ledPinDebug1, LOW); digitalWrite(ledPinDebug2, LOW);
photoState = digitalRead(photoPin);
if (photoState == LOW) { delayMicroseconds(4500);
digitalWrite(ledPinDebug1, HIGH); // test 1t delay(3000);
photoState = digitalRead(photoPin); if (photoState == HIGH){
delay(1);
digitalWrite(ledPinDebug1, LOW); // test 2d delay(3000);
photoState = digitalRead(photoPin); if (photoState == LOW){
delay(1);
digitalWrite(ledPinDebug2, HIGH); // test 3d delay(3000);
photoState = digitalRead(photoPin); if (photoState == HIGH){
delay(1);
digitalWrite(ledPinDebug2, LOW); // test 4h delay(3000);
photoState = digitalRead(photoPin); if (photoState == LOW){
delayMicroseconds(3500); digitalWrite(ledPinDebug1, HIGH);// 5h digitalWrite(ledPinDebug2, HIGH); delay(3000);
photoState = digitalRead(photoPin); if (photoState == HIGH){
digitalWrite(ledPinRed, LOW); digitalWrite(ledPinGreen, HIGH); delay(5000); digitalWrite(ledPinGreen, LOW);
}
}
}
}
}
}
}
}
Места проверки я выделил, чтобы было понятно, как должны вести себя отладочные светодиоды.
Что ж, всё, что можно было проверить за компьютером, я проверил, и настал момент, когда пора проверить совместную работу устройств на «живых» макетных платах. Тем более, что были сомнения относительно времён посылок кода.
111