Гид компьютерного мира - Информационный портал
  • Главная
  • Ошибки
  • Описание языка ардуино на русском. Программирование Arduino

Описание языка ардуино на русском. Программирование Arduino

Этот урок дает минимальные знания, необходимые для программирования систем Ардуино на языке C. Можно только просмотреть его и в дальнейшем использовать как справочную информацию. Тем, кто программировал на C в других системах можно пропустить статью.

Повторю, что это минимальная информация. Описание указателей, классов, строковых переменных и т.п. будет дано в последующих уроках. Если что-то окажется непонятным, не беспокойтесь. В дальнейших уроках будет много примеров и пояснений.

Структура программы Ардуино.

Структура программы Ардуино достаточно проста и в минимальном варианте состоит из двух частей setup() и loop().

void setup() {

void loop() {

Функция setup() выполняется один раз, при включении питания или сбросе контроллера. Обычно в ней происходят начальные установки переменных, регистров. Функция должна присутствовать в программе, даже если в ней ничего нет.

После завершения setup() управление переходит к функции loop(). Она в бесконечном цикле выполняет команды, записанные в ее теле (между фигурными скобками). Собственно эти команды и совершают все алгоритмические действия контроллера.

Первоначальные правила синтаксиса языка C.

; точка с запятой Выражения могут содержать сколь угодно много пробелов, переносов строк. Признаком завершения выражения является символ ”точка с запятой ”.

z = x + y;
z= x
+ y ;

{ } фигурные скобки определяют блок функции или выражений. Например, в функциях setup() и loop().

/* … */ блок комментария , обязательно закрыть.

/* это блок комментария */

// однострочный комментарий , закрывать не надо, действует до конца строки.

// это одна строка комментария

Переменные и типы данных.

Переменная это ячейка оперативной памяти, в которой хранится информация. Программа использует переменные для хранения промежуточных данных вычислений. Для вычислений могут быть использованы данные разных форматов, разной разрядности, поэтому у переменных в языке C есть следующие типы.

Тип данных Разрядность, бит Диапазон чисел
boolean 8 true, false
char 8 -128 … 127
unsigned char 8 0 … 255
byte 8 0 … 255
int 16 -32768 … 32767
unsigned int 16 0 … 65535
word 16 0 … 65535
long 32 -2147483648 … 2147483647
unsigned long 32 0 … 4294967295
short 16 -32768 … 32767
float 32 -3.4028235+38 … 3.4028235+38
double 32 -3.4028235+38 … 3.4028235+38

Типы данных выбираются исходя из требуемой точности вычислений, форматов данных и т.п. Не стоит, например, для счетчика, считающего до 100, выбирать тип long. Работать будет, но операция займет больше памяти данных и программ, потребует больше времени.

Объявление переменных.

Указывается тип данных, а затем имя переменной.

int x; // объявление переменной с именем x типа int
float widthBox; // объявление переменной с именем widthBox типа float

Все переменные должны быть объявлены до того как будут использоваться.

Переменная может быть объявлена в любой части программы, но от этого зависит, какие блоки программы могут ее использовать. Т.е. у переменных есть области видимости.

  • Переменные, объявленные в начале программы, до функции void setup(), считаются глобальными и доступны в любом месте программы.
  • Локальные переменные объявляются внутри функций или таких блоков, как цикл for, и могут использоваться только в объявленных блоках. Возможны несколько переменных с одним именем, но разными областями видимости.

int mode; // переменная доступна всем функциям

void setup() {
// пустой блок, начальные установки не требуются
}

void loop() {

long count; // переменная count доступна только в функции loop()

for (int i=0; i < 10;) // переменная i доступна только внутри цикла
{
i++;
}
}

При объявлении переменной можно задать ее начальное значение (проинициализировать).

int x = 0; // объявляется переменная x с начальным значением 0
char d = ‘a’; // объявляется переменная d с начальным значением равным коду символа ”a”

При арифметических операциях с разными типами данных происходит автоматическое преобразование типов данных. Но лучше всегда использовать явное преобразование.

int x; // переменная int
char y; // переменная char
int z; // переменная int

z = x + (int) y; // переменная y явно преобразована в int

Арифметические операции.

Операции отношения.

Логические операции.

Операции над указателями.

Битовые операции.

& И
| ИЛИ
^ ИСКЛЮЧАЮЩЕЕ ИЛИ
~ ИНВЕРСИЯ
<< СДВИГ ВЛЕВО
>> СДВИГ ВПРАВО

Операции смешанного присваивания.

Выбор вариантов, управление программой.

Оператор IF проверяет условие в скобках и выполняет последующее выражение или блок в фигурных скобках, если условие истинно.

if (x == 5) // если x=5, то выполняется z=0
z=0;

if (x > 5) // если x >
{ z=0; y=8; }

IF … ELSE позволяет сделать выбор между двух вариантов.

if (x > 5) // если x > 5, то выполняется блок z=0, y=8;
{
z=0;
y=8;
}

{
z=0;
y=0;
}

ELSE IF – позволяет сделать множественный выбор

if (x > 5) // если x > 5, то выполняется блок z=0, y=8;
{
z=0;
y=8;
}

else if (x > 20) // если x > 20, выполняется этот блок
{
}

else // в противном случае выполняется этот блок
{
z=0;
y=0;
}

SWITCH CASE - множественный выбор. Позволяет сравнить переменную (в примере это x) с несколькими константами (в примере 5 и 10) и выполнить блок, в котором переменная равна константе.

switch (x) {

case 5:
// код выполняется если x = 5
break;

case 10:
// код выполняется если x = 10
break;

default:
// код выполняется если не совпало ни одно предыдущее значение
break;
}

Цикл FOR . Конструкция позволяет организовывать циклы с заданным количеством итераций. Синтаксис выглядит так:

for (действие до начала цикла;
условие продолжения цикла;
действие в конце каждой итерации) {

// код тела цикла

Пример цикла из 100 итераций.

for (i=0; i < 100; i++) // начальное значение 0, конечное 99, шаг 1

{
sum = sum + I;
}

Цикл WHILE . Оператор позволяет организовывать циклы с конструкцией:

while (выражение)
{
// код тела цикла
}

Цикл выполняется до тех пор, пока выражение в скобках истинно. Пример цикла на 10 итераций.

x = 0;
while (x < 10)
{
// код тела цикла
x++;
}

DO WHILE – цикл с условием на выходе.

do
{
// код тела цикла
} while (выражение);

Цикл выполняется пока выражение истинно.
BREAK – оператор выхода из цикла. Используется для того, чтобы прервать выполнение циклов for, while, do while.

x = 0;
while (x < 10)
{
if (z > 20) break; // если z > 20, то выйти из цикла
// код тела цикла
x++;
}

GOTO – оператор безусловного перехода.

goto metka1; // переход на metka1
………………
metka1:

CONTINUE - пропуск операторов до конца тела цикла.

x = 0;
while (x < 10)
{
// код тела цикла
if (z > 20) continue; // если z > 20, то вернуться на начало тела цикла
// код тела цикла
x++;
}

Массивы.

Массив это область памяти, где последовательно хранятся несколько переменных.

Объявляется массив так.

int ages; // массив из 10 переменных типа int

float weight; // массив из 100 переменных типа float

При объявлении массивы можно инициализировать:

int ages = { 23, 54, 34, 24, 45, 56, 23, 23, 27, 28};

Обращаются к переменным массивов так:

x = ages; // x присваивается значение из 5 элемента массива.
ages = 32; // 9 элементу массива задается значение 32

Нумерация элементов массивов всегда с нуля.

Функции.

Функции позволяют выполнять одни и те же действия с разными данными. У функции есть:

  • имя, по которому ее вызывают;
  • аргументы – данные, которые функция использует для вычисления;
  • тип данных, возвращаемый функцией.

Описывается пользовательская функция вне функций setup() и loop().

void setup() {
// код выполняется один раз при запуске программы
}

void loop() {
// основной код, выполняется в цикле
}

// объявление пользовательской функции с именем functionName
type functionName(type argument1, type argument1, … , type argument)
{
// тело функции
return();
}

Пример функции, вычисляющей сумму квадратов двух аргументов.

int sumQwadr (int x, int y)
{
return(x* x + y*y);
}

Вызов функции происходит так:

d= 2; b= 3;
z= sumQwadr(d, b); // в z будет сумма квадратов переменных d и b

Функции бывают встроенные, пользовательские, подключаемые.

Очень коротко, но этих данных должно хватить для того, чтобы начать писать программы на C для систем Ардуино.

Последнее, что я хочу рассказать в этом уроке, как принято оформлять программы на C. Думаю, если вы читаете этот урок в первый раз, стоит пропустить этот раздел и вернутся к нему позже, когда будет что оформлять.

Главная цель внешнего оформления программ это улучшить читаемость программ, уменьшить число формальных ошибок. Поэтому для достижения этой цели можно смело нарушать все рекомендации.

Имена в языке C.

Имена, представляющие типы данных, должны быть написаны в смешанном регистре. Первая буква имени должна быть заглавная (верхний регистр).

Signal, TimeCount

Переменные должны быть записаны именами в смешанном регистре, первая буква строчная (нижний регистр).

Рубрика: . Вы можете добавить в закладки.

Основа языка программирования модуля Arduino - это язык Си (скорее Си++). Ещё точнее, этот диалект языка называется Processing/Wiring. Хорошее обозрение языка вы найдёте в приложении. А мне хочется больше рассказать не о языке, а о программировании.

Программа - это некий набор команд, которые понимает процессор, процессор вашего компьютера или процессор микроконтроллера модуля Arduino, не суть важно. Процессор читает команды и выполняет их. Любые команды, которые понимает процессор - это двоичные числа. Это только двоичные числа и ничто иное. Выполняя арифметические операции, для которых процессор некогда и предназначался, процессор оперирует с числами. Двоичными числами. И получается, что и команды, и то, к чему они относятся, это только двоичные числа. Вот так. Но как же процессор разбирается в этой «куче» двоичных чисел?

Во-первых, все эти двоичные числа записываются в последовательные ячейки оперативной памяти, имеющие адреса. Когда вы загружаете программу, и она начинает работать, процессор получает первый адрес программы, где обязательно должна быть записана команда. Те команды, которые требуют от процессора операций с числами, имеют «опознавательные знаки», например, что в следующих двух ячейках памяти два числа, которые нужно сложить. А счётчик, назовём его счётчиком команд, где записан адрес следующей команды, в данном случае увеличивает адрес так, что в программе по этому адресу будет следующая команда. При неправильной работе программы или сбоях процессор может ошибиться, и тогда, прочитав вместо команды число, процессор делает совсем не то, что должен делать, а программа «зависает».

Таким образом, любая программа - это последовательность двоичных чисел. А программирование - это умение правильно записывать правильные последовательности двоичных чисел. Достаточно давно для записи программ стали использовать специальные средства, которые называются языками программирования.

Однако любая программа в первую очередь требует от вас ясного понимания того, что должна делать программа, и для чего она нужна. Чем яснее вы это понимаете, тем легче создать программу. Небольшие программы, хотя трудно сказать, какие программы небольшие, а какие нет, можно рассматривать целиком. Более сложные программы лучше разбить на части, которые можно рассматривать как самостоятельные программы. Так их лучше создать, легче отладить и проверить.

Я не готов спорить, но считаю, что программу удобнее начинать с описания на обычном языке. И в этом смысле я считаю, что программирование не следует путать с написанием кода программы. Когда программа описана обычными словами, вам легче определить, например, какой язык программирования выбрать для создания кода программы.

Ближе всего к записи программы с помощью двоичных чисел, язык ассемблер. Для него характерно соответствие команд языка двоичным командам, понятным процессору. Но кодирование программ на ассемблере требует больших усилий и ближе к искусству, чем к формальным операциям. Более универсальны и легче в применении языки высокого уровня, как Бэйсик или Си. И давно для записи программ в общем виде используют графический язык, а в последнее время появились и «переводчики» с этого языка на язык процессоров.

Кроме языков программирования общего применения, всегда существовала некоторая специализация языков программирования, и существовали специализированные языки. К последним я бы отнёс и язык программирования модуля Arduino.

Всё, что нужно сказать модулю, чтобы он сделал что-то нужное нам, организовано в удобный набор команд. Но вначале о том, что нам нужно от Arduino?

Модуль можно использовать в разных качествах - это и сердце (или голова) робота, это и основа прибора, это и удобный конструктор для освоения работы с микроконтроллерами и т.д.

Выше мы уже использовали простые программы для проверки подключения модуля к компьютеру. Кому-то они могут показаться слишком простыми, а поэтому не интересными, но любые сложные программы состоят из более простых фрагментов, похожих на те, с которыми мы уже знакомились.

Давайте посмотрим, о чём нам может рассказать самая простая программа «Помигать светодиодом».

int ledPin = 13;

pinMode (ledPin, OUTPUT);

digitalWrite (ledPin, HIGH);

digitalWrite (ledPin, LOW);

Вначале вспомним, что такое светодиод. В сущности это обычный диод, у которого, благодаря его конструкции, при протекании тока в прямом направлении начинает светиться переход. То есть, чтобы светодиод светился, нужно чтобы через него протекал ток, а, значит, к светодиоду следует приложить напряжение. А чтобы ток не превысил допустимого значения, последовательно со светодиодом следует включить резистор, который называют токоограничительным (см. Приложение А, цифровой выход). Напряжение к светодиоду прикладывает микроконтроллер, составляющий основу модуля Arduino. У микроконтроллера, кроме процессора, выполняющего наши команды, есть один или несколько портов ввода-вывода. Не вдаваясь в рассмотрение конкретного устройства порта, скажем так - когда вывод порта работает на выход, его можно представить как выход цифровой микросхемы с двумя состояниями, включено и выключено (есть напряжение на выходе, нет напряжения на выходе).

Но этот же вывод порта может работать и как вход. В этом случае его можно представить, например, как вход цифровой микросхемы – на вход подаётся логический уровень, высокий или низкий (см. Приложение А, цифровой ввод).

Как мы мигаем светодиодом:

Включить выходной вывод порта. Выключить вывод порта.

Но процессор работает очень быстро. Мы не успеем заметить мигания. Чтобы заметить это мигание, нам нужно добавить паузы. То есть:

Включить выходной вывод порта. Пауза 1 секунда.

Выключить вывод порта.

Пауза 1 секунда.

Это наша программа. Процессор прочитает первую команду и включит вывод, светодиод загорится. Затем процессор сделает паузу в работе и выключить вывод, светодиод погаснет. Но он только один раз мигнул.

Повторение какого-либо процесса или набора команд называется в программировании циклом. Используются разные виды циклов. Есть цикл, который выполняется заданное число раз. Это цикл for. Есть циклы, которые выполняются до тех пор, пока не будет выполнено некоторое условие, которое является частью языковой конструкции цикла. А если условие не будет выполнено никогда, то цикл выполняется бесконечное число раз. Это бесконечный цикл.

Я не думаю, что микроконтроллеры используются с программами того вида, который приведён выше. То есть, один раз выполнено несколько команд и больше контроллер не работает. Как правило, он работает постоянно, как только на него подаётся питающее напряжение. А, значит, микроконтроллер должен работать в бесконечном цикле.

Именно об этом говорит функция void loop(), loop - это петля, замкнутый цикл. Условия прекращения работы цикла нет, а, следовательно, нет условия его завершения.

Кроме того, мы должны сообщить модулю Arduino, какой вывод порта и как мы хотим использовать, для выхода (OUTPUT) или для входа (INPUT). Этой цели служит функция void setup(), которая для языка Arduino является обязательной, даже если она не используется, и команда pinMode(), для задания режима работы вывода.

pinMode (ledPin, OUTPUT);

И ещё, языковая конструкция использует переменные для определения номера вывода:

int ledPin = 13;

Использование переменных удобно. Решив, что вы будете использовать не вывод 13, а 12, вы внесёте изменение только в одной строке. Особенно сильно это сказывается в больших программах. Имя переменной можно выбирать по своему усмотрению, но, как правило, оно должно быть только символьным, и часто количество символов ограничивается. Если вы неверно зададите имя переменной, думаю, компилятор вас поправит.

Функция digitalWrite (ledPin, HIGH) устанавливает заданный вывод в состояние с высоким уровнем, то есть включает вывод.

А delay (1000), как вы уже поняли, означает паузу в 1000 миллисекунд или 1 секунду.

Осталось понять, что означают такие приставки, как int, void. Любые значения, любые переменные размещаются в памяти, как и команды программы. В ячейки памяти записываются числа зачастую из 8 битов. Это байт. Но байт - это числа от 0 до 255. Для записи больших чисел нужно два байта или больше, то есть, две или больше ячеек памяти. Чтобы процессору было ясно, как отыскать число, разные типы чисел имеют разные названия. Так число по имени byte, займёт одну ячейку, int (integer, целое) больше. Кроме того, функции, используемые в языках программирования, тоже возвращают числа. Чтобы определить, какой тип числа должна вернуть функция, перед функцией записывают этот тип возвращаемого числа. Но некоторые функции могут не возвращать числа, такие функции предваряют записью void (см. Приложение А, переменные).

Вот, сколько интересного может рассказать даже самая простая программа.

Обо всём этом вы, надеюсь, прочитаете в приложении. А сейчас проделаем простые эксперименты, используя только то, что мы уже знаем из возможностей языка. Первое, заменим переменную типа int, которая занимает много места в памяти, на byte - одно место, одна ячейка памяти. Посмотрим, что у нас получится.

byte ledPin = 13;

pinMode (ledPin, OUTPUT);

digitalWrite (ledPin, HIGH);

digitalWrite (ledPin, LOW);

После компиляции и загрузки программы в модуль мы не заметим изменений в работе программы. Хорошо. Тогда изменим программу так, чтобы заметить изменения в её работе.

Для этого мы заменим число в функции delay (1000) переменной, назвав её my_del. Эта переменная должна быть целым числом, то есть, int.

int my_del = 5000;

Не забывайте заканчивать каждую команду точкой с запятой. Внесите изменения в программу, скомпилируйте её и загрузите в модуль. Затем поменяйте переменную и повторите компиляцию и загрузку:

byte my_del = 5000;

Разница, уверен, получится ощутимая.

Проделаем ещё один эксперимент с изменением длительности пауз. Уменьшение длительности пауз выполним, скажем, пять раз. Сделаем паузу в 2 секунды, а затем будем увеличивать тоже пять раз. И вновь сделаем паузу в 2 секунды. Цикл, выполняемый заданное количество раз, называется циклом for и записывается он так:

for (int i = 0; i<5; i++)

что-то, что выполняется в цикле for

Для выполнения цикла ему нужна переменная, у нас это i, переменной нужно задать начальное значение, которое мы ей и присвоили. Затем следует условие завершения работы цикла, у нас i меньше 5. А запись i++ - это характерная для языка Си запись увеличения переменной на единицу. Фигурные скобки ограничивают набор команд, подлежащих выполнению в цикле for. В других языках программирования могут быть другие ограничители для выделения блока кода функции.

Внутри цикла мы выполняем то же, что и раньше, с небольшими изменениями:

for (int i = 0; i<5; i++)

digitalWrite (ledPin, HIGH);

digitalWrite (ledPin, LOW);

my_del = my_del - 100;

Об изменении записи паузы мы говорили выше, а изменение самой паузы достигается уменьшением переменной на 100.

Для второго цикла мы запишем этот же блок кода, но переменную длительности паузы будем увеличивать на 100.

for (int i = 0; i<5; i++)

digitalWrite (ledPin, HIGH);

digitalWrite (ledPin, LOW);

Вы заметили, что запись уменьшения паузы и её увеличения выглядят по-разному. Это тоже особенность языка Си. Хотя для ясности следовало повторить эту запись, изменив только знак минус на плюс. Итак, мы получаем такую программу:

int ledPin = 13;

int my_del = 1000;

pinMode (ledPin, OUTPUT);

for (int i = 0; i<5; i++)

digitalWrite (ledPin, HIGH);

digitalWrite (ledPin, LOW);

for (int i = 0; i<5; i++)

digitalWrite (ledPin, HIGH);

digitalWrite (ledPin, LOW);

Скопируем код нашей программы в программу Arduin, скомпилируем её и загрузим в модуль. Изменение длительности пауз заметно. И будет ещё заметнее, попробуйте, если цикл for выполнить, скажем, раз 8.

То, что мы сейчас сделали, делают и профессиональные программисты - имея готовую программу, её легко можно модифицировать под свои нужды или желания. Поэтому все свои программы они хранят. Что я советую делать и вам.

Что мы упустили в своём эксперименте? Мы не прокомментировали нашу работу. Для добавления комментария используется либо двойная «прямая» косая черта, либо одиночная, но со звёздочками (см. Приложение А). Я советую вам это сделать самостоятельно, поскольку вернувшись к программе через некоторое время, вы легче в ней разберётесь, если будут пояснения, что вы делаете в том или ином месте программы. И ещё советую в папке с каждой программой хранить её описание на обычном языке, выполненное в любом текстовом редакторе.

Самая простая программа «помигать светодиодом» может послужить ещё для десятка экспериментов (даже с одним светодиодом). Мне кажется эта часть работы, придумывать, что ещё можно сделать интересного, самая интересная. Если вы обратитесь к приложению, где описан язык программирования, к разделу «управление программой», то можно заменить цикл for на другой вид цикла. И попробовать, как работают другие виды цикла.

Хотя процессор микроконтроллера, как любой другой, может производить вычисления (для того его и придумывали), и это используется, например, в приборах, всё-таки наиболее характерной операцией для микроконтроллера будет установка выхода порта в высокое или низкое состояние, то есть, «помигать светодиодом», как реакция на внешние события.

О внешних событиях микроконтроллер узнаёт, в основном, по состоянию входов. Настроив выводы порта на цифровой вход, мы можем следить за ним. Если исходное состояние входа - высокий уровень, а событие вызывает переход входа в низкое состояние, то мы можем что-то сделать, реагируя на это событие.

Самый простой пример - на входе кнопка. Когда кнопка не нажата, вход в высоком состоянии. Если нажать кнопку, то вход переходит в низкое состояние, а мы можем «зажечь» светодиод на выходе. При следующем нажатии на кнопку светодиод можно погасить.

Это опять пример простой программы. Даже начинающему она может показаться неинтересной. Однако и эта простая программа может найти вполне полезное применение. Приведу только один пример: мы будем после нажатия на кнопку не зажигать светодиод, а помигаем (определённым образом). И светодиод возьмём с инфракрасным излучением. В результате мы получим пульт управления. Вот такая простая программа.

В разных версиях программы есть различия в списке примеров. Но можно обратиться к руководству по языку в приложении, где есть пример и схема программы (в разделе примеров, названном «приложение») для работы с вводом. Я скопирую программу:

int ledPin = 13;

pinMode (ledPin, OUTPUT);

pinMode (inPin, INPUT);

if (digitalRead(inPin) == HIGH)

digitalWrite(ledPin, HIGH);

digitalWrite (ledPin, LOW);

И, как вы видите, совершенно новую программу мы получаем, модифицируя старую. Теперь светодиод будет мигать только тогда, когда нажата кнопка, которая присоединена к выводу 2. Вывод 2 через резистор 10 кОм присоединён к общему проводу (земле, GND). Кнопка одним концом присоединена к питающему напряжению +5В, а другим концом к выводу 2.

В программе мы встречаем новую языковую конструкцию if из раздела управления программой. Читается она так: если выполняется условие (заключённое в скобках), то выполняется блок программы, заключённый в фигурные скобки. Обратите внимание, что в условии (digitalRead(inPin) == HIGH) равенство входа высокому состоянию выполнено с помощью двух знаков равенства! Очень часто в спешке об этом забывается, и условие получается неверным.

Программу можно скопировать и загрузить в модуль Arduino. Однако, чтобы проверить работу программы, понадобиться внести некоторые изменения в конструкцию модуля. Впрочем, это зависит от разновидности модуля. Оригинальный модуль имеет розетки для соединения с платами расширения. В этом случае можно вставить подходящие одножильные провода в нужные места разъёма. Мой модуль имеет ножевые контакты для соединения с платами расширения. Я могу либо поискать подходящий разъём, либо, что дешевле, использовать подходящую панельку для микросхемы в корпусе DIP.

Второй вопрос - как найти у модуля те выводы, которые используются в программе?

С этим вопросом поможет разобраться картинка, которую я взял с сайта: http://robocraft.ru/.

Рис. 4.1. Расположение и назначение выводов контроллера и модуля Arduino

Все выводы моего модуля CraftDuino промаркированы, так что найти нужный вывод не составит труда. Можно подключать кнопку и резистор и проверять работу программы. Кстати, на вышеупомянутом сайте RoboCraft весь процесс отображён на картинках (но программа использует не совсем такие выводы!). Советую посмотреть.

Многие микроконтроллеры в своём составе имеют дополнительные аппаратные устройства. Так Atmega168, на основе которого собран модуль Arduino имеет UART, встроенный блок для связи с другими устройствами с помощью последовательного обмена данными. Например, с компьютером через COM-порт. Или с другим микроконтроллером с помощью его встроенного блока UART. Есть ещё и аналого-цифровой преобразователь. И формирователь широтно- импульсной модуляции.

Использование последнего иллюстрирует программа, которую я тоже скопирую с сайта RoboCraft. Но программу можно взять и из приложения. И, возможно, она есть в примерах программы Arduino.

// Fading LED by BARRAGAN

int value = 0; // переменная для хранения нужного значения

int ledpin = 9; // светодиод подключен к digital pin 9

// Нет необходимости вызвать функцию pinMode

for(value = 0 ; value <= 255; value+=5) // постепенно зажигаем светодиод

analogWrite(ledpin, value); // значение вывода (от 0 до 255)

delay(30); // ждѐм 🙂

for(value = 255; value >=0; value-=5) // постепенно гасим светодиод

analogWrite(ledpin, value);

Если в предыдущей программе новой для нас была функция digitalRead(inPin), чтение цифрового ввода, то в этой программе новая для нас функция analogWrite(ledpin, value), хотя параметры этой функции - уже знакомые нам переменные. Об использовании аналогового входа, использовании АЦП (аналого-цифрового преобразователя), мы поговорим позже. А сейчас вернёмся к общим вопросам программирования.

Программирование это то, что доступно всем, но потребуется время, чтобы освоить и программирование, и какой-либо язык программирования. Сегодня есть ряд программ, помогающих освоить именно программирование. И одна из них имеет непосредственное отношение к модулю Arduino. Называется она Scratch for Arduino или сокращённо S4A. Найти и скачать эту программу можно по адресу: http://seaside.citilab.eu/scratch/arduino. Я не знаю, как точно переводится название программы, но «to begin from scratch» переводится, как «начать с нуля».

На сайте проекта S4A есть версии для Windows и Linux, но для последней операционной системы готовая к установке программа в версии дистрибутива Debian. Не хочу сказать, что её нельзя использовать с другими дистрибутивами Linux, но вначале посмотрим, как работать в программе с модулем Arduino в Windows.

После установки программы обычным образом можно настроить интерфейс на русский язык, используя переключатель языков.

Рис. 4.2. Переключатель языков интерфейса программы

Первый значок инструментальной панели, если его нажать, отображает все возможные языки интерфейса программы. Русский язык можно найти в разделе…

Рис. 4.3. Список языков для использования в интерфейсе программы

… отмеченном, как «больше…».

Если ничего не предпринимать, то надпись в правом окне «Searching board…» остаётся, но модуль не находится. Чтобы модуль Arduino подключить к программе S4A, следует загрузить с сайта проекта ещё кое-что.

Рис. 4.4. Файл для загрузки в модуль Arduino для S4A

Этот файл не что иное, как программа для Arduino (Sketch). То есть, текстовый файл, который можно скопировать в редактор Arduino, откомпилировать и загрузить в модуль. После выхода из программы Arduino можно запустить программу S4A и теперь модуль находится.

Рис. 4.5. Подключение модуля к программе

Аналоговые входы модуля не подключены, как и цифровые, поэтому значения, отображаемые для модуля, постоянно меняются произвольным образом.

Начать свой путь в IT бывает очень сложно хотя бы просто потому, что глядя на окружающие технологии невозможно отделить «железный» интерес от программного. С одной стороны - желание создать устройство с безупречным внешним видом, множеством датчиков и безграничными возможностями, с другой - таинство обработки данных, стремление максимально увеличить быстродействие, не пренебрегая функциональностью. Arduino - первый шаг к большим изобретениям, не требующий ни глубоких знаний схемотехники, ни опыта в программировании.

Что такое Arduino

Если называть вещи своими именами, то Arduino - это конструктор для тех, кому надоело созидать бесполезные образы и захотелось хоть немного наделить их жизнью. В самом простейшем случае Arduino - печатная плата, на которой расположен контроллер, кварцевый генератор, АЦП/ЦАП, несколько разъёмов, диодов и кнопок. Остальное - дело рук хозяина: хотите - создавайте робота, хотите - программно-аппаратную платформу для «умного» дома, ну или забудьте про практическую пользу и развлекайтесь .

Конечно, в зависимости от того. насколько далеко вы хотите зайти в своих экспериментах, хотите ли вы получать фильтрованное удовольствие или сделать из Arduino платформу для собственного заработка, вам придётся совершенствоваться и в проектировании железа, и в изучении языков программирования. О последнем сегодня чуть подробнее.

Arduino достаточно ограниченная платформа в плане возможностей программирования, особенно в сравнении с Raspberry Pi. В силу того, что порог входа неприлично низкий (базовый Tutorial занимает 3 листа формата A4), то рассчитывать на изобилие языков без подключения дополнительных модулей не приходится. За основу здесь принят C/C++ , но с использованием различных IDE и библиотек вы получите доступ к оперированию Python, C#, Go, а также таким детским развлечениям, как Snap! и ArduBlock. О том как, когда и кому их использовать, поговорим далее.

C/C++

Базовый язык платформы Arduino, который с некоторыми доработками и упрощениями используется в стандартной программной оболочке. Найти все доступные команды «для новичка» можно , но никто не мешает вам воспользоваться исходными возможностями языка C++, никаких надстроек не потребуетс. Если же есть желание поиграть с «чистым» C, то к вашим услугам программа , предназначенная, как следует из названия, для взаимодействия ОС Windows и МК серии AVR, которые и используются на Arduino. Более подробное руководство можете прочитать вот .

Ardublock

Временно отойдем от языков взрослых к любимому ребятней языку Scratch, а вернее к его адаптации - Ardublock. Здесь всё тоже самое, но с адаптацией к вашей платформе: цветные блоки, конструктор, русские названия, простейшая логика. Такой вариант здорово подойдет даже тем, кто с программированием не знаком вовсе. Подобно тому, как в языке Logo вы можете перемещать виртуальную черепашку по виртуальной плоскости, здесь с помощью нехитрых операций вы можете заинтересовать ребенка реальной интерпретацией его программных действий.

Да, кстати, для использования необходимо на вашу стандартную среду Arduino IDE установить . Последние версии лучше не хватать, они довольно сложные, для начала подойдет датированная концом 2013 года. Для установки скачанный файл переименовываем в «ardublock-all» и запихиваем в папку «Мои документы/Arduino/tools/ArduBlockTool/tool». Если её не существует - создаем. Если что-то не поняли, то вот более подробно.

Snap!

По сравнению с Ardublock, Snap! имеет расширенные возможности в виде дополнительных блоков, возможности использования списков и функций. То есть Snap! в общем и целом уже похож на взрослый язык программирования, не считая, что вам по прежнему необходимо играть в конструктор кода.

Для того, чтобы использовать этот язык, придется сходить на сайт snap4arduino.org и скачать необходимые компоненты для вашей ОС. Инструкции по установке, использованию и видеопримеры ищите здесь же.

Python

Формально программировать на Arduino вы можете используя хоть язык Piet, просто потому что при должном упорстве вы скомпилируете в машинный код что угодно. Но в силу того, что Python - один из наиболее популярных языков с практически оптимальным сочетанием сложность\возможности, то обойти стороной его применяемость в Arduino было бы нелепо. Начать изучение Python вы можете с нашего бесплатного .

Итак, для этого вам понадобится библиотеки PySerial (ранее, возможно, вы использовали её для общения с портами компьютера) и vPython . О том, как правильно всё настроить и заставить в конечном счёте работать, можете соответственно почитать и .

Go и другие языки.

Подобно тому, как Arduino взаимодействует с Python через библиотеку PySerial, он может взаимодействовать и с , и c Java , и с HTML , и с чем только захотите. Arduino - достаточно популярная платформа, чтобы такой банальный вопрос, как выбор удобного языка, не остановил очередного исследователя. Единственное, что требуется от владельца этой маленькой платы - задумать что-нибудь удивительно интересное, а удобный инструмент неизбежно найдётся.

Вам понадобится

  • - плата Arduino UNO,
  • - кабель USB (USB A - USB B),
  • - персональный компьютер,
  • - светодиод,
  • - резистор 220 Ом,
  • - пара проводов 5-10 см,
  • - при наличии - макетная плата (breadboard).

Инструкция

Загрузите среду разработки Arduino для своей операционной системы (поддерживаются ОС Windows, Mac OS X, Linux) на странице http://arduino.cc/en/Main/Software, можно установщик, можно . Скачанный файл содержит также и драйверы для плат Arduino.

Установите драйвер. Рассмотрим вариант для ОС Windows. Для этого дождитесь, когда операционная система предложит установить драйвер. Откажитесь. Нажмите Win + Pause, запустите Диспетчер устройств. Найдите раздел "Порты (COM & LPT)". Увидите там порт с названием "Arduino UNO (COMxx)". Кликните правой кнопкой мыши на нём и выберите "Обновить драйвер". Далее выбираете расположение драйвера, который вы только что скачали.

Среда разработки уже содержит в себе множество примеров для изучения работы платы. Откройте пример "Blink": Файл > Примеры > 01.Basics > Blink.

Укажите среде разработки свою плату. Для этого в меню Сервис > Плата выберите "Arduino UNO".

Выберите порт, которому назначена плата Arduino. Чтобы узнать, к какому порту подключена плата, запустите диспетчер устройств и найдите раздел Порты (COM & LPT). В скобках после названия платы будет указан порта. Если платы нет в списке, попробуйте её от компьютера и, выждав несколько секунд, подключить снова.

Отключите плату от компьютера. Соберите схему, как показано на рисунке. Обратите внимание, что короткая ножка светодиода должна быть соединена с выводом GND, длинная через резистор с цифровым пином 13 платы Arduino. Удобнее пользоваться макетной платой, но при её отсутствии можно соединить провода скруткой.
Важное примечание! Цифровой пин 13 уже имеет свой резистор на плате. Поэтому при подключении светодиода к плате внешний резистор использовать не обязательно. При подключении светодиода к любым другим выводам Ардуино использование токоограничивающего резистора обязательно!

Теперь можно загрузить программу в память платы. Подключите плату к компьютеру, подождите несколько секунд, пока происходит инициализация платы. Нажмите кнопку "Загрузить", и Ваш скетч запишется в память платы Arduino. Программирование под Arduino весьма интуитивно и совсем не сложно. Посмотрите на изображение - в комментариях к программе есть небольшие пояснения. Этого достаточно чтобы разобраться с вашим первым экспериментом.

Каждый язык программирования имеет набор команд управления, обеспечивающих многократное выполнение одного и того же кода (цикл), выбор подходящего фрагмента кода (условия) и инструкции для выхода из текущего фрагмента кода.

Arduino IDE позаимствовал с C/C++ большинство необходимых элементов управления. Их синтаксис идентичен с C. Ниже мы в двух словах опишем их синтаксис.

Оператор if

Оператор if позволяет выполнить определенный фрагмент программы в зависимости от результата проверки определенного условия. Если условие выполняется, то код программы будет выполнен, если же условие не выполняется, то код программы будет пропущен. Синтаксис команды if выглядит следующим образом:

If(условие) { инструкция1; инструкция2; }

Условием может быть любое сравнение переменной или значения, возвращаемое функцией. Основным критерием условия if является то, что ответ всегда должен быть или истина (true) или ложь (false). Примеры условий для оператора if:

if(a!=2) { } if(x<10) { } if(znak==’B’) { }

Внутри скобок, которые прописаны внутри условия, можно выполнить код.

Люди, которые приступают к изучению программирования, часто делают ошибку, приравнивая значение указанной переменной с помощью одного знака «=». Такая запись однозначно указывает на присвоение значения переменно, и, следовательно, условие всегда будет «true», то есть выполняться. Проверка того, что переменная равна определенному значению, всегда обозначается двойным знаком равно (==).

В качестве условия можно использовать состояние функции, например:

If(init()) { Serial.print(«ок»); }

Приведенный выше пример будет выполнен следующим образом: на первом этапе вызывается функция init(). Эта функция возвращает значение, которое будет интерпретировано как «true» или «false». В зависимости от результата сравнения будет отправлен текст «ок» или ничего не будет отправлено.

Оператор if…else

Расширенным оператором if является оператор if….else. Он обеспечивает выполнение одного фрагмента кода, когда условие выполняется (true), и выполнение второй фрагмент кода, если условие не выполняется (false). Синтаксис операторf if….else выглядит следующим образом:

If (условие) { // команда A } else { // команда B }

Команды «A» будут выполняться только в том случае, если условие выполнено, команда «B» будет выполняться, когда условие не выполнено. Одновременное выполнение команды «A» и «B» невозможно. Следующий пример показывает, как использовать синтаксис if…else:

If (init()) { Serial.print(«ок»); } else { Serial.print(«ошибка»); }

Подобным образом можно проверить правильность выполнения функции и информировать об этом пользователя.

Обычной практикой является отрицание условия. Это связано с тем, что функция, которая выполнена правильно возвращает значение 0, а функция, которая отработала неверно по какой-то причине, возвращает ненулевое значение.

Объяснение такого «усложнения жизни» — просто. Если функция выполнена правильно, то это единственная информация, которая нам нужна. В случае же ошибки, стоит иногда понять, что пошло не так, почему функция не выполнена правильно. И здесь на помощь приходят числа, отличающиеся от нуля, т. е. с помощью цифровых кодов мы можем определить тип ошибки. Например, 1 — проблема с чтением какого-то значения, 2 — нет места в памяти или на диске и т. д.

В последнем измененном примере показано, как вызвать функцию, которая возвращает ноль при правильном выполнении:

If (!init()) { Serial.print(«ок»); } else { Serial.print(«ошибка»); }

Оператор switch case

Оператор if позволяет проверить только одно условие. Иногда необходимо выполнить одно из действий в зависимости от возвращаемого или прочитанного значения. Для этого идеально подходит оператор множественного выбора switch. Ниже показан синтаксис команды switch:

Switch (var) { case 1: //инструкция для var=1 break; case 2: // инструкция для var=2 break; default: // инструкция по умолчанию (если var отличается от 1 и 2) }

В зависимости от значения переменной var выполняются инструкции в определенных блоках. Метка case означает начало блока для указанного значения. Например, case 1: означает, что данный блок будет выполнен для значения переменной var, равной один.

Каждый блок должен быть завершен с помощью команды break. Он прерывает дальнейшее выполнение оператора switch. Если команду break пропустить, то инструкции будут выполняться и в последующих блоках до команды break. Метка default не является обязательной, как и else в команде if. Инструкции, расположенные в блоке default выполняются только тогда, когда значение переменной var не подходит ни к одному шаблону.

Часто бывает так, что одни и те же инструкции должны быть выполнены для одного из нескольких значений. Это можно достичь следующим образом:

Switch (x) { case 1: //инструкция для x=1 break; case 2: case 3: case 5: // инструкция для x=2 или 3 или 4 break; case 4: // инструкция для x=4 break; case 6: // инструкция для x=6 break; default: // инструкция по умолчанию (если х отличается от 1,2,3,4,5,6) }

В зависимости от значения переменной x будет выполнен соответствующий блок инструкций. Повторение case 2: case 3: case 5: информирует компилятор о том, что если переменная x имеет значение 2 или 3 или 5, то будет выполнен один и тот же фрагмент кода.

Оператор for

Оператор for используется для многократного выполнения одного и того же кода. Часто необходимо выполнить одни и те же инструкции, изменив только значение какой-то переменной. Для этого идеально подходит цикл for. Синтаксис команды выглядит следующим образом:

Int i; for(i=0;i<10;i++) { // инструкции для выполнения в цикле }

Первый параметр, приводимый в инструкции for — начальное значение переменной. Еще один элемент — это проверка условия о продолжении выполнения цикла. Цикл выполняется до тех пор, пока выполняется условие. Последний элемент — это изменение значения переменной. Чаще всего мы увеличиваем или уменьшаем ее значение (по необходимости). В этом примере, инструкции, содержащиеся в цикле будут выполняться при i=0…9.

Часто переменная, используемая в цикле объявляется там же:

For(int i=0;i<10;i++) { // инструкции для выполнения в цикле }

Переменная, которая используется для подсчета последующих шагов цикла, может использоваться внутри нее для вызова функции с соответствующими параметрами.

For(int i=10;i>0;i—) { Serial.print(i); // отправятся номера 10,9,8,7,6,5,4,3,2,1 }

Оператор while

Цикл for идеально подходит там, где мы хотим выполнить подсчет. В ситуации, когда необходимо выполнить определенные действия в результате какого-то события, которое не обязательно является предсказуемым (например, мы ждем нажатия кнопки), то мы можем использовать оператор while, который выполняет блок оператора до тех пор, пока выполняется условие. Синтаксис оператора while выглядит следующим образом:

While(условие) { // блок инструкций для выполнения }

Важно, чтобы проверка состояния происходила в начале цикла. Может случиться так, что инструкции внутри цикла while не исполняться никогда. Кроме того, возможно создание бесконечного цикла. Давайте посмотрим два примера:

Int x=2; while(x>5) { Serial.print(x); } —————————————- int y=5; while(y>0) { Serial.print(y); }

Первый блок операторов, расположенный внутри while не выполнится никогда. Переменная x имеет значение два и она не станет больше 5. Во втором примере мы имеем дело с бесконечным циклом. Переменная «y» имеет занчение 5, т. е. больше нуля. Внутри цикла не происходит никакого изменения переменной «y», поэтому цикл никогда не будет завершен.

Это распространенная ошибка, когда мы забываем об изменении параметра, вызывающего прекращение цикла. Ниже приведено два правильных примера применения цикла while:

Int x=0; while(x<10) { //блок инструкций x++; } —————————————- while(true) { if(условие) break; // блок инструкций }

В первом примере мы позаботились об изменении значения переменной, которая проверяется в условии. В результате цикл когда-нибудь завершится. Во втором примере был преднамеренно создан бесконечный цикл. Этот цикл эквивалентен функции loop () в Arduino IDE. Кроме того, внутри цикла введена проверка условия, после выполнения которого цикл завершается командой break.

Оператор do…while

Разновидностью цикла while является цикл do…while. Кроме синтаксиса он отличается местом проверки условия. В случае do…while проверка условия производится после выполнения блока инструкций. Это означает, что блок инструкций в теле цикла выполнится хотя бы один раз. Ниже приведен синтаксис команды do…while:

Do { // блок инструкций } while(условие)

Все, что написано об операторе while относится также и к do…while. Ниже приведен пример использования цикла do…while:

Int x=10; do { // блок инструкций x—; } while(x>0); —————————————- do { // блок инструкций if(условие) break; } while(true);

Оператор break

Оператор break позволяет выйти из цикла (do…while, for, while) и выйти из опции switch. В следующем примере рассмотрим выполнение команды break:

For(i=0;i<10;i++) { if(i==5) break; Serial.print(i); }

Цикл должен быть исполнен для чисел от 0 до 9, но для числа 5 выполняется условие, которое запускает оператор break. Это приведет к выходу из цикла. В результате в последовательный порт (Serial.print) будет отправлены только числа 0,1,2,3,4.

Оператор continue

Оператор continue вызывает прекращение выполнения инструкций цикла (do…while, for, while) для текущего значения и переход к выполнению следующего шага цикла. В следующем примере показано, как работает оператор continue:

For(i=0;i<10;i++) { if(i==5) continue; Serial.print(i); }

Как не трудно заметить, цикл будет выполнен для значения от 0 до 9. Для значения 5 исполнится команда continue, в результате чего инструкции, находящиеся после этой команды выполнены не будут. В результате в последовательный порт (Serial.print) будут отправлены числа 0,1,2,3,4,6,7,8,9.

Оператор return

Оператор return завершает выполнение вызываемой функции и возвращает значение определенного типа. В качестве параметра команды можно указать число, символ или переменную определенного типа. Важно, чтобы возвращаемое значение соответствует типу заявленной функции. В следующем примере показано, как использовать оператор return:

Int checkSensor(){ if (analogRead(0) > 400) { // чтение аналогового входа return 1; // Для значений больше 400 возвращается 1 else{ return 0; // для других возвращается 0 } }

Как вы можете видеть, в одной функции можно использовать несколько операторов return, но сработает всегда только один из них. Допустимо использование оператора return без параметров. Это позволяет досрочно прекратить работу функции, которая не возвращает никакого значения.

Void имя_функции() { инструкция1; if(x==0) return; инструкция2; инструкция3; }

В приведенном выше примере инструкция1 будет выполнять всегда, когда вызывается функция. Выполнение же инструкция2 и инструкция3 зависит от результата команды if. Если условие будет выполнено (true), то будет выполнена команда return и функция завершит работу.

В случае, когда условие не выполнено команда return так же не выполняется, а выполняются инструкции инструкция2 и инструкция3, и после этого функция завершает свою работу.

Оператор goto

Из идеологических соображений необходимо пропустить это описание… Оператор goto является командой, которую не следует использовать в обычном программировании. Он вызывает усложнения кода и является плохой привычкой в программировании. Настоятельно рекомендуем не использовать эту команду в своих программах. Из-за того, что goto есть в официальной документации на сайте arduino.cc приведем его краткое описание. Синтаксис команды goto:

…. goto metka; // перейдите на строку с надписью ‘metka’ ….. …. …. metka: // метка, с которой программа продолжит работу …

Команда позволяет переход к обозначенной метке, т. е. к месту в программе.

Лучшие статьи по теме