на главную

Автоматизация технологических процессов при помощи микроконтроллеров

1. Режим работы пинов
1/11
В уроке про возможности микроконтроллера мы обсуждали такое понятие, как GPIO – входы-выходы общего назначения, которые позволяют читать и выдавать цифровой сигнал.
На плате выведенные GPIO подписаны как Dцифра мы можем обращаться к ним по этой нумерации
К пинам GPIO, подписанным как D (D0-D13), можно обращаться по номеру: D2 – просто 2.
Режимы работы пинов
Цифровой пин может находиться в двух состояниях, вход и выход. В режиме входа пин может считывать напряжение от 0 до напряжения питания МК, а в режиме выхода – выдавать такое же напряжение. Режим работы выбирается при помощи функции pinMode(pin, mode), где pin это номер пина, а mode это режим:
• INPUT – вход
• OUTPUT – выход
• INPUT_PULLUP – подтянутый к питанию вход
Если со входом/выходом всё понятно, то с подтяжкой давайте разберёмся. В режиме входа пин МК не подключен никуда и ловит из воздуха всякие наводки, получая практически случайное значение. Для задания пину “состояния по умолчанию” используют подтяжку резистором к земле или питанию. Режим INPUT_PULLUP включает встроенную в микроконтроллер подтяжку пина к питанию при помощи внутреннего резистора
Вывод цифрового сигнала
Цифровой пин в режиме выхода (OUTPUT) может генерировать цифровой сигнал, т.е. выдавать напряжение. Так как понятие “цифровой” обычно связано с двумя состояниями, 0 и 1, цифровой пин тоже может выдать 0 или 1, точнее сигнал низкого или высокого уровня:
• Сигнал низкого уровня это 0V, пин подключается к GND микроконтроллера.
• Сигнал высокого уровня подключает пин к VCC микроконтроллера, то есть к питанию.
Пример:
digitalWrite(pin, value):

pin – пин GPIO (нумерацию смотри выше).
value – уровень сигнала: HIGH высокий, LOW низкий. Также можно использовать цифры 1 и 0 соответственно.

Чтение цифрового сигнала

Цифровой пин может измерять напряжение, но сообщить он может только о его отсутствии (сигнал низкого уровня, LOW) или наличии (сигнал высокого уровня, HIGH), причём отсутствием напряжения считается промежуток от 0 до ~VCC/2 Вольт, а от VCC/2 до VCC микроконтроллер считает за наличие сигнала высокого уровня.
Для чтения уровня сигнала на пине используется функция digitalRead(pin), где пин – номер GPIO (нумерацию смотри выше).
1
delay(2000)
2
#define pin 5
3
digitalWrite (pin, HIGH)
4
digitalWrite (pin, LOW)
5
pinMode(pin, OUTPUT)
6
delay(1000)
В уроке про возможности микроконтроллера мы обсуждали такое понятие, как GPIO – входы-выходы общего назначения, которые позволяют читать и выдавать цифровой сигнал. На плате выведенные GPIO подписаны как Aцифра и в программе мы можем обращаться к ним по этой нумерации.
К пинам GPIO, подписанным как A (A0-A5), можно обращаться по подписи на плате: A2 – A2. Также нумерация A пинов продолжает нумерацию D пинов по порядку, то есть A0 это 14, A1 это 15.. A5 – 19.
Чтение сигнала
“Аналоговые” пины могут принимать напряжение от 0V (GND) до опорного напряжения и преобразовывать его в цифровое значение, просто в какие-то условные единицы. АЦП на AVR и esp8266 имеет разрядность в 10 бит, т.е. мы получаем измеренное напряжение в виде числа от 0 до 1023.
Функция, которая оцифровывает напряжение, называется analogRead(pin). Она принимает в качестве аргумента номер аналогового пина и возвращает оцифрованное напряжение. Сам пин должен быть сконфигурирован как INPUT (вход).
1.
2.
Простейшей с точки зрения использования функцией времени является задержка: программа “зависает” внутри функции задержки и ожидает указанное время. Задержка позволяет очень удобно и наглядно организовать работу простой “однозадачной” программы, у нас есть два варианта задержек:

