Ta siffran i 4 olika byte och sätta i en enskild int?

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

Ta siffran i 4 olika byte och sätta i en enskild int?

Inlägg av Henry »

Har nämnt detta projekt förr som jag nu har tid att bråka med lite igen: Jag har en vakuumsensor som kontinuerligt kallas 5 ggr/s och ger värdet tillbaka i formatet x.xxeZx där Z = + eller - så tex 1.23E-4.

Jag har sedan knappar där jag på en display tänkt kunna flytta ruta för ruta till höger eller vänster vid x:en och i varje ruta mata in ett tal så det blir likadant som det jag får tillbaka från sensorn för att sedan jämföra dessa tal med varandra vilket som är större eller mindre.

Det är egentligen dock bara området ned till minimum 1.00E0 som jag behöver kunna ställa in då det bara är max ned till dit där jag kan vara för plasma experiment. Under detta så är det för andra experiment och då skall systemet bara gå ned så lågt det kan, och just den delen är förstås lätt att fixa till när allt annat är klart.

På detta vis behöver jag då inte ändra + och - tecknen utan de kan vara statiskt alltid tex + som kanske gör det hela en gnutta enklare, jag har ingen aning. Hade strikt bara velat behöva skriva in rent 999 - 001 men det blir än mer huvudvärk tror jag så jag skippar det.


Att omvandla string till float från sensorn för att få tex ett decimaltal har jag fått bra hjälp med här och som jag fått ihop vilket sedan gör det ypperligt lätt att kunna jämföra inmatat tal med det från sensorn, eller vilket som nu är bäst.

Jag har däremot helt gått bet på och inte heller hittat något på nätet ens i närheten om hur jag fixar till att mha två knappar (höger och vänster) flytta mellan 4 platser på displayen och med två andra knappar mata in siffror på dessa platser och därefter (inkl en "." ett "E" och ett "+" på rätt ställen) lägga allt i en float för att få ut decimalvärdet att kunna jämföra med.



Men först är det själva principen för att få ihop sidoförflyttnings systemet i grunden tror jag.

Första tanken var att göra en switch case, principiellt ev något sådant här ingen färdig kod alls förstås, enda grundprincip jag kan komma på för tillfället för detta men den får problem som jag skrivit om i botten:

Kod: Markera allt


knapptryckning                           // Skriver 0 - 9 i en int.

int knapptryckning = 0;               // Denna uppdateras med 0 - 9 från knapptrycknings funktionen
int siffracount = 0;                      // Vilken plats som siffran i knapptryckning behöver skrivas in på displayen

byte siffra1 = 0;                         // Hålla det jag matar in med knapparna för att kontinuerligt skrivas ut på var sin plats på displayen
byte siffra2 = 0;
byte siffra3 = 0;
byte siffra4 = 0;

void setup() {

}

