Kirjautuminen

Haku

Tehtävät

Keskustelu: Ohjelmointikysymykset: Arduinon C++ ja rivin lukeminen

Sivun loppuun

tesmu [06.05.2010 14:16:45]

#

Käytössä on Arduino Duemilanove (ATMega328 pohjanen) mikrokontrolleri.

Käytännössä mikrokontrollerin ohjelmoiminen on minulle peruskauraa, jota on tullut jo suhteellisen kauan harrastettua.

Ongelmakseni kuitenkin tuli kyseisen kielen "laajuus".
Varsinaiseen kysymykseen. Miten pystyn lukemaan Serial-portista kokonaisen merkkijonon ja tallentaa sen string-tyyppiseen muuttujaan.

LCD-näytölle tulostushan serialista onnistuu näin

while (Serial.available() > 0) {
     lcd.write(Serial.read());
 }

Eli käytännössä luetaan kaikki merkit, jota ollaan saatu Serial-portista.

Tarkoituksena olisi kuitenkin saada esim seuraavaan enteriin asti luettua ja tallennettua tämä "komento" muuttujaan.

http://arduino.cc/en/Tutorial/HomePage


Sattuuko kenenkään silmään ratkaisua?

Grez [06.05.2010 14:31:58]

#

Jos käytössä on String luokka, niin lisäilet siihen merkki kerrallaan. Jos ei ole (vaan joutuu käyttämään tavutaulukkoja) niin sitten varaat riittävän ison taulukon, teet indeksimuuttujan jonka alustat nollaksi ja laitat niitä merkkejä taulukkoon aina indeksiä kasvatten. Samalla kannattaa katsoa ettei indeksi pääse kasvamaan taulukkoa suuremmaksi. Kun vastaan tulee "enteri" niin käsittelet sen.

Metabolix [06.05.2010 14:42:41]

#

Eihän se asia ole yhtään mutkikkaampi kuin tavallinen silmukka:

const int MAX_PITUUS = 15;
char rivi[MAX_PITUUS + 1];
int pituus;

// Luetaan teksti, kuitenkin enintään MAX_PITUUS merkkiä.
for (pituus = 0; pituus < MAX_PITUUS; ++pituus) {
  rivi[pituus] = Serial.read();
  // Jos luettiin lopetusmerkki, poistutaan silmukasta.
  if (rivi[pituus] == '\r' || rivi[pituus] == '\n') {
    break;
  }
}
// Asetetaan tekstin loppuun nollamerkki, kuten C:ssä yleensä on tapana.
rivi[pituus] = 0;

// Tulostus: käydään läpi alusta nollamerkkiin asti.
for (int i = 0; rivi[i] != 0; ++i) {
  Serial.write(rivi[i]);
}
Serial.write('\n');

tesmu [06.05.2010 14:45:43]

#

Metabolix kirjoitti:

(koodia)

Juu hieman tämäntyyppistä ratkaisua haettiin, mutta tarkoitus olis tämän jälkeen pystyä vertaamaan, onko komento esim "readset" tai "writeset" esim...

Metabolix [06.05.2010 14:48:34]

#

tesmu kirjoitti:

tarkoitus olis tämän jälkeen pystyä vertaamaan, onko komento esim "readset" tai "writeset" esim...

No kai nyt tuon verran osaat itsekin ohjelmoida, vai kannattaisiko sittenkin aloittaa vaikka lukemalla jokin ohjelmoinnin perusopas?

tesmu [06.05.2010 15:36:41]

#

Noniin, sain ratkaistua ongelmani muuntelemalla koodia hieman. Nyt kyseinen koodi kokonaisuudessaan näyttää tältä.

int pituus = 0 ;
void setup() {
 Serial.begin(9600);
}


void loop() {
  const int MAX_PITUUS=15;
  char rivi[MAX_PITUUS +1];
  int finished = 0;
  int i = 0;
  int inByte;

  while (Serial.available() >0) {
    inByte = Serial.read();

    if (inByte == '\n' || inByte == '\r') {
      finished = 1;
      rivi[pituus+1] = '\0';
      pituus = 0;
      break;
    }
    else {
      rivi[pituus] = inByte;
      pituus++;
    }

  }
   if (finished) {
     if (strcmp(rivi, "readset") == 0) {
       Serial.println("Reading settings from EEPROM");
     }
     if (strcmp(rivi, "writeset") == 0) {
       Serial.println("Writing settings to EEPROM");
     }
   }
}

