Промышленное производство
Промышленный Интернет вещей | Промышленные материалы | Техническое обслуживание и ремонт оборудования | Промышленное программирование |
home  MfgRobots >> Промышленное производство >  >> Manufacturing Technology >> Производственный процесс

Как многопоточно на Arduino (Учебное пособие по протопоточности)

Компоненты и расходные материалы

Arduino UNO
× 1
Синий жидкокристаллический дисплей Sunfounder 16x2 (ЖКД)
× 1
Макет (общий)
и, конечно же, провода.
× 1
Поворотный потенциометр (общий)
Не уверен в рейтинге сопротивления, вероятно, подойдет 1 кОм.
× 1

Об этом проекте

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

  • Импульсная подсветка с постоянной частотой без прерывания.
  • Увеличение целого числа каждую секунду и запись его на дисплей без прерывания.
  • Ротация нескольких сообщений каждые несколько секунд и непрерывная запись их на дисплей.

Вы видели название!

Протопоточность - это способ выполнения того, что обычно является многозадачной операцией (выполнение двух или более действий одновременно или с разными интервалами) на Arduino . Другими словами, он «многопоточный»! Но подождите, Спарки, Arduino - это одноядерный чип с процедурным кодом, поэтому настоящая многопоточность невозможна. Но почему? Чем отличается протопоточность?

«Настоящая» многопоточность против протопоточности

Чтобы понять протопоточность правильно, нам сначала нужно понять, почему это НЕ действительно многопоточность.

Помните, в те времена, когда Intel продавала нам эту новую технологию «Hyperthreading» на процессорах Pentium? Нет? Вы еще не родились? Что ж, время для урока истории, сынок! Гиперпоточность - это технология, которую Intel использует для того, чтобы одно ядро ​​процессора «действовало», как два ядра, или два ядра «действовали», как будто они 4 ядра и т. Д. Но почему и как это имеет отношение к Arduino? Ответ - циклы.

И микроконтроллеры, и процессоры работают «циклами». Насколько быстро они их делают (сколько в секунду) - это тактовая частота. Вы видели рейтинг процессора в ГГц и, вероятно, знаете, что он связан с его скоростью. Чем больше Ghz, тем лучше, правда? но почему? Потому что это количество циклов в секунду, которое может достичь процессор (правда, без перегрева и возгорания!).

Если вы фанат технических данных, вы можете знать, что микропроцессорный чип Arduino Uno, Atmel ATMega328P, работает на частоте 16 МГц из коробки. Он способен работать на 20 МГц, но набирается обратно, поэтому он не испортит такие вещи, как запись данных в память (или, вы знаете, не загорится). 16 МГц означает, что каждую секунду ваш Arduino обрабатывает 16000000 циклов, то есть выполняет 16 миллионов операций. Теперь это НЕ строки кода - это было бы невероятно быстро, а Arduino относительно медленный. Это инструкции процессора, такие как перемещение данных в регистры и из них. Переход на более низкий уровень, чем этот обзор, становится довольно техническим, поэтому я оставлю это в качестве упражнения для читателя, но в этом суть :)

Итак, если мы сможем работать так быстро на ядре, прежде чем загорится лучший из доступных чипов, застрянем ли мы на этой скорости навсегда? Это самая быстрая работа, которую мы можем сделать? Оказывается, нет! Введите многоядерные процессоры и многопоточность. В ЦП компьютера многопоточные приложения - это два отдельных процесса, которые работают параллельно друг другу на разных ядрах ЦП. Эти процессы взаимодействуют для совместной работы, но не обязательно разделяют работу поровну, как вы могли предположить. Обычно существует главный процесс / «поток», который функционирует как менеджер других потоков, а затем один или несколько рабочих потоков, которыми он управляет, каждый из которых может выполнять определенные задачи. Хороший пример - Chrome. Chrome является менеджером всех вкладок (потоков) вашей веб-страницы, но поскольку Chrome многопоточен, каждая вкладка представляет собой свою собственную небольшую программу. Это означает, что он не только может работать быстрее, если у вас есть несколько ядер для распределения каждой вкладки, но и имеет другие преимущества, такие как отсутствие сбоя всего браузера при сбое одной вкладки. Это первая причина, по которой протопоточность не является многопоточностью - у нас есть только одно ядро ​​для работы на MCU, поэтому традиционная многопоточность прямо невозможна. Нам нужно управлять работой только на одном ядре, но при этом делать несколько дел одновременно. Нам нужна протопоточность.