void loop() {


  switch (siffracount) {
                
    case 0:
      siffra1 = knapptryckning;     // Detta funkar ju tyvärr inte eftersom inte displayen uppdateras vid varje
      lcd.Set(1, 0);                      // knapptryckning då case inte är en loop utan koden där i bara körs en gång
      lcd.print(siffra1);                            
      break;
    case 1:
      siffra2 = knapptryckning;
      lcd.Set(3, 0);                     // "." skall skrivas på position "2"
      lcd.print(siffra2);
      break;
    case 2:
      siffra3 = knapptryckning;
      lcd.Set(4, 0);
      lcd.print(siffra3);
      break;
    case 3:
      siffra4 = knapptryckning;   // "E" skall skrvas på position "4"
      lcd.Set(5, 0);
      lcd.print(siffra5);
      break;                                     // Osv för alla siffror och tecken eller ur man nu gör
  }
 

Men i alla fall principen som sådan, vet ej om det kommer att fungera alls eller om jag skall överge detta tänkande helt för något annat som jag säkert inte har en aning om hur det fungerar.
Användarvisningsbild
Icecap
Inlägg: 26106
Blev medlem: 10 januari 2005, 14:52:15
Ort: Aabenraa, Danmark

Re: Ta siffran i 4 olika byte och sätta i en enskild int?

Inlägg av Icecap »

Undrar om inte atof() kan klara biffen?
Alltså mata in den inhämtade strängen och få ut en färdig float.
Användarvisningsbild
hawkan
Inlägg: 2586
Blev medlem: 14 augusti 2011, 10:27:40

Re: Ta siffran i 4 olika byte och sätta i en enskild int?

Inlägg av hawkan »

För att flytta sej i horisontell led så tror jag såhär utan att ha tänkt jättemycket (friskrivningsklausul)

Börja med läge=0 så att du pekar ut att du vill jobba med siffran i position 0.

Sedan får du hålla ordning på när höger eller vänster knapp trycks ned. Använd isr eller pollning.
Vad ska då hända?
Om höger: läge=(läge+1) % 4; // se till att läge bara kan vara 0,1,2,3
Om vänster: lämnas som övning åt läsaren.

Börja med detta och få det att funka så du tror på det. Varning för studs i knapparna så du kanske måste avstudsa de (googla på debounce).

Då har du en variabel "läge" som säger vilken av de fyra siffrorna du fokuserar på.

Grov fortsättning
Gör en variabel uint8 värde[4] som har de fyra värde du vill stega upp ner.
Stega upp/ner på samma sätt som i sidled.
Skapa det slutliga värdet med (värde[0]*10+värde[1]*1)*pow(10,värde[2]*10+värde[3]);
Om format såg ut typ 12E08
Användarvisningsbild
Andax
Inlägg: 4373
Blev medlem: 4 juli 2005, 23:27:38
Ort: Jönköping

Re: Ta siffran i 4 olika byte och sätta i en enskild int?

Inlägg av Andax »

Vad kör du på för MCU? Håller med Icecap, atof är ju det rimligaste sättet.
Användarvisningsbild
hawkan
Inlägg: 2586
Blev medlem: 14 augusti 2011, 10:27:40

Re: Ta siffran i 4 olika byte och sätta i en enskild int?

Inlägg av hawkan »

Här är nåt du kan testa.
Två knappar H_PIN och V_PIN kopplas till pinne och jord.
Otestat av mej, men borde funka efter att stvafel åtgärdats.

Kod: Markera allt

#include <EnableInterrupt.h>
#define H_PIN ..
#define V_PIN ..
volatile uint8_t lage=0;

void hoger_isr()
{
  static long int lastcalled = 0;
  long int diff = millis() - lastcalled;
  lastcalled = millis();
  if (diff < 200) { // studs, skippa
     return;
  }
  lage = (lage + 1) %4;
}

void vanster_isr()
{
pss
}

setup()
{
  pinMode(H_PIN, INPUT);  //
  digitalOutput(H_PIN, HIGH); //Enable internal pullups
  pinMode(V_PIN, INPUT);  //
  digitalOutput(V_PIN, HIGH); //Enable internal pullups
  enableInterrupt(H_PIN, hoger_isr, FALLING);
  enableInterrupt(V_PIN, vanster_isr, FALLING);
  Serial.begin(115200);
}

loop()
{
  Serial.println(lage);
  delay(100); // För att inte floda
}
Användarvisningsbild
Henry
Inlägg: 23588
Blev medlem: 20 april 2005, 02:52:47
Ort: Lund

Re: Ta siffran i 4 olika byte och sätta i en enskild int?

Inlägg av Henry »

Tack för tipsen! Kan nämna de andra delgrejerna som är "klara", det är grejer kvar som skall fixas på vissa men grundprincipen har fungerat efter min teori om hur de skulle fungera och jag förstår denna typ av kod, är det mer grejer som läggs till som jag inte känner igen så gör jag inte det längre utan måste då kolla upp vad dessa grejer gör och hur de fungerar och beroende på komplexitet även måste se en ren exempelkod för att koppla. Ser redan lite nu att det är grejer i någon kod jag inte sett förr.

En del nedan är tips av exempelkod från snällt folk här som gjort att jag då först helt förstått uppbyggnaden och funktionen av någon grej och sedan kunnat modifiera så det passat, eller från exempel från Arduino vilka sedan också blivit lite modifierat för att funka.


Detta är lite kod för att få tag på det seriella värdet från sensorn och sedan även överföra det till decimalform, samt även så att säga i ren form från sensorn för att kunna skriva på displayen, det är inte jag som gjort koden om någon nu skulle fått för sig det. Kommer att använda andra namn senare vid huvud koden men just nu är det bara att få de enskilda delblocken att fungerar som jag vill, vilket tex detta gör:

Kod: Markera allt

#include <LiquidCrystal.h>

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

String data;

void setup() {
  
  lcd.begin(20, 4);
  Serial.begin(9600);
  Serial.setTimeout(50);
}

void loop() {

  while (Serial.available() == 0) {        // kommer senare att ändras till if
  }                                        // och else för att skriva något vid ej data  

  //lcd.clear();
  data = Serial.readString();

  // lcd.clear();
  String str4 = data.substring(7, 14);
  lcd.print(data);
  lcd.setCursor(0, 1);
  float tr4 = data.toFloat();
  lcd.print(tr4, 9);
}

Knapptrycknings kod för upp och ned har jag också fixat men om det är bästa varianten vet jag ej men funkar i alla fall, och innan någon får frispel så ja "delay" kommer att tas bort det är bara där vid test för jag kommer att använda knappar av gummimembran, som jag inte har än, och då behövs inte debounce för lite enklare kod var tanken, men här är denna upp och ned knapp kod just nu med lite lcd grejer i när jag testat den:

Kod: Markera allt

#include <LiquidCrystal.h>

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

const byte upp = 53;
const byte ned = 51;
int buttonPresses = 0;                 // how many times the button has been pressed
int lastPressCount = 0;                // to keep track of last press count

void setup() {
  pinMode(upp, INPUT);               // Set the switch pin as input
  pinMode(ned, INPUT);
  digitalWrite(upp, HIGH);
  digitalWrite(ned, HIGH);            // set pullup resistor

  lcd.begin(20, 4);
  //lcd.print("0.00");
}

void loop() {

   lcd.setCursor(0, 0);
  
  if (digitalRead(upp) == LOW)          // check if button was pressed
  {
    buttonPresses ++;                   // if pressed increment buttonPresses count
    delay(300);                         // debounce
  }

  if (digitalRead(ned) == LOW)          // check if button was pressed
  {
    buttonPresses --;                   // if pressed decrement buttonPresses count
    delay(300);                         // debounce
  }

  if (buttonPresses < 0) buttonPresses = 0;
  if (buttonPresses > 9) buttonPresses = 9;

  if (lastPressCount != buttonPresses)              // only do output if the count has changed

  {
    lcd.print(buttonPresses);
    lastPressCount = buttonPresses;                // track last press count

  }
}

Skall kolla på grejerna och koderna som nämnts i tråden, koderna ovan är bara grundprinciper så att säga så de kan komma att behövas ändras om en hel del senare men inte riktigt haft tid att bråka med detta helt och fullt än bara lite sporadiskt. Tror också jag skall lägga detta som ett projekt så är allt samlat istället för lite trådar här och var, får se.
Användarvisningsbild
hawkan
Inlägg: 2586
Blev medlem: 14 augusti 2011, 10:27:40

Re: Ta siffran i 4 olika byte och sätta i en enskild int?

Inlägg av hawkan »

Det är så man får jobba. Steg för steg framåt så man känner sej bekväm med koden.

Det jag kan se på din kod ovan är testet digitalRead(upp) == LOW som inte blir så bra om man håller knappen intryckt för då blir den sann även om man håller knappen intryckt.
Du vill nog snarare registrera att knappen går från HIGH till LOW. Och för att få det att funka så är det lättaste sättet att komma ihåg om knappen var uppe eller nere förra gången som loop() kördes. Ändrades knappen från förra gången så är det en nedtryckning (eller uppsläpp).

Har du knappar som inte studsar är det såklart bäst. Det blir några rader om än inte så många för att parera det, och det kluttrar till det bara.
Användarvisningsbild
Henry
Inlägg: 23588
Blev medlem: 20 april 2005, 02:52:47
Ort: Lund

Re: Ta siffran i 4 olika byte och sätta i en enskild int?

Inlägg av Henry »

Lite tid att bråka med detta igen.

I mitt fall är det inte bara att vara bekväm och nöjd med koden utan att få den att fungera överhuvudtaget. :) Men visst är det så annars går det inte att få ihop det, för mig vls.

