Fråga:
Vad händer om det finns ett runtime-fel?
The Guy with The Hat
2014-02-14 07:33:03 UTC
view on stackexchange narkive permalink

Vad händer om det finns ett runtime-fel i ett program? Kommer programmet att bara sluta? Finns det något sätt att få Arduino att berätta vad felet är?

Sex svar:
#1
+21
Ricardo
2014-02-15 03:24:20 UTC
view on stackexchange narkive permalink

Låt oss först se några exempel på vad som kan gå fel.

Oinitialiserade lokala variabler

  ogiltig inställning () {int status; pinMode (13, OUTPUT); digitalWrite (13, status);} 

Som påpekats av Edgar Bonet i kommentarerna, lokala variabler som status i koden ovan initialiseras inte implicit av C ++ - kompilatorn. Så resultatet av koden ovan är obestämt. För att undvika det, se till att du alltid tilldelar värden till dina lokala variabler.

Saker och ting är lite annorlunda med globala och statiska variabler:

Globala och statiska variabler garanteras att initieras till 0 av C-standarden.

Källa: AVR Libc Referenshandbok - Vanliga frågor - Ska jag inte initialisera alla mina variabler?

Det betyder att du inte bör oroa dig för att initialisera dem till 0 i din kod. I själva verket bör du verkligen undvika det, eftersom initialiseringen kan slösa minne. Initiera dem bara till andra värden än 0.

Memory overflow

  int array [10]; int v = array [100]; array [-100] = 10; 

Det första problemet här är att du inte vet vad som kommer att tilldelas v, men värre är att du inte vet vad du trasslat med uppdraget till position -100 av -array.

