Vraag:
Welke ontwerppatronen kan ik gebruiken om gebruikersinvoer en het bijwerken van schermen te verwerken?
Cybergibbons
2014-03-01 15:46:44 UTC
view on stackexchange narkive permalink

Ik heb genoeg producten met ingebouwde microcontrollers en niet-reagerende gebruikersinterfaces gebruikt om te weten dat het een product kan maken of breken. Zelfs een kleine vertraging of vertraging tussen het indrukken van een knop en het updaten van het scherm, of het negeren of dubbeltellen van het indrukken van knoppen, kan buitengewoon frustrerend zijn.

Welke ontwerppatronen kunnen worden gebruikt om om te gaan met gebruikersinvoer (van knoppen ) en het bijwerken van schermen zonder deze problemen te veroorzaken?

Ik gebruik momenteel het volgende soort patroon (dit is tot het absolute minimum vereenvoudigd):

  #include <Bounce.h> #define GREEN_LED 6 // Pin voor groene LED # definieer BUTTON_PIN 15 // Pin voor knop - gebruikt externe pull-down zo actief hoog # definieer DISPLAY_REFRESH_INT 100 // Hoeveel MS tussen display-updates Bounce-knop = Bounce (BUTTON_PIN, 5); // Signaal tussen de knop gelezen en de display updatebool ledState = false; // Wordt gebruikt om de laatste display-update bij te houden displayUpdate = 0; void setup () {pinMode (GREEN_LED, OUTPUT); pinMode (BUTTON_PIN, INPUT);} void loop () {// Lees de knopstatus if (button.update ()) {if (button.risingEdge ()) {ledState =! ledState; }} // Werk het display periodiek bij if (millis () - displayUpdate > DISPLAY_REFRESH_INT) {displayUpdate = millis (); digitalWrite (GREEN_LED, ledState); }}  

Welke andere opties zijn er? Is het ooit de moeite waard om onderbrekingen voor het wisselen van pinnen te gebruiken om knoppen te lezen (als we de levensduur van de batterij niet in overweging nemen!).

Vier antwoorden:
#1
+6
Peter Bloomfield
2014-03-01 17:50:10 UTC
view on stackexchange narkive permalink

Het antwoord hangt af van hoe de schets precies bedoeld is om te reageren op de gebruikersinteractie.

Externe onderbrekingen
Als de interactie afhangt van het zeer nauwkeurig reageren op de stijgende of dalende flank van een invoergebeurtenis (zoals in uw voorbeeld), dan is een externe onderbreking de beste keuze, indien mogelijk.

Dit is vooral belangrijk als de invoergebeurtenis kan korter zijn dan de duur van een aanroep naar loop () . Als dat gebeurt, kunnen opeenvolgende pogingen om de invoer te pollen de statuswijziging volledig missen. Het komt echter vrij zelden voor dat een gebruikersinvoergebeurtenis zo kort is, tenzij loop () vrij traag is om uit te voeren.

Externe hardware om daarbij hulp te krijgen, bijv. door een ingang te hebben die vergrendelt totdat deze wordt gelezen en gereset door de microcontroller.

Verbetering van de pollingfrequentie
Externe interrupts zijn vaak niet mogelijk (bijvoorbeeld omdat de chip alleen een beperkt aantal), of ze zijn gewoon overdreven / onnodig voor een bepaalde toepassing.

