Vraag:
Wat gebeurt er als er een runtime-fout optreedt?
The Guy with The Hat
2014-02-14 07:33:03 UTC
view on stackexchange narkive permalink

Wat gebeurt er als er een runtime-fout in een programma zit? Zal de uitvoering van het programma gewoon stoppen? Is er een manier waarop ik de Arduino zover kan krijgen dat hij me vertelt wat de fout is?

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

Laten we eerst een paar voorbeelden bekijken van wat er mis kan gaan.

Niet-geïnitialiseerde lokale variabelen

  void setup () {int status; pinMode (13, UITGANG); digitalWrite (13, status);} 

Zoals aangegeven door Edgar Bonet in de commentaren, lokale variabelen zoals status in de code hierboven worden niet impliciet geïnitialiseerd door de C ++ - compiler. Het resultaat van de bovenstaande code is dus onbepaald. Om dit te voorkomen, moet u ervoor zorgen dat u altijd waarden toekent aan uw lokale variabelen.

Dingen zijn een beetje anders met globale en statische variabelen:

Globale en statische variabelen zijn gegarandeerd worden geïnitialiseerd op 0 door de C-standaard.

Bron: AVR Libc Referentiehandleiding - Veelgestelde vragen - Moet ik niet al mijn variabelen initialiseren?

Dat betekent dat u zich geen zorgen hoeft te maken over het initialiseren naar 0 in uw code. In feite moet u het echt vermijden, omdat de initialisatie geheugen kan verspillen. Initialiseer ze alleen op andere waarden dan 0.

Geheugenoverloop

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

Het eerste probleem hier is dat je niet weet wat er aan v wordt toegewezen, maar erger is dat je niet weet wat je hebt verknoeid met de toewijzing aan positie -100 van array.