Hoppa till en olaglig instruktion

  void doSomething (void) {for (int i = 0; i < 1000; i ++) ; } void setup () {void (* funcPtr) (void); funcPtr = &doSomething; funcPtr (); // kallar doSomething (); funcPtr = NULL; funcPtr (); // odefinierat beteende}  

Det första samtalet till funcPtr () blir faktiskt ett samtal till doSomething () . Samtal som den andra kan leda till odefinierat beteende.

Andra dåliga saker som kan hända

Tja, du kan tömma RAM till exempel. Vad annars. I vilket fall som helst tror jag att ditt program kommer att fortsätta, förmodligen inte som du tänkt det.

Typer av skydd

I datorsystem hanteras vanligtvis sådana problem på olika nivåer:

  1. Av kompilatorn
  2. Genom programmeringsspråkets körtid (som till exempel i Java) .
  3. Av operativsystemet eller processorn (om ditt minne får åtkomst till en position utanför gränserna för det adressutrymme som är reserverat för ditt program, kan operativsystemet eller processorn ha säkerhetsmekanismer för att förhindra det)

Arduinos har bara begränsat skydd av kompilatorn, och förmodligen inget annat. Den goda nyheten är att de inte har flera uppgifter, så det enda programmet som påverkas är ditt. I vilket fall som helst kommer någon av dessa buggar att leda till oregelbundna beteenden.

Svaren

Antagandena är alla de problem som jag angav ovan är runtime-problem.

Vad händer om det finns ett runtime-fel i ett program?

Programmet fortsätter och vad som händer beror på biverkningarna av runtime-felet. Ett samtal till nollfunktionspekaren kommer förmodligen att få programmet att hoppa till en okänd plats.

Kommer programmet att sluta bara?

Nej, det kommer att fortsätta som om inget extraordinärt hände, förmodligen göra det du inte tänkte göra. Det kan återställas eller agera felaktigt. Det kan förvandla vissa ingångar till utgångar och bränna en sensor eller två (men det är mycket osannolikt ).

Finns det något sätt att få Arduino att berätta för mig vad fel är?

Jag tror inte det. Som jag sa tidigare är skyddsmekanismerna inte där. Det finns inget runtime-stöd från språket, inget operativsystem, ingen hårdvarukontroll för minnesåtkomst utanför gränserna (startladdaren räknas inte heller). Du måste bara vara försiktig med ditt program och förmodligen ställa in dina egna skyddsnät.

Anledningen till bristen på skydd är förmodligen för att Arduino-kontroller är för billiga, har för lite minne och inte bör köra något för viktigt (ja, det verkar finnas en ansvarsfriskrivning från AVR någonstans för att du inte ska använda MCU: erna används normalt av Arduino i livsuppehållande system).

Bra! Det bästa svaret jag har sett på Arduino.SE hittills!
Tack!! Jag tror att vi bör sträva efter att ge bra svar så mycket som möjligt. Men det oroar mig lite det faktum att vi inte har så många REAL EE-EXPERTER som kan titta på svar som mina och hitta några uppenbara misstag. Det är faktiskt anledningen till att jag publicerade svaret även om jag inte vet så mycket om AVR MCU. Det är för att se om vi får någon att korrigera det. Vi vill säkert inte att smarta penter som jag säger saker som inte stämmer och kommer undan med det. Men det är förmodligen en diskussion för Meta-webbplatsen.
Skulle något av detta skada Arduino?
@AnnonomusPerson - Den enda troliga mekanismen för skada skulle vara kod som ändrar stiftstatus på ett sätt som resulterar i en busskonflikt (t.ex. ATmega försöker ställa in en stift hög, medan extern hårdvara sätter den låg). Det är också möjligt att om det finns extern hårdvara så kontrollerar ATmega som inte kan hantera vissa kontrollingångstillstånd, * den externa hårdvaran * kan orsaka ett visst misslyckande och skada, men en arduino utan ingenting anslöt den ganska skottsäker. Arduinos har seriemotstånd för att förhindra eventuella konfliktproblem på serielinjerna.
@Ricardo - En kommentar jag skulle göra är att icke-uttryckligen initialiserade variabler inte * nödvändigtvis * är oinitialiserade. Variabler som definieras utanför funktioner har i allmänhet det som kallas "automatisk lagringstid", som sedan initialiseras som standard till noll. Se http://en.cppreference.com/w/cpp/language/default_initialization för mer information. Initieringsbeteendet är tillräckligt komplicerat för att det förmodligen är farligt att lita på, men att göra filtuttalanden är * förmodligen * ingen bra idé.
Dessutom initieras SRAM till 0 vid återställning eller start, så att du kan göra * några * informerade gissningar om oinitialiserade variabler, om du vill leva farligt. Du bör inte * lita på * detta beteende, men det är intressant.
Det finns ett intressant exempel på vad som händer när du tar slut på SRAM här: http://electronics.stackexchange.com/questions/42049/arduino-serial-print-changes-behavior-of-program-undesireably/42069. I grund och botten klumpar stacken en del av högen, eller tvärtom. Detta kan göra intressanta saker som att förstöra någon del av stack-ramen (bryta funktion returnerar, etc) eller skriva ogiltiga data till variabler.
Frågan om rekursion är också relevant: http://arduino.stackexchange.com/questions/355/how-much-can-i-recurse-how-much-can-i-recurse-how-much-caqfsdrfw eftersom rekursion är ett av de enkla sätten att blåsa stacken.
@FakeName - Rätt! Jag redigerar mitt svar för att fixa uttalandet om oinitialiserade variabler. När det gäller de andra fantastiska förslagen som du har lagt upp, varför gör du dem inte till svar så lägger jag till en hänvisning till det från mitt? Glad att se dig (eller kanske bara bilden av din irriterade katt) här.
@FakeName - BTW, den bilden påminner mig alltid om den stora Cat Yodeling * -tekniken * från [Engineer's Guide to Cats] (http://www.youtube.com/watch?v=mHXBL6bzAR4) vid 4: 57min.
En anmärkning: "Den goda nyheten är att du bara trasslat med RAM och inte med EEPROM, så ditt program är säkert." Programmet som körs på ATmega lagras i Flash-minnet, inte EEPROM. EEPROM är i allmänhet bara 1-2 kB och är mer för att lagra små mängder icke-flyktiga data (tänk: användarkonfigurationsinställningar, serienummer, etc ...), inte faktisk kod.
@ConnorWolf Rätt! Väl prickig. Redigerade och fixade mitt svar.
`C ++ - kompilatorn gör det åt dig. Det sätter det som noll` Lokala variabler initialiseras inte. Jag tolkar "status" som lokal i ditt exempel, därför är det fel. `det anses inte vara god praxis att förlita sig på den beteendet` det är faktiskt ** anses ** vara god praxis att förlita sig på detta beteende för globala variabler eftersom det är garanterat att de kommer att initialiseras noll och noll initialiserande globaler i din kod kan slösa minne (även om nuvarande kompilatorer borde vara smarta för att undvika detta) se http://www.atmel.com/webdoc/AVRLibcReferenceManual/FAQ_1faq_varinit.html
Du skrev: “_`array [-100] = 10;` [...] du förstörde bara med RAM [...] så att ditt program är säkert._ ”Du kan mycket väl sluta skriva i IO-utrymmet i MCU, som är minneskartad precis under RAM på AVR: erna. Detta är definitivt _inte säkert_. “_ [Ringa en NULL-funktionspekare] som motsvarar en mjuk start_”. Inte exakt. Programmet startar om från början: det initialiserar stackpekaren, RAM, samtalshuvud etc. Men, till skillnad från en mjuk start, återställer det inte _ inte_ IO-registren till deras standardstartläge.
@Connor Wolf: Du skrev: “_SRAM initialiseras till 0 vid återställning eller start_”. Detta är felaktigt. Till skillnad från IO-registren initialiseras inte SRAM av hårdvaran vid start. BSS-sektionen i RAM (och endast detta avsnitt) initialiseras till noll av C-körtiden. DATA-avsnittet initialiseras till vilket innehåll som programmeraren begär. Allt återstående RAM lämnas oinitialiserat.
@EdgarBonet - Punkt tas. Synd att jag inte kan redigera mina äldre kommentarer.
@EdgarBonet - Tack för att du påpekade problemet med mitt svar. Jag läste länken du angav och har försökt korrigera uttalandena om lokala variabler. Kan du snälla kolla in det? Tack!
Ditt uttalande om att programmet startar om när du ringer till en NULL-funktionspekare var korrekt, åtminstone på AVR. Jag påpekade bara att omstart av programmet inte är helt detsamma som en återställning. BTW, det finns ingen olaglig instruktion inblandad i processen. ”_Vill du snälla kolla in det? _” Jag kan inte hitta något fel i ditt svar.
#2
+9
Connor Wolf
2014-02-15 05:26:18 UTC
view on stackexchange narkive permalink

Det finns inga undantag för runtime. Det finns bara odefinierat beteende.

Det finns verkligen inga undantag alls . Om du försöker utföra en ogiltig åtgärd blir resultaten okända.

Det finns ingen kontroll av runtime alls förutom vad du implementerar. Ditt program körs på hårdmetall. Det är skrivbordsekvivalenten för att köras i ring-0 hela tiden, eftersom ATmega inte har ringar .

#3
+6
nio
2014-02-15 17:44:12 UTC
view on stackexchange narkive permalink

Det finns en mekanism som kan få MCU från oberoende tillstånd och det är vakthundstimern . Om du implementerar en kod som körs upprepade gånger i en slinga, som inte kommer att köras längre än någon fast tid, kan du ställa in den här tiden som vakthundperiod och aktivera timern.

Då måste du återställa timern upprepade gånger i slingan. Om din kod fryser vid någon tillståndsslinga som aldrig kommer att sluta räknar vakthunden till noll och slutligen återställer MCU.

På det här sättet tappar du data, men om du kör AVR WDT i avbrottsläge , kan du lagra lite data innan du återställer MCU.

Så vakthundstimern kan skydda din kod från oavsiktliga oavsiktliga slingor.

Dokumentation: AVR132: Använda Enhanced Watchdog Timer

#4
+5
sachleen
2014-02-14 07:47:14 UTC
view on stackexchange narkive permalink

Du behöver en maskinvarufelsökning för något liknande detta. Men vanligtvis ser du att programmet inte beter sig som du förväntar dig och måste titta på det avsnittet i koden för att identifiera problemet.

Ett vanligt / snabbt / enkelt sätt att göra detta är att lägg till utskriftsuttalanden för att skriva ut värdena på variabler eller bara vad som helst så att du vet att programmet kommer till den punkten i koden utan problem. Detta hjälper dig att isolera problemet ytterligare.

Jag tror att VisualMicro har inbyggd felsökningsfunktionalitet.

#5
+3
TheDoctor
2014-02-14 07:50:32 UTC
view on stackexchange narkive permalink

Jag antar att AVR-CPU inte har några verktyg för feldetektering eller återställning. Det kan bara sluta eller fortsätta ignorera felet och konsekvenserna. Som sachleen sa, bör du lägga till några felsökningsuttalanden i ditt program som skriver ut data mitt i en operation för att testa om det fungerar. Om du använder en emulator eller ställer in brytpunkter kan du enkelt hitta ett problem.

#6
-2
user28739
2016-12-03 04:18:45 UTC
view on stackexchange narkive permalink

Arduino startar om (dvs. den startar om inställning () och slinga () ).

Inte nödvändigtvis. Ett körtidsfel kan få programmet att gå i en krets utan att starta om.


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...