In die gevallen kan het nog steeds mogelijk zijn om de timingprecisie te verbeteren bij het gebruik van polling. Een mogelijkheid is om alle verschillende delen van de hoofdlus op te splitsen in afzonderlijke functies. Bij elke opeenvolgende iteratie van loop () , zal het de volgende functie aanroepen, en dan ronddraaien naar de eerste. Tussen elk van deze functies kan het de knop pollen. Hier is een eenvoudig voorbeeld:

  unsigned int g_section = 0; void setup () {} void pollButton () {//...}void runSection0 () {//...}void runSection1 () {//...}void runSection2 () {//...}void loop () {// Poll de knop bij elke pass: pollButton (); // Voer de volgende sectie van de hoofdcode uit: switch (g_section) {case 0: runSection0 (); breken; geval 1: runSection1 (); breken; geval 2: runSection2 (); breken; } // Voer bij de volgende iteratie de volgende sectie uit: if (++ g_section > 2) g_section = 0;}  

Een belangrijk probleem met deze benadering is dat het erg moeilijk is om elk van die runSectionX () -functies dezelfde uitvoeringstijd te laten nemen. Dat kan ertoe leiden dat de knop van de ene iteratie naar de volgende inconsistent wordt gepolld. Als het echter snel genoeg is, zou het geen al te groot probleem moeten zijn.

Display-update
Het updaten van een display is helaas vaak vrij traag, vergeleken met veel andere activiteiten. Dat betekent dat je heel voorzichtig moet zijn waar je het doet. Binnen een Interrupt Service Routine zou vaak niet geschikt zijn, omdat dat andere timingproblemen in je sketch zou kunnen introduceren.

Realistisch gezien zou je het in de hoofdlus moeten doen. Als je het echter absoluut snel moet uitvoeren, kan het worden opgenomen in het snellere polling-voorbeeld dat ik hierboven heb gegeven - d.w.z. update de weergave bij elke iteratie, hetzelfde als polling. U moet echter voorzichtig zijn om gedeeltelijke updates te vermijden.

Dit is trouwens een geweldig antwoord. Precies het soort antwoord dat de site nodig heeft.
#2
+2
Chris K
2014-03-06 07:17:51 UTC
view on stackexchange narkive permalink

Voor programmabeheer heb ik een raamwerk voor menubeheer gemaakt voor een van mijn projecten en deelde ik de bron op Github. Merk op dat dit voor chipKIT is, maar de menu-afhandelingscode is generiek. Na het bouwen van mijn 3e of 4e enorme if-else-if en switch-structuur, besloot ik dat er een betere manier moest zijn. Met dank aan de bron van de statische menustructuren.

Ik gebruik alleen de hoofdlus om de knop te controleren.

I Ik wil zeggen dat de eerste stap is om een ​​TFT te krijgen. Als je het probeert, ga je nooit meer terug ... Ik ben vooral dol op de Adafruit 1.8 "TFT met joystick. Arduino's zijn traag genoeg zodat ik me niet kan herinneren dat ik de input van de gebruiker heb ontkracht.

Ik hou van de manier waarop je dat hebt gedaan - het is begrijpelijk, schoon en erg klein van formaat. Ik had gekeken naar het gebruik van een bibliotheek (MenuBackend) maar het is moeilijk te begrijpen voor nieuwe programmeurs (met behulp van callbacks) en kan niet in PROGMEM blijven zitten.
Ik vind dat dempen vaak niet nodig is, maar sommige schakelaars lijken veel luidruchtiger te zijn dan andere. De rechtopstaande, aan de rand gemonteerde tactiele schakelaars op de printplaat lijken verreweg het slechtst, misschien omdat gebruikers deze in plaats van ze naar voren te drukken, vaak naar voren bewegen. Debouncen is zo gemakkelijk dat ik het nu bijna altijd doe.
Sorry voor alle vragen - waarom een ​​TFT? Ik werk momenteel met een 128x64 LCD-scherm dat veel voordelen heeft (voornamelijk fysiek groot). Ook goedkoop.
@Cybergibbons ah, ik heb geen melding van een display gezien. Degene die ik leuk vind, is een kant-en-klaar schild, goedkoop genoeg, en je kunt dingen doen met kleuren. Hier is een build-rapport van mijn meest recente project: http://forums.adafruit.com/viewtopic.php?f=22&t=44710&p=223543#p223543
#3
+1
JRobert
2014-03-03 05:19:02 UTC
view on stackexchange narkive permalink

U zou kunnen onderbreken in plaats van pollen als u de knoppen in hardware kunt de-bouncen. Anders neemt u veel meer interrupts dan wanneer u op een knop drukt, en moet u ze nog steeds in software de-bouncen.

Maar wat de primaire vraag betreft: een verzameling toestandsmachines kan in ieder geval erg nuttig zijn voor de ui, en geeft u de meeste voordelen van multi-tasking zonder de benodigde am / t-kernel. kan zich helaas in RAM-apparaten bevinden, omdat

De techniek zou vooral handig kunnen zijn op deze kleine apparaten, maar vanwege de strenge limieten aan RAM, waardoor het een uitdaging wordt om uw state-machine-gegevens te verdelen tussen flash en RAM, passend.

#4
  0
neu-rah
2017-03-04 01:56:11 UTC
view on stackexchange narkive permalink

Als Chris K heb ik ook een statische menubibliotheek geïmplementeerd met een breed scala aan uitvoeropties zoals Serieel, LCD, TFT, enz. Ik ben ermee begonnen om te helpen in een vriendenproject en ik deel het ook open source voor mensen die met soortgelijke problemen hopen dat je het nuttig kunt vinden.

https://github.com/neu-rah/ArduinoMenu



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