{"id":3182,"date":"2020-12-30T12:50:49","date_gmt":"2020-12-30T15:50:49","guid":{"rendered":"https:\/\/arduxop.com.br\/loja\/?p=3182"},"modified":"2021-08-04T18:16:57","modified_gmt":"2021-08-04T21:16:57","slug":"multi-tasking-the-arduino-part-1","status":"publish","type":"post","link":"https:\/\/arduxop.com.br\/loja\/multi-tasking-the-arduino-part-1\/","title":{"rendered":"Multi-tasking the Arduino &#8211; Part 1"},"content":{"rendered":"<h1>Multi-tasking the Arduino &#8211; Part 1<\/h1>\n<h3><img decoding=\"async\" class=\"alignleft md-max image-padding\" title=\"\" src=\"https:\/\/www.digikey.com\/-\/media\/MakerIO\/Images\/projects\/2015\/10\/30\/16\/54\/ca6284b4db004195ab25dba6b2b2cbb6.png?ts=f78300ad-4296-4fb9-b5af-b1758cd2b160\" alt=\"\" \/><\/h3>\n<p><a href=\"https:\/\/learn.adafruit.com\/multi-tasking-the-arduino-part-1\" target=\"_blank\" rel=\"nofollow noopener\">Courtesy of Adafruit Industries<\/a><\/p>\n<p><strong>Bigger and Better Projects<\/strong><\/p>\n<p>Once you have mastered the basic blinking leds, simple sensors and sweeping servos, it\u2019s time to move on to bigger and better projects. \u00a0That usually involves combining bits and pieces of simpler sketches and trying to make them work together. \u00a0The first thing you will discover is that some of those sketches that ran perfectly by themselves, just don\u2019t play well with others.<\/p>\n<p>The Arduino is a very simple processor with no operating system and can only run one program at a time. \u00a0Unlike your personal computer or a Raspberry Pi, the Arduino has no way to load and run multiple programs.<\/p>\n<p>That doesn\u2019t mean that we can\u2019t manage multiple tasks on an Arduino. \u00a0We just need to use a different approach. \u00a0Since there is no operating system to help us out, We have to take matters into our own hands.<\/p>\n<p><img decoding=\"async\" class=\"project-pic\" src=\"https:\/\/www.digikey.com\/maker-media\/36fc4260-d06e-4cd6-b388-1457967c46fe\" alt=\"\" \/><\/p>\n<p><em><strong>Ditch the delay()<\/strong><\/em><\/p>\n<p><strong>The first thing you need to do is stop using delay().<\/strong><\/p>\n<p>Using delay() to control timing is probably one of the very first things you learned when experimenting with the Arduino. \u00a0Timing with delay() is simple and straightforward, but it does cause problems down the road when you want to add additional functionality. \u00a0The problem is that delay() is a &#8220;busy wait&#8221; that monopolizes the processor.<\/p>\n<p>During a delay() call, you can\u2019t respond to inputs, you can&#8217;t process any data and you can\u2019t change any outputs. \u00a0The delay() ties up 100% of the processor. \u00a0So, if any part of your code uses a delay(), everything else is dead in the water for the duration.<\/p>\n<p><em><strong>Remember Blink?<\/strong><\/em><\/p>\n<div class=\"code\"><span class=\"copy-text\">Copy Code<\/span><\/p>\n<pre class=\"prettyprint\">      \/*\r\n  Blink\r\n  Turns on an LED on for one second, then off for one second, repeatedly.\r\n \r\n  This example code is in the public domain.\r\n *\/\r\n \r\n\/\/ Pin 13 has an LED connected on most Arduino boards.\r\n\/\/ give it a name:\r\nint led = 13;\r\n \r\n\/\/ the setup routine runs once when you press reset:\r\nvoid setup() {                \r\n  \/\/ initialize the digital pin as an output.\r\n  pinMode(led, OUTPUT);     \r\n}\r\n \r\n\/\/ the loop routine runs over and over again forever:\r\nvoid loop() {\r\n  digitalWrite(led, HIGH);   \/\/ turn the LED on (HIGH is the voltage level)\r\n  delay(1000);               \/\/ wait for a second\r\n  digitalWrite(led, LOW);    \/\/ turn the LED off by making the voltage LOW\r\n  delay(1000);               \/\/ wait for a second\r\n}<\/pre>\n<\/div>\n<p>The simple Blink sketch spends almost all of its time in the delay() function. \u00a0So, the processor can&#8217;t do anything else while it is blinking.<\/p>\n<p><em><strong>And sweep too?<\/strong><\/em><\/p>\n<p>Sweep uses the delay() to control the sweep speed. \u00a0If you try to combine the basic blink sketch with the servo sweep example, you will find that it alternates between blinking and sweeping. \u00a0But it won&#8217;t do both simultaneously.<\/p>\n<div class=\"code\"><span class=\"copy-text\">Copy Code<\/span><\/p>\n<pre class=\"prettyprint\">#include &lt;Servo.h&gt;\r\n     \r\n\/\/ Pin 13 has an LED connected on most Arduino boards.\r\n\/\/ give it a name:\r\nint led = 13;\r\n     \r\nServo myservo;  \/\/ create servo object to control a servo \r\n                \/\/ twelve servo objects can be created on most boards\r\n     \r\nint pos = 0;    \/\/ variable to store the servo position \r\n     \r\nvoid setup() \r\n{ \r\n  \/\/ initialize the digital pin as an output.\r\n  pinMode(led, OUTPUT);     \r\n  myservo.attach(9);  \/\/ attaches the servo on pin 9 to the servo object \r\n} \r\n     \r\nvoid loop() \r\n{ \r\n  digitalWrite(led, HIGH);   \/\/ turn the LED on (HIGH is the voltage level)\r\n  delay(1000);               \/\/ wait for a second\r\n  digitalWrite(led, LOW);    \/\/ turn the LED off by making the voltage LOW\r\n  delay(1000);               \/\/ wait for a second\r\n      \r\n  for(pos = 0; pos &lt;= 180; pos  = 1) \/\/ goes from 0 degrees to 180 degrees \r\n      {                              \/\/ in steps of 1 degree \r\n        myservo.write(pos);          \/\/ tell servo to go to position in variable 'pos' \r\n        delay(15);                   \/\/ waits 15ms for the servo to reach the position \r\n      } \r\n      for(pos = 180; pos&gt;=0; pos-=1) \/\/ goes from 180 degrees to 0 degrees \r\n      {                                \r\n        myservo.write(pos);          \/\/ tell servo to go to position in variable 'pos' \r\n        delay(15);                   \/\/ waits 15ms for the servo to reach the position \r\n  } \r\n}<\/pre>\n<\/div>\n<p><em>So, how do we control the timing without using the delay function?<\/em><\/p>\n<p><strong><em>Using millis() for timing\u00a0<\/em><\/strong><\/p>\n<p><strong>Become a clock-watcher!<\/strong><\/p>\n<p>One simple technique for implementing timing is to make a schedule and keep an eye on the clock. \u00a0Instead of a world-stopping delay, you just check the clock regularly so you know when it is time to act. \u00a0Meanwhile the processor is still free for other tasks to do their thing. \u00a0A very simple example of this is the <strong>BlinkWithoutDelay<\/strong> example sketch that comes with the IDE.<\/p>\n<p>The code on this page uses the wiring shown in the diagram below:<\/p>\n<p><img decoding=\"async\" class=\"project-pic\" src=\"https:\/\/www.digikey.com\/maker-media\/0692b6e5-b88a-4617-9495-d8401dbedf28\" alt=\"\" \/><\/p>\n<p><em><strong>Blink Without Delay<\/strong><\/em><\/p>\n<p>This is the BlinkWithoutDelay example sketch from the IDE:<\/p>\n<div class=\"code\"><span class=\"copy-text\">Copy Code<\/span><\/p>\n<pre class=\"prettyprint\">\/* Blink without Delay\r\n     \r\n Turns on and off a light emitting diode(LED) connected to a digital  \r\n pin, without using the delay() function.  This means that other code\r\n can run at the same time without being interrupted by the LED code.\r\n     \r\n The circuit:\r\n * LED attached from pin 13 to ground.\r\n * Note: on most Arduinos, there is already an LED on the board\r\n that's attached to pin 13, so no hardware is needed for this example.\r\n     \r\n     \r\n created 2005\r\n by David A. Mellis\r\n modified 8 Feb 2010\r\n by Paul Stoffregen\r\n     \r\n This example code is in the public domain.\r\n     \r\n     \r\n http:\/\/www.arduino.cc\/en\/Tutorial\/BlinkWithoutDelay\r\n *\/\r\n     \r\n\/\/ constants won't change. Used here to \r\n\/\/ set pin numbers:\r\nconst int ledPin =  13;      \/\/ the number of the LED pin\r\n     \r\n\/\/ Variables will change:\r\nint ledState = LOW;             \/\/ ledState used to set the LED\r\nlong previousMillis = 0;        \/\/ will store last time LED was updated\r\n     \r\n\/\/ the follow variables is a long because the time, measured in miliseconds,\r\n\/\/ will quickly become a bigger number than can be stored in an int.\r\nlong interval = 1000;           \/\/ interval at which to blink (milliseconds)\r\n     \r\nvoid setup() {\r\n  \/\/ set the digital pin as output:\r\n  pinMode(ledPin, OUTPUT);      \r\n}\r\n     \r\nvoid loop()\r\n{\r\n  \/\/ here is where you'd put code that needs to be running all the time.\r\n     \r\n  \/\/ check to see if it's time to blink the LED; that is, if the \r\n  \/\/ difference between the current time and last time you blinked \r\n  \/\/ the LED is bigger than the interval at which you want to \r\n  \/\/ blink the LED.\r\n  unsigned long currentMillis = millis();\r\n     \r\n  if(currentMillis - previousMillis &gt; interval) {\r\n    \/\/ save the last time you blinked the LED \r\n    previousMillis = currentMillis;   \r\n     \r\n    \/\/ if the LED is off turn it on and vice-versa:\r\n    if (ledState == LOW)\r\n      ledState = HIGH;\r\n    else\r\n      ledState = LOW;\r\n     \r\n    \/\/ set the LED with the ledState of the variable:\r\n    digitalWrite(ledPin, ledState);\r\n  }\r\n}<\/pre>\n<\/div>\n<p><em><strong>What&#8217;s the point of that?<\/strong><\/em><\/p>\n<p>At first glance, BlinkWithoutDelay \u00a0does not seem to be a very interesting sketch. \u00a0It looks like just a more complicated way to blink a LED. \u00a0However, BinkWithoutDelay illustrates a very important concept known as a <strong>State Machine<\/strong>.<\/p>\n<p>Instead of relying on delay() to time the blinking. \u00a0BlinkWithoutDelay remembers the current state of the LED and the last time it changed. \u00a0On each pass through the loop, it looks at the millis() clock to see if it is time to change the state of the LED again.<\/p>\n<p><em><strong>Welcome to the Machine<\/strong><\/em><\/p>\n<p>Let\u2019s look at a slightly more interesting blink variant that has a different on-time and off-time. \u00a0We\u2019ll call this one \u201cFlashWithoutDelay\u201d.<\/p>\n<div class=\"code\"><span class=\"copy-text\">Copy Code<\/span><\/p>\n<pre class=\"prettyprint\">\/\/ These variables store the flash pattern\r\n\/\/ and the current state of the LED\r\n     \r\nint ledPin =  13;      \/\/ the number of the LED pin\r\nint ledState = LOW;             \/\/ ledState used to set the LED\r\nunsigned long previousMillis = 0;        \/\/ will store last time LED was updated\r\nlong OnTime = 250;           \/\/ milliseconds of on-time\r\nlong OffTime = 750;          \/\/ milliseconds of off-time\r\n     \r\nvoid setup() \r\n{\r\n  \/\/ set the digital pin as output:\r\n  pinMode(ledPin, OUTPUT);      \r\n}\r\n     \r\nvoid loop()\r\n{\r\n  \/\/ check to see if it's time to change the state of the LED\r\n  unsigned long currentMillis = millis();\r\n     \r\n  if((ledState == HIGH) &amp;&amp; (currentMillis - previousMillis &gt;= OnTime))\r\n  {\r\n    ledState = LOW;  \/\/ Turn it off\r\n    previousMillis = currentMillis;  \/\/ Remember the time\r\n    digitalWrite(ledPin, ledState);  \/\/ Update the actual LED\r\n  }\r\n  else if ((ledState == LOW) &amp;&amp; (currentMillis - previousMillis &gt;= OffTime))\r\n  {\r\n    ledState = HIGH;  \/\/ turn it on\r\n    previousMillis = currentMillis;   \/\/ Remember the time\r\n    digitalWrite(ledPin, ledState);\t  \/\/ Update the actual LED\r\n  }\r\n}<\/pre>\n<\/div>\n<p><em><strong>State Machine = State Machine<\/strong><\/em><\/p>\n<p>Note that we have variables to keep track of whether the LED is ON or OFF. \u00a0And variables to keep track of when the last change happened. \u00a0 That is the <strong>State<\/strong> part of the State Machine.<\/p>\n<p>We also have code that looks at the state and decides when and how it needs to change. \u00a0That is the <strong>Machine<\/strong> part. \u00a0Every time through the loop we \u2018run the machine\u2019 and the machine takes care of updating the state.<\/p>\n<p>Next, we&#8217;ll look at how you can combine multiple state machines and run them concurrently.<\/p>\n<p><em><strong>Now for two at once\u00a0<\/strong><\/em><\/p>\n<p>Now it is time to do some multi-tasking! \u00a0First wire up another LED as in the diagram below.<\/p>\n<p><img decoding=\"async\" class=\"project-pic\" src=\"https:\/\/www.digikey.com\/maker-media\/65b2bf44-7569-4126-9caa-53d9d1a2ba6d\" alt=\"\" \/><\/p>\n<p>Then we&#8217;ll create another state machine for a second LED that flashes at completely different rates. \u00a0Using two separate state machines allows us to blink the two LEDs completely independent of one another. Something that would be surprisingly complicated to do using delays alone.<\/p>\n<div class=\"code\"><span class=\"copy-text\">Copy Code<\/span><\/p>\n<pre class=\"prettyprint\">\/\/ These variables store the flash pattern\r\n\/\/ and the current state of the LED\r\n     \r\nint ledPin1 =  12;      \/\/ the number of the LED pin\r\nint ledState1 = LOW;             \/\/ ledState used to set the LED\r\nunsigned long previousMillis1 = 0;        \/\/ will store last time LED was updated\r\nlong OnTime1 = 250;           \/\/ milliseconds of on-time\r\nlong OffTime1 = 750;          \/\/ milliseconds of off-time\r\n     \r\nint ledPin2 =  13;      \/\/ the number of the LED pin\r\nint ledState2 = LOW;             \/\/ ledState used to set the LED\r\nunsigned long previousMillis2 = 0;        \/\/ will store last time LED was updated\r\nlong OnTime2 = 330;           \/\/ milliseconds of on-time\r\nlong OffTime2 = 400;          \/\/ milliseconds of off-time\r\n     \r\nvoid setup() \r\n{\r\n  \/\/ set the digital pin as output:\r\n  pinMode(ledPin1, OUTPUT);      \r\n  pinMode(ledPin2, OUTPUT);      \r\n}\r\n     \r\nvoid loop()\r\n{\r\n  \/\/ check to see if it's time to change the state of the LED\r\n  unsigned long currentMillis = millis();\r\n     \r\n  if((ledState1 == HIGH) &amp;&amp; (currentMillis - previousMillis1 &gt;= OnTime1))\r\n  {\r\n    ledState1 = LOW;  \/\/ Turn it off\r\n    previousMillis1 = currentMillis;  \/\/ Remember the time\r\n    digitalWrite(ledPin1, ledState1);  \/\/ Update the actual LED\r\n  }\r\n  else if ((ledState1 == LOW) &amp;&amp; (currentMillis - previousMillis1 &gt;= OffTime1))\r\n  {\r\n    ledState1 = HIGH;  \/\/ turn it on\r\n    previousMillis1 = currentMillis;   \/\/ Remember the time\r\n    digitalWrite(ledPin1, ledState1);\t  \/\/ Update the actual LED\r\n  }\r\n      \r\n  if((ledState2 == HIGH) &amp;&amp; (currentMillis - previousMillis2 &gt;= OnTime2))\r\n  {\r\n    ledState2 = LOW;  \/\/ Turn it off\r\n    previousMillis2 = currentMillis;  \/\/ Remember the time\r\n    digitalWrite(ledPin2, ledState2);  \/\/ Update the actual LED\r\n  }\r\n  else if ((ledState2 == LOW) &amp;&amp; (currentMillis - previousMillis2 &gt;= OffTime2))\r\n  {\r\n    ledState2 = HIGH;  \/\/ turn it on\r\n    previousMillis2 = currentMillis;   \/\/ Remember the time\r\n    digitalWrite(ledPin2, ledState2);\t  \/\/ Update the actual LED\r\n  }\r\n}<\/pre>\n<\/div>\n<p><em><strong>Thank you sir! \u00a0May I have another?<\/strong><\/em><\/p>\n<p>You can add more state machines until you run out of memory or GPIO pins. \u00a0Each state machine can have its own flash rate. \u00a0As an exercise, edit the code above to add a third state machine.<\/p>\n<ul>\n<li>First duplicate all of the state variables and code from one state machine.<\/li>\n<li>Then re-name all the variables to avoid conflicts with the first machine.<\/li>\n<\/ul>\n<p>It&#8217;s not very difficult to do. \u00a0But it seems rather wasteful writing the same code over and over again. There must be a more efficient way to do this!<\/p>\n<p>There are better ways to manage this complexity. \u00a0There are programming techniques that are both simpler and more efficient. \u00a0In the next page, we&#8217;ll introduce some of the more advanced features of the Arduino programming language.<\/p>\n<p><em><strong>A classy solution<\/strong><\/em><\/p>\n<p>Let&#8217;s take another look at that last sketch. \u00a0As you can see, it is very repetitive. \u00a0The same code is duplicated almost verbatim for each flashing LED. \u00a0The only thing that changes (slightly) is the varable names.<\/p>\n<p>This code s a prime candidate for a little Object Oriented Programming (OOP).<\/p>\n<p><strong><em>Put a little OOP in your loop.<\/em><\/strong><\/p>\n<p>The Arduino Language is a variant of C which supports Object Oriented Programming. \u00a0Using the OOP features of the language we can gather together all of the state variables and functionality for a blinking LED into a C class.<\/p>\n<p>This isn\u2019t very difficult to do. \u00a0We already have written all the code for it. \u00a0We just need to re-package it as a class.<\/p>\n<p><em><strong>Defining a class:<\/strong><\/em><\/p>\n<p>We start by declaring a \u201cFlasher\u201d class:<\/p>\n<p>Then we add in all the variables from FlashWithoutDelay. \u00a0Since they are part of the class, they are known as <strong>member variables<\/strong>.<\/p>\n<div class=\"code\"><span class=\"copy-text\">Copy Code<\/span><\/p>\n<pre class=\"prettyprint\">class Flasher\r\n{\r\n    \/\/ Class Member Variables\r\n    \/\/ These are initialized at startup\r\n    int ledPin;      \/\/ the number of the LED pin\r\n    long OnTime;     \/\/ milliseconds of on-time\r\n    long OffTime;    \/\/ milliseconds of off-time\r\n     \r\n    \/\/ These maintain the current state\r\n    int ledState;             \t\t\/\/ ledState used to set the LED\r\n    unsigned long previousMillis;  \t\/\/ will store last time LED was updated\r\n};<\/pre>\n<\/div>\n<p>Next we add a <strong>constructor<\/strong>. \u00a0The constructor has the same name as the class and its job is to initialize all the variables.<\/p>\n<div class=\"code\"><span class=\"copy-text\">Copy Code<\/span><\/p>\n<pre class=\"prettyprint\">class Flasher\r\n{\r\n    \/\/ Class Member Variables\r\n    \/\/ These are initialized at startup\r\n    int ledPin;      \/\/ the number of the LED pin\r\n    long OnTime;     \/\/ milliseconds of on-time\r\n    long OffTime;    \/\/ milliseconds of off-time\r\n     \r\n    \/\/ These maintain the current state\r\n    int ledState;             \t\t\/\/ ledState used to set the LED\r\n    unsigned long previousMillis;  \t\/\/ will store last time LED was updated\r\n     \r\n  \/\/ Constructor - creates a Flasher \r\n  \/\/ and initializes the member variables and state\r\n  public:\r\n  Flasher(int pin, long on, long off)\r\n  {\r\n    ledPin = pin;\r\n    pinMode(ledPin, OUTPUT);     \r\n    \t  \r\n    OnTime = on;\r\n    OffTime = off;\r\n    \t\r\n    ledState = LOW; \r\n    previousMillis = 0;\r\n  }\r\n};<\/pre>\n<\/div>\n<p>Finally we take our loop and turn it into a <strong>member function<\/strong> called \u201cUpdate()\u201d. \u00a0Note that this is identical to our original void loop(). \u00a0Only the name has changed.<\/p>\n<div class=\"code\"><span class=\"copy-text\">Copy Code<\/span><\/p>\n<pre class=\"prettyprint\">class Flasher\r\n{\r\n    \/\/ Class Member Variables\r\n    \/\/ These are initialized at startup\r\n    int ledPin;      \/\/ the number of the LED pin\r\n    long OnTime;     \/\/ milliseconds of on-time\r\n    long OffTime;    \/\/ milliseconds of off-time\r\n     \r\n    \/\/ These maintain the current state\r\n    int ledState;             \t\t\/\/ ledState used to set the LED\r\n    unsigned long previousMillis;  \t\/\/ will store last time LED was updated\r\n     \r\n  \/\/ Constructor - creates a Flasher \r\n  \/\/ and initializes the member variables and state\r\n  public:\r\n  Flasher(int pin, long on, long off)\r\n  {\r\n    ledPin = pin;\r\n    pinMode(ledPin, OUTPUT);     \r\n    \t  \r\n    OnTime = on;\r\n    OffTime = off;\r\n    \t\r\n    ledState = LOW; \r\n    previousMillis = 0;\r\n  }\r\n     \r\n  void Update()\r\n  {\r\n    \/\/ check to see if it's time to change the state of the LED\r\n    unsigned long currentMillis = millis();\r\n         \r\n    if((ledState == HIGH) &amp;&amp; (currentMillis - previousMillis &gt;= OnTime))\r\n    {\r\n        ledState = LOW;  \/\/ Turn it off\r\n      previousMillis = currentMillis;  \/\/ Remember the time\r\n      digitalWrite(ledPin, ledState);  \/\/ Update the actual LED\r\n    }\r\n    else if ((ledState == LOW) &amp;&amp; (currentMillis - previousMillis &gt;= OffTime))\r\n    {\r\n      ledState = HIGH;  \/\/ turn it on\r\n      previousMillis = currentMillis;   \/\/ Remember the time\r\n      digitalWrite(ledPin, ledState);\t  \/\/ Update the actual LED\r\n    }\r\n  }\r\n};<\/pre>\n<\/div>\n<p>By simply re-arranging our existing code into the Flasher class, we have encapsulated all of the variables (the <strong>state<\/strong>) and the functionality (the <strong>machine<\/strong>) for flashing a LED.<\/p>\n<p>Now lets use it:<\/p>\n<p>Now, for every LED that we want to flash, we create an <strong>instance<\/strong> of the Flasher class by calling the <strong>constructor<\/strong>. \u00a0And on every pass through the loop we just need to call Update() for each instance of Flasher.<\/p>\n<p>There is no need to replicate the entire state machine code anymore. \u00a0We just need to ask for another instance of the Flasher class!<\/p>\n<div class=\"code\"><span class=\"copy-text\">Copy Code<\/span><\/p>\n<pre class=\"prettyprint\">class Flasher\r\n{\r\n    \/\/ Class Member Variables\r\n    \/\/ These are initialized at startup\r\n    int ledPin;      \/\/ the number of the LED pin\r\n    long OnTime;     \/\/ milliseconds of on-time\r\n    long OffTime;    \/\/ milliseconds of off-time\r\n     \r\n    \/\/ These maintain the current state\r\n    int ledState;             \t\t\/\/ ledState used to set the LED\r\n    unsigned long previousMillis;  \t\/\/ will store last time LED was updated\r\n     \r\n  \/\/ Constructor - creates a Flasher \r\n  \/\/ and initializes the member variables and state\r\n  public:\r\n  Flasher(int pin, long on, long off)\r\n  {\r\n    ledPin = pin;\r\n    pinMode(ledPin, OUTPUT);     \r\n    \t  \r\n    OnTime = on;\r\n    OffTime = off;\r\n    \t\r\n    ledState = LOW; \r\n    previousMillis = 0;\r\n  }\r\n     \r\n  void Update()\r\n  {\r\n    \/\/ check to see if it's time to change the state of the LED\r\n    unsigned long currentMillis = millis();\r\n         \r\n    if((ledState == HIGH) &amp;&amp; (currentMillis - previousMillis &gt;= OnTime))\r\n    {\r\n        ledState = LOW;  \/\/ Turn it off\r\n      previousMillis = currentMillis;  \/\/ Remember the time\r\n      digitalWrite(ledPin, ledState);  \/\/ Update the actual LED\r\n    }\r\n    else if ((ledState == LOW) &amp;&amp; (currentMillis - previousMillis &gt;= OffTime))\r\n    {\r\n      ledState = HIGH;  \/\/ turn it on\r\n      previousMillis = currentMillis;   \/\/ Remember the time\r\n      digitalWrite(ledPin, ledState);\t  \/\/ Update the actual LED\r\n    }\r\n  }\r\n};\r\n     \r\n     \r\nFlasher led1(12, 100, 400);\r\nFlasher led2(13, 350, 350);\r\n     \r\nvoid setup()\r\n{\r\n}\r\n     \r\nvoid loop()\r\n{\r\n    led1.Update();\r\n    led2.Update();\r\n}<\/pre>\n<\/div>\n<p><em><strong>Less is more!<\/strong><\/em><\/p>\n<p>That\u2019s it \u2013 <strong><em>each additional LED requires just two lines of code!<\/em><\/strong><\/p>\n<p>This code shorter and easier to read. \u00a0And, since there is no duplicated code,<em><strong> it also compiles smaller! <\/strong><\/em>That leaves you even more precious memory to do other things!<\/p>\n<p><em><strong>A clean sweep<\/strong><\/em><\/p>\n<p><strong>What else can we do with it?<\/strong><\/p>\n<p>Let\u2019s apply the same principles to some servo code and get some action going.<\/p>\n<p>First hook up a couple of servos on your breadboard as shown below. \u00a0As long as we are at it, let&#8217;s hook up a third LED too.<\/p>\n<p><img decoding=\"async\" class=\"project-pic\" src=\"https:\/\/www.digikey.com\/maker-media\/99bd1f31-43aa-433d-8f28-876c0fb323b5\" alt=\"\" \/><\/p>\n<p>Here is the standard Servo sweep code. \u00a0Note that it calls the dreaded delay(). \u00a0We&#8217;ll take the parts we need from it to make a &#8220;Sweeper&#8221; state machine.<\/p>\n<div class=\"code\"><span class=\"copy-text\">Copy Code<\/span><\/p>\n<pre class=\"prettyprint\">\/\/ Sweep\r\n\/\/ by BARRAGAN  \r\n\/\/ This example code is in the public domain.\r\n     \r\n     \r\n#include  \r\n     \r\nServo myservo;  \/\/ create servo object to control a servo \r\n                \/\/ a maximum of eight servo objects can be created \r\n     \r\nint pos = 0;    \/\/ variable to store the servo position \r\n     \r\nvoid setup() \r\n{ \r\n  myservo.attach(9);  \/\/ attaches the servo on pin 9 to the servo object \r\n} \r\n     \r\n     \r\nvoid loop() \r\n{ \r\n  for(pos = 0; pos &lt; 180; pos  = 1)  \/\/ goes from 0 degrees to 180 degrees \r\n  {                                  \/\/ in steps of 1 degree \r\n    myservo.write(pos);              \/\/ tell servo to go to position in variable 'pos' \r\n    delay(15);                       \/\/ waits 15ms for the servo to reach the position \r\n  } \r\n  for(pos = 180; pos&gt;=1; pos-=1)     \/\/ goes from 180 degrees to 0 degrees \r\n  {                                \r\n    myservo.write(pos);              \/\/ tell servo to go to position in variable 'pos' \r\n    delay(15);                       \/\/ waits 15ms for the servo to reach the position \r\n  } \r\n}<\/pre>\n<\/div>\n<p>The Sweeper class below encapsulates the sweep action, but uses the millis() function for timing, much like the Flasher class does for the LEDs.<\/p>\n<p>We also need to add Attach() and Detach() functions to associate the servo with a specific pin:<\/p>\n<div class=\"code\"><span class=\"copy-text\">Copy Code<\/span><\/p>\n<pre class=\"prettyprint\">class Sweeper\r\n{\r\n  Servo servo;              \/\/ the servo\r\n  int pos;              \/\/ current servo position \r\n  int increment;        \/\/ increment to move for each interval\r\n  int  updateInterval;      \/\/ interval between updates\r\n  unsigned long lastUpdate; \/\/ last update of position\r\n     \r\npublic: \r\n  Sweeper(int interval)\r\n  {\r\n    updateInterval = interval;\r\n    increment = 1;\r\n  }\r\n      \r\n  void Attach(int pin)\r\n  {\r\n    servo.attach(pin);\r\n  }\r\n      \r\n  void Detach()\r\n  {\r\n    servo.detach();\r\n  }\r\n      \r\n  void Update()\r\n  {\r\n    if((millis() - lastUpdate) &gt; updateInterval)  \/\/ time to update\r\n    {\r\n      lastUpdate = millis();\r\n      pos  = increment;\r\n      servo.write(pos);\r\n      Serial.println(pos);\r\n      if ((pos &gt;= 180) || (pos &lt;= 0)) \/\/ end of sweep\r\n      {\r\n        \/\/ reverse direction\r\n        increment = -increment;\r\n      }\r\n    }\r\n  }\r\n};<\/pre>\n<\/div>\n<p><em><strong>How many would you like?<\/strong><\/em><\/p>\n<p>Now we can instantiate as many Flashers and Sweepers as we need.<\/p>\n<p>Each instance of a Flasher requires 2 lines of code:<\/p>\n<ul>\n<li>One to declare the instance<\/li>\n<li>One to call update in the loop<\/li>\n<\/ul>\n<p>Each instance of a Sweeper requires just 3 lines of code:<\/p>\n<ul>\n<li>One to declare the instance<\/li>\n<li>One to attach it to a pin in setup<\/li>\n<li>And one call to update in the loop<\/li>\n<\/ul>\n<div class=\"code\"><span class=\"copy-text\">Copy Code<\/span><\/p>\n<pre class=\"prettyprint\">#include &lt;Servo.h&gt;\r\n     \r\nclass Flasher\r\n{\r\n    \/\/ Class Member Variables\r\n    \/\/ These are initialized at startup\r\n    int ledPin;      \/\/ the number of the LED pin\r\n    long OnTime;     \/\/ milliseconds of on-time\r\n    long OffTime;    \/\/ milliseconds of off-time\r\n     \r\n    \/\/ These maintain the current state\r\n    int ledState;             \t\t\/\/ ledState used to set the LED\r\n    unsigned long previousMillis;  \t\/\/ will store last time LED was updated\r\n     \r\n  \/\/ Constructor - creates a Flasher \r\n  \/\/ and initializes the member variables and state\r\n  public:\r\n  Flasher(int pin, long on, long off)\r\n  {\r\n    ledPin = pin;\r\n    pinMode(ledPin, OUTPUT);     \r\n    \t  \r\n    OnTime = on;\r\n    OffTime = off;\r\n    \t\r\n    ledState = LOW; \r\n    previousMillis = 0;\r\n  }\r\n     \r\n  void Update()\r\n  {\r\n    \/\/ check to see if it's time to change the state of the LED\r\n    unsigned long currentMillis = millis();\r\n         \r\n    if((ledState == HIGH) &amp;&amp; (currentMillis - previousMillis &gt;= OnTime))\r\n    {\r\n        ledState = LOW;  \/\/ Turn it off\r\n      previousMillis = currentMillis;  \/\/ Remember the time\r\n      digitalWrite(ledPin, ledState);  \/\/ Update the actual LED\r\n    }\r\n    else if ((ledState == LOW) &amp;&amp; (currentMillis - previousMillis &gt;= OffTime))\r\n    {\r\n      ledState = HIGH;  \/\/ turn it on\r\n      previousMillis = currentMillis;   \/\/ Remember the time\r\n      digitalWrite(ledPin, ledState);\t  \/\/ Update the actual LED\r\n    }\r\n  }\r\n};\r\n     \r\nclass Sweeper\r\n{\r\n  Servo servo;              \/\/ the servo\r\n  int pos;              \/\/ current servo position \r\n  int increment;        \/\/ increment to move for each interval\r\n  int  updateInterval;      \/\/ interval between updates\r\n  unsigned long lastUpdate; \/\/ last update of position\r\n     \r\npublic: \r\n  Sweeper(int interval)\r\n  {\r\n    updateInterval = interval;\r\n    increment = 1;\r\n  }\r\n      \r\n  void Attach(int pin)\r\n  {\r\n    servo.attach(pin);\r\n  }\r\n      \r\n  void Detach()\r\n  {\r\n    servo.detach();\r\n  }\r\n      \r\n  void Update()\r\n  {\r\n    if((millis() - lastUpdate) &gt; updateInterval)  \/\/ time to update\r\n    {\r\n      lastUpdate = millis();\r\n      pos  = increment;\r\n      servo.write(pos);\r\n      Serial.println(pos);\r\n      if ((pos &gt;= 180) || (pos &lt;= 0)) \/\/ end of sweep\r\n      {\r\n        \/\/ reverse direction\r\n        increment = -increment;\r\n      }\r\n    }\r\n  }\r\n};\r\n     \r\n     \r\nFlasher led1(11, 123, 400);\r\nFlasher led2(12, 350, 350);\r\nFlasher led3(13, 200, 222);\r\n     \r\nSweeper sweeper1(15);\r\nSweeper sweeper2(25);\r\n     \r\nvoid setup() \r\n{ \r\n  Serial.begin(9600);\r\n  sweeper1.Attach(9);\r\n  sweeper2.Attach(10);\r\n} \r\n     \r\n     \r\nvoid loop() \r\n{ \r\n  sweeper1.Update();\r\n  sweeper2.Update();\r\n      \r\n  led1.Update();\r\n  led2.Update();\r\n  led3.Update();\r\n}<\/pre>\n<\/div>\n<p>Now we have 5 independent tasks running non-stop with no interference. \u00a0And our loop() is only 5 lines of code! \u00a0Next we&#8217;ll add a button so we can interact with some of these tasks.<\/p>\n<p><strong><em>All together now!<\/em><\/strong><\/p>\n<p><strong>We want your input too<\/strong><\/p>\n<p>The other problem with delay()-based timing is that user inputs like button presses tend to get ignored because the processor can&#8217;t check the button state when it is in a delay(). \u00a0With our millis()-based timing, the processor is free to check on button states and other inputs regularly. \u00a0This allows us to build complex programs that do many things at once, but still remain responsive.<\/p>\n<p>We&#8217;ll demonstrate this by adding a button to our circuit as shown below:<\/p>\n<p><img decoding=\"async\" class=\"project-pic\" src=\"https:\/\/www.digikey.com\/maker-media\/92048304-8882-4084-a4ce-a50dcf0c6aa4\" alt=\"\" \/><\/p>\n<p>The code below will check the button state on each pass of the loop. \u00a0Led1 and sweeper2 will not be updated when the button is pressed.<\/p>\n<div class=\"code\"><span class=\"copy-text\">Copy Code<\/span><\/p>\n<pre class=\"prettyprint\">#include &lt;Servo.h&gt;\r\n     \r\n     \r\nclass Flasher\r\n{\r\n    \/\/ Class Member Variables\r\n    \/\/ These are initialized at startup\r\n    int ledPin;      \/\/ the number of the LED pin\r\n    long OnTime;     \/\/ milliseconds of on-time\r\n    long OffTime;    \/\/ milliseconds of off-time\r\n     \r\n    \/\/ These maintain the current state\r\n    int ledState;             \t\t\/\/ ledState used to set the LED\r\n    unsigned long previousMillis;  \t\/\/ will store last time LED was updated\r\n     \r\n  \/\/ Constructor - creates a Flasher \r\n  \/\/ and initializes the member variables and state\r\n  public:\r\n  Flasher(int pin, long on, long off)\r\n  {\r\n    ledPin = pin;\r\n    pinMode(ledPin, OUTPUT);     \r\n    \t  \r\n    OnTime = on;\r\n    OffTime = off;\r\n    \t\r\n    ledState = LOW; \r\n    previousMillis = 0;\r\n  }\r\n     \r\n  void Update()\r\n  {\r\n    \/\/ check to see if it's time to change the state of the LED\r\n    unsigned long currentMillis = millis();\r\n         \r\n    if((ledState == HIGH) &amp;&amp; (currentMillis - previousMillis &gt;= OnTime))\r\n    {\r\n        ledState = LOW;  \/\/ Turn it off\r\n      previousMillis = currentMillis;  \/\/ Remember the time\r\n      digitalWrite(ledPin, ledState);  \/\/ Update the actual LED\r\n    }\r\n    else if ((ledState == LOW) &amp;&amp; (currentMillis - previousMillis &gt;= OffTime))\r\n    {\r\n      ledState = HIGH;  \/\/ turn it on\r\n      previousMillis = currentMillis;   \/\/ Remember the time\r\n      digitalWrite(ledPin, ledState);\t  \/\/ Update the actual LED\r\n    }\r\n  }\r\n};\r\n     \r\nclass Sweeper\r\n{\r\n  Servo servo;              \/\/ the servo\r\n  int pos;              \/\/ current servo position \r\n  int increment;        \/\/ increment to move for each interval\r\n  int  updateInterval;      \/\/ interval between updates\r\n  unsigned long lastUpdate; \/\/ last update of position\r\n     \r\npublic: \r\n  Sweeper(int interval)\r\n  {\r\n    updateInterval = interval;\r\n    increment = 1;\r\n  }\r\n      \r\n  void Attach(int pin)\r\n  {\r\n    servo.attach(pin);\r\n  }\r\n      \r\n  void Detach()\r\n  {\r\n    servo.detach();\r\n  }\r\n      \r\n  void Update()\r\n  {\r\n    if((millis() - lastUpdate) &gt; updateInterval)  \/\/ time to update\r\n    {\r\n      lastUpdate = millis();\r\n      pos  = increment;\r\n      servo.write(pos);\r\n      Serial.println(pos);\r\n      if ((pos &gt;= 180) || (pos &lt;= 0)) \/\/ end of sweep\r\n      {\r\n        \/\/ reverse direction\r\n        increment = -increment;\r\n      }\r\n    }\r\n  }\r\n};\r\n     \r\n     \r\nFlasher led1(11, 123, 400);\r\nFlasher led2(12, 350, 350);\r\nFlasher led3(13, 200, 222);\r\n     \r\nSweeper sweeper1(15);\r\nSweeper sweeper2(25);\r\n     \r\nvoid setup() \r\n{ \r\n  Serial.begin(9600);\r\n  sweeper1.Attach(9);\r\n  sweeper2.Attach(10);\r\n} \r\n     \r\n     \r\nvoid loop() \r\n{ \r\n  sweeper1.Update();\r\n      \r\n  if(digitalRead(2) == HIGH)\r\n  {\r\n     sweeper2.Update();\r\n     led1.Update();\r\n  }\r\n      \r\n  led2.Update();\r\n  led3.Update();\r\n}<\/pre>\n<\/div>\n<p>The 3 LEDs will flash at their own rates. \u00a0The 2 sweepers will sweep at their own rates. \u00a0But when we press the button, sweeper2 and led1 will stop in their tracks until we release the button.<\/p>\n<p>Since there are no delays in the loop, the button input has nearly instantaneous response.<\/p>\n<p><img decoding=\"async\" class=\"project-pic\" src=\"https:\/\/www.digikey.com\/maker-media\/a7721206-d169-4a04-b9bf-65fa48268290\" alt=\"\" \/><\/p>\n<p>So now we have 5 tasks executing independently and with user input. \u00a0There are no delays to tie up the processor. \u00a0And our efficient Object Oriented code leaves plenty of room for expansion!<\/p>\n<p><em><strong>Conclusion:<\/strong><\/em><\/p>\n<p>In this guide we have demonstrated that it is indeed possible for the Arduino to juggle multiple independent tasks while remaining responsive to external events like user input.<\/p>\n<ul>\n<li>We\u2019ve learned how to time things using millis() instead of delay() so we can free up the processor to do other things.<\/li>\n<li>We\u2019ve learned how to define tasks as state machines that can execute independently of other state machines at the same time.<\/li>\n<li>And we\u2019ve learned how to encapsulate these state machines into C classes to keep our code simple and compact.<\/li>\n<\/ul>\n<p>These techniques won\u2019t turn your Arduino into a supercomputer. \u00a0But they will help you to get the most out of this small, but surprisingly powerful little processor.<\/p>\n<p>In the part 2 of this series, we&#8217;ll build on these techniques and explore other ways to make your Arduino responsive to external events while managing multiple tasks.<\/p>\n<p><img decoding=\"async\" class=\"project-pic\" src=\"https:\/\/www.digikey.com\/maker-media\/85734dd5-002b-40f8-8119-3893c6142128\" alt=\"\" \/><\/p>\n<div class=\"part-list-wrap\">\n<h2>Key Parts and Components<\/h2>\n<ul class=\"the-part-list small-block-grid-2 medium-block-grid-3\">\n<li>\n<div class=\"box-thumb\"><a href=\"https:\/\/www.digikey.com\/product-detail\/en\/adafruit-industries-llc\/170\/1528-1077-ND\/5154652?WT.mc_id=frommaker.io\"> <img decoding=\"async\" src=\"https:\/\/media.digikey.com\/Photos\/Adafruit%20Industries%20LLC\/170_tmb.jpg\" \/> <\/a><\/div>\n<h3>Adafruit Industries LLC<\/h3>\n<div class=\"title\"><a href=\"https:\/\/www.digikey.com\/product-detail\/en\/adafruit-industries-llc\/170\/1528-1077-ND\/5154652?WT.mc_id=frommaker.io\">EXPERIMENT KIT ARD UNO R3 V1.3<\/a><\/div>\n<div class=\"serial\">170<\/div>\n<div class=\"price\"><a href=\"https:\/\/www.digikey.com\/product-detail\/en\/adafruit-industries-llc\/170\/1528-1077-ND\/5154652?WT.mc_id=frommaker.io\">$84.95<\/a><\/div>\n<\/li>\n<li>\n<div class=\"box-thumb\"><a href=\"https:\/\/www.digikey.com\/product-detail\/en\/arduino\/A000073\/1050-1041-ND\/3476357?WT.mc_id=frommaker.io\"> <img decoding=\"async\" src=\"https:\/\/media.digikey.com\/Photos\/Arduino\/A000073_tmb.jpg\" \/> <\/a><\/div>\n<h3>Arduino<\/h3>\n<div class=\"title\"><a href=\"https:\/\/www.digikey.com\/product-detail\/en\/arduino\/A000073\/1050-1041-ND\/3476357?WT.mc_id=frommaker.io\">ARDUINO UNO SMD REV3<\/a><\/div>\n<div class=\"serial\">A000073<\/div>\n<div class=\"price\"><a href=\"https:\/\/www.digikey.com\/product-detail\/en\/arduino\/A000073\/1050-1041-ND\/3476357?WT.mc_id=frommaker.io\">$22.00<\/a><\/div>\n<\/li>\n<li>\n<div class=\"box-thumb\"><a href=\"https:\/\/www.digikey.com\/product-detail\/en\/adafruit-industries-llc\/68\/1528-1073-ND\/5154648?WT.mc_id=frommaker.io\"> <img decoding=\"async\" src=\"https:\/\/media.digikey.com\/Photos\/Adafruit%20Industries%20LLC\/MFG_68_tmb.jpg\" \/> <\/a><\/div>\n<h3>Adafruit Industries LLC<\/h3>\n<div class=\"title\"><a href=\"https:\/\/www.digikey.com\/product-detail\/en\/adafruit-industries-llc\/68\/1528-1073-ND\/5154648?WT.mc_id=frommaker.io\">STARTER PACK W\/METRO 328<\/a><\/div>\n<div class=\"serial\">68<\/div>\n<div class=\"price\"><a href=\"https:\/\/www.digikey.com\/product-detail\/en\/adafruit-industries-llc\/68\/1528-1073-ND\/5154648?WT.mc_id=frommaker.io\">$44.95<\/a><\/div>\n<\/li>\n<li>\n<div class=\"box-thumb\"><a href=\"https:\/\/www.digikey.com\/product-detail\/en\/adafruit-industries-llc\/193\/1528-1078-ND\/5154653?WT.mc_id=frommaker.io\"> <img decoding=\"async\" src=\"https:\/\/media.digikey.com\/Photos\/Adafruit%20Industries%20LLC\/193-contents_tmb.jpg\" \/> <\/a><\/div>\n<h3>Adafruit Industries LLC<\/h3>\n<div class=\"title\"><a href=\"https:\/\/www.digikey.com\/product-detail\/en\/adafruit-industries-llc\/193\/1528-1078-ND\/5154653?WT.mc_id=frommaker.io\">STARTER KIT W\/ARDUINO UNO R3<\/a><\/div>\n<div class=\"serial\">193<\/div>\n<div class=\"price\"><a href=\"https:\/\/www.digikey.com\/product-detail\/en\/adafruit-industries-llc\/193\/1528-1078-ND\/5154653?WT.mc_id=frommaker.io\">More Info<\/a><\/div>\n<\/li>\n<li>\n<div class=\"box-thumb\"><a href=\"https:\/\/www.digikey.com\/product-detail\/en\/arduino\/A000067\/1050-1018-ND\/2639006?WT.mc_id=frommaker.io\"> <img decoding=\"async\" src=\"https:\/\/media.digikey.com\/Photos\/Arduino\/MFG_A000067_tmb.jpg\" \/> <\/a><\/div>\n<h3>Arduino<\/h3>\n<div class=\"title\"><a href=\"https:\/\/www.digikey.com\/product-detail\/en\/arduino\/A000067\/1050-1018-ND\/2639006?WT.mc_id=frommaker.io\">BOARD MCU MEGA2560<\/a><\/div>\n<div class=\"serial\">A000067<\/div>\n<div class=\"price\"><a href=\"https:\/\/www.digikey.com\/product-detail\/en\/arduino\/A000067\/1050-1018-ND\/2639006?WT.mc_id=frommaker.io\">$38.50<\/a><\/div>\n<\/li>\n<\/ul>\n<p><a class=\"part-add-all\" href=\"https:\/\/www.digikey.com\/classic\/ordering\/fastadd.aspx?newCart=true&amp;part0=1528-1077-ND&amp;qty0=1&amp;part1=1050-1041-ND&amp;qty1=1&amp;part2=1528-1073-ND&amp;qty2=1&amp;part3=1528-1078-ND&amp;qty3=1&amp;part4=1050-1018-ND&amp;qty4=1\" rel=\"nofollow\">Add all Digi-Key Parts to Cart<\/a><\/div>\n<div>\n<ul>\n<li>1528-1077-ND<\/li>\n<li>1050-1041-ND<\/li>\n<\/ul>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>Multi-tasking the Arduino &#8211; Part 1 Courtesy of Adafruit Industries Bigger and Better Projects Once you have mastered the basic blinking leds, simple sensors and sweeping servos, it\u2019s time to move on to bigger and better projects. \u00a0That usually involves combining bits and pieces of simpler sketches and trying to make them work together. \u00a0The [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[569,207,1],"tags":[],"class_list":["post-3182","post","type-post","status-publish","format-standard","hentry","category-artigos","category-blog","category-sem-categoria","entry","owp-thumbs-layout-horizontal","owp-btn-normal","owp-tabs-layout-horizontal","has-no-thumbnails","has-product-nav"],"_links":{"self":[{"href":"https:\/\/arduxop.com.br\/loja\/wp-json\/wp\/v2\/posts\/3182","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/arduxop.com.br\/loja\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/arduxop.com.br\/loja\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/arduxop.com.br\/loja\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/arduxop.com.br\/loja\/wp-json\/wp\/v2\/comments?post=3182"}],"version-history":[{"count":0,"href":"https:\/\/arduxop.com.br\/loja\/wp-json\/wp\/v2\/posts\/3182\/revisions"}],"wp:attachment":[{"href":"https:\/\/arduxop.com.br\/loja\/wp-json\/wp\/v2\/media?parent=3182"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/arduxop.com.br\/loja\/wp-json\/wp\/v2\/categories?post=3182"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/arduxop.com.br\/loja\/wp-json\/wp\/v2\/tags?post=3182"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}