ParseInt () ga tezkor alternativ nima?

Men Arduino Due va mening kompyuterim bilan LED spektr analizatorini qilmoqdaman. Ovozni qayta ishlash kompyuterda amalga oshiriladi va keyin Arduino-ga yuboriladi. Yuborilgan aniq ma'lumot "koordinat" yoki undan ko'ra aniqroq, ma'lum bir bandni ifodalovchi raqam va ushbu bandning maksimal amplitudasini aks ettiradigan boshqa raqam. 11 ta bant mavjud. Har bir koordinatada x va y qiymatlari vergul bilan ajralib, keyin yangi satrda yuboriladi.

Bu mening kodim:

void loop() {
  if (Serial.available()) {
    xCoord = Serial.parseInt();
    yCoord = Serial.parseInt();
    if (xCoord != 0) {
      int r, g, b;
      for (int i = 0; i < 8; i++) {
        int fromCoordToIndex = ((xCoord - 1) * 8) + i;
        //
        //do some calculations for the color
        //
        strip.setPixelColor(fromCoordToIndex, strip.Color(r, g, b));
        strip.show();
      }
    }
  }
}

Muammo parseInt juda sekin ko'rinib turadi (bu takrorlash muammosi emas, 1-ga sozlangan). Ko'rib turganimdek, ba'zi ma'lumotlarga o'tish kabi ko'rinadi, shuning uchun har bir kishi hozir va keyin guruhni o'tkazib yuboradi. Buni tuzatishimning yagona usuli - jo'natilgan har koordinatalar orasidagi kechikish. 40 milodiy ishni yaxshi deb topdim, ammo 11 bandni eslayman, shuning uchun slayd-shou kabi his etadigan barcha kartani yangilash uchun yarim soniyani anglatadi ...

Men shaxsiy belgilarni kiritishni va undan so'ng toInt dan foydalanishni sinab ko'rdim, men parseInt ni aniq qilib ko'rdim, men mahalliy USBni sinab ko'rdim bod stavkalari bilan ajralib turadi. Hech qanday ta'siri yo'q ko'rinadi.

