1

Тема: Як помножити число в ASCII на 2

Читаю книжку по Arduino і там є скетч, за допомогою якого можна вводити число через монітор послідовного порту і воно зразу множиться на 2. Проблема в тому, що я до кінця не розумію ті перетворення.
Припустимо, я хочу помножити на 2 число 235. Якщо подивится в табл. ASCII, то воно буде передаватися блоками (я так розумію):
00110010 00110011 00110101
Потім треба змістити попередні цифри на розряд вліво (помножити на 10)... І тут не ясно чи треба кожен блок зміщувати на розряд вліво, чи зразу всі три блоки. Виходить не зрозуміло що.

long number = 0;
long a = 0;
void setup()
{
Serial.begin(9600);
}
void loop()
{
number = 0; // обнулить переменную, подготовив
// ее к приему нового числа
Serial.flush(); // очистить буфер порта от "мусора" перед ожиданием
while (Serial.available() == 0)
{
// ничего не делать, пока что-то не появится в буфере порта,
// когда что-то появится в буфере, Serial.available вернет
// количество символов, ожидающих обработки в буфере
}
// как минимум один символ имеется в буфере,
// начать вычисления
while (Serial.available() > 0)
{
// сдвинуть предыдущие цифры на разряд влево;
// иными словами, 1 превратится в 10, если в буфере имеются данные
number = number * 10;
// прочитать следующую цифру из буфера и вычесть из нее
// код символа '0', чтобы превратить в фактическое целое число
a = Serial.read() - '0';
// прибавить это значение к накапливаемому значению
number = number + a;
// выполнить короткую задержку, чтобы дать возможность
// следующим цифрам достичь буфера
delay(5);
}
Serial.print("You entered: ");
Serial.println(number);
Serial.print(number);
Serial.print(" multiplied by two is ");
number = number * 2;
Serial.println(number);
}
Подякували: 221VOLT1

2

Re: Як помножити число в ASCII на 2

1. Коментарі не мовою форуму, в принципі, допустимі, але не вітаються.
2. Ви заплуталися, що у вас в якій формі. Цифра перестає бути символом ASCII одразу після введення в 27-му рядку.

Подякували: 221VOLT, 0xDADA11C72

3

Re: Як помножити число в ASCII на 2

27-ий рядок більш-менш розумію: там символ ASCII перетворюється в цифру у двійковій системі, якщо віднімати '0' (перетворення йде побайтно).
А з 24-им рядком.... ледь прояснилося після двох годин роздумів. І то якось абстрактно. Якщо буфер може зберігати до 128 байтів, то чого операції йдуть побайтно (як я розумію)?

4

Re: Як помножити число в ASCII на 2

До 128 байтів буфера це не має жодного стосунку, number зберігається у вигляді 32-бітного long. Очевидно, що на 10-11 символі (коли число перевищить 2,147,483,647) воно переповниться і буде показувати якусь дурню, в цьому коді немає захисту від такого.
Що ж до перетворень числа, то там чомусь рознесені операції з number, що може трохи збити з пантелику. Я б робив так:

a = Serial.read() - '0'; //прочитати цифру
number = number * 10 + a; //зсунути все число на 1 розряд і додати останню введену цифру

Цей код повністю еквівалентний тому, що у вас, але мені здається наочнішим.

Крім того, мені здається нерозумною логіка коду в цілому. Мабуть, варто не чекати по 5мс на цифру, а завершувати введення якимось маркером, наприклад, не-цифрою:

#include<climits>
...
long number = 0;
long a = 0;
while( true ) {//виходитимемо по break
  while (Serial.available() == 0) {
    delay(5);//я не знаю, як це реалізовано в Arduino, але сучасні процесори зазвичай мають культурніший спосіб очікування за цикл
  }
  a = Serial.read() - '0';
  if( (a < 0) || (10 <= a ) ) {
    break;//ввели щось не те - кінець числа
  }
  if( number > (LONG_MAX-a)/10 ) {
    //тут можна обробити ситуацію з переповненням
    //трохи грубо, насправді
  }
  number = 10 * number + a;
}

Одразу попереджаю: на Arduino не програмував жодного разу :)

Подякували: gensir1

5 Востаннє редагувалося ReAl (15.01.2018 12:48:57)

Re: Як помножити число в ASCII на 2

setup() і loop() у першому повідомленні були на місці.

koala, той loop(), якщо грубо, викликається з while(1) всередині main(), яка знаходиться десь в глибинах самої arduino. Воно там спочатку ініціалізує себе, потім викликає setup(), потім в циклі loop(), але залежно від — може ще щось там робити, не копав.

gensir тому краще віддавати керування, якщо воно непотрібне.

// setup як був

void loop()
{
    // поки є, вигрібаємо, як нема, вивалюємося і віддаємо час arduino
    while (Serial.available() != 0) {
        char ch = Serial.read(); // не треба відразу віднімати, воно нам ще знадобиться
        // тут набираємо число з контролем переповнення
        //
        // ознакою може бути прийнятий символ кінця рядка '\n'
        // або не-цифра, по ESC взагалі можемо обнуляти набрану суму і скидати 
        // простір для фантазії великий
        if (число_прийняте) { 
            // робимо що з ним треба зробити
        }
    }
    //
    // а тут можемо подібним чином обслуговувати щось інше
    //
}
printf("Nested comments is %s\n", */*/**/"*/"/*"/**/ == '*' ? "OFF" : "ON");
Подякували: koala, sensei, leofun013