Хорошо, а чем же тогда отличается Protothreading?

Протопоточность в некоторой степени похожа на то, что я упоминал о Hyperthreading. Гиперпоточность имитирует второе ядро ​​и буквально разделяет работу, которую выполняет одно ядро, притворяясь двумя виртуальными ядрами. Это сработало, потому что они действительно существовали в одном ядре и, следовательно, использовали одно и то же пространство ресурсов. Поскольку микроконтроллер arduino не поддерживает гиперпоточность, мы не можем сделать это здесь. Протопоточность аналогична, за исключением того, что вместо циклов и инструкций ЦП мы можем разбить работу на «циклы» или «строки» кода, выполняемые нашим скетчем. Как вы можете себе представить, если мы будем делать больше, циклы будут занимать больше времени, поэтому каждый проект будет иметь совершенно разные «циклы в секунду». Существуют разные реализации протопотоков, и тот, который я использую здесь, вероятно, дрянный, но он работает. В основном, с каждым циклом у нас нет другой работы, мы выполняем менее требовательную или менее частую работу в основном цикле (или вообще ничего). Когда мы не заняты, мы проверяем, не пора ли еще заняться чем-то другим. Если так, мы разойдемся и сделаем это. Важно отметить, что действия, которые являются «блокирующими», то есть они должны выполняться все сразу без прерывания и, таким образом, блокировать MCU на определенный период времени (например, считывание данных с SD-карты и некоторые другие задачи) все равно будет блокировать другие протопотоки происходят «вовремя», но для простых вещей, таких как одновременное выполнение двух циклов, выполняющих быстрые действия, такие как изменение переменных или изменение выходных значений, он будет работать превосходно. Это более или менее то, чем мы здесь будем заниматься. Некоторые микроконтроллеры поддерживают операционную систему реального времени (RTOS), которая может обеспечивать больше возможностей многозадачности, подобных гиперпоточности, что может помочь смягчить проблемы, вызванные «блокирующими» задачами.

Приступим.

Сначала выясняем, какие задачи нам нужно выполнить. В моем случае я выбрал (а) затемнение и затемнение подсветки моей ЖК-панели для аккуратного «пульсирующего» эффекта, в то время как (б) подсчет числа в гораздо более медленном (и, возможно, неделимом) интервале, и (c) чередование некоторых строковых сообщений с гораздо более медленным интервалом. Чтобы обеспечить бесперебойную работу этого процесса, необходимо следовать некоторым рекомендациям:оценивать свои функции от наименее блокирующего до наиболее блокирующего. Действия (с этого момента назовем их «функциями»), которые занимают больше времени, например, чтение данных или имеют другие длительные задержки, и функции с большими интервалами между запусками являются наиболее блокирующими функциями. Функции, которые запускаются очень часто, если не каждый цикл, и не занимают много времени для выполнения, являются наименее блокирующими функциями. Функция наименьшей блокировки - это то, что вы должны использовать в качестве основного «потока». Сможете угадать, что это вверху?

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

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

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

Это действительно вкратце, остальное вы, вероятно, сможете выяснить сами, пройдя по коду. Позвольте мне в заключение сказать, что, хотя я могу это звучать так, я НЕ ПРОТОПРОТОЧНЫЙ ПРОТОКОЛ ни в коем случае, это всего лишь простой пример, который я взломал. Если у вас есть какие-либо советы или если я в чем-то ошибался, я призываю вас оставлять отзывы и исправления! Спасибо :)

Код

  • Многопоточный ЖК-код - multithread.ino (обновлено, v1.1)