Har sett det där tex "statechange" i många knapp koder men förstår inte riktigt vitsen med det på ett sätt.

Jag menar att även om jag håller knappen intryckt, som jag uppfattade att du menade, en längre stund eller bara trycker snabbt på den så ger den ju alltid först en nolla (i min kod) och ger en nolla så länge som jag trycker på knappen vilket gör att koden räknar fram ett steg vid första gången nollan detekterades oavsett hur länge den finns där och när jag släpper knappen är det ju en etta?

----

Angående trådens huvudproblem sedan med display siffergrejen så räkningen upp ned som så vet jag det, är bara resten att få ihop en fungerande hel funktion för allt så att säga som jag fattar. Såg dock precis att man visst kunde ta de enskilda tecknen i en char array och omvandla dessa till en string med någon funktion tror jag. Då går det ju att göra om detta sedan till en float vilket då kan användas vid jämförelsen med värdet från sensorn? Detta gav mig en bra möjlighet att ev få ihop trådens problem på ett sätt jag fattar.

Tanken var då att jag skriver siffrorna och även tecknen som inte är siffror (".", "E" samt "+") i en char array och jag har för mig jag läste något om att char i en array kan ändras on the fly?

När då alla siffror är inskrivna (men hela tiden uppdateras i displayen på något vis så jag vet vad som skrivs in) och även skrivna på rätta sifferplatser i arrayn och jag trycker på en knapp att jag är klar med inmatningen så omvandlas då innehållet i de enskilda delarna till en string som kan, vid behov, skrivas direkt på en display och även omvandlas till en float för att kunna jämföras med sensordatan.