Spring naar een illegale instructie

  void doSomething (void) {for (int i = 0; i < 1000; i ++) ; } void setup () {void (* funcPtr) (void); funcPtr = &doSomething; funcPtr (); // roept doSomething () aan; funcPtr = NULL; funcPtr (); // ongedefinieerd gedrag}  

De eerste aanroep naar funcPtr () zal in feite een aanroep zijn naar doSomething () . Oproepen zoals de tweede kunnen tot ongedefinieerd gedrag leiden.

Andere slechte dingen die kunnen gebeuren

Nou, je kunt bijvoorbeeld geen RAM meer hebben. Wat nog meer. In ieder geval denk ik dat je programma blijft draaien, waarschijnlijk niet zoals je het bedoeld had.

Soorten bescherming

In computersystemen worden problemen zoals deze gewoonlijk op verschillende niveaus aangepakt:

  1. Door de compiler
  2. Door de programmeertaal runtime (zoals in Java bijvoorbeeld) .
  3. Door het besturingssysteem of de processor (als uw geheugen toegang krijgt tot een positie buiten de grenzen van de adresruimte die is gereserveerd voor uw programma, kan het besturingssysteem of de processor veiligheidsmechanismen hebben om dat te voorkomen)

Arduinos hebben slechts een beperkte bescherming van de compiler, en waarschijnlijk niets anders. Het goede nieuws is dat ze niet multi-tasked zijn, dus het enige programma dat wordt beïnvloed, is dat van jou. In elk geval zal elk van deze bugs leiden tot grillig gedrag.

De antwoorden

De veronderstellingen zijn dat alle problemen die ik hierboven noemde runtime-problemen zijn.

Wat gebeurt er als er een runtime-fout in een programma zit?

Het programma zal doorgaan en wat er gebeurt, hangt af van de bijwerkingen van de runtime-fout. Een aanroep van de null-functie pointer zal het programma waarschijnlijk naar een onbekende locatie laten springen.

Zal de uitvoering van het programma gewoon stoppen?

Nee, het zal doorgaan alsof er niets buitengewoons is gebeurd, waarschijnlijk doen wat u niet van plan was. Het kan worden gereset of onregelmatig werken. Het kan sommige inputs in outputs veranderen en een of twee sensoren verbranden (maar dat is hoogst onwaarschijnlijk ).

Is er een manier waarop ik de Arduino zover krijg dat hij me vertelt wat de fout is?

Ik denk het niet. Zoals ik al eerder zei, zijn de beschermingsmechanismen er niet. Er is geen runtime-ondersteuning van de taal, geen besturingssysteem, geen hardwarecontroles voor out-of-bounds geheugentoegang (de bootloader telt ook niet mee). Je moet gewoon voorzichtig zijn met je programma en waarschijnlijk je eigen vangnetten instellen.

De reden voor het gebrek aan bescherming is waarschijnlijk omdat Arduino-controllers te goedkoop zijn, te weinig geheugen hebben en niets te belangrijks zouden moeten draaien (ja, er lijkt ergens een disclaimer van AVR te zijn waar je de MCU's niet mag gebruiken normaal gebruikt door Arduino in levensondersteunende systemen).

Super goed! Het beste antwoord dat ik tot nu toe heb gezien op Arduino.SE!
Bedankt!! Ik vind dat we ernaar moeten streven om zoveel mogelijk goede antwoorden te geven. Maar het baart me een beetje zorgen dat we niet zoveel ECHTE EXPERTS hebben die naar antwoorden zoals de mijne kunnen kijken en flagrante fouten kunnen vinden. Dat is eigenlijk de reden waarom ik het antwoord heb gepost, ook al weet ik niet zoveel van AVR MCU's. Dat is om te zien of we iemand krijgen om het te corrigeren. We willen zeker geen slimme pents zoals ik die dingen zeggen die niet kloppen en ermee wegkomen. Maar dat is waarschijnlijk een discussie voor de Meta-site.
Zou dit de Arduino beschadigen?
@AnnonomusPerson - Het enige waarschijnlijke mechanisme voor schade is code die de pinstatus verandert op een manier die resulteert in een busconflict (bijv. De ATmega probeert een pin hoog te zetten, terwijl externe hardware deze laag zet). Het is ook mogelijk dat als er externe hardware is die de ATmega bestuurt en die bepaalde controle-ingangstoestanden niet aankan, * de externe hardware * op de een of andere manier een storing en beschadiging kan veroorzaken, maar een Arduino met niets aangesloten is behoorlijk kogelvrij. De arduino's hebben serieweerstanden om mogelijke problemen op de seriële lijnen te voorkomen.
@Ricardo - Een opmerking die ik zou maken is dat niet-expliciet geïnitialiseerde variabelen niet * noodzakelijk * niet-geïnitialiseerd zijn. Variabelen die buiten de functies zijn gedefinieerd, hebben over het algemeen een zogenaamde "automatische opslagduur", die vervolgens standaard op nul wordt geïnitialiseerd. Zie http://en.cppreference.com/w/cpp/language/default_initialization voor meer informatie. Het initialisatiegedrag is zo complex dat het waarschijnlijk gevaarlijk is om erop te vertrouwen, maar algemene uitspraken doen is * waarschijnlijk * geen goed idee.
Bovendien wordt de SRAM geïnitialiseerd op 0 bij het resetten of opstarten, dus u kunt * enkele * geïnitialiseerde gissingen doen over niet-geïnitialiseerde variabelen, als u gevaarlijk wilt leven. Je moet niet * vertrouwen * op dit gedrag, maar het is interessant.
Er is een interessant voorbeeld van wat er gebeurt als je SRAM op is: http://electronics.stackexchange.com/questions/42049/arduino-serial-print-changes-behavior-of-program-undesireably/42069. Kortom, de stapel beslaat een deel van de hoop, of vice versa. Dit kan interessante dingen doen, zoals het beschadigen van een deel van het stapelframe (retournering van de functie breken, enz.), Of het schrijven van ongeldige gegevens naar variabelen.
Ook relevant is de vraag over recursie: http://arduino.stackexchange.com/questions/355/how-much-can-i-recurse-how-much-can-i-recurse-how-much-caqfsdrfw aangezien recursie is een van de gemakkelijke manieren om de stapel op te blazen.
@FakeName - Juist! Ik zal mijn antwoord bewerken om de verklaring over niet-geïnitialiseerde variabelen te corrigeren. Wat betreft de andere geweldige suggesties die je hebt gepost, waarom geef je ze geen antwoord en ik zal er een verwijzing naar toevoegen vanuit de mijne? Blij je hier te zien (of misschien gewoon de foto van je geïrriteerde kat).
@FakeName - Tussen haakjes, die foto doet me altijd denken aan de geweldige Cat Yodeling * -techniek * van [Engineer's Guide to Cats] (http://www.youtube.com/watch?v=mHXBL6bzAR4) om 4:57 minuten.
Een opmerking: "Het goede nieuws is dat je alleen met RAM hebt verknoeid en niet met de EEPROM, dus je programma is veilig". Het programma dat op de ATmega wordt uitgevoerd, wordt opgeslagen in het Flash-geheugen, niet in EEPROM. De EEPROM is over het algemeen slechts 1-2 KB, en is meer voor het opslaan van kleine hoeveelheden niet-vluchtige gegevens (denk aan: gebruikersconfiguratie-instellingen, serienummer, enz ...), niet voor de werkelijke code.
@ConnorWolf Juist! Goed gezien. Ik heb net mijn antwoord bewerkt en opgelost.
`de C ++ - compiler doet dat voor je. Het stelt het in op nul. Lokale variabelen worden niet geïnitialiseerd. Ik interpreteer `status` als lokaal in jouw voorbeeld, daarom is dit verkeerd. 'het wordt niet als een goede gewoonte beschouwd om op dat gedrag te vertrouwen' het wordt in feite ** als een goede gewoonte beschouwd om op dat gedrag te vertrouwen voor globale variabelen, aangezien het gegarandeerd is dat ze nul-geïnitialiseerd zijn en nul-initialisatie van globals in je code geheugen kan verspillen (hoewel de huidige compilers slim genoeg zouden moeten zijn om dit te vermijden) zie http://www.atmel.com/webdoc/AVRLibcReferenceManual/FAQ_1faq_varinit.html
Je schreef: "_`array [-100] = 10;" [...] je hebt alleen met RAM verknoeid [...] dus je programma is veilig._ "Je zou wel eens kunnen schrijven in de IO-ruimte van de MCU, die in het geheugen is toegewezen direct onder het RAM op de AVR's. Dit is absoluut _niet veilig_. "_ [Een NULL-functieaanwijzer aanroepen] die gelijk is aan een soft-boot_". Niet precies. Het programma zal opnieuw opstarten vanaf het allereerste begin: het zal de stack pointer, het RAM, call main, etc. initialiseren. Maar, in tegenstelling tot een soft boot, reset dit _not_ de IO registers naar hun standaard initiële staat.
@Connor Wolf: U schreef: "_de SRAM wordt op 0 geïnitialiseerd bij reset of opstarten_". Dit is incorrect. In tegenstelling tot de IO-registers, wordt de SRAM niet geïnitialiseerd door de hardware bij het opstarten. De BSS-sectie van het RAM (en _alleen_ deze sectie) wordt op nul geïnitialiseerd door de C-runtime. De DATA-sectie wordt geïnitialiseerd met de inhoud van de programmeur. Al het resterende RAM wordt niet geïnitialiseerd.
@EdgarBonet - Punt ingenomen. Jammer dat ik mijn oudere opmerkingen niet kan bewerken.
@EdgarBonet - Bedankt dat je op het probleem met mijn antwoord hebt gewezen. Ik heb de link gelezen die je hebt opgegeven en heb geprobeerd de uitspraken over lokale variabelen te corrigeren. Wilt u het alsjeblieft bekijken? Bedankt!
Uw uitspraak over het herstarten van het programma bij het aanroepen van een NULL-functieaanwijzer was correct, althans op de AVR. Ik wees er net op dat het herstarten van het programma niet helemaal hetzelfde is als een reset. Trouwens, er is geen illegale instructie bij het proces betrokken. "_Wilt u het alsjeblieft bekijken? _" Ik kan niets fout vinden in uw antwoord.
#2
+9
Connor Wolf
2014-02-15 05:26:18 UTC
view on stackexchange narkive permalink

Er zijn geen uitzonderingen tijdens de uitvoering. Er is alleen ongedefinieerd gedrag.

Echt, er zijn geen uitzonderingen helemaal . Als u een ongeldige bewerking probeert uit te voeren, zijn de resultaten onbekend.

Er is helemaal geen runtime-controle, behalve wat u implementeert. Je programma draait op bare-metal hardware. Het is het desktop-equivalent van de hele tijd in ring-0 draaien, omdat de ATmega geen ringen heeft.

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

Er is één mechanisme dat MCU uit een grillige toestand kan halen en dat is de watchdog-timer . Als u een code implementeert die herhaaldelijk in een lus wordt uitgevoerd, die niet langer zal duren dan een bepaalde vaste tijd, kunt u deze tijd instellen als watchdog-periode en de timer inschakelen.

Vervolgens moet u de timer herhaaldelijk opnieuw instellen in de lus. Als uw code vastloopt bij een conditielus die nooit zal eindigen, zal de watchdog tot nul tellen en uiteindelijk de MCU resetten.

Op deze manier verliest u gegevens, maar als u de AVR WDT in de interruptmodus laat draaien , kunt u enkele gegevens opslaan voordat u de MCU opnieuw instelt.

Zodat de watchdog-timer uw code kan beschermen tegen incidentele onbedoelde eindeloze lussen.

Documentatie: AVR132: de Enhanced Watchdog gebruiken Timer

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

Voor zoiets als dit heb je een hardware debugger nodig. Maar meestal zul je zien dat het programma zich niet gedraagt ​​zoals je verwacht, en zul je dat gedeelte van de code moeten bekijken om het probleem te identificeren.

Een veel voorkomende / snelle / gemakkelijke manier om dit te doen is door voeg afdrukinstructies toe om de waarden van variabelen of iets anders af te drukken, zodat u weet dat het programma zonder problemen op dat punt in de code komt. Dit zal je helpen het probleem verder te isoleren.

Ik denk dat VisualMicro een aantal ingebouwde foutopsporingsfunctionaliteit heeft.

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

Ik neem aan dat de AVR-CPU geen hulpprogramma's voor foutdetectie of herstel heeft. Het kan gewoon stoppen, of doorgaan met het negeren van de fout en de gevolgen. Zoals Sachleen al zei, moet u enkele debug-instructies in uw programma toevoegen die gegevens afdrukken tijdens een operatie, om te testen of het werkt. Als je een emulaor gebruikt en breekpunten instelt, zou je gemakkelijk een probleem kunnen vinden.

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

De Arduino zal opnieuw opstarten (d.w.z. hij zal setup () en loop () ) opnieuw starten.

Niet noodzakelijk. Door een runtime-fout kan het programma in een lus terechtkomen zonder opnieuw op te starten.


Deze Q&A is automatisch vertaald vanuit de Engelse taal.De originele inhoud is beschikbaar op stackexchange, waarvoor we bedanken voor de cc by-sa 3.0-licentie waaronder het wordt gedistribueerd.
Loading...