Ställa in tal display med knappar och jämföra detta med Rx

PIC, AVR, Arduino, Raspberry Pi, Basic Stamp, PLC mm.
Användarvisningsbild
Henry
Inlägg: 23611
Blev medlem: 20 april 2005, 02:52:47
Ort: Lund

Ställa in tal display med knappar och jämföra detta med Rx

Inlägg av Henry »

Jag har nedan kod som funkar som jag vill genom att den skriver ut det specifika värdet från en vakuumsensor på en display och kommer ingen info så blir man varnad om det då alla funktioner kommer att baseras på detta värde.

Funkar fint om än kanske inte efter konstens regler som att tex displayens tecken blinkar lite grand (om man inte tittar rakt på den utan från sidan) i takt med uppdateringsfrekvensen som datan skickas med till sensorn då ju allt går i samma loop, men men och jag är mer än nybörjare i detta så det får gå as is as now.


Det jag hade velat ha implementerat så enkelt som möjligt är att kunna ställa in vakuumnivån genom displayen med knappar så när rätt nivå nås eller lägre av inställt värde så går en utgång hög tills nivån går över satt värde igen då den går låg.

Så tex första siffran ställs in med en upp och en ned knapp, stega vidare till nästa siffra med en knapp och göra samma tills alla är klara och då trycka på en annan knapp som både startar en vakuumpump och öppnar en ventil. Pumpen går då tills rätt nivå eller lägre nåtts vilket stänger ventilen till pumpen vilket då håller vakuumnivån tills det stiger över satt värde igen då ventilen öppnas, osv.


Har ingen aning hur detta kan göras, några tips/hänvisningar åt rätt håll till grejer jag skall titta på för att få ihop något sådant? Då har jag något att gå efter och kanske få ihop något med och kolla upp mer för jag hittar dock inga konkreta exempel på något liknande på nätet som det är nu.

Sensorn ger även ut en linjär analog utgång men då blir det en massa jobb med att anpassa värdet exakt till ADCn och det blir ändå inte exakt vilket jag behöver och spannet är dessutom även på tok för stort för mätaren jag använder, men med en enskild grovvakuummätare så hade det kanske funkat, men då blir det ev en annan tråd.


Gick bara att få ihop nedan kod efter en hel del hjälp härifrån och genomkoll av exempel på nätet om olika grejer, jag är som ni nog alla vet mer än nybörjare på detta så helst gärna ev info därefter. :)

Kod: Markera allt

#include <LiquidCrystal.h>

LiquidCrystal lcd(40, 42, 28, 26, 24, 22);

String value;

void setup() {

  Serial.begin(9600);
  Serial.setTimeout(75);        //Hade ingen aning om detta innan vilket skapade en jäkla massa huvudbry
  pinMode(13, OUTPUT);
  lcd.begin(20, 4);
  lcd.clear(); 
  delay(1000);        //Så att sensorer och allt hinner stabilisera sig

}