• delay(time)
o Задержка на указанное количество миллисекунд (мс). 1 секунда = 1’000 мс.
o time принимает тип данных unsigned long и может приостановить выполнение на срок от 1 до 4 294 967 295 мс (~50 суток) с разрешением 1 мс.
o Работает на системном таймере, поэтому не работает внутри прерывания и при отключенных прерываниях.
• delayMicroseconds(time)
o Задержка на указанное количество микросекунд (мкс). 1 секунда = 1’000’000 мкс.
o time принимает тип данных unsigned int и может приостановить выполнение на срок от 4 до 16383 мкс (да, меньше чем максимум для этого типа данных) с разрешением 4 мкс.
o Работает не на таймере, а на пропуске тактов процессора, поэтому может работать в прерывании и при отключенных прерываниях.
o Иногда не совсем корректно работает с переменными, поэтому нужно стараться использовать константы (const или просто число).
o Часто используется в библиотеках для эмуляции цифровых интерфейсов связи.

Функция yield()

Разработчики Arduino позаботились о том, чтобы функция delay() не просто блокировала выполнение кода, но и позволяла выполнять другой код во время этой задержки. Данная функция получила название yield() и работает следующим образом: если объявить функцию то расположенный внутри неё код будет выполняться во время работы любой задержки delay() в программе.

Функции счёта времени

