Fråga:
Kan en funktion anropas automatiskt när en ingång ändras?
Peter Bloomfield
2014-02-20 06:42:53 UTC
view on stackexchange narkive permalink

För närvarande kontrollerar min skiss en inmatningsstift varje gång runt huvudslingan. Om den upptäcker en förändring, kallar den en anpassad funktion för att svara på den. Här är koden (trimmad till det väsentliga):

  int pinValue = LOW; void pinChanged () {//...}avid setup () {pinMode (2, INPUT);} void loop () {// Läs aktuell ingång int newValue = digitalRead (2); // Har ingången förändrats? if (newValue! = pinValue) {pinValue = newValue; pinChanged (); }}  

Tyvärr fungerar det inte alltid ordentligt för mycket korta ändringar på ingången (t.ex. korta pulser), särskilt om loop () kör en lite långsamt.

Finns det ett sätt att få Arduino att upptäcka ingångsändringen och ringa min funktion automatiskt?

Vad du letar efter är ett externt avbrott
Tre svar:
#1
+26
Peter Bloomfield
2014-02-20 06:42:53 UTC
view on stackexchange narkive permalink

Du kan göra detta med externa avbrott. De flesta Arduinos stöder dock bara detta på ett begränsat antal stift. För fullständig information, se dokumentationen om attachInterrupt () .

Förutsatt att du använder en Uno kan du göra det så här:

  ogiltig pinChanged () {//...} ogiltig installation () {pinMode (2, INPUT); attachInterrupt (0, pinChanged, CHANGE);} void loop () {}  

Detta kommer att ringa pinChanged () när en ändring upptäcks vid externt avbrott 0. På Uno motsvarar det GPIO-stift 2. Den externa avbrottsnumreringen är annorlunda på andra kort, så det är viktigt att kontrollera relevant dokumentation.

Det finns dock begränsningar för detta tillvägagångssätt. Den anpassade pinChanged () -funktionen används som en Interrupt Service Routine (ISR). Det betyder att resten av koden (allt i loop () ) stoppas tillfälligt medan samtalet körs. För att förhindra att någon viktig tidpunkt störs bör du sträva efter att göra ISR så snabbt som möjligt.

Det är också viktigt att notera att inga andra avbrott kommer att köras under din ISR. Det betyder att allt som förlitar sig på avbrott (som kärnfunktionerna delay () och millis () ) kanske inte fungerar korrekt inuti den.

Slutligen, om din ISR behöver ändra några globala variabler i skissen, ska de vanligtvis förklaras som flyktiga , t.ex.:

  flyktiga int someNumber;  

Det är viktigt eftersom det säger till kompilatorn att värdet kan ändras oväntat, så det bör vara försiktigt så att inga föråldrade kopior / cachar av det används.

angående de "korta pulserna" som nämns i frågan, finns det en minsta tid som stiftet måste vara i ett tillstånd för att det ska utlösa avbrottet? (uppenbarligen blir det mycket mindre än avfrågning, vilket beror på vad som händer i slingan)
@sachleen Det fungerar så länge det inte händer under utförandet av en ISR-funktion (som förklaras i svaret); det är därför `pinChanged ()` ska vara så kort som möjligt. Därför bör minimitiden vara tiden för att utföra själva funktionen 'pinChanged ()'.
+1 för detta mycket detaljerade svar som innehåller alla viktiga saker man måste bry sig om när man använder avbrott!
Förutom att förklara delade globaler som "flyktiga", om den globala variabeln är bredare än 1 byte, som someNumber är, måste du skydda mot avbrottet för pin-change som uppstår mellan byte-åtkomst från programmet. Ett uttalande som "someNumber + = 5;" innebär att man lägger till låga byte och lägger till höga byte med bär inkluderat. Dessa två (mer, för bredare variabler) får inte delas med ett avbrott. Det är tillräckligt att stänga av avbrottet och återställa dem före respektive efter operationen.
@sachleen - angående minsta pulsstorlek. Det är svårt att hitta ett definitivt svar i databladet, men att döma av tidpunkten för stiftbytesavbrott låses de inom en halv klockcykel. När avbrottet "kommer ihåg" förblir det ihåg tills ISR sparkar in och hanterar det.
#2
+5
mpflaga
2014-02-24 20:36:06 UTC
view on stackexchange narkive permalink

Varje förändringstillstånd på alla stift som är konfigurerade som digitalingång kan skapa ett avbrott. Till skillnad från de unika vektorerna för avbrottsorsakerna av INT1 eller INT2, använder PinChangeInt-funktionen en gemensam vektor och sedan behöver Interrupt Service Routine (även kallad ISR) för denna vektor bestämma vilken stift som har ändrats.

Lyckligtvis gör PinChangeInt Library det här enkelt.

  PCintPort :: attachInterrupt (PIN, burcount, RISING); // bifoga en PinChange Interrupt till vår pin på den stigande kanten // (RISING, FALLING and CHANGE allt fungerar med det här biblioteket) // och kör funktionen burpcount när den pin ändras  
#3
  0
Nick Gammon
2015-07-01 07:27:55 UTC
view on stackexchange narkive permalink

Om du vill detektera en spänning som passerar en tröskel , snarare än att bara vara HÖG eller LÅG, kan du använda den analoga komparatorn. Exempel på skiss:

  flyktig boolean utlöst; ISR (ANALOG_COMP_vect) {triggered = true; } ogiltig installation () {Serial.begin (115200); Serial.println ("Startad."); ADCSRB = 0; // (Inaktivera) ACME: Analog Comparator Multiplexer Aktivera ACSR = bit (ACI) // (Clear) Analog Comparator Interrupt Flag | bit (ACIE) // Analog Comparator Interrupt Enable | bit (ACIS1); // ACIS1, ACIS0: Analog Comparator Interrupt Mode Select (trigger on falling edge)} // slutet av setupvoid loop () {if (triggered) {Serial.println ("Triggered!"); utlöst = falskt; }} // slingans slut  

Detta kan vara användbart för saker som ljusdetektorer, där du kan behöva upptäcka en ändring från (säg) 1V till 2V på en ingång.

Exempel på krets:

enter image description here

Du kan också använda Input Capture Unit på processorn, som kommer ihåg den exakta tiden för vissa ingångar genom att spara aktuellt antal timer / räknare 1. Detta låter dig lagra det exakta (ja, nästan exakta) ögonblicket som händelsen av intresse inträffade, snarare än att införa förseningen (förmodligen några mikrosekunder) innan en ISR kan användas för att fånga den aktuella tid.

För tidskritiska applikationer kan detta ge något ökad noggrannhet.

Exempel på applikation: Förvandla din Arduino till en kondensatortestare



Denna fråga och svar översattes automatiskt från det engelska språket.Det ursprungliga innehållet finns tillgängligt på stackexchange, vilket vi tackar för cc by-sa 3.0-licensen som det distribueras under.
Loading...