void loop() {

  delay(200);
  Serial.print("@254PR3?;FF");       //Skicka förfråga till sensorn om vakuumnivå 5 ggr i sekunden (klarar 10 ggr men tyvärr inte displayen)
                                     //och få tillbaka tex @254ACK6.48E-7;FF där siffrorna i mitten är värdet  
                                                   
  if (Serial.available()) {            //Finns det någon data i den seriella bufferten?
    digitalWrite(13, LOW);         //Om ja gå vidare
    lcd.clear();
    lcd.print("Vacuum: ");
    lcd.setCursor(16, 0);
    lcd.print("Torr");
    lcd.setCursor(8, 0);
    value = Serial.readString();
    for (int mod = 7; mod < 14; mod++) {  //Skriver enbart ut värdet tex 6.48E-7 på displayen
      lcd.write(value[mod]);

    }
  }
Användarvisningsbild
Icecap
Inlägg: 26139
Blev medlem: 10 januari 2005, 14:52:15
Ort: Aabenraa, Danmark

Re: Ställa in tal display med knappar och jämföra detta med

Inlägg av Icecap »

Blinkandet tas bort vid att ta bort display.clear() men samtidig se till att det blir fyllt upp i displayen vid att formatera en utskriftsträng ordentligt.

Ögat + display hinner inte med mer än 3 gg/sek, detta kan enkelt lösas med en prescale.

Det är enkelt att dels ta bort det förhatliga delay() och dels att få en snabbare funktion på d3t hela utan att displayen flipprar.

En "meny" för att ställa in värdet är enkelt också - men alla saker kräver att du sluter använda delay() helt.
En timing behövs men i arduino-skiten finns det väl en systemtimer att använda?

Då kan main-loop köra full patte medan displayen uppdateras i sin takt, sensorn läsas i sin takt och knappsatsen läsas i full speed.

Du måste ju även tolka värdet som sensorn skickar så att du kan jämföra värden.
Användarvisningsbild
hawkan
Inlägg: 2619
Blev medlem: 14 augusti 2011, 10:27:40

Re: Ställa in tal display med knappar och jämföra detta med

Inlägg av hawkan »

Ja det finns massa olika sätt att köra fristående "tasks" i arduino-skiten.
Frågan är vilken nivå och abstractionsnivå man vill ha.
TimerOne är en enkel men den kan bara köra en återkommande rutin.
Freertos är fullständig med multi-tasking med tasks, semaforer, mm.
TaskScheduler är nåt mittemellan. https://github.com/arkhipenko/TaskScheduler
Den kör jag med nu, verkar smidigt.

Skamlös copy-paste från github

Kod: Markera allt

 
#include <TaskScheduler.h>

// Callback methods prototypes
void t1Callback();
void t2Callback();
void t3Callback();

//Tasks
Task t4();
Task t1(2000, 10, &t1Callback);
Task t2(3000, TASK_FOREVER, &t2Callback);
Task t3(5000, TASK_FOREVER, &t3Callback);

Scheduler runner;

.. arduino-skit saker ...


void loop () {
  runner.execute();
}

Och då gör den det som är i txCallback med de intervall som specats.
Detta är inte preemptive, dvs den ena tasken avbryter inte en annan
utan det sker den ena efter den andra.

Kanske kan vara något.
Användarvisningsbild
Icecap
Inlägg: 26139
Blev medlem: 10 januari 2005, 14:52:15
Ort: Aabenraa, Danmark

Re: Ställa in tal display med knappar och jämföra detta med

Inlägg av Icecap »

Och man kan köra utan all RTOS o skit också!

Har man bara en systemtimer med en räknare som kan räkna den längsta tiden som behövs är det enkelt.

Jag brukar ha en timer-interrupt som - om de är icke-noll - räknar ner de timer-variabler jag behöver.
Man ger sedan variabeln ett värde som motsvarer den tiden man behöver. Detta brukar jag göra i den snudd som kollar om tiden har gått ut:

Kod: Markera allt

if (!Timeout_1)
  {
  Timeout_1 = MILISEC(300); // För display-uppdatering
  }
MILISEC() är ett macro som ger rätt antal steg för en given tid. Kan såklart ersättas av fasta tal.

Man kan ha ett antal av dessa funktioner i main-loop, i detta fall behövs det en timer till displayen, en timer till att hämta data från sensorn, en timer för läsning av knappar samt en timer för timeout av insignalen.

Med en smart rutin för att ta emot seriella data kan man enkelt fånga texten som kommer i svaret från sensorn och trigga en läsning som omvandlas till ett värde som då kan jämföras med det inlagda värdet.

Alla funktioner finns alltså, det fattas bara ett bra program.
Användarvisningsbild
lillahuset
Gått bort
Inlägg: 13969
Blev medlem: 3 juli 2008, 08:13:14
Ort: Norrköping

Re: Ställa in tal display med knappar och jämföra detta med

Inlägg av lillahuset »

Jag återkommer med min trotjänare sedan tio år. :)

I mitt fall hanteras systemtiden "ticks" av en 32 bits räknare, det är därför jag använder uint32_t. Har du en 16 bits räknare så använder du en uint16_t.
Räknarens värde läses med getTicks().

Funktionen måste anropas minst så ofta som man får ett overflow i räknaren.
Funktionen garanterar, om du anropar tillräckligt ofta, bara att det är minst "ticks" mellan timeouter, inte högst.
Du kan hantera godtyckligt antal "timers" eftersom du anropar timeout() med en pekare till "timern".

Jag vet att funktionen funkar med räknare som räknar upp men har ingen aning om den funkar med räknare som räknar ner. Det intresserar mig inte.

Kod: Markera allt

/**
  * @brief  check if *timer has timed out
  * @brief  initialise *timer by a call with ticks = 0
  * @param  timer: pointer to timer variable
  * @param  ticks: number of ticks to wait
  * @retval return 0 if not timeout, !0 if timeout
  * @date   2012-12-14
  */