Ainoa vaan, että välillä tuonne tulee jotain ihan outoja merkkejä väliin...

Grez [06.05.2010 16:31:27]

#

Tossa tapahtuu myös jotain tosi hassua, jos sarjaportista tulee enemmän kuin 15 merkkiä ennen \r tai \n merkkejä.

Grez kirjoitti:

Samalla kannattaa katsoa ettei indeksi pääse kasvamaan taulukkoa suuremmaksi.

Metabolix kirjoitti:

for (pituus = 0; pituus < MAX_PITUUS; ++pituus) {

Torgo [06.05.2010 16:36:04]

#

Helpottaa sun elämää kummasti jatkossa, jos teet ihan kunnollisen getline-funktion lukemaan rivejä, missä otetaan erikoismerkkejäkin huomioon ja jonkinlaisen köyhän miehen komentoriviparserin. Niin ja tietysti noi yli-indeksoinnin tarkistukset getlineen ja parseriin mukaan kans.

Eli teet vaikka promptin joka kutsuu tuota sun getline -funktiota. Sit teet handlerin, joka käsittelee getlinella saatua riviä.

Varsinaisen komentojen suorittamisen voit tehdä callbackeilla. Tällä tavoin tuo sun handleri on siirrettävissä suoraan aina uuteen projektiin, eikä sun tarvi tehdä mitään uusiksi. Ainoastaan tarvii tehdä lista hyväksytyistä komennoista ja proseduurit niiden suorittamiseen.

Komennon prototyyppi voisi olla esim:

typedef int (*serial_command_handler_t)(int argn, char** argc);

Sitten vaan taulukko komennoille ja niiden handlereille:

#define MAX_COMMAND_LENGTH 9  // esimerkki komennon maksimipituudeksi 8 + null
typedef struct serial_command_list_t {
	char command[MAX_COMMAND_LENGTH];
	serial_command_handler_t handler;
} serial_command_list_t;

// Asenna hyväksytyt komennot ja assosioi ne oikeisiin käsittelijöihin.
static serial_command_list_t serial_command_list[] = {
	{"command1", &command1_handler},
	{"command2", &command2_handler},
};

Sit vaan teet tolle handlerin, missä sun omalla getline -funktiolla luet rivin, pilkot sen komentoon ja sen argumentteihin (esim. strtok). Sen jälkeen etsit vain listasta sopivaa komentoa. Jos löytyi niin kutsut komentoon assosioutua käsittelijää juuri pilkkomillasi argumenteilla. Kertaalleen kun saat tuon tehtyä, niin voit käyttää sitä missä vaan vastaavassa tilanteessa. Handlerin paluuarvon voit muuttaa halutessasi voidiksi, jos "komentotulkkisi" ei tarvitse tutkia funktioiden paluuarvoja.

tesmu kirjoitti:

Ainoa vaan, että välillä tuonne tulee jotain ihan outoja merkkejä väliin...

Yritätkö lähettää sinne tavaraa pc:ltä terminaaliohjelman kautta? Jos näin, niin luultavasti kyse on terminaaliohjelmastasi tai sen asetuksista ja se lähettää kontrollimerkkejä sinne väliin.

tesmu [06.05.2010 18:30:01]

#

Grez kirjoitti:

Tossa tapahtuu myös jotain tosi hassua, jos sarjaportista tulee enemmän kuin 15 merkkiä ennen \r tai \n merkkejä.

Juu tapahtuu hassua, mutta ohjelma joka kommunikoi kyseisen laitteen kanssa ei laita yli 10-merkkisiä komentoja sinne...

Grez [06.05.2010 18:39:30]

#

Ja sarjaliikenteessähän on tietenkin mahdotonta, että \n jäisi välistä tai korruptoituisi joksikin muuksi merkiksi, jolloin olisi jo 21 merkkiä ennen rivinvaihtoa ja ohjelma täysin sekaisin.


Sivun alkuun

Vastaus

Aihe on jo aika vanha, joten et voi enää vastata siihen.

Tietoa sivustosta