Моя первая программа на Arduino :)

Тема в разделе "Глядите, что я сделал", создана пользователем Zander, 29 дек 2016.

  1. Zander

    Zander Нерд

    Предисловие - захотелось узнать, сколько времени тратит Arduino на передачу данных на экран в 4 строки. Описание экрана почитал, примеры потыкал - получилось вот такое:
    Код (C++):
    // the setup function runs once when you press reset or power the board
    #include <LiquidCrystal.h>
    // Инициализируем объект-экран, передаём использованные
    // для подключения контакты на Arduino в порядке:
    // RS, E, DB4, DB5, DB6, DB7
    LiquidCrystal lcd(4, 5, 10, 11, 12, 13);
    String stringOne, stringTwo, stringThree, stringFour, strMain;
    unsigned long time_1, time_2;
    unsigned long last_time_1, last_time_2;
    unsigned long delta_1, delta_2;
    unsigned long cycle_count, sltime;
    unsigned long timedata, display_time;
    String str5, str6, str7, str8;
    unsigned long ms_in_slw, mcs_in_slw, upd_cnt, fast_time;
    unsigned int change_key;
    boolean display_phase;

    unsigned long slow_loop()
    {
        sltime = micros();
        if (display_phase) {
       
          lcd.clear();
          lcd.setCursor(0, 0);
        strMain = stringOne + delta_1;
         lcd.print(strMain);
         lcd.setCursor(0, 1);
        strMain = stringTwo + delta_2;
         lcd.print(strMain);
         lcd.setCursor(0, 2);
        strMain = stringThree + cycle_count;
        lcd.print(strMain);
        lcd.setCursor(0, 3);
         strMain = stringFour + display_time;
         lcd.print(strMain);
     
        } else {

          lcd.clear();
          lcd.setCursor(0, 0);
        strMain = str5 + ms_in_slw;
         lcd.print(strMain);
         lcd.setCursor(0, 1);
        strMain = str6 + mcs_in_slw;
         lcd.print(strMain);
         lcd.setCursor(0, 2);
        strMain = str7 + upd_cnt;
        lcd.print(strMain);
        lcd.setCursor(0, 3);
         strMain = str8 + fast_time;
         lcd.print(strMain);

        }
        change_key = change_key + 1;
        if (change_key > 5) {
          display_phase = !display_phase;
          change_key = 0;
        }
         return micros() - sltime;
    }
    void setup()
    {
        lcd.begin(20, 4);
        lcd.print("Hello Zander!");
        // нафиг нам world, программа должна приветствовать своего создателя.
        lcd.setCursor(0, 1);
        // печатаем вторую строку
        lcd.print("Calc updates...");
        last_time_1 = 0;
        last_time_2 = 0;
        delta_1 = 0;
        delta_2 = 0;
        cycle_count = 0;
        timedata = 0;
        display_time = 0;
        ms_in_slw = 0;
        mcs_in_slw = 0;
        upd_cnt = 0;
        fast_time = 0;
        change_key = 0;
        display_phase = true;
        stringOne = "MS in fast:"; // число миллисекунд от одного
        // вызова loop() до другого
        stringTwo = "MCS in fast:"; // число микросекунд от одного
        // вызова loop() до другого
        stringThree = "Upd per s:"; // число вызовов loop() в секунду
        stringFour = "LCDtime:"; // время вывода информации на экран
        // в микросекундах
        str5 = "MS in s:"; // число миллисекунд от одного вызова slow_loop()
        // до следующего
        str6 = "MCS in s:"; // число микросекунд от одного вызова slow_loop()
        // до следующего
        str7 = "Prog time:"; // число вызовов slow_loop() от старта программы
        str8 = "Fast time:"; // время выполнения тела функции loop() в микросекундах
        delay(10000);
    }
    void loop()
    {
        time_2 = micros();
        time_1 = millis();
        cycle_count = cycle_count + 1;
        delta_1 = time_1 - last_time_1;
        last_time_1 = time_1;
        ms_in_slw = ms_in_slw + delta_1;
        delta_2 = time_2 - last_time_2;
        last_time_2 = time_2;
        mcs_in_slw = mcs_in_slw + delta_2;
        timedata = timedata + delta_2;
        if (timedata >= 1000000) {
            upd_cnt = upd_cnt + 1;
            display_time = slow_loop();
            timedata = 0;
            cycle_count = 0;
            ms_in_slw = 0;
            mcs_in_slw = 0;
        }
        fast_time = micros() - time_2;
    }

    Картинки
    http://imgur.com/a/MvtG3
    http://imgur.com/a/3YPyp

    Почти 20 миллисек убиваем на "рисование" - печалька :(
    Поковырялся в библиотеке LiquidCristal.h, увидел там в многих методах задержки delayMicroseconds, в общем-то ясно стало, где собака зарыта. И к знающим-опытным - вопросы:
    1) сократится ли существенно время работы с экраном, если вместо 4 пинов использовать 8. И кстати где накопать схему подключения под это дело? В "инструкции" доступной из магазина, только под 4 пина.
    2) Пробовал ли кто писать библиотеку умеющую работать с экраном через выходной сдвиговый регистр, если да, можно ли где-то найти? или самому писать.
    3) Пробовал ли кто писать библиотеку, или организовывать структуру loop() таким образом, чтобы не мешать Ардуине заниматься своими делами, пока экран "просит подождать".
    В том же lcd.clear() в библиотеке например, наблюдаю delayMicroseconds(овердофига), можно же время засечь и свои дела дальше делать, просто экран не трогать.
    Вернее так, по вопросам 2 и 3 ясное дело что пробовали :) точнее будет спросить, есть ли эти результаты где-то в свободном доступе.
     
  2. AlexU

    AlexU Гуру

    1) Сократиться, но не существенно. Может даже и не заметите разницы.
    2) Пробовали -- Google || Yandex дадут ответ. Один из примеров: https://github.com/AlexUg/LiquidCrystal_3WI_Rus.
    3) Самый простой способ -- использовать потоки: http://forum.amperka.ru/threads/Потоки-в-avr.9856/. Либо нужно переделывать библиотеку для работы с LCD и правильно организовывать код в 'loop()'.
     
    Zander нравится это.
  3. Zander

    Zander Нерд

    Ну, в численном измерении я в любом случае разницу увижу, если она есть :) А за ответ спасибо.
     
  4. mcureenab

    mcureenab Гуру

    Микросекунды уйдут только на переключение контекста задачи. Чем с регистрами бодаться, проще отдельный микроконтроллер задействовать.
     
  5. Zander

    Zander Нерд

    Конечно проще. Только это прямолинейный метод "грубой силы". На каждую задачу, где требуется быстродействие, вешать отдельный микроконтроллер... так не интересно.
    Вот организовать код так, чтобы и экран работал, и клавиатуру успеть опросить, и еще актуальные задачи выполнять с должным быстродействием, и все это на одном микроконтроллере - вот это интересная задачка для начинающего программиста вроде меня :)
     
  6. rkit

    rkit Гуру

    Это общепринятый в цифровой электронике метод, и на хороших основаниях. Загляните в любой более-менее сложный прибор - увидите десятки микроконтроллеров.
     
  7. LenovDan

    LenovDan Нуб

    эээээээээээто как там же дисплей на 2 строки
     
  8. Zander

    Zander Нерд

    на 4
    На программистах экономят жеж. Это мешает мне развивать себя как программиста?)
    Так то я знаю что вы правы, микроконтроллеры стоят недорого. Но я же свое устройство делаю не на продажу, а для саморазвития.
     
  9. mcureenab

    mcureenab Гуру

    Тем более в этом нет смысла. Если бы тираж был многотысячным в условиях конкуренции, экономия на железках имела бы смысл. А тут вы скорее всего получите уникальное решение, которое невозможно использовать повторно. Ну может быть сама методика будет интересной, хотя бы с точки зрения оценки затрат.

    Ради эксперимента, попробуйте заменить хотя бы одну задержку в библиотеке своим полезным кодом. Учтите, что на разных Ардуино частота МК отличается, так что один из тот же код может выполняться за разное время.
     
  10. Zander

    Zander Нерд

    Совершенно верно, и в данном случае, меня это устраивает.
    Однако, можно будет использовать архитектуру кода :)

    Разнообразные частоты спокойно могут учитываться тем же кодом. Я же говорю не о том чтобы "подождать столько-то действий, авось времени пройдет сколько надо". А о том чтобы подождать именно столько времени, сколько требуется. Занимаясь при этом полезностями.
     
  11. mcureenab

    mcureenab Гуру

    Сделайте библиотеку с неблокирующими вызовами. Хотя бы очистку экрана можно переделать.
    С выводом текста сложнее, там еще библиотека Print задействована и задержек много. Но она тоже не большая.

    Суть в том, что вызов clear не ждет, когда дисплей отработает команду, а сохраняет в контексте время, до которого модуль занят и возвращает false.
    После вызова clear, программа делает свои дела и периодически повторно дергает метод clear с тем же контекстом. Метод возвращает true, если таймаут истек и выполнение команды завершено.
    Получив true, программа может уничтожить контекст команды clear и переключить автомат взаимодействия с lcd в следующее состояние.

    Аналогично с print. Но тут блокировка происходит после вывода каждого байта или полубайта. Поэтому надо или отказаться от вывода строк в пользу посимвольного вывода, или например поступить так.
    print возвращает true, если вся работа с буфером закончена или false, если в буфере еще остались символы. Тогда программа может заниматься своими делами и периодически дергать print с тем же контекстом и тем же буфером.

    И, понятно, если программа вызывает метод не дождавшись завершения предыдущего, поыедение может быть непредсказуемым.
     
  12. mcureenab

    mcureenab Гуру

    Что еще добавить...
    Отказаться от произвольного распределения пинов - использовать для подключения 8 бит один регистр МК и выдавать на пины не по одному биту, а сразу байт в регистр.