Industriële fabricage
Industrieel internet der dingen | Industriële materialen | Onderhoud en reparatie van apparatuur | Industriële programmering |
home  MfgRobots >> Industriële fabricage >  >> Manufacturing Technology >> Productieproces

Een Arduino multithreaden (Protothreading Tutorial)

Componenten en benodigdheden

Arduino UNO
× 1
Sunfounder Blue 16x2 Liquid Crystal Display (LCD)
× 1
Broodplank (algemeen)
en draden natuurlijk.
× 1
Draaipotentiometer (generiek)
Niet zeker van de weerstandsclassificatie, waarschijnlijk zou 1Kohm voldoende zijn.
× 1

Over dit project

Deze video toont iets wat je misschien al had willen doen tijdens je ontluikende carrière als prototype, een single-core arduino overhalen om 3 dingen tegelijk te doen. In dit geval zijn we:

  • De achtergrondverlichting pulseren met een constante snelheid zonder onderbreking
  • Elke seconde een geheel getal verhogen en dit zonder onderbreking naar het scherm schrijven
  • Om de paar seconden een paar berichten draaien en ze zonder onderbreking naar het scherm schrijven

Je hebt de titel gezien!

Protothreading is een manier om op een Arduino uit te voeren wat normaal gesproken een multitasking-bewerking zou zijn (twee of meer dingen tegelijk of met verschillende tussenpozen doen) . Met andere woorden, het is "multithreaded"! Maar wacht even Sparky, de Arduino is een single-core chip met procedurele code, dus echte multithreading is onmogelijk. Waarom? Hoe is protothreading anders?

"Echte" multithreading versus protothreading

Om protothreading te begrijpen goed, we moeten eerst begrijpen waarom het NIET echt multithreading is.

Weet je nog toen Intel ons dit nieuwe "Hyperthreading"-ding op Pentium-processors verkocht? Nee? Ben je nog niet geboren? Tijd voor een geschiedenisles dus, zoon! Hyperthreading is een technologie die Intel gebruikt om een ​​enkele kern op een processor te laten "werken" alsof het twee kernen zijn, of twee kernen "doen" alsof het 4 kernen zijn, enz. Maar waarom, en hoe is dat relevant voor Arduino? Het antwoord is cycli.

Zowel microcontrollers als CPU's werken in "cycli". Hoe snel ze ze doen (hoeveel in een seconde) is de kloksnelheid. Je hebt de Ghz-classificatie van een CPU gezien en je weet waarschijnlijk dat dit verband houdt met hoe snel het is. Hoe meer Ghz, hoe beter, toch? maar waarom? Want dat is het aantal cycli per seconde dat een processor kan bereiken (zonder oververhitting en vlam te vatten - echt waar!).

Als je een datasheet-nerd bent, weet je misschien dat de microprocessorchip van de Arduino Uno, de Atmel ATMega328P, uit de doos op 16Mhz werkt. Het is in staat tot 20 Mhz, maar wordt teruggebeld zodat het geen dingen verprutst zoals het schrijven van gegevens naar het geheugen (of, weet je, vlam vatten). 16 Mhz betekent dat je Arduino elke seconde 16.000.000 cycli verwerkt, oftewel 16 miljoen stukjes werk. Dit zijn GEEN regels code - dat zou razendsnel zijn en Arduino is relatief traag. Dit zijn processorinstructies zoals het verplaatsen van gegevens in en uit registers. Een lager niveau gaan dan dit overzicht is nogal technisch, dus ik laat dat als een oefening aan de lezer over, maar dat is de kern :)

Dus, als we maar zo snel op een kern kunnen gaan voordat de beste beschikbare chip vlam vat, zitten we dan voor altijd vast aan die snelheid? Is dat het snelste dat we kunnen doen? Het blijkt, nee! Voer multicore-CPU's en multithreading in. Op een computer-CPU zijn multithreaded-toepassingen twee afzonderlijke processen die parallel aan elkaar werken op verschillende kernen van een CPU. Deze processen werken samen om het werk samen gedaan te krijgen, maar verdelen het werk niet noodzakelijkerwijs gelijk, zoals je zou verwachten. Er is meestal een hoofdproces / "thread" dat functioneert als een beheerder van de andere threads, en vervolgens een of meer werkthreads die het beheert, die elk specifieke taken kunnen uitvoeren. Een goed voorbeeld is Chrome. Chrome is de beheerder van al uw webpaginatabbladen (threads), maar omdat Chrome multithreaded is, is elk tabblad zijn eigen kleine programma. Dat betekent dat het niet alleen sneller kan werken als je meerdere kernen hebt om elk tabblad over te verdelen, het heeft ook andere voordelen, zoals niet de hele browser crashen wanneer een tabblad crasht. Dit is de eerste reden waarom Protothreading geen multithreading is - we hebben maar één kern om mee te werken op een MCU, dus traditionele multithreading is regelrecht onmogelijk. We moeten het werk op slechts één kern beheren, maar toch meerdere dingen tegelijk doen. We hebben protothreading nodig.