6

Re: Як помножити число в ASCII на 2

Оскільки в Arduino нема хоч у якомусь вигляді багатозадачної операційної системи і її delay() це не sleep(), який віддає час, треба відразу звикнути робити великі затримки не вглибині, а назовні дій.

// загалом millis() повертає unsigned long, але для часів, менших за 65 секунд,
// нам буде досить 16 біт
static unsigned const task1_period = 500; // щопівсекунди щось робимо
unsigned task1_timer;

void setup()
{
    Serial.begin(9600);
    task1_timer = millis();
}

void loop()
{
    // а можна if (Serial.available() != 0) , наступний символ
    // візьмемо, коли повернемося
    while (Serial.available() != 0) {
        // оброблюємо символи
    }
    // це замість delay(task1_period) десь глибоко всередині
    if ( (unsigned)(millis() - task1_timer) >= task1_period) {
        task1_timer += task1_period; // наступна точка
        // тут щось робимо, наприклад, опитуємо терморезистор
    }
    // віддаємо час середовищу виконання arduino,
    // воно незабаром знов викличе loop()
}

p.s. Сам я arduino теж не користуюся, лише платами як зручними носіями мікросхем, які 1) паяв хтось інший і 2) дешевші за суму цін компонентів тут у нас.

printf("Nested comments is %s\n", */*/**/"*/"/*"/**/ == '*' ? "OFF" : "ON");
Подякували: koala, sensei2

7 Востаннє редагувалося ReAl (15.01.2018 19:35:23)

Re: Як помножити число в ASCII на 2

І ще, користуючись нагодою.

gensir, я ще восени завершив переклад оболонки arduino українською, прохання взяти з їхнього сайту найсвіжішу версію (зараз там в HOURLY BUILDS висить LAST UPDATE 3 January 2018), увімкнути українську і звертати увагу на вірність перекладу всіх позицій меню, повідомлень, ...

Сам я, як вже сказав, нею не користуюся, то дещо доперекладав всліпу, можуть бути помилки та некрасиві місця. Щось побачите, штурхайте мене. Якби був розділ по arduino, можна було б в ньому тему, а так, мабуть, краще у коментарях до того повідомлення, щоб було в одному місці.

printf("Nested comments is %s\n", */*/**/"*/"/*"/**/ == '*' ? "OFF" : "ON");
Подякували: NagarD, koala, sensei, gensir, leofun015

8

Re: Як помножити число в ASCII на 2

ReAl, крутий пацик (чи дядько), щось там перекладає. Завантажив тільки що останню версію, то в мене зразу почало все на українській мові працювати. Але й на старій версії також було по українськи (а я її вже давненько скачував).
---
І ще, ReAl, я запам'ятав ваш сайт, я на нього заходив десь 5 років назад :)

9

Re: Як помножити число в ASCII на 2

gensir написав:

Але й на старій версії також було по українськи (а я її вже давненько скачував).

Так я ж написав — десь із майже 600 позицій для перекладу (фраз, окремих слів) було не перекладено під 200. Тобто 2/3 було зроблене станом десь на 2015-2016 рік (хоча дещо підправити довелося). Частина, схоже, залишалася неперекладеною ще тоді, частина додалася під час розвитку IDE.

gensir написав:

І ще, ReAl, я запам'ятав ваш сайт, я на нього заходив десь 5 років назад :)

:D

printf("Nested comments is %s\n", */*/**/"*/"/*"/**/ == '*' ? "OFF" : "ON");

10 Востаннє редагувалося ReAl (31.01.2018 12:14:08)

Re: Як помножити число в ASCII на 2

gensir написав:

Завантажив тільки що останню версію, то в мене зразу почало все на українській мові працювати. Але й на старій версії також було по українськи (а я її вже давненько скачував).

«працювати» можна по різному, от щойно завантажив бету оболонки версії 1.9 (найсвіжіша «стабільна» зараз 1.8.5, та, яка «LAST UPDATE» — 1.8.6). Там одна бага тягнеться давно з гарячими клавішами зміни розміру шрифта Ctrl+Plus / Ctrl+Minus. То кажуть «перевірте у беті».
Показує Ctrl+Plus вже правильно, але збільшення шрифта так і не працює.

Але я не про те. В українському варіанті оболонки досі на старті повідомлення «Ініціалізуємо пакеті…». Хоч я це і виправив у проекті перекладу файлах 4 місяці тому, у мовні файли оболонки воно ще не потрапило. Так само досі пише «Increase Font Size» замість «Збільшити розмір шрифту».

p.s. Тобто я хотів сказати, що, одночасно:
1. Не завжди видно, що робота зроблена ще не вся.
2. Вже зроблену роботу на завжди видно.

printf("Nested comments is %s\n", */*/**/"*/"/*"/**/ == '*' ? "OFF" : "ON");
Подякували: leofun011