Stämmer min teori med dessa grejer eller är det helt åt helvete? Vill bara få ihop det logiska så att säga innan jag börjar bråka med kod.
Användarvisningsbild
hawkan
Inlägg: 2586
Blev medlem: 14 augusti 2011, 10:27:40

Re: Ta siffran i 4 olika byte och sätta i en enskild int?

Inlägg av hawkan »

Jo men din knapptryckarkod gör inte det du tror.

Kod: Markera allt

  if (digitalRead(upp) == LOW)          // check if button was pressed
  {
    buttonPresses ++;                   // if pressed increment buttonPresses count
    delay(300);                         // debounce
  }
Varenda gång som koden körs och "upp" är nedtryckt så blir det en buttonPress++. Det finns inget som säger att det bara ska göras första gången utan det sker precis alla gånger som "upp" är nedtryckt. Det är där som statechange kommer in. Det kan se ut något sånt här. Man får alltså kolla om knappen var uppe förra gången man kollade och då och endast då ska man göra buttonPress++

Kod: Markera allt

bool upptryckt; 
uint8_t uppknapp;
...
  if ((uppknapp = digitalRead(upp)) == LOW && !upptryckt)          // check if button was pressed
  {
    buttonPresses ++;                   // if pressed increment buttonPresses count
    delay(300);                         // debounce
    upptryckt = true;
  } else if (uppknapp == HIGH) {
    upptryckt = false;
  }
Variabeln "upptryckt" håller ordning på om knappen var uppe eller nere förra gången man kollade. Det gör att man bara får en buttonPress++ den gången som knappen blir nedtryckt, inte när den hålls nedtryckt.

Angående att forma en float av de fyra inten så finns det flera sätt. Välj ett. Som du beskriver det finns det väl två kandidater som ligger nära till hands
Om char *s = "1.23E-04" så kan du ändra positionerna i s
s[0] = char('0') + buttonPress; // Hmm blev castingen rätt här?
s[2] = .. byt ut "2"
s[3] = .. byt ut "3"
s[6] = .. byt yt "0"
s[7] = .. byt ut "4"
Gör sedan en "toFloat".

Eller testa med sprintf. T ex sprintf(s, "%d.%d%dE-%d%d", buttonPress, ..andra ints. hmm är det fem?) Även här en toFloat.
Eller direkt forma en float utan att gå via en string som jag skrev i början
float en = buttonPress + buttonPress1*0.1 + buttonPress2*0.01; // Forma första mantissan. Detta ska bli typ 1.23
en = en * pow(10, -1*buttonPress3); // Multiplicera med 0.0001 eller 10^-4 1.23*10^-4 1.23E-4
Men finns flera sätt så välj ett.
Användarvisningsbild
rvl
Inlägg: 5721
Blev medlem: 5 april 2016, 14:58:53
Ort: Helsingfors

Re: Ta siffran i 4 olika byte och sätta i en enskild int?

Inlägg av rvl »

Debounce delayen blir överflödig, när man kör med states. Men... vill man däremot ha "auto repeat" på knappen, så måste det skarvas i mer logik.
Användarvisningsbild
Henry
Inlägg: 23588
Blev medlem: 20 april 2005, 02:52:47
Ort: Lund

Re: Ta siffran i 4 olika byte och sätta i en enskild int?

Inlägg av Henry »

Ok då förstår jag hur du menade men. Knapp koden ligger ju visserligen sedan även i loop, det kommer den inte att göra sedan utan är tänkt att vara en funktion så blir det ev lättare att få ihop koden sedan.

Angående huvudkoden sedan så måste väl sedan Arrayn benämnas som char och inte byte eftersom det ju är tecken i den, så topic är lite fel. Skall mer vara ta tecknen i en Array och sätta in en char, eller dylikt. Vill ha med allt i Arrayn för att det skall bli lättare för mig att få ihop det hela sedan och inte tex lägga till tecken och bokstäver m.m. i efterhand eller dylikt, även om principen i omvandlingen sedan ju blir den samma.

Utmärkt då vet jag att jag jag trots allt var på rätt väg, tackar. :)
Skriv svar