Ok, hoe is Protothreading dan anders?

Protothreading lijkt tot op zekere hoogte erg op dat Hyperthreading-ding dat ik noemde. Hyperthreading zou een tweede kern nabootsen en het werk dat een kern doet letterlijk verdelen door zich voor te doen als twee virtuele kernen. Dit werkte omdat ze echt op dezelfde kern bestonden en dus dezelfde bronruimte deelden. Omdat de arduino MCU geen hyperthreading ondersteunt, kunnen we dat hier niet doen. Protothreading is vergelijkbaar, behalve dat in plaats van CPU-cycli en instructies, we het werk kunnen opsplitsen door de 'loops' of 'regels' code die door onze sketch worden uitgevoerd. Zoals je je misschien kunt voorstellen, als we meer dingen doen, zouden loops langer duren, dus elk project zal enorm verschillende 'loops per seconde' hebben. Er zijn verschillende implementaties van protothreading, en degene die ik hier gebruik is weliswaar waarschijnlijk slordig, maar het werkt. Kortom, voor elke lus hebben we geen ander werk te doen, we doen wat minder veeleisend of minder frequent werk in de hoofdlus (of helemaal niets). Als we niet bezig zijn, kijken we of het tijd is om nog een van die andere klussen te doen. Als dat zo is, vertakken we ons en gaan we het doen. Het is belangrijk op te merken dat acties die "blokkeren", wat betekent dat ze allemaal tegelijk moeten worden voltooid zonder onderbreking en dus de MCU voor een bepaalde tijd moeten vastzetten (zoals het lezen van gegevens van een SD-kaart en een paar andere taken) zal nog steeds blokkeren andere protothreads komen niet "op tijd" voor, maar voor eenvoudige dingen zoals twee lussen die tegelijk snelle acties uitvoeren zoals variabele wijzigingen of het wijzigen van uitvoerwaarden, zal het uitstekend werken. Dit is min of meer wat we hier gaan doen. Sommige MCU's ondersteunen een real-time besturingssysteem (RTOS) dat meer hyperthreading-achtige multitasking-mogelijkheden kan bieden, wat kan helpen bij het verminderen van problemen veroorzaakt door "blokkerende" taken.

Laten we beginnen.

We zoeken eerst uit welke taken we moeten uitvoeren. In mijn geval koos ik (a) de achtergrondverlichting van mijn LCD-paneel in en uit te doen voor een mooi "pulserend" effect, terwijl (b) een getal op een veel langzamer (en mogelijk niet-deelbaar) interval te tellen, en (c) het roteren van enkele stringberichten met een nog veel langzamer interval. Enkele richtlijnen die u moet volgen om ervoor te zorgen dat dit proces soepel verloopt, is om uw functies te beoordelen van de minst blokkerende tot de meest blokkerende. Acties (laten we ze vanaf dit punt "functies" noemen) die langer duren, zoals het lezen van gegevens of andere lange vertragingen hebben, en functies met grotere intervallen tussen het moment waarop ze worden geactiveerd, zijn de meest blokkerende functies. Functies die zeer vaak worden geactiveerd, zo niet elke lus, en die niet lang duren om te voltooien, zijn de minst blokkerende functies. De minste blokkerende functie is wat u als uw primaire "thread" zou moeten gebruiken. Kun jij raden welke het hierboven is?

Dat klopt, het is een "a", die de achtergrondverlichting in- en uitschakelt. Dit zal met een regelmatig en zeer snel interval zijn, eeuwigdurend zonder vertragingen tussen branden, behalve om het werk gedaan te krijgen, en het werk zelf is erg snel. De perfecte managerthread.

We zullen deze thread (en eventuele lussen erin) gebruiken om te controleren of de andere threads enig werk moeten doen. Het is waarschijnlijk het beste om de code op dit punt door te lezen - deze is zwaar gedocumenteerd. Zie de hoofdlus naar beneden. Je kunt me zien controleren of threads werk nodig hebben, waar ik numberThread.check() call bel en textThread.check() .

