В этом уроке
- Что такое переменные. Типы переменных
- Как обойтись без delay() и почему это необходимо
- Параллельное выполнение нескольких задач
- Системное время и как с ним работать
- Условный оператор
Видео версия урока
Переменные
В жизни Вы часто сталкивались с переменными, когда работали с какой-либо формулой. Например, в формуле закона Ома I = U/R, U и R — это переменные, вместо которых мы подставляем числа, чтобы найти значение I. Точно таким же образом переменные можно использовать и в программировании.
Вместе с тем, очень часто возникает необходимость менять какие-либо значения. Включение-выключение светодиода — вот к примеру постоянно меняющееся значение. Время, прошедшее с момента начала выполнения программы, — ещё одно значение и т.д. Эти данные удобно записывать в переменные — своеобразные ящики для хранения информации.
Переменные имеют свой тип, который показывает, данные какого размера и с каким знаком можно в них записать. Например, включенный/выключенный светодиод может иметь только два состояния и никак не больше, поэтому рациональнее будет использовать переменную типа bool, которая может хранить только два значения: 1 или 0 ( true или false). А вот в переменную со значением времени может быть записано очень большое число, и для его записи обычно пользуются типом unsigned long, который вмещает числа от 0 до 4294967295.
Для работы с переменной её необходимо сначала создать:
bool ledState; // Создаём переменную с именем ledState типа bool
Значение в переменной можно менять при необходимости, например:
ledState = 1; // Записываем в переменную ledState значение 1
И, разумеется, это значение можно считать:
bool ledState = 1; // Создаём переменную с именем ledState типа bool и сразу присваиваем ей значение 1 bool x; // Создаём переменную с именем x. Так как мы не указали значение, по умолчанию она равна 0 x = ledState; // Присваиваем переменной x значение переменной ledState // Теперь и ledState, и x равны 1
Называть переменные можно как угодно, но лучше, чтобы названия отражали назначение переменной (х — плохое название, так как непонятно, для чего она нужна).
Ниже мы привели самые распространённые типы переменных. Они могут записываться с помощью нескольких вариантов, приведенных в первом столбце.
Тип переменной | Возможные значение | Назначение |
bool boolean | 0, 1 (или false, true) | Целочисленные значения |
char int8_t | -128...127 (или 'a'...'z') | Целочисленные значения или символы |
byte uint8_t | 0...255 | Беззнаковые целочисленные значения |
int int16_t | -32768...32767 | Целочисленные значения |
unsigned int uint16_t | 0...65535 | Беззнаковые целочисленные значения |
long int32_t | -2147483648...2147483647 | Целочисленные значения |
unsigned long uint32_t | 0...4294967295 | Беззнаковые целочисленные значения |
float | -2147483648,0...-2147483647,0 | Числа с плавающей точкой |
Формально, можно всем переменным в программе присвоить тип long, но лучше так не делать, т.к. чем большее значение может вместить переменная, тем больше места она займёт в памяти контроллера. И даже если Вы записываете в переменную значение 0 или 1, а тип переменной — long, в памяти контроллера она займет столько же места, как если бы Вы записали в неё число, например, 1546834346. Поэтому лучше использовать типы переменных подходящего размера.
Важность применения принципа многозадачности
До этого момента для установки длительности какого-либо действия (время вращения мотора или время его паузы, время звучания зуммера и т.д.) мы использовали функцию delay(). Однако, мы сразу сказали, что её крайне нежелательно использовать в настоящих проектах для управления модулями.
Дело в том, что время, указанное в этой функции, контроллер расходует впустую — он не может выполнять никаких действий, он просто ждёт, пока это время закончится. А ведь он мог бы считывать показания датчиков, регулировать скорость двигателей и т.д. Поэтому сейчас мы рассмотрим принцип, позволяющий не останавливать работу контроллера.
Приведённый ниже скетч позволяет одновременно мигать светодиодом на плате и воспроизводить звук полицейской сирены с помощью зуммера. Зуммер, как и в предыдущих уроках, остаётся быть подключенным к 6 пину.
long timeLed; // Переменная, хранящая время включения светодиода long zumStart; // Переменная, хранящая время последнего изменения частоты зуммера (для создания эффекта сирены) bool ledState = 0; // Состояние светодиода: 0 - выключен, 1 - включен int i = 0; // Начало отсчёта для увеличения частоты зуммера void setup(){ pinMode (6, OUTPUT); // 6 пин - выход. К нему подключен зуммер pinMode (13, OUTPUT); // 13 пин - выход. К нему подключен светодиод (на плате) } void loop(){ if (timeLed + 150 < millis()){ // Если с момента последнего изменения состояния прошло более 150 мс ledState = !ledState; // Инвертируем (меняем на противоположное) состояние светодиода timeLed = millis(); // Обновляем время смены состояния. В следующем цикле отсчёт будет идти уже от него } digitalWrite (13, ledState); // Записываем состояние (зажигаем или гасим светодиод). if (zumStart + 15 < millis()){ // Если с момента последнего изменения тона прошло больше 15 миллисекунд zumStart = millis(); // Обновляем время смены тона i++; // Увеличиваем значение для пересчёта тона if (i >= 255) i = 0; // Если произошло переполнение, сбрасываем в 0 int res = (sin((2*PI*i)/128)+1)*45+160; // Формула для расчёта тона через синус tone(6, res*3); // Генерируем звуковой сигнал на 6 выводе } }
Как реализуется многозадачность
Функция millis() — функция, возвращающая значение времени в миллисекундах, прошедшее с момента запуска программы. Если задать переменной значение времени, полученное от этой функции, а потом сравнивать его с текущим временем, то можно узнать, сколько времени прошло с момента задания этого времени в переменную.
Например, инструкция timeLed = millis() (13 строка) записывает в переменную timeLed системное время момента, когда изменилось состояние светодиода (12 строка). Далее, ориентируясь на текущее системное время, мы можем сделать вывод о том, сколько времени прошло (11 строка). Если это время больше заданного значения ( в нашем случае это 150 мс), то состояние светодиода меняется.
Таким образом, можно организовать параллельное выполнение множества процессов. Посмотрите — одновременно со светодиодом мы управляем ещё и зуммером (17-23 строки). При использовании функции delay() сделать это было бы невозможно.
Также, как Вы уже заметили, мы используем условие: if ( УСЛОВИЕ ) { ДЕЙСТВИЕ }.
ДЕЙСТВИЕ выполнится в том случае, если будет истинно УСЛОВИЕ, записанное в скобках.
Обсуждение