1
Ma'lumotni olganingizdan keyin qilgan hisob-kitoblar sekin bo'lgan qismdir. O'zgaruvchan nuqta operatsiyalari shunchaki arduinolarda sekinlashadi, buning o'rniga turg'un nuqta o'lchagichlari mavjud emas, buning o'rniga faqat integral turlarni qo'llagan holda sobit nuqtalarni hisoblashni afzal ko'rish mumkin.
qo'shib qo'ydi muallif CTKeane, manba
strip.show (); pastga aylanish jarayonini kattaroq tezlik bilan almashtirish uchun
qo'shib qo'ydi muallif Alastair, manba
Sizning raqamlaringiz o'rtasida bir-biridan ajratuvchi belgilar yuborasizmi?
qo'shib qo'ydi muallif Sprogz, manba
Juda tezroq alternativa ajralishni talab qilmaydi. Buning o'rniga ikkilik ma'lumotni yuboring.
qo'shib qo'ydi muallif Ignacio Vazquez-Abrams, manba
@LookAlterno bu qattiq emas, lekin uni qattiqlashtirish uchun 2 soniya kerak bo'ladi, format x, y (ayrachuvchi sifatida vergulni qo'shib, chiziq sifatida yuboriladi)
qo'shib qo'ydi muallif xandriksson, manba
Nima demoqchi ekanini tushunmayapman
qo'shib qo'ydi muallif xandriksson, manba
Lekin bu mag'lubiyatga o'xshamaydi, men uni ishlatish uchun uni tahlil qilishim kerak.
qo'shib qo'ydi muallif xandriksson, manba
Men yuqoridan olib tashlash uchun boshqa hisob-kitoblarim bor, ikkilanadigan bo'lsak, men buni qila olamanmi?
qo'shib qo'ydi muallif xandriksson, manba
@dandavis yaxshi nuqta, rahmat, men buni ko'rganman ...
qo'shib qo'ydi muallif xandriksson, manba
Birinchi maslahat - ma'lumotlarni qayta ishlash va namoyish qilishdan oldin o'qish. Bundan tashqari, oldingi tugatilishigacha qo'shimcha ma'lumotlarni jo'natmaslik kerak. Ikkinchidan, qo'shimcha qurilmani ketma-ket qo'llashni tekshirish, bu aslida uzilib qolgan va buferlarni o'chiradi.
qo'shib qo'ydi muallif Mikael Patel, manba
Sizning ma'lumotlaringiz qattiq formatga ega bo'lsa (masalan, har doim 3 dona raqamli, nol yoki bo'sh joy bilan to'ldirilgan bo'lsa) parseInt ni tezroq qilishingiz mumkin. .
qo'shib qo'ydi muallif user31481, manba
Masalan, barcha qiymatlar ijobiy 3 xonali (nol bilan to'ldirilgan) va ular juftlik bilan, vergul bilan ajratilgan, 003,456 ... 450,001 ...
qo'shib qo'ydi muallif user31481, manba
Savolga erishish uchun formatingizdagi ma'lumotlarni yozing.
qo'shib qo'ydi muallif user31481, manba
⇒ Bu savolni boshqa joyga berish yaxshi, lekin bizdan yashirishga urinmang. Siz " forumga bog'lanishingiz kerak. Forum.arduino.cc/index.php?topic=508343.0
qo'shib qo'ydi muallif Standback, manba
Albatta, va, 1ms'lik vaqt tugashi parseInt abortini (biz bilmagan bodratga bog'liq) amalga oshiradi. Lekin oldin biz ketma-ket ma'lumotlar protokolini aniqlashimiz kerak.
qo'shib qo'ydi muallif Standback, manba
MatthewInglis formatini ko'rsatishingiz kerak. Bu erda boshlash kerak. Qaysi raqamlar soni katta bo'lgan bayt bo'lishi mumkin, ular salbiy bo'lishi mumkin va hokazo. Buni bildirganingizdan so'ng, uni @LookAlterno sizga aytib berishga harakat qilib, uni sobit/ridig formatiga aylantiring. Shundan so'ng, nazorat summasini, yoki STX va ETX (markerni boshlash va tugatish) ni qo'shishingiz mumkin. Yoki oxirida har doim LineFeed yoki CarriageReturn borligini ko'rsating. Lekin oldin formatini belgilang, sizga savol bering va unga qo'shing.
qo'shib qo'ydi muallif Standback, manba

5 javoblar

parseInt() haqida bezovta qiluvchi narsa uning tezligi emas, bu haqiqat u vaqt tugashiga tayanadi. Vaqt tugashi juda uzun bo'lsa, u sekinlashadi pastga. Agar u juda qisqa bo'lsa, u xatoga yo'l qo'yishi mumkin.

Foydalanadigan xabar turlarini tahlil qilishning xavfsizroq usuli bularning barchasini bufer qilishdir kiradigan harflarni topib bo'lmaguncha, keladigan belgilarni kiriting butun yo'nalish. Misol uchun:

// Just echo the messages with a different separator.
void parse(char *buffer)
{
    char *s = strtok(buffer, ",");
    int x = atoi(s);
    s = strtok(NULL, ",");
    int y = atoi(s);
    Serial.print(x);
    Serial.print(':');
    Serial.println(y);
}

void loop()
{
    static char buffer[BUFFER_SZ];
    static size_t lg = 0;
    while (Serial.available()) {
        char c = Serial.read();
        if (c == '\r') {       //carriage return
            buffer[lg] = '\0'; //terminate the string
            parse(buffer);
            lg = 0;            //get ready for next message
        }
        else if (lg < BUFFER_SZ - 1) {
            buffer[lg++] = c;
        }
    }
}

strtok() deb nomlaganingizda ba'zi bir xatolarni tekshirish kerak.

3
qo'shib qo'ydi

Men buni bodning tezligini 115200 dan 9600 gacha kamaytirish orqali aniqladim. Ushbu javob o'zgarishlarni ilhomlantirdi. Ko'rinishli tomoni, axborot uzatish tezligi qanchalik yuqori bo'lsa, lekin xatolarning ehtimolligi qanchalik yuqori bo'lsa va bod tezligi qanchalik past bo'lsa, u yuborilgandan ko'ra sekinroq, lekin undan ishonchli bo'ladi.

0
qo'shib qo'ydi

Prematüre optimallash, barcha yovuzliklarning ildizidir (yoki hech bo'lmaganda   dasturlashda). Donald Knut.

Juda tez/sekin parseInt() ni bilmayman. Siz ham emas. Buni birinchi marta qilish kerak.

OK. Ehtimol, bu juda sekin, lekin kodning eng sekin qismi bo'ladimi? Nima bilan solishtirganda sekin?

parseInt nima kerak? parseInt salbiy qadriyatlarni aylantirmaydi va vaqt tugashi mumkin (lekin yana nolga aylanadi ... Duh!).

Agar butun chiziqni bir satr sifatida o'qib chiqsangiz va qiymatlarni ajratib olsangiz, vaqtni tugatish muammosidan qochib, ma'lumotlarning to'g'ri ekanligini tasdiqlashingiz mumkin.

Ushbu eskiz ma'lumotlaringizni qanday ishlashni ko'rsatmoqda:

void setup() {
  Serial.begin(9600);
  while(!Serial);

  String lines[] = {
    "1,1",
    "10,20",
    "11,1000",
  };
  int channel;
  int value;

  for (int i=0; i < 3; i++) {      
    sscanf(lines[i].c_str(), "%d,%d", &channel, &value);
    Serial.print("channel="); Serial.print(channel);
    Serial.print(" value="); Serial.println(value);
  }
}

void loop() { 
}

Men sscanf dan foydalanmoqdaman, bu parseInt ga nisbatan ancha sekin, lekin ish bajarildi. Men siz (yoki men) buni yaxshiroq qila olamiz, deb o'ylayman va bizning vaqtimiz bilan bog'liq yana foydali narsa bor.

Tahrirlash:

Men profil hosil qildim

sscanf("0001,0001", "%d,%d", &channel, &value);

Bir Arduino BMT bilan birga, bir qadam qadriyatni aylantirish uchun 147us oldi.

0
qo'shib qo'ydi

Sizning ma'lumotlaringiz 11 kanal va har bir kanal uchun bitta qiymatga ega. Qiymatlar grafik formatda taqdim etiladi, shuning uchun taqdimotni tanqid qilmasdan 0-255 oralig'ida bo'ladi. Har doim o'qishlaringizni ekraningizning o'lchamiga moslashtira olasiz.

Keyin bu 11 qiymatlarni ikkilik shaklda yuboring. Har bir kanal uchun bitta bayt va ortiqcha bir baytni boshqa ma'lumotlardan ajratish. Sizga faqat kanal raqamini yuborish kerak emas.

Arduino uchida siz 12 bayt o'qidingiz va keyin baytlarni ints ga aylantirish orqali aylantirdingiz.

#define CHANNELS 11

void setup()
{
  Serial.begin(9600);

  while(!Serial);
}

void loop()
{
  char packet[CHANNELS + 1];
  int values[CHANNELS];

 //Read 12 bytes (11 bytes of data + 1 byte delimiter)
  int nBytes = Serial.readBytes(packet, sizeof(CHANNELS + 1));

  if(nBytes == CHANNELS + 1) {
   //Convert bytes to ints;
    for(int i=0; i

Ushbu kodda xato aniqlanmaydi. Buning uchun barcha ma'lumotlar to'plamining checksum bilan qo'shimcha bayt qo'shishingiz mumkin.

0
qo'shib qo'ydi
Bu bilan qiziqarli masala, nBytes hech qachon 11 + 1 bo'ladi, uni sinab ko'rganimda, u har doim 4, keyin 4, keyin esa 4, o'rniga 12 emas. Har qanday fikr bormi?
qo'shib qo'ydi muallif xandriksson, manba
Siz deyarli to'g'ri ish qilyapsiz. Comms bilan aloqa qilishda (serial, tcp/ip) hech qachon bir baytda barcha baytlaringizni qabul qilasiz deb o'ylamang. Ma'lumotlarni ma'lumotlarni o'qish uchun tayyor bo'lishingiz kerak. Asosiy fikringiz bor; endi qolgan tafsilotlarni to'ldirish uchun siz tomoningizdan. Sizning oldingizda turgan yana bir muammo, ikkala kompyuterni ham sinxronlashtirmoqda: ma'lumotlar to'plamining boshlanishini (yoki oxirini) ko'rsatish uchun maxsus qiymatni (masalan, 255) zaxiralash kerak. Ayni paytda yuborilgan birinchi baytlar ehtimol yo'qolgan. Sizning barcha xatolarni tekshirish, qayta tiklash va buferlashni qo'shganingizdan so'ng kodingiz 5x kattaroq bo'ladi. Bu qanday qilib ishlaydi.
qo'shib qo'ydi muallif user31481, manba

Parseintni ishlatish o'rniga, Arduino uchun "11-band" uchun ma'lumotni juda aniq shaklda Arduino-ga yuboring, shuning uchun Arduino uni "osonlikcha" ajrata oladi.

Ehtimol, matnni yuborish o'rniga, RGB (3) marta 33 bayt jo'natish 11 tarmoqli ketma-ket kanallarning sathi (0-255). Undan keyin konvertatsiya qilish kerak emas (byte o'qishdan tashqari).

0
qo'shib qo'ydi
OK, shuning uchun ketma-ketlik bilan arduino "025" ni yuboradigan bo'lsam, serial.readBytes() foydalanishi mumkinmi? Va agar buni qilsam, uni butun bir songa aylantiradimi?
qo'shib qo'ydi muallif xandriksson, manba
Kechirasiz, mening jaholatim yo'q, lekin siz nimani aniqlaysiz? Har bir guruhda 0 va 13 orasida (va shu jumladan) bir raqam bo'lsa, uni qanday qilib bayt sifatida ifodalashim mumkin?
qo'shib qo'ydi muallif xandriksson, manba
Menga rangni jo'natishning hojati yo'q, men har bir guruhning qanchalik yuqori bo'lishi kerakligini bilishim kerak. Shunday qilib, qo'shimcha qiymatlarni yuborish beg'ubor bo'lar edi.
qo'shib qo'ydi muallif xandriksson, manba
Bunday holda 11 bayt har bir band uchun bitta qiymatga ega bo'ladi.
qo'shib qo'ydi muallif Pat, manba
Bayt 8 bit (8 ta nol yoki bir). Agar baytda (8 bit) 0 va 255 (yoki 256 xil qiymat) o'rtasida raqamni saqlashingiz mumkin. Siz qiymatni hisoblash yo'li bilan 0 dan 13 gacha bir baytda 2 qiymatni yuborishingiz mumkin (bu har doim ham 256 dan kam bo'ladi). Yoki yana bittadan bittalar: value1 << 4 + value2 ... << operator bitlarni to'rtdan chapga o'zgartiradi, bu tenglama bilan 16 ga ko'payadi. Value1 chapdagi (MSB) to'rtta bit va qiymati o'ng (LSB) to'rtta bit. Shunday qilib, agar sizning tizimingiz 16 kanalni o'zgartirsa, siz hech narsa o'zgartirishingiz shart emas (bu orqali 11 kanalga nisbatan).
qo'shib qo'ydi muallif Pat, manba
Xo'sh, "025" ni jo'natmaslik mumkin, chunki u 3 belgidan iborat (bayt). Masalan, dastlabki ikkitani 0 * 16 + 2 = 2 ga yuborishingiz mumkin ... shuning uchun qiymati 2 bo'lgan baytni yuboring (bu 2 belgisi emas).
qo'shib qo'ydi muallif Pat, manba