Ik moet dit ook binnen alle lussen in de hoofdthread doen, omdat ze tot voltooiing zullen blokkeren als ik dat niet doe. Ik stel het interval in waarmee de threads moeten worden geactiveerd wanneer ik ze initialiseer tijdens init of het setup-gedeelte van de code. Als het tijd is om deze threads te activeren, .check() zullen dat zien en hun werk uitvoeren voordat ze verder gaan met de hoofdthread.

Dat is het eigenlijk in een notendop, de rest kun je waarschijnlijk zelf achterhalen door door de code te stappen. Laat me eindigen met te zeggen, hoewel ik zo mag klinken, ik ben op geen enkele manier een protothreading-professional, dit is slechts een eenvoudig voorbeeld dat ik heb gehackt. Als je tips hebt of als ik het bij het verkeerde eind had, moedig ik feedback en correcties aan! Bedankt :)

Code

  • Multithreaded LCD-code - multithread.ino (bijgewerkt, v1.1)
Multithreaded LCD-code - multithread.ino (bijgewerkt, v1.1)Arduino
Dit stukje code gebruikt de -bibliotheek om 3 herhalende acties met afzonderlijke intervallen tegelijkertijd uit te voeren op één Arduino Uno-processor. Het zal (a) de achtergrondverlichting in- en uitfaden, terwijl (b) een getal wordt verhoogd en (c) tussen een paar tekstreeksen wordt geroteerd. Zie de video hierboven voor een demo :)
/*Arduino Protothreading Voorbeeld v1.1 door Drew Alden (@ReanimationXP) 1/12/2016- Update:v1.1 - 18/8/17 Arduino 1.6.6+ prototyping gewijzigd , kleine reparaties. (maak functies voor gebruik, verwijderde foreach en gerelateerde bibliotheek). Houd er rekening mee dat TimedAction nu verouderd is. Zorg ervoor dat u de opmerkingen over TimedAction en WProgram.h / Arduino.h-fouten leest. *///COMPONENTS/*Deze code is gemaakt met behulp van het blauwe LCD-scherm van de Sunfounder Arduino-starterkit. Hij is te vinden op Amazon.com in verschillende kits .*///THIRD-PARTY LIBRARIES//deze moeten handmatig worden toegevoegd aan uw Arduino IDE-installatie//TimedAction// stelt ons in staat om acties in te stellen die op afzonderlijke getimede intervallen moeten worden uitgevoerd//http://playground.arduino.cc/Code /TimedAction//http://wiring.uniandes.edu.co/source/trunk/wiring/firmware/libraries/TimedAction#include //OPMERKING:Deze bibliotheek heeft een probleem met nieuwere versies van Arduino. Na// het downloaden van de bibliotheek MOET u naar de bibliotheekdirectory gaan en// TimedAction.h bewerken. Overschrijf WProgram.h met Arduino.h//NATIVE LIBRARIES#include  /* LiquidCrystal Library - Hello World Demonstreert het gebruik van een 16x2 LCD-scherm. De LiquidCrystal-bibliotheek werkt met alle LCD-schermen die compatibel zijn met de Hitachi HD44780-driver. Er zijn er veel en je kunt ze meestal zien aan de 16-pins interface. Een voorbeeldschakeling:* LCD RS-pin naar digitale pin 12. * LCD Enable/E/EN-pin naar digitale pin 11 * LCD D4-pin naar digitale pin 5 * LCD D5-pin naar digitale pin 4 * LCD D6-pin naar digitale pin 3 * LCD D7 pin naar digitale pin 2 * LCD R/W pin naar aarde * LCD VSS pin naar aarde * LCD VCC/VDD pin naar 5V * 10K weerstand:* eindigt op +5V en aarde * wiper (middelste) naar LCD VO pin ( pin 3) *Displays met achtergrondverlichting:* LCD K pin naar aarde (indien aanwezig) * LCD A pin naar 220ohm (rood rood zwart zwart (bruin)) weerstand, dan weerstand naar pin 9 Deze voorbeeldcode is in het publieke domein. http://www.arduino.cc/en/Tutorial/LiquidCrystal *///GLOBALSint backlightPin =9; // gebruikt voor backlight fadeint timerCounter =0; // oplopende teller. zal uiteindelijk crashen.int stringNo =0; //welke tekenreeks moet worden weergegeven// "16 KARAKTER MAX"char* stringArray[]={"Bekijk het eens... ", "Ik heb 3 threads", "ga meteen...", "Cool, huh ?! :D "}; //INIT// Dit zou waarschijnlijk binnen setup() moeten worden gedaan, maar wat dan ook.// initialiseer de LCD-bibliotheek met de nummers van de interface-pinnenLiquidCrystal lcd (12, 11, 5, 4, 3, 2);//FUNCTIES/ / dit is onze eerste taak, druk een oplopend getal af naar de LCDvoid incrementNumber(){ // zet de cursor op kolom 0, regel 1 // (let op:regel 1 is de tweede rij, aangezien het tellen begint met 0):lcd. setCursor(0, 1); // voeg er een toe aan de teller en geef deze weer. timerCounter =timerCounter + 1; lcd.print(timerCounter);}//onze tweede taak wordt om de paar seconden geactiveerd en roteert tekststringsvoid changeText(){ // Druk een bericht af op het LCD-scherm. lcd.setCursor(0, 0); lcd.print(stringArray[stringNo]); // vervelende hack om het aantal array-elementen te krijgen if (stringNo>=sizeof(stringArray)/sizeof(char *)){ stringNo =0; veranderText(); } else{ stringNo =stringNee + 1; }}//Maak een paar timers die elke x ms herhaaldelijk worden geactiveerd//edit:deze regels stonden vroeger voor de functies incrementNumber en changeText//. dit werkte niet omdat de functies nog niet waren gedefinieerd!TimedAction numberThread =TimedAction(700,incrementNumber);TimedAction textThread =TimedAction(3000,changeText);// waar is onze derde taak? wel, het is de hoofdlus zelf :) de taak// die het vaakst wordt herhaald, moet als de lus worden gebruikt. andere// taken kunnen de snelst herhalende task.void setup() "onderbreken" { //definieer het aantal kolommen en rijen van het LCD-scherm:lcd.begin(16, 2); // vuur changeText één keer af om de eerste string [0] changeText ();}void loop () te schilderen { // controleer onze threads. op basis van hoe lang het systeem // draait, moeten ze vuren en werken? zo ja, doen! nummerThread.check(); textThread.check(); // derde taak, achtergrondverlichting vervagen van min tot max helderheid // in stappen van 5 punten:digitalWrite (13, HIGH); for (int fadeValue =0; fadeValue <=255; fadeValue +=10) { // wacht even, waarom controleer ik de threads hier? omdat //dit een for-lus is. je moet je threads controleren tijdens ELKE //loops die zich voordoen, inclusief de belangrijkste! nummerThread.check(); textThread.check(); // stelt de waarde in (bereik van 0 tot 255):analogWrite (backlightPin, fadeValue); // wacht 20 milliseconden om het dimeffect te zien // houd vertragingen op de hoofdlus KORT. deze ZULLEN voorkomen dat // andere threads op tijd afvuren. vertraging(20); } //fade out van max naar min in stappen van 5 punten:digitalWrite(13, LOW); for (int fadeValue =255; fadeValue>=0; fadeValue -=10) { // check onze threads opnieuw numberThread.check(); textThread.check(); // stelt de waarde in (bereik van 0 tot 255):analogWrite (backlightPin, fadeValue); // wacht 20 milliseconden om de vertraging van het dimeffect (20) te zien; } /* Voor wat plezier met scrollen in de toekomst... lcd.setCursor(15,0); // zet de cursor op kolom 15, regel 0 voor (int positionCounter1 =0; positionCounter1 <26; positionCounter1++) { lcd.scrollDisplayLeft(); // Schuift de inhoud van het scherm één spatie naar links. lcd.print(array1[positionCounter1]); // Druk een bericht af op het LCD-scherm. vertraging (tijd); // wacht 250 microseconden } lcd.clear (); // Wist het LCD-scherm en plaatst de cursor in de linkerbovenhoek. lcd.setCursor(15,1); // zet de cursor op kolom 15, regel 1 voor (int positionCounter =0; positionCounter <26; positionCounter++) { lcd.scrollDisplayLeft(); // Schuift de inhoud van het scherm één spatie naar links. lcd.print(array2[positionCounter]); // Druk een bericht af op het LCD-scherm. vertraging (tijd); // wacht 250 microseconden } lcd.clear (); // Wist het LCD-scherm en plaatst de cursor in de linkerbovenhoek. */ }

Productieproces

  1. Hoe de luchtkwaliteit op OpenSensors te meten
  2. Arduino RFID Lock-zelfstudie
  3. IR-afstandsbedieningen hacken
  4. Hoe lang ben je?
  5. Hoe gemakkelijk is het om een ​​thermistor te gebruiken?!
  6. Muziek maken met een Arduino
  7. Hoe NMEA-0183 te gebruiken met Arduino
  8. Tutorial Arduino-vingerafdruksensor
  9. Modbus gebruiken met Arduino
  10. Arduino-zelfstudie:minipiano
  11. Arduino-zelfstudie 01:Aan de slag