Муниципальное общеобразовательное учреждение «Гимназия №6» г. Воркуты
- Вы здесь:
- Главная
- Робототехника
- Arduino для начинающих
- Урок 2. Программирование Arduino
Урок 2. Программирование Arduino
Микроконтроллер способен выполнять только точные инструкции. Общение с микроконтроллером происходит на языке программирования, который имеет свой синтаксис и нормы оформления. Непосредственно в сам микроконтроллер загружается бинарный машинный код. Данный код может быть получен из любого языка программирования, тут всё зависит от среды разработки и транслятора. Официальной средой разработки является Arduino IDE, где программирование осуществляется на языке программирования C++ (читается «Си плюс плюс») , одном из самых популярных и мощных языков. Сами разработчики называют язык Arduino Wiring, так как в стандартной библиотеке Arduino.h используются функции и инструменты из фреймворка Wiring. Но языком из которого берётся синтаксис, является C (читается «Си») . Помимо С существуют среды разработки, позволяющие писать на Java , например Espruino WEB IDE, или B4R – на языке Basic , XOD – программирование с помощью визуальных блоков.
Синтаксис
Комментарии
Комментарии нужны для пояснения кода, как для себя, так и для других. Комментарий это обычный текст, который игнорируется на этапе компиляции, то есть перевода в машинный код. В C++ у нас два типа комментариев:
Переменные
Имена переменных могут содержать латинские буквы в верхнем и нижнем регистре (ЗАГЛАВНЫЕ и строчные), цифры и нижнее подчеркивание. Имена переменных не могут начинаться с цифры. Только с буквы или нижнего подчёркивания.
Пример: myVar_1 .
Регистр имеет значение, т. е. заглавная буква отличается от строчной. Пример: переменные var1 и Var1 – не одно и то же.
Операторы и функции
Каждая команда заканчивается точкой с запятой ;
Вызов функции или метода всегда заканчивается скобками, даже если функция не принимает параметров. Пример: loop()
Тела функций заключаются в фигурные скобки
Разделитель десятичных дробей – точка. Пример: 0.25
Запятыми перечисляются аргументы функций и методов, а также членов массива. Пример: digitalWrite(3, HIGH); массив – int myArray[] = <3, 4, 5 ,6>; Также запятая является самостоятельным оператором.
Одиночный символ заключается в одиночные кавычки ‘а’
Строка заключается в двойные кавычки “строка”
Метод применяется к объекту через точку. Например: Serial.begin();
Оформление
Есть такое понятие, как форматирование (выравнивание) кода, то есть соблюдение пробелов и интервалов. Есть автоформатирование кода, оно работает как в процессе написания, так и по вызову. В Arduino IDE код форматируется по горячей комбинации Ctrl+T.
Между математическими действиями, знаками сравнения, присваивания и всем подобным ставится пробел. Как и в обычном тексте, пробел ставится после и не ставится перед запятой, двоеточием, точкой с запятой.
Отступ от левого края экрана – знак табуляции, код сдвигается вправо и на одном расстоянии формируются команды из одного блока кода. В Arduino IDE одна табуляция равна двум пробелам.
Каждое действие выполняется с новой строки (автоформатирование это не исправляет).
Фигурные скобки начала и окончания блока кода принято писать на отдельной строке. Можно писать открывающую скобку на строке с оператором, это экономит место.
Общепринятые правила (не синтаксис) именования переменных, функций и методов.
Имена переменных принято писать начиная с маленькой буквы, называть их так, чтобы было понятно. Пример: value
Если название переменной необходимо составить из двух и более слов, они разделяются верхним регистром первой буквы каждого нового слова. Пример: myButtonState
Имена типов данных и классов принято писать с большой буквы. Пример: Signal, Servo
Имена констант принято писать в верхнем регистре, разделение – нижнее подчеркивание. Пример: MOTOR_SPEED
При написании библиотек и классов, имена внутренних переменных принято писать, начиная со знака нижнего подчёркивания. Пример: _position
Несколько общепринятых сокращений для названий переменных, которые встречаются в прошивках и библиотеках:
button – btn , кнопка
index – idx – i, индекс
buffer – buf , буфер
value – val , значение
variable – var , переменная
pointer – ptr , указатель
Имена функций и методов принято начинать с глагола, кратко описывающего действие функции:
get – получить значение ( getValue )
set – установить значение ( setTime )
print, show – показать что-то
read – прочитать
write – записать
change – изменить
clear – очистить
begin, start – начать
end, stop – закончить, остановить
Структура кода
Прежде чем переходить к структуре и порядку частей кода, нужно кое-что запомнить:
Переменная любого типа должна вызываться после своего объявления. Иначе будет ошибка.
Объявление и использование классов или типов данных из библиотеки/файла должно быть после подключения библиотеки/файла.
Функция может вызываться как до, так и после объявления, потому что C++ компилируемый язык, компиляция проходит в несколько этапов, и функции “выделяются” отдельно, поэтому могут вызываться в любом месте программы.
При запуске Arduino IDE даёт нам заготовку в виде двух обязательных функций: setup и loop.
Код в блоке setup выполняется один раз при каждом запуске микроконтроллера. Код в блоке loop выполняется в цикле (“по кругу”) на всём протяжении работы микроконтроллера, начиная с момента завершения выполнения setup .
Структура реального скетча:
- Описание прошивки, полезные ссылки, заметки, авторство.
- Константы настройки (define и обычные).
- Служебные константы (которые следует менять только с полным осознанием дела).
- Подключаемые библиотеки и внешние файлы, объявление соответствующих им типов данных и классов.
- Глобальные переменные.
- Блок setup .
- Блок loop .
- Пользовательские функции.
Пример кода
Пример того же кода с комментариями (пояснениями)
Подключение библиотек и файлов
В реальной работе очень часто используются библиотеки или просто внешние файлы, они подключаются к главному файлу при помощи директивы #include , данная директива сообщает препроцессору, что нужно найти и включить в компиляцию указанный файл. Этот файл может подключать и другие файлы, но они подключаются автоматически. Например:
#include // подключает библиотеку Servo.h
#include “Servo.h” // тоже подключает библиотеку Servo.h
Когда указываем название “в кавычках”, компилятор сначала ищет файл в папке со скетчем, а затем в папке с библиотеками. При использовании компилятор ищет файл только в папке с библиотеками!
Практическое задание к уроку
Создавать небольшие проекты и программировать можно и при отсутствии платы Ардуино, в онлайн программном комплексе TinkerCad (https://www.tinkercad.com/). Для быстрого доступа (чтобы избавить вас от длительной процедуры регистрации) учащихся МОУ «Гимназия №6» г. Воркуты создан специальный виртуальный класс Arduino214 (как вы догадались, по номеру кабинета робототехники). Для реализации данного способа входа в программный комплекс необходимо:
- Зайти в класс Arduino214 по адресу https://www.tinkercad.com/joinclass/NDK3RBS86WX6.
- Ввести псевдоним, назначенный преподавателем (Если вы не получили или забыли псевдоним, то можно сделать запрос в электронном дневнике, отправив письмо на имя Янактаева Евгения Владимировича).
Практическая работа 2.1. Мигающий встроенный светодиод.
Будем использовать в программном комплексе TinkerCad собранную на предыдущем уроке схему, в которую входят: плата Arduino Uno, малая макетная плата, мультиметр.
После входа в программный комплекс выберите в левом меню Circuits, выберите созданную схему и нажмите Изменить.
Для выполнения задания нужна только плата Arduino, но можно оставить на месте малую макетную плату и мультиметр.
Создадим программу для управления встроенным светодиодом.
В верхнем меню справа выберите Код и поменяйте в выпадающем меню Блоки на Текст.
При появлении предупреждения нажмите на кнопку Продолжить. В рабочей области текстового редактора появится следующий код:
В процедуре void setup() изменим используемый порт 13 на встроенный светодиод LED_BUILTIN . То же самое сделаем с функцией digitalWrite в процедуре void loop() .
Получится следующий код:
Нажмите на кнопку Начать моделирование. Встроенный светодиод должен включиться и через 1 секунду (времени моделирования, оно может отличаться от реального) выключиться. И так будет продолжаться в цикле: встроенный светодиод будет «мигать».
Разберем подробнее, как это все работает.
Обратите внимание на два блока со словами setup и loop. Это две функции, которые вызываются всегда, когда запускается наш скетч. Блоки ограничены фигурными скобками – все, что внутри них, принадлежит блоку.
Блок функции void setup()
Для инициализации системы мы должны указать микроконтроллеру команды, которые он выполнит в момент загрузки, т. е. эти команды выполнятся только один раз при старте системы.
Синтаксис void setup():
Слово setup – это название функции. Все слово в нижнем регистре. Слово перед названием описывает тип возвращаемых данных. В данном случае никаких данных подпрограмма не возвращает, поэтому мы должны указать слово void . Все команды функции должны размещаться внутри фигурных скобок <> .
Чаще всего внутри void setup указываются следующие инструкции:
- pinMode с указанием номера и типа порта. Это инструкция определяет режим работы портов Ардуино.
- Serial.begin с указанием скорости (чаще всего, 9600). Эта инструкция инициализирует работы с последовательным портом на указанной скорости.
- Инструкции подключения и инициализации различных объектов библиотек Ардуино. Например, servo.atach(10) укажет библиотеке, что сервопривод мы подключили к 10 порту, и все последующие действия код библиотеки будет совершать именно с этим портом.
- Инициализацию глобальных переменных, если нет возможности инициализировать их в глобальной области видимости.
- Выполнение других настроек и начальных значений для переменных и объектов.
В блоке функции loop() сосредоточены наши команды, управляющие светодиодом:
digitalWrite – это название функции, которая отвечает за подачу напряжения на определенный порт.
LED_BUILDIN – это название внутреннего светодиода. В большинстве плат этому названию соответствует порт 13. Для платы Uno можно было не менять значение 13 на LED_BUILDIN.
HIGH – условное название высокого уровня сигнала. Включает светодиод. Можно заменить цифрой 1.
LOW – условное обозначение низкого уровня сигнала. Выключает светодиод. Можно заменить цифрой 0.
delay – функция, которая останавливает выполнение скетча на определенное время. Крайне нежелательно использовать ее в реальных проектах. В скобках указывается количество миллисекунд, которые нужно ждать. Значение 1000 соответствует 1 секунде.
Как только программа дойдет до конца, контроллер перейдет в начало блока loop и будет выполнять все команды заново. Наш светодиод мигает без остановки.
В функцию loop мы должны поместить команды, которые будут выполняться все время, пока включена плата Arduino. Начав выполнение с первой команды, микроконтроллер дойдет до конца и сразу же перепрыгнет в начало, чтобы повторить ту же последовательность. И так до тех пор, пока на плату будет подан электричество.
Arduino, MK-90 и другие
Программирование Arduino, оживление микроэвм Электроника МК-90, аппаратный хакинг.
Страницы
17.07.2010
Уроки Wiring (4)
Урок 4. Немного о синтаксисе Wiring
Итак, из прошлого урока вы уже знаете про переменные и оператор присваивания:
val = a + b / c * d — 2;
int a; // от -32,768 до 32,767
byte b; // от 0 до 255
float с; // от -3.4028235 x 10^38 до 3.4028235 x 10^38
Объявление можно совмещать с присвоением:
double result = sqrl(15); // извлекаем квадратный корень
float result1 = 5/2; // результат — 2.0
float result2 = 5.0/2.0; // результат — 2.5
#define ledPin 13
но оба варианта допускают использование таким образом:
if ( логическое выражение )
else
boolean b = buttonPressed();
if (b) <
// действия при нажатой кнопке
> else <
// действия при отпущенной кнопке
>
while ( логическое выражение ) оператор;
while ( buttonPressed() ) delay(100);
do оператор while ( логическое выражение );
do <
c = beepUltrasonic(outPin);
> while (echoUltrasonic(inPin) > 30);
for (инициализатор; логическое выражение; шаг) оператор;
- инициализатор выполняется один раз, перед началом цикла;
- логическое выражение проверяется перед очередным выполнением тела цикла — если оно ложно, цикл завершается;
- шаг — действие, которое выполняется по завершении итерации цикла, и часто туда вписывают приращение счетчика на единицу.
тип_возвращаемого_значения имя_функции(тип1 имя1, тип2 имя2, . )
< return возвращаемое значение;
>
16 комментариев:
Илья,здравствуйте! На Ваших уроках http://mk90.blogspot.com/2010/06/wiring-4.html пытаюсь овладеть навыками програмирования.Если это уместно,подскажите пожалуйста, где у меня ошибка в скетче.Задача: нажатие кнопки-горит светодиод и ШД делает определенное кол-во оборотов и останавливается.При повторном нажатии кнопки-светодиод гаснет и ШД отрабатывает движение назад.
У меня получается при нажатии кнопки ШД отрабатывает вперед и назад сразу.Где ошибка? Заранее благодарен.Александр.
#include
int inPin = 2; // the number of the input pin
int outPin = 9; // the number of the output pin
AF_Stepper motor(200, 2);
int state = HIGH; // the current state of the output pin
int reading; // the current reading from the input pin
int previous = LOW; // the previous reading from the input pin
// the follow variables are long’s because the time, measured in miliseconds,
// will quickly become a bigger number than can be stored in an int.
long time = 0; // the last time the output pin was toggled
long debounce = 200; // the debounce time, increase if the output flickers
void setup()
<
pinMode(inPin, INPUT);
pinMode(outPin, OUTPUT);
motor.setSpeed(100); // 100 оборотов в минуту
>
void loop()
<
reading = digitalRead(inPin);
// if the input just went from LOW and HIGH and we’ve waited long enough
// to ignore any noise on the circuit, toggle the output pin and remember
// the time
if (reading == HIGH && previous == LOW && millis() — time > debounce) <
motor.step(600, FORWARD, SINGLE); //3 оборота
if (state == HIGH)
state = LOW;
else
state = HIGH;
motor.step(600, BACKWARD, SINGLE); //3 оборота
Знаете, Александр — скетч написан в точности так, как он себя и ведет (с ваших слов). Т.е. последовательность команд сначала крутит вперед, потом назад.
Надо дописать таким образом, чтобы направление поворота зависело от переменной state, например — справьте команду первого поворота:
motor.step(600, (STATE == HIGH) ? FORWARD:BACKWARD, SINGLE);
. а второй motor.step уберите вообще.
Илья,благодарю за помощь!Все заработало.С уважением,Александр.
Илья,здравствуйте!Пршу меня простить за назойливость,но без Вашей помощи не обойтись.Не могу разобраться,как добавить в скетч серву.Все время выдает ошибку,а знаний не хватает, чтобы исправить.Задача: отрабатывать поворот сервы на заданный угол паралельно с работой ШД.Т.е,при нажатии кнопки ШД делает определенное кол-во шагов,серва поворачивается на определенный угол.При повторном нажатии кнопки ШД и серва отрабатывают назад.Если не затруднит подскажите,пожалуйста,как добиться желаемого.Заранее благодарен,Александр.
#include
#include «Servo.h»
Servo myservo;
int servoPin = 10; // порт подключения сервы
int myAngle; // будет хранить угол поворота
int pulseWidth; // длительность импульса
void servoPulse(int servoPin, int myAngle)
<
pulseWidth = (myAngle * 11) + 500; // конвертируем угол в микросекунды
digitalWrite(servoPin, HIGH); // устанавливаем серве высокий уровень
delayMicroseconds(pulseWidth); // ждём
digitalWrite(servoPin, LOW); // устанавливаем низкий уровень
delay(20); //
>
int inPin = 2; // контакт, к которому подключена кнопка
int outPin = 9; // контакт, к которому подключен светодиод
AF_Stepper motor(200, 2);//Создаем объект для двигателя на 2 канале (M3 и M4)
int state = HIGH; // the current state of the output pin
int reading; // the current reading from the input pin
int previous = LOW; // the previous reading from the input pin
// the follow variables are long’s because the time, measured in miliseconds,
// will quickly become a bigger number than can be stored in an int.
long time = 0; // the last time the output pin was toggled
long debounce = 200; // the debounce time, increase if the output flickers
void setup()
<
pinMode(inPin, INPUT);
pinMode(outPin, OUTPUT);
motor.setSpeed(100); // 100 оборотов в минуту
pinMode(servoPin, OUTPUT);// конфигурируем пин сервы, как выход
>
void loop()
<
reading = digitalRead(inPin);
// if the input just went from LOW and HIGH and we’ve waited long enough
// to ignore any noise on the circuit, toggle the output pin and remember
// the time
if (reading == HIGH && previous == LOW && millis() — time > debounce) <
motor.step(860, (state == HIGH) ? FORWARD:BACKWARD, SINGLE);
Servo myservo((state == HIGH) ? (myAngle=0; myAngle =0; myAngle—));
if (state == HIGH)
state = LOW;
else
state = HIGH;
time = millis();
>
digitalWrite(outPin, state);
previous = reading;
>