int timeout(uint32_t *timer, uint32_t ticks)
{
  uint32_t t, diff;
  int tout;

  tout = 0;
  t = getTicks();
  diff = t - *timer;

  if (0 == ticks || diff >= ticks) {
    *timer = t;
    tout = 1;
  }
Användarvisningsbild
hawkan
Inlägg: 2619
Blev medlem: 14 augusti 2011, 10:27:40

Re: Ställa in tal display med knappar och jämföra detta med

Inlägg av hawkan »

Så här kan det se ut om man använder TaskScheduler.
Detta följer aurdions sanna anda att man försöker få någon annan att skriva koden :)
Ej kompilerat, ej testat, finns säkert fel. Men principen.

Dela upp i fristående rutiner som sköter sej själva.

Kod: Markera allt

#include <TaskScheduler.h>

byte sensorOK;
String sensorValue;

// Callback methods prototypes
void displayRoutine();
void readSensor();
void readButtonsandControl();

//Tasks
Task t1(500, TASK_FOREVER, &displayRoutine);
Task t2(200, TASK_FOREVER, &readSensor); // 5 ggr i sekunden
Task t3(50, TASK_FOREVER, &readButtonsandControl); 

Scheduler Runner;

void setup()
{
  sensorOK = TRUE;
  
  lcd.begin(20, 4);
  lcd.clear(); 
  Runner.init();
  Runner.addTask(t1);
  Runner.addTask(t2);
  Runner.addTask(t3);
  t1.enable();
  t2.enable();
  t3.enable();
  Serial.print("@254PR3?;FF");       //Skicka förfråga till sensorn om vakuumnivå 5 ggr i sekunden (klarar 10 ggr men tyvärr inte displayen)
                                     //och få tillbaka tex @254ACK6.48E-7;FF där siffrorna i mitten är värdet 
}

void loop () {
  runner.execute();
}

void displayRoutine()
{
  lcd.clear();
  lcd.print("Vacuum: ");
  lcd.setCursor(16, 0);
  lcd.print("Torr");
  lcd.setCursor(8, 0);
  if (sensorOK = TRUE) {
    for (int mod = 7; mod < 14; mod++) {  //Skriver enbart ut värdet tex 6.48E-7 på displayen
      lcd.write(sensorValue[mod]);
    }
  } else {
    lcd.write("Not OK");
  }
}

void readSensor()
{
  if (Serial.available()) {            //Finns det någon data i den seriella bufferten?
    sensorOK = TRUE;
    sensorValue = Serial.readString();
  } else {
    sensorOK = FALSE;
  }
  Serial.print("@254PR3?;FF");       //Skicka förfråga till sensorn om vakuumnivå 5 ggr i sekunden (klarar 10 ggr men tyvärr inte displayen)
                                     //och få tillbaka tex @254ACK6.48E-7;FF där siffrorna i mitten är värdet 
  
}

void readButtonsandControl()
{
  if (sensorOK == TRUE)
    digitalWrite(13, LOW);
  else
    digitalWrite(13, HIGH);
}


Användarvisningsbild
hawkan
Inlägg: 2619
Blev medlem: 14 augusti 2011, 10:27:40

Re: Ställa in tal display med knappar och jämföra detta med

Inlägg av hawkan »

När det gäller knapparna och som du vill ha det. Det blir ofta lite pilligt att få till det. Strategin är i alla fall att aldrig fastna i något vänteläge och att använda variabler, statevariabler brukar jag tänka men det är nog formellt fel benämning, för att hålla ordning på vilket läge/siffra man påverkar.

Nåt sånt här kanske?

Kod: Markera allt

void knappar_mm()
{
  om pumppå {
    om nivågivare == av 
        sätt på pumpen
    annars
        stäng av pumpen
  }

 if ingen knapp nedtryckt return

 Om sifferknapp tryckt, siffraavintresse++ plus nån mod för att cirkulera mellan så många siffror du har

  om siffraavintrresse > 0 && upp eller nerknapp tryckt
        öka nämnda värde i en variabel som displayRoutine visar.

  om siffraavintresses == 0 && onoffknapp tryckt
       slå på/av pumpen
       pumppå = not pumppå

}
Nåt sån't här skulle väl funka, den exakta logiken får du såklart fylla i. Man får ta sakerna en och en. Statevariabeln siffraavintresse håller ordning på vilken siffra man trycker på mellan de olika anropen av knappar_mm. knappar_mm kan anropas så ofta du vill. Kompliceringar kan vara att du får studs i kappen och/eller att du håller knappen intryckt så länge att det registeras som två eller flera tryck alternativt att rutinen loopar så snabbt att detta sker. Finns medel mot detta också.
Om du som här skiljer på visning av data och knappar och kontrollsaker så blir det lättare att hålla ordning på det. Den här rutinen ser till att fylla i de varibler som visas av displayRoutine. Fast det är såklart inget måste. Men smidigt.
Användarvisningsbild
Henry
Inlägg: 23611
Blev medlem: 20 april 2005, 02:52:47
Ort: Lund