Многопоточный ЖК-код - multithread.ino (Обновлено, v1.1) Arduino
Этот фрагмент кода использует библиотеку для одновременного выполнения 3 повторяющихся действий с отдельными интервалами на одном процессоре Arduino Uno. Он будет (а) постепенно увеличивать и уменьшать яркость подсветки, (б) увеличивать число и (в) переключаться между несколькими строками текста. См. Видео выше для демонстрации :)
 / * Arduino Protothreading Example v1.1 от Drew Alden (@ReanimationXP) 12.01.2016 - Обновление:v1.1 - 18.08.17 Прототипирование Arduino 1.6.6+ изменено , мелкие исправления. (создать функции перед использованием, удалить foreach и связанную библиотеку). Обратите внимание, что TimedAction теперь устарел. Обязательно прочтите примечания об ошибках TimedAction и WProgram.h / Arduino.h. * /// КОМПОНЕНТЫ / * Этот код был создан с использованием синего ЖК-дисплея стартового набора Sunfounder Arduino. Его можно найти на Amazon.com в различных наборах. . * /// СТОРОННИЕ БИБЛИОТЕКИ // они должны быть вручную добавлены в вашу инсталляцию Arduino IDE // TimedAction // позволяет нам устанавливать действия для выполнения через отдельные временные интервалы // http://playground.arduino.cc/Code /TimedAction//http://wiring.uniandes.edu.co/source/trunk/wiring/firmware/libraries/TimedAction#include  // ПРИМЕЧАНИЕ. У этой библиотеки есть проблемы с более новыми версиями Arduino. После // загрузки библиотеки вы ДОЛЖНЫ перейти в каталог библиотеки и // отредактировать TimedAction.h. Внутри перезапишите WProgram.h с помощью Arduino.h // НАТУРАЛЬНЫЕ БИБЛИОТЕКИ # include  / * Библиотека LiquidCrystal - Hello World Демонстрирует использование ЖК-дисплея 16x2. Библиотека LiquidCrystal работает со всеми ЖК-дисплеями, совместимыми с драйвером Hitachi HD44780. Их много, и обычно вы можете определить их по 16-контактному интерфейсу. Один пример схемы:* Вывод ЖК-дисплея RS на цифровой вывод 12. * Вывод ЖК-дисплея / E / EN на цифровой вывод 11 * Вывод ЖК-дисплея D4 на цифровой вывод 5 * Вывод ЖК-дисплея D5 на цифровой вывод 4 * Вывод ЖК-дисплея D6 на цифровой вывод 3 * Вывод D7 LCD на цифровой вывод 2 * Вывод LCD R / W на землю * Вывод VSS LCD на землю вывод 3) * Дисплеи с подсветкой:* Вывод K ЖК-дисплея на землю (при наличии) * Вывод ЖК-дисплея на резистор 220 Ом (красный, красный, черный, черный (коричневый)), затем резистор на вывод 9 Этот пример кода находится в открытом доступе. http://www.arduino.cc/en/Tutorial/LiquidCrystal * /// GLOBALSint backlightPin =9; // используется для затухания подсветкиint timerCounter =0; // увеличиваем счетчик. рано или поздно произойдет сбой. int stringNo =0; // какую текстовую строку показывать // "16 CHARACTER MAX" char * stringArray [] ={"Проверить ...", "У меня 3 потока", "иду сразу ...", "Круто, да ?!:D "}; // INIT // Это, вероятно, должно быть сделано внутри setup (), но неважно. // инициализировать ЖК-библиотеку номерами контактов интерфейса LiquidCrystal lcd (12, 11, 5, 4, 3, 2); // ФУНКЦИИ / / это наша первая задача, напечатать увеличивающееся число на LCDvoid incrementNumber () {// установить курсор в столбец 0, строка 1 // (примечание:строка 1 - вторая строка, так как счет начинается с 0):lcd. setCursor (0, 1); // добавляем единицу к счетчику, затем отображаем. timerCounter =timerCounter + 1; lcd.print (timerCounter);} // наша вторая задача запускается каждые несколько секунд и меняет текстовые строкиvoid changeText () {// Выводит сообщение на ЖК-дисплей. lcd.setCursor (0, 0); lcd.print (stringArray [stringNo]); // неприятный способ получить количество элементов массива if (stringNo> =sizeof (stringArray) / sizeof (char *)) {stringNo =0; changeText (); } еще {строкаNo =строкаNo + 1; }} // Создаем пару таймеров, которые будут срабатывать повторно каждые x мс // редактировать:раньше эти строки находились перед функциями incrementNumber и changeText //. это не сработало, потому что функции еще не были определены! TimedAction numberThread =TimedAction (700, incrementNumber); TimedAction textThread =TimedAction (3000, changeText); // где наша третья задача? ну, это сам главный цикл :) задача, // которая повторяется чаще всего, должна использоваться как цикл. другие // задачи могут «прерывать» самую быструю повторяющуюся задачу. void setup () {// определить количество столбцов и строк ЖК-дисплея:lcd.begin (16, 2); // запускаем changeText один раз, чтобы нарисовать начальную строку [0] changeText ();} void loop () {// проверяем наши потоки. в зависимости от того, как долго // работает система, нужно ли им запускать и работать? если да, то сделай это! numberThread.check (); textThread.check (); // третья задача, уменьшение яркости подсветки от минимальной до максимальной // с шагом 5 баллов:digitalWrite (13, HIGH); for (int fadeValue =0; fadeValue <=255; fadeValue + =10) {// подождите секунду, почему я проверяю потоки здесь? потому что // это цикл for. вы должны проверять свои потоки во время ЛЮБЫХ // циклов, включая основной! numberThread.check (); textThread.check (); // устанавливает значение (диапазон от 0 до 255):analogWrite (backlightPin, fadeValue); // ждем 20 миллисекунд, чтобы увидеть эффект затемнения // сохраняем задержки в основном цикле SHORT. они БУДУТ предотвращать // запуск других потоков вовремя. задержка (20); } // постепенное уменьшение от максимального до минимального с шагом в 5 точек:digitalWrite (13, LOW); for (int fadeValue =255; fadeValue> =0; fadeValue - =10) {// снова проверяем наши потоки numberThread.check (); textThread.check (); // устанавливает значение (диапазон от 0 до 255):analogWrite (backlightPin, fadeValue); // ждем 20 миллисекунд, чтобы увидеть задержку эффекта затемнения (20); } / * Для забавы с прокруткой сообщений в будущем ... lcd.setCursor (15,0); // установить курсор в столбец 15, строка 0 для (int positionCounter1 =0; positionCounter1 <26; positionCounter1 ++) {lcd.scrollDisplayLeft (); // Прокручивает содержимое дисплея на одну позицию влево. lcd.print (array1 [positionCounter1]); // Выводим сообщение на ЖК-дисплей. задержка (время); // ждем 250 микросекунд} lcd.clear (); // Очищает ЖК-экран и помещает курсор в левый верхний угол. lcd.setCursor (15,1); // установить курсор в столбец 15, строка 1 для (int positionCounter =0; positionCounter <26; positionCounter ++) {lcd.scrollDisplayLeft (); // Прокручивает содержимое дисплея на одну позицию влево. lcd.print (array2 [positionCounter]); // Выводим сообщение на ЖК-дисплей. задержка (время); // ждем 250 микросекунд} lcd.clear (); // Очищает ЖК-экран и помещает курсор в левый верхний угол. * /} 

Производственный процесс

  1. Как измерить качество воздуха на OpenSensors
  2. Учебное пособие по блокировке RFID для Arduino
  3. Как взломать ИК-пульты
  4. Какой ты рост?
  5. Насколько легко использовать термистор ?!
  6. Как создавать музыку с помощью Arduino
  7. Как использовать NMEA-0183 с Arduino
  8. Учебное пособие по датчику отпечатков пальцев Arduino
  9. Как использовать Modbus с Arduino
  10. Учебник по Arduino 01:Начало работы