Данные функции возвращают время, прошедшее с момента запуска программы, так называемый аптайм (англ. uptime). Таких функций у нас две:
• millis() – миллисекунды, тип unsigned long, от 1 до 4 294 967 295 мс (~50 суток), разрешение 1 мс. После “переполнения” отсчёт начинается с нуля.
• micros() – микросекунды, тип unsigned long, от 4 до 4 294 967 295 мкс (~70 минут), разрешение 4 мкс. После “переполнения” отсчёт начинается с нуля.
Эти функции позволяют организовать программу практически любой сложности с любым количеством параллельно выполняющихся по таймеру задач.
boolean LEDflag = false; void setup() { pinMode(13, OUTPUT); } void loop() { digitalWrite(13, LEDflag); LEDflag = !LEDflag; delay(1000); }
boolean LEDflag = false; uint32_t myTimer; void setup() { pinMode(13, OUTPUT); } void loop() { if (millis() - myTimer >= 1000) { myTimer = millis(); digitalWrite(13, LEDflag); LEDflag = !LEDflag; } }
uint32_t myTimer1, myTimer2, myTimer3; void setup() {} void loop() { if (millis() - myTimer1 >= 500) { myTimer1 = millis(); } if (millis() - myTimer2 >= 333) { myTimer2 = millis(); } if (millis() - myTimer3 >= 100) { myTimer3 = millis(); } }
void setup() { pinMode(13, OUTPUT); pinMode(12, INPUT); } void loop() { digitalWrite(13, 1); delay(1000); digitalWrite(13, 0); delay(1000); } void yield() { bool btn = digitalRead(12); fi(btn){ digitalWrite(13, 0); } }
В программе реализовано моргание светодиодом каждую 1 секунду с задержкой.
В программе реализовано не прерывное моргание светодиодом каждую 1 секунду.
В программе реализовано независимое моргание 3 светодиодами каждый светодиод загарается и тухнет с разной частотой.
В коде предусмотрен опрос кнопки в момент задержек выполнения основного цикла программы.
У многих микроконтроллеров есть интерфейс UART, позволяющий передавать и принимать различные данные. У интерфейса есть два вывода на плате – пины TX и RX. На большинстве Arduino-плат к этим пинам подключен USB-UART преобразователь (расположен на плате), при помощи которого плата может определяться компьютером при подключении USB кабеля и обмениваться с ним информацией. На компьютере создаётся виртуальный COM порт (последовательный порт), к которому можно подключиться при помощи программ-терминалов и принимать-отправлять текстовые данные.
В самой Arduino IDE есть встроенная “консоль” – монитор порта, кнопка с иконкой лупы в правом верхнем углу программы. Нажав на эту кнопку мы откроем сам монитор порта, в котором будут настройки.
Объект Serial
Serial позволяет просто принимать и отправлять данные через последовательный порт.
Serial.begin(speed) - Запустить связь по Serial на скорости speed (измеряется в baud, бит в секунду). (стандартная скорость 9600)
Serial.end() - Прекратить связь по Serial. Также освобождает пины RX и TX.
Serial.available() - Возвращает количество байт, находящихся в буфере приёма и доступных для чтения.
Serial.availableForWrite() - Возвращает количество байт, которые можно записать в буфер последовательного порта, не блокируя при этом функцию записи.
Serial.write(val), Serial.write(buf, len) - Отправляет в порт val численное значение или строку, или отправляет количество len байт из буфера buf. Важно! Отправляет данные как байт (см. таблицу ASCII), то есть отправив 88 вы получите букву X: Serial.write(88);
Serial.print(val), Serial.print(val, format) - Отправляет в порт значение val – число или строку, фактически “печатает”. В отличие от write выводит именно текст, т.е. отправив 88, вы получите 88: Serial.print(88);. Отправляет любые стандартные типы данных: численные, символьные, строковые. Также методы print()/println() имеют несколько настроек для разных данных. format позволяет настраивать вывод данных: BIN, OCT, DEC, HEX выведут число в соответствующей системе счисления: двоичная, восьмеричная, десятичная (по умолчанию) и 16-ричная. Цифра после вывода float позволяет настраивать выводимое количество знаков после точки
Serial.println(), Serial.println(val), Serial.println(val, format) - Полный аналог print(), но автоматически переводит строку после вывода. Позволяет также вызываться без аргументов (с пустыми скобками) просто для перевода курсора на новую строку.
Serial.flush() - Ожидает окончания передачи данных.
Serial.peek() - Возвращает текущий байт с края буфера, не убирая его из буфера. При вызове Serial.read() будет считан тот же байт, но из буфера уже уберётся.
Serial.read() - Читает и возвращает крайний символ из буфера.
Serial.setTimeout(time) - Устанавливает time (миллисекунды) таймаут ожидания приёма данных для следующих ниже функций. По умолчанию равен 1000 мс (1 секунда).
Serial.find(target), Serial.find(target, length) - Читает данные из буфера и ищет набор символов target (тип char), опционально можно указать длину length. Возвращает true, если находит указанные символы. Ожидает передачу по таймауту.
Плоттер
Помимо монитора последовательного порта, в Arduino IDE есть плоттер – построитель графиков в реальном времени по данным из последовательного порта. Достаточно отправлять значение при помощи команды Serial.println(значение) и открыть плоттер по последовательному соединению, например построим график значения с аналогового пина A0:
Пример:
void setup() {
Serial.begin(9600);
}
void loop() {
Serial.println(analogRead(0));
delay(10);
}
Плоттер поддерживает несколько линий графиков одновременно, для их отображения нужно соблюдать следующий протокол отправки данных: значения выводятся в одну строку, одно за другим по порядку, разделяются пробелом или запятой и в конце обязательно перенос строки.
значение1 пробел_или_запятая значение2 пробел_или_запятая значение3 пробел_или_запятая перенос_строки
void setup() { Serial.begin; } void loop() { Serial.print(analogRead(0)); Serial.print(','); Serial.print(analogRead(1)); Serial.print(','); Serial.print(analogRead(2)); Serial.println(); delay(5); }
void setup() { Serial.begin(9600); }; { Serial.print(analogRead(0)); Serial.print(','); Serial.print(analogRead(1)); Serial.print(','); Serial.print(analogRead(2)); Serial.println(); delay(5); }
void setup() { Serial.begin(9600); } void loop() { Serial.print(analogRead(0)); Serial.print(','); Serial.print(analogRead(1)); Serial.print(','); Serial.print(analogRead(2)); Serial.println(); delay(5); }
#define
float
char
int
const byte
byte

! логическое

&& логическое

|| логическое

1
Читает состояние пина pin и возвращает
2
Устанавливает режим работы пина pin (ATmega 328: D0-D13, A0-A5) на режим mode
3
Подаёт на пин pin сигнал value
На главную