Re: Ställa in tal display med knappar och jämföra detta med

Inlägg av Henry »

Jo något sådant, hur grunduppbyggnaden, eller vad man kall kalla det för, är jag dock rätt klar med i huvudet men det är mer hur programmeringen skall vara som så som är det stora problematiska just nu.

Problemet är att jag inte vet tex vad för funktioner och variabler som kan användas för tex knappdelen och jämförelsedelen men håller på för fullt att kolla upp och försöka hitta något liknande exempel på vad jag vill åstadkomma för att få idéer men det ser rätt mörkt ut än så länge.

Displaydelen att få bort ev flimmer och dylikt men framförallt delays, som jag vet jag att det inte kan användas om koden utvidgas, har jag rätt klart för mig att som du visade innan bara att lägga de enskilda delarna för displayen i tex 2 olika subrutiner som blir kallade vid rätt tillstånd på signalen från sensorn och det kan få ihop utan större problem.

Men jämförandet av värdena har jag dock tyvärr fått uppfattningen av att det var bra mer komplicerat är jag trodde/hoppade på.


Jag tänker dock i alla fall på en uppbyggnad liknande så här med knappdelen, som jag beskriver med egna ord:

Har den enklaste räknare/rutin för en knapp som räknar upp från 0 - 9 och tillbaka till 0 (ev inte även "ned" med en annan knapp bara för att göra det så enkelt som möjligt) och även visar innehållet på displayen så man får det bekräftat att det är rätt i rutinen då det är av yttersta vikt. Med en annan knapptryckning går man sedan till nästa siffra och samma där trycker in 0 - 9 och så vidare tills alla siffrorna är inmatade.

Jag tror att jag möjligtvis kunnat få ihop i alla fall en räknarrutin med en knapp då det borde finnas gott om exempel om liknande som jag kan få ideér från. Men hur sedan skifta till nästa rutin med en knapp vet jag dock ej men dessa delar är nog ändå det som jag oroar mig allra minst för.


Hur jag sedan skall göra (eller hur man nu kan/bör göra) för att kunna jämföra värdet i räkningsrutinerna med värdet från strängen från sensorn och se om det är högre eller lägre har jag inte ens en teori om.


Men i alla fall som exempel så har det i var och en av de 4 räkningsrutinerna (kan även göra så det bara blir 3 siffror från sensorn) följande siffror blivit inmatade:

2 6 8 5

På displayen läses värdet direkt från rutinerna och visas som vald vakuumnivån:

2.68E-5

Vid en annan knapptryckning bekräftas inmatningen och då tas värdet från den seriella bufferten som säg tex är @254ACK9.27E-3;FF och omvandlat blir

9.27E-3.


Nu skall siffrorna i var och en av räkningsrutinerna jämföras med var och en av siffrorna i strängen och på något vis se om hela värdet i sig (dock visserligen inte varje siffra för sig, det fungerar inte som jag ser det) är högre eller lägre än det sammanlagda som motsvarar värdet man matat in och sätta en utgång hög eller låg baserat på detta.

Men hur denna jämförelse kan göras rent programmässigt har jag absolut ingen som helst aning om ens mindre en teori. Har än så länge inte hittat något exempel på nätet om något i närheten där någon jämfört ett inmatat tal eller annat på en display på liknande sätt jag tänkt mig med ett tal från en sträng från Rx, det jag hittat än så länge vls, men den som söker han finner förhoppningsvis.
Användarvisningsbild
hawkan
Inlägg: 2619
Blev medlem: 14 augusti 2011, 10:27:40

Re: Ställa in tal display med knappar och jämföra detta med

Inlägg av hawkan »

Undrar om du inte gör det svårare än det är?
2685 är ett tal, behandla det som det. Likaså är 9273 ett tal. Använd en unsigned int som typ och du kan göra direkta jämförelser if (2685 == 9273). Åtminstone så länge exponentdelen håller sej inom 0-9. Om det inte funkar så gör två tal av det. 268 är ett tal och 5 är ett tal. När du jämför behöver du jämföra if (268 == 927 && 5 == 3) (med variabler så klart). 2.68e-5 är även ett flyttal och likaså 9.27e-3, bara att använda. Men anar att det kan vara opraktiskt när du har fixa positioner och vill matcha mot displayen.
Det är också möjligt att använda en String. Funkar utmärkt att göra direkt jämförelse mellan två String if (String("2685") == String(9273")).
Det kanske är smidigast faktiskt. Eller om du vill spara "9.27E-3" i en String och likaså göra inmatningen till "2.68E-5". En konvention hur du sparar det numeriska värdet i String behöver du ha i alla fall. Hmm, ska du göra jämförelser > eller < får du nog jobba med tal. Fast se toInt() nedan.

Dra ur det numeriska värdet från seriella indata först genom att isolera det med string2=value.substring(7,14).

Numeriskt värde kan du få genom lite pill t ex int tal = string2.substring(0,1).toInt()*1000+string2.substring(2,4).toInt()*10+string2.substring(6,7).toInt()
"9.27E-5" borde bli talet 9275 med detta. Göra om till String med String str(9275).
Användarvisningsbild
Wedge
Inlägg: 1026
Blev medlem: 8 juli 2012, 17:33:33

Re: Ställa in tal display med knappar och jämföra detta med

Inlägg av Wedge »

Kom ihåg att aldrig ha flyttal och exakt likhet i en jämförelse. Det är att be om problem.
Användarvisningsbild
Henry
Inlägg: 23611
Blev medlem: 20 april 2005, 02:52:47
Ort: Lund

Re: Ställa in tal display med knappar och jämföra detta med

Inlägg av Henry »

Ett rent tex 9273 från sensorn är väl inte att beteckna som ett flyttal? Det är väl mer vid matematiska beräkningar som något sådan kan förekomma med decimaler och avrundningar från ett tal och så? Värdet från sensorn och genom hela operationen sedan är ju statiskt hela vägen så att säga.

---

Undrar om du inte gör det svårare än det är?

Ingen aning, jag hoppas på det så det kan bli lättare. :)


2685 är ett tal, behandla det som det. Likaså är 9273 ett tal.

Ok, hänger med.


Använd en unsigned int som typ och du kan göra direkta jämförelser if (2685 == 9273). Åtminstone så länge exponentdelen håller sej inom 0-9.

Ok, hänger med hyfsat även här.

Exponentdelen håller sig inom 0 - 9, dock går den tyvärr mellan negativt och positivt i övre delen av vakuumnivån.

Vanligt lufttryck är tex runt 7.60E+3 Torr och då ett plustecken, alternativt inget tecken alls där från sensorn, kommer inte ihåg vad den visar här vid övergången kan hända den inte visar något tecken alls där. Vid grovvakuum och lägre så går den sista siffran dock till slut till negativt, stöter detta på några andra problem mer än jag förmodligen måste göra det i två delar?


Om det inte funkar.. m.m.

En hel del intressanta bra konkreta tips där som jag till stor del kopplar och säkert kan bygga vidare på, tackar!
Användarvisningsbild
Icecap
Inlägg: 26139
Blev medlem: 10 januari 2005, 14:52:15
Ort: Aabenraa, Danmark

Re: Ställa in tal display med knappar och jämföra detta med

Inlägg av Icecap »

Det kan gå mycket enkelt att ta värdet med exponent och fixa till ett heltal.
Att exponenten är negativ betyder ju bara att man kan använda en minsta enhet på t.ex. 1E-9.

Det viktiga är att talen kan jämföras rakt av och att de därför har samma basvärde.
Användarvisningsbild
Henry
Inlägg: 23611
Blev medlem: 20 april 2005, 02:52:47
Ort: Lund

Re: Ställa in tal display med knappar och jämföra detta med

Inlägg av Henry »

Tänker rent programmeringsmässigt nu för det går väl inte som jag förstått det att ha ett värde sparat tex som 224-2 utan det måste vara ett helt negativt tal så att säga och således tvådelat med exponenten för sig?
Användarvisningsbild
hawkan
Inlägg: 2619
Blev medlem: 14 augusti 2011, 10:27:40

Re: Ställa in tal display med knappar och jämföra detta med

Inlägg av hawkan »

Om du bara ska använda givarens värde för att sätta på eller av en pump vid ett visst värde fungerar det bra med float eller double. Man är inte intresserad av om de två talen är samma, bara om det är mer eller mindre än det givna värdet.

Får säga att lägga exponenten sist i en String som jag gjorde tidigare var en rätt dålig idé. Jämförelser blir inte lätt. Glöm det, det var ett exempel.
Användarvisningsbild
Icecap
Inlägg: 26139
Blev medlem: 10 januari 2005, 14:52:15
Ort: Aabenraa, Danmark

Re: Ställa in tal display med knappar och jämföra detta med

Inlägg av Icecap »

Om xxx,xxxE-9 är lägsta värde kan man enkelt beskriva det som xxxxxx.
Yyy,yyyE-6 blir då yyyyyy000.

Dessa värden kan enkelt jämföras.
Skriv svar