Arduino Playstation joystick, Serial между 2 ардуинами

Тема в разделе "Флудилка", создана пользователем Alex19, 8 дек 2014.

  1. Alex19

    Alex19 Гуру

    Добрый вечер.
    Потихоньку ковыряюсь с Rov.
    Времени стало меньше, но проект не останавливается.

    Здесь не будет чего-то особенного, все можно найти в интернете. Но раз сделал, хотелось поделится, может кому-то будет полезно.

    Возник вопрос, с помощью чего управлять данным Rov-ом с береговой станции (корабля). Первое, что пришло в голову, сделать собственный блок управления с данными джойстиками
    http://amperka.ru/product/joystick-module

    Но беда в том, что живу не в России, а у нас такие вещи редкость. Заказывать долго и надо напрягать друзей, случайно нашел в сети
    http://www.billporter.info/2010/06/05/playstation-2-controller-arduino-library-v1-0/.

    Библиотека тут.

    Данный джойстик был куплен в ближайшем магазине, по цене 7$ производства Китай.
    Что мы получаем за эти деньги 16 (2 на джойстике) кнопок и 2 джойстика, аналогичных этому
    http://amperka.ru/product/joystick-module, нормальный дизайн.
    Кроме это 2 моторчика, с их помощью поддерживается вибрация или обратная связь, не знаю как назвать, такой приставки не было. Сама библиотека ее поддерживает, но мне ни к чему, поэтому были отправлены на склад.

    Поддерживаемые джойстики от PS2
    Можно самому соорудить радио канал, разместить в данный джойстик ардуину. Возможно есть и другие варианты.
    [​IMG]
    Об этом, тут
    http://fabioangeletti.altervista.or...ing_wp_cron=1418064141.0479130744934082031250

    Для тех кто решится попробовать, советую внимательно ознакомится, со списком возможных проблем
    http://www.billporter.info/2011/03/...n-2-controller-library-troubleshooting-guide/

    Вот, что пишут
    Если коротко, не верить цветам, а проверять тестером фишку.

    По питанию, предлагают проверить, подключив вначале 3,3V (тут так не пишут, просто начинать нужно с меньшего вольтажа) c резистором на лини Data и если не получится без, а потом тоже самое с 5V. Рисунок ниже
    [​IMG]
    У меня данный джойстик заработал от 5V с резистором 10K, подключенным таким образом. И других нюансов не было, так же не использовал 13 пин, по привычке всегда оставляю свободным. Проверял на Mega 2560 и Leonardo, Uno отродясь не было:), но все примеры в сети на ней.

    У одного человека, заработало только по такой схеме.
    [​IMG]
    И такими резисторами
    У некоторых пользователей были проблемы с 13 пином линии CLK, как говорил, по привычке ни когда не занимаю 13 пин.

    Если все еще не работает читаем, так как делают их разные производители, в том числе и "не честные" Китайцы:).

    Качаем библиотеку, пробуем пример PS2X_Example.ino. Там неплохая система проверок. И проверяем, все выше описанные варианты.

    Напоследок описание протокола.

    Теперь о соединении Serial между 2 ардуинами, с передачей данных в обе стороны.
     
    Последнее редактирование: 8 дек 2014
  2. Alex19

    Alex19 Гуру

    Одним словом идея очень простая, наверху джойстик с ардуиной, провод и ардуина внизу. Отправка и получение в обе стороны.

    Схема подключения для Serial
    [​IMG]

    Использовал Leonardo и Mega 2560, одним словом, что было под рукой.

    Ардуина на корабле (вверху)

    Код (Text):

    /******************************  Библиотеки  **********************************/
    #include <PS2X_lib.h>            // Библиотека для работы с Playstation joystick
    /******************************  /Библиотеки  **********************************/

    /******************************  Настройки и переменные для Playstation joystick  **********************************/
    // TODO: Перенести объявления пинов в отдельный файл

    /// <summary>
    /// Константа - пин Arduino для Playstation joystick линия Dat
    /// </summary>
    #define ps2PinDat        12
    /// <summary>
    /// Константа - пин Arduino для Playstation joystick линия Cmd
    /// </summary>
    #define ps2PinCmd        11
    /// <summary>
    /// Константа - пин Arduino для Playstation joystick линия Sel
    /// </summary>
    #define ps2PinSel        10
    /// <summary>
    /// Константа - пин Arduino для Playstation joystick линия Clk
    /// </summary>
    #define ps2PinClk        9

    /// <summary>
    /// Объявляем класс - для работы с Playstation joystick
    /// </summary>
    PS2X ps2x;

    /// <summary>
    /// Переменная хранящая тип Playstation joystick
    /// </summary>
    byte type = 0;

    /// <summary>
    /// Переменная хранящая наличие ошибок для Playstation joystick
    /// </summary>
    int error = 0;

    /// <summary>
    /// Переменная хранящая время последнего чтения данных от Playstation joystick
    /// </summary>
    unsigned long ps2PreviousT = 0;
     
    /// <summary>
    /// Переменная хранящая промежуток между чтениями данных от Playstation joystick
    /// </summary>
    unsigned long ps2T = 200;
    /******************************  /Настройки и переменные для Playstation joystick  **********************************/

    /******************************  Переменные для работы с Serial портом  **********************************/
    /// <summary>
    /// Константа - Скорость Serial порта, для соединения с Arduino
    /// </summary>
    #define speedSerialToArduino 115200

    /// <summary>
    /// Константа - Скорость Serial порта, для соединения монитором порта
    /// </summary>
    #define speedSerialToMonitorPort 115200
    /******************************  /Переменные для работы с Serial портом **********************************/

    /******************************  Переменные для работы передачи данных  **********************************/
    /// <summary>
    /// Константа - Символ новой строки
    /// </summary>
    #define newLine '\n'

    /// <summary>
    /// Константа - Символ начала пакета
    /// </summary>
    #define beginChar '?'

    /// <summary>
    /// Константа - Символ разделитель параметров пакета
    /// </summary>
    #define breakChar ';'

    /// <summary>
    /// Константа - Символ конца пакета
    /// </summary>
    #define endChar '!'

    /// <summary>
    /// Константа - Символ для очистки значения char
    /// </summary>
    #define clearChar '\0'

    /// <summary>
    /// Переменная хранящая последний полученный char
    /// </summary>
    char incomingChar;

    /// <summary>
    /// Переменная хранящая индекс текущего char в массиве хранящего пакет данных
    /// </summary>
    int indexCharInArray;

    /// <summary>
    /// Константа хранящая мак. размер массива хранящего пакет данных
    /// </summary>
    #define receiveSizeArrayCOM 100
    /// <summary>
    /// Массив хранящий пакет данных
    /// </summary>
    char receiveCharArrayCOM[receiveSizeArrayCOM];

    /// <summary>
    /// Переменная хранящая завершено ли получения данных
    /// </summary>
    boolean finishReceiveData = false;

    /******************************  /Переменные для работы передачи данных  **********************************/

    /******************************  Переменные отладки  **********************************/
    /// <summary>
    /// Константа - включение общего дебага
    /// </summary>
    //#define IS_DEBUG true

    /// <summary>
    /// Константа - включение проверки максимального времени прохождения loop
    /// </summary>
    //#define IS_DEBUG_SPEED true

    /// <summary>
    /// Константа - включение проверки Playstation joystick
    /// </summary>
    //#define IS_DEBUG_JOYSTICK true

    /// <summary>
    /// Константа - включение проверки Serial1
    /// </summary>
    //#define IS_DEBUG_SERIAL true

    /// <summary>
    /// Переменная хранящее время старта цикла, для проверки скорости выполнения цикла
    /// </summary>
    unsigned long timeStartCycleWork = 0;

    /// <summary>
    /// Переменная хранящее время окончания цикла, для проверки скорости выполнения цикла
    /// </summary>
    unsigned long timeEndCycleWork = 0;

    /// <summary>
    /// Переменная хранящее минимальное время цикла, для проверки скорости выполнения цикла
    /// </summary>
    unsigned long timeMinCycleWork = 0;

    /// <summary>
    /// Переменная хранящее максимальное время цикла, для проверки скорости выполнения цикла
    /// </summary>
    unsigned long timeMaxCycleWork = 0;

    /// <summary>
    /// Переменная хранящее время цикла, для проверки скорости выполнения цикла
    /// </summary>
    unsigned long resultCycleTime = 0;

    /// <summary>
    /// Переменная хранящее максимальное значение unsigned long
    /// </summary>
    unsigned long unsignedLongMax = 4294967295;

    /// <summary>
    /// Переменная хранящее 1, для проверки скорости выполнения цикла
    /// </summary>
    unsigned long digitalOne = 1;
    /******************************  /Переменные отладки  **********************************/

    /// <summary>
    /// Настройка при запуске arduino
    /// </summary>
    void setup()
    {
        // Инициирует последовательное соединение и задает скорость передачи данных, для соединения монитором порта
        Serial.begin(speedSerialToMonitorPort);
        // Инициирует последовательное соединение и задает скорость передачи данных, для соединения с Arduino
        Serial1.begin(speedSerialToArduino);
        // Ждем подключение Serial, только для Leonardo
        while (!Serial)
        {
            ;
        }

        // Если включена отладка и отладка джойстика
        #if defined(IS_DEBUG) && defined(IS_DEBUG_JOYSTICK)
            // Ждем подключение Serial, только для Leonardo, почему-то код выше не сработал
            delay(2000);
        #endif

        // Настраиваем Playstation joystick, указываем пины и настройки в формате (Clock, Command, Attention, Data, Pressures, Rumble), возвращает int говорящий о ошибке
        error = ps2x.config_gamepad(ps2PinClk, ps2PinCmd, ps2PinSel, ps2PinDat, false, false);

        // Если включена отладка и отладка джойстика
        #if defined(IS_DEBUG) && defined(IS_DEBUG_JOYSTICK)
            // Проверка ошибок Playstation joystick
            if(error == 1)
            {
                Serial.println("No controller found, check wiring, see readme.txt to enable debug. visit www.billporter.info for troubleshooting tips");
            }
            else if(error == 2)
            {
                Serial.println("Controller found but not accepting commands. see readme.txt to enable debug. Visit www.billporter.info for troubleshooting tips");
            }
            else if(error == 3)
            {
                Serial.println("Controller refusing to enter Pressures mode, may not support it. ");
            }

            // Получение типа Playstation joystick
            type = ps2x.readType();

            switch(type)
            {
                case 0:
                    Serial.println("Unknown Controller type found ");
                    break;
                case 1:
                    Serial.println("DualShock Controller found ");
                    break;
                case 2:
                    Serial.println("GuitarHero Controller found ");
                    break;
                case 3:
                    Serial.println("Wireless Sony DualShock Controller found ");
                    break;
            }
        #endif

        // Ждем 2 сек.
        delay(2000);

        ps2PreviousT = millis();
    }
     
    Не влазит поэтому разбиваю
     
  3. Alex19

    Alex19 Гуру

    Продолжение
    Код (Text):

    /// <summary>
    /// Основной цикл
    /// </summary>
    void loop()
    {
        // Если error не равно 0, значит есть ошибка, поэтому дальнейшее выполнение прерываем
        if(error != 0)
        {
            return;
        }

        // Если включена отладка и отладка Speed
        #if defined(IS_DEBUG) && defined(IS_DEBUG_SPEED)      
            timeStartCycleWork = micros();
        #endif

        // Получение данных с Arduino
        GetDataFromSerial();

        // Если получение данных завершёно
        if (finishReceiveData)
        {
            // Если включена отладка и отладка Serial1
            #if defined(IS_DEBUG) && defined(IS_DEBUG_SERIAL)
                // Отображаем полученные данные в мониторе порта
                Serial.println(receiveCharArrayCOM);
            #endif  

            // Очистка переменных получения данных, после получения данный
            ClearReceiveDataVariable();
        }

        if (CheckTimerMillis(ps2PreviousT, ps2T))
        {
            // Мой Playstation joystick - DualShock Controller
            ps2x.read_gamepad(false, 0);

            // Проверка, изменился ли статус кнопок
            if (ps2x.NewButtonState())
            {
                // Проверка, нажата кнопка Start
                if(ps2x.Button(PSB_START))
                {
                    Serial1.println("CR");
                }

                // Проверка, нажата кнопка Select
                if(ps2x.Button(PSB_SELECT))
                {
                    Serial1.println("CL");    
                }

                // Проверка, нажата кнопка вверх
                if(ps2x.Button(PSB_PAD_UP))
                {
                    Serial1.println("LU");
                }

                // Проверка, нажата кнопка вправо
                if(ps2x.Button(PSB_PAD_RIGHT)){
                    Serial1.println("LR");
                }

                // Проверка, нажата кнопка влево
                if(ps2x.Button(PSB_PAD_LEFT))
                {
                    Serial1.println("LL");
                }

                // Проверка, нажата кнопка вниз
                if(ps2x.Button(PSB_PAD_DOWN))
                {
                    Serial1.println("LD");
                }

                // Проверка, нажат левый джойстик
                if(ps2x.Button(PSB_L3))
                {
                    Serial1.println("JL");
                }
     
                // Проверка, нажат правый джойстик
                if(ps2x.Button(PSB_R3))
                {
                    Serial1.println("JR");
                }
     
                // Проверка, нажата кнопка L2
                if(ps2x.Button(PSB_L2))
                {
                    Serial1.println("TLD");
                }
     
                // Проверка, нажата кнопка R2
                if(ps2x.Button(PSB_R2))
                {
                    Serial1.println("TRD");
                }
     
                // Проверка, нажата кнопка L1
                if(ps2x.Button(PSB_L1))
                {
                    Serial1.println("TLU");
                }
     
                // Проверка, нажата кнопка R1
                if(ps2x.Button(PSB_R1))
                {
                    Serial1.println("TRU");
                }
     
                // Проверка, нажата кнопка "треугольник"
                if(ps2x.Button(PSB_TRIANGLE))
                {
                    Serial1.println("RU");      
                }
     
                // Проверка, нажата кнопка "круг"
                if(ps2x.Button(PSB_CIRCLE))
                {
                    Serial1.println("RR");      
                }
     
                // Проверка, нажата кнопка "крест"
                if(ps2x.Button(PSB_CROSS))
                {
                    Serial1.println("RD");      
                }
     
                // Проверка, нажата кнопка "квадрат"
                if(ps2x.Button(PSB_SQUARE))
                {
                    Serial1.println("RL");      
                }
            }

            // Проверка джойстиков, отличаются ли они от значений по умолчанию
            if(ps2x.Analog(PSS_LY) != 123
                    || ps2x.Analog(PSS_LX) != 123
                    || ps2x.Analog(PSS_RY) != 123
                    || ps2x.Analog(PSS_RX) != 123)
            {

                String sendPacket = "SV" + String(ps2x.Analog(PSS_LY)) + "," + String(ps2x.Analog(PSS_LX)) + "," + String(ps2x.Analog(PSS_RY)) + "," + String(ps2x.Analog(PSS_RX));
                Serial1.println(sendPacket);  
            }
        }

        // Если включена отладка и отладка Speed
        #if defined(IS_DEBUG) && defined(IS_DEBUG_SPEED)      
            timeEndCycleWork = micros();

            resultCycleTime = GetDifferenceULong(timeStartCycleWork, timeEndCycleWork);

            if (resultCycleTime > timeMaxCycleWork)
            {
                timeMaxCycleWork = resultCycleTime;
                String sendPacket = "Max : " + String(timeMaxCycleWork);
                Serial.println(sendPacket);
            }

            if (timeMinCycleWork == 0)
            {
                timeMinCycleWork = resultCycleTime;
                String sendPacket = "Min : " + String(timeMinCycleWork);
                Serial.println(sendPacket);
            }
            else
            {
                if (resultCycleTime < timeMinCycleWork)
                {
                    timeMinCycleWork = resultCycleTime;
                    String sendPacket = "Min : " + String(timeMinCycleWork);
                    Serial.println(sendPacket);
                }
            }
        #endif
    }

    /******************************  Функции работы с полученными данными  **********************************/
    /// <summary>
    /// Получение данных с Arduino
    /// </summary>
    void GetDataFromSerial()
    {
        while(Serial1.available())
        {
            incomingChar = (char)Serial1.read();
       
            if(incomingChar != newLine &&
            incomingChar != clearChar)
            {
                receiveCharArrayCOM[indexCharInArray] = incomingChar;
                indexCharInArray++;
            }
            else
            {
                receiveCharArrayCOM[indexCharInArray] = clearChar;
       
                finishReceiveData = true;
            }
        }
    }

    /// <summary>
    /// Очистка переменных получения данных, после получения данный
    /// </summary>
    void ClearReceiveDataVariable()
    {
      indexCharInArray = 0;
      memset(receiveCharArrayCOM,clearChar,receiveSizeArrayCOM);

      finishReceiveData = false;
    }
    /******************************  /Функции работы с полученными данными  **********************************/

    /******************************  Функции работы с таймерами **********************************/
    /// <summary>
    /// Проверка таймера на основе millis
    /// </summary>
    boolean CheckTimerMillis(long PreviousTimmer, int Time)
    {
        // Если предыдущие значение, больше 0
        if (PreviousTimmer > 0)
        {
            // Получаем время с момента запуска программы и отнимем значение PreviousTimmer (время с начала запуска таймера). После это проверяем, прошло ли установленное время Time
            if (GetDifferenceULong(PreviousTimmer, millis()) >= Time)
            {
                // Возвращаем true
                return true;
            }
            else
            {
                // Возвращаем false
                return false;
            }
        }
        else
        {
            // Возвращаем false
            return true;
        }
    }

    /// <summary>
    /// Получение разницы между 2 unsigned long
    /// </summary>
    unsigned long GetDifferenceULong(unsigned long BeginTime, unsigned long EndTime)
    {
      if (EndTime<BeginTime)
      {
        // Защита от переполнения
        resultCycleTime = unsignedLongMax - BeginTime + EndTime + digitalOne;
      }
      else
      {
        resultCycleTime = EndTime - BeginTime;
      }

      return resultCycleTime;
    }
    /******************************  /Функции работы с таймерами **********************************/
     
    Ардуина внизу (на самом ROV)
    Код (Text):

    /******************************  Переменные для работы с Serial портом  **********************************/
    /// <summary>
    /// Константа - Скорость Serial порта, для соединения с Arduino
    /// </summary>
    #define speedSerialToArduino 115200  

    /// <summary>
    /// Константа - Скорость Serial порта, для соединения монитором порта
    /// </summary>
    #define speedSerialToMonitorPort 115200
    /******************************  /Переменные для работы с Serial портом **********************************/

    /******************************  Переменные для работы передачи данных  **********************************/
    /// <summary>
    /// Константа - Символ новой строки
    /// </summary>
    #define newLine '\n'

    /// <summary>
    /// Константа - Символ начала пакета
    /// </summary>
    #define beginChar '?'

    /// <summary>
    /// Константа - Символ разделитель параметров пакета
    /// </summary>
    #define breakChar ';'

    /// <summary>
    /// Константа - Символ конца пакета
    /// </summary>
    #define endChar '!'

    /// <summary>
    /// Константа - Символ для очистки значения char
    /// </summary>
    #define clearChar '\0'

    /// <summary>
    /// Переменная хранящая последний полученный char
    /// </summary>
    char incomingChar;

    /// <summary>
    /// Переменная хранящая индекс текущего char в массиве хранящего пакет данных
    /// </summary>
    int indexCharInArray;

    /// <summary>
    /// Константа хранящая мак. размер массива хранящего пакет данных
    /// </summary>
    #define receiveSizeArrayCOM 100
    /// <summary>
    /// Массив хранящий пакет данных
    /// </summary>
    char receiveCharArrayCOM[receiveSizeArrayCOM];

    /// <summary>
    /// Переменная хранящая завершено ли получения данных
    /// </summary>
    boolean finishReceiveData = false;

    /******************************  /Переменные для работы передачи данных  **********************************/
     
     
  4. Alex19

    Alex19 Гуру

    Продолжение

    Код (Text):
    /******************************  Переменные отладки  **********************************/
    /// <summary>
    /// Константа - включение общего дебага
    /// </summary>
    //#define IS_DEBUG true

    /// <summary>
    /// Константа - включение проверки максимального времени прохождения loop
    /// </summary>
    //#define IS_DEBUG_SPEED true

    /// <summary>
    /// Константа - включение проверки Playstation joystick
    /// </summary>
    //#define IS_DEBUG_JOYSTICK true

    /// <summary>
    /// Константа - включение проверки Serial1
    /// </summary>
    //#define IS_DEBUG_SERIAL true

    /// <summary>
    /// Переменная хранящее время старта цикла, для проверки скорости выполнения цикла
    /// </summary>
    unsigned long timeStartCycleWork = 0;

    /// <summary>
    /// Переменная хранящее время окончания цикла, для проверки скорости выполнения цикла
    /// </summary>
    unsigned long timeEndCycleWork = 0;

    /// <summary>
    /// Переменная хранящее минимальное время цикла, для проверки скорости выполнения цикла
    /// </summary>
    unsigned long timeMinCycleWork = 0;

    /// <summary>
    /// Переменная хранящее максимальное время цикла, для проверки скорости выполнения цикла
    /// </summary>
    unsigned long timeMaxCycleWork = 0;

    /// <summary>
    /// Переменная хранящее время цикла, для проверки скорости выполнения цикла
    /// </summary>
    unsigned long resultCycleTime = 0;

    /// <summary>
    /// Переменная хранящее максимальное значение unsigned long
    /// </summary>
    unsigned long unsignedLongMax = 4294967295;

    /// <summary>
    /// Переменная хранящее 1, для проверки скорости выполнения цикла
    /// </summary>
    unsigned long digitalOne = 1;
    /******************************  /Переменные отладки  **********************************/

    /// <summary>
    /// Настройка при запуске arduino
    /// </summary>
    void setup()
    {
        // Инициирует последовательное соединение и задает скорость передачи данных, для соединения монитором порта
        Serial.begin(speedSerialToMonitorPort);
        // Инициирует последовательное соединение и задает скорость передачи данных, для соединения с Arduino
        Serial1.begin(speedSerialToArduino);
    }

    /// <summary>
    /// Основной цикл
    /// </summary>
    void loop()
    {
        // Если включена отладка и отладка Speed
        #if defined(IS_DEBUG) && defined(IS_DEBUG_SPEED)
            timeStartCycleWork = micros();
        #endif

        // Получение данных с Arduino
        GetDataFromSerial();

        // Если получение данных завершёно
        if (finishReceiveData)
        {
            // Отправляем полученные данные обратно
            Serial1.println(receiveCharArrayCOM);

            // Если включена отладка и отладка Serial1
            #if defined(IS_DEBUG) && defined(IS_DEBUG_SERIAL)
                // Отображаем полученные данные в мониторе порта
                Serial.println(receiveCharArrayCOM);    
            #endif

            // Очистка переменных получения данных, после получения данный
            ClearReceiveDataVariable();
        }

        // Если включена отладка и отладка Speed
        #if defined(IS_DEBUG) && defined(IS_DEBUG_SPEED)
            timeEndCycleWork = micros();

            resultCycleTime = GetDifferenceULong(timeStartCycleWork, timeEndCycleWork);

            if (resultCycleTime > timeMaxCycleWork)
            {
                timeMaxCycleWork = resultCycleTime;
                String sendPacket = "Max : " + String(timeMaxCycleWork);
                Serial.println(sendPacket);
            }

            if (timeMinCycleWork == 0)
            {
                timeMinCycleWork = resultCycleTime;
                String sendPacket = "Min : " + String(timeMinCycleWork);
                Serial.println(sendPacket);
            }
            else
            {
                if (resultCycleTime < timeMinCycleWork)
                {
                    timeMinCycleWork = resultCycleTime;
                    String sendPacket = "Min : " + String(timeMinCycleWork);
                    Serial.println(sendPacket);
                }
            }
        #endif
    }

    /******************************  Функции работы с полученными данными  **********************************/
    /// <summary>
    /// Получение данных с Arduino
    /// </summary>
    void GetDataFromSerial()
    {
        while(Serial1.available())
        {
            incomingChar = (char)Serial1.read();

            if(incomingChar != newLine &&
            incomingChar != clearChar)
            {
                receiveCharArrayCOM[indexCharInArray] = incomingChar;
                indexCharInArray++;
            }
            else
            {
                receiveCharArrayCOM[indexCharInArray] = clearChar;

                finishReceiveData = true;
            }
        }
    }

    /// <summary>
    /// Очистка переменных получения данных, после получения данный
    /// </summary>
    void ClearReceiveDataVariable()
    {
      indexCharInArray = 0;
      memset(receiveCharArrayCOM,clearChar,receiveSizeArrayCOM);

      finishReceiveData = false;
    }
    /******************************  /Функции работы с полученными данными  **********************************/

    /******************************  Функции работы с таймерами **********************************/
    /// <summary>
    /// Проверка таймера на основе millis
    /// </summary>
    boolean CheckTimerMillis(long PreviousTimmer, int Time)
    {
        // Если предыдущие значение, больше 0
        if (PreviousTimmer > 0)
        {
            // Получаем время с момента запуска программы и отнимем значение PreviousTimmer (время с начала запуска таймера). После это проверяем, прошло ли установленное время Time
            if (GetDifferenceULong(PreviousTimmer, millis()) >= Time)
            {
                // Возвращаем true
                return true;
            }
            else
            {
                // Возвращаем false
                return false;
            }
        }
        else
        {
            // Возвращаем false
            return true;
        }
    }

    /// <summary>
    /// Получение разницы между 2 unsigned long
    /// </summary>
    unsigned long GetDifferenceULong(unsigned long BeginTime, unsigned long EndTime)
    {
      if (EndTime<BeginTime)
      {
        // Защита от переполнения
        resultCycleTime = unsignedLongMax - BeginTime + EndTime + digitalOne;
      }
      else
      {
        resultCycleTime = EndTime - BeginTime;
      }

      return resultCycleTime;
    }
    /******************************  /Функции работы с таймерами **********************************/
    Для меня, это еще не законченное решение, планируется RS-485, пакетная передача данных, работа с Serial на более низком уровне и т.д. Постараться сделать более оптимальным.

    Но те, кому выше перечисленное не надо, могут воспользоватся этим решением.
     
    Последнее редактирование: 8 дек 2014
  5. Alex19

    Alex19 Гуру

    Для передачи по RS-485, в обе стороны пришлось сделать передачу по Serial на прерываниях и кольцевом буфере, заодно немного разобрался в AVR.

    Те кто как и я только начинают познавать AVR, подробное описание кольцевого буфера и прерываний. Кроме этой статьи есть и другие, кому любопытно просто набейте в интернете AVR кольцевой буфер.

    Затем был взят проект MultiWii и была изучена их передача, как начинающему, хотелось отлаженного решения, поэтому искал проекты. После изучения, пришел к выводу, что это именно то, что искал.

    Возможно есть более оптимальные решения, но для меня было очень важно понимать код, так как предстоит его модифицировать.

    Код поддерживает ATmega328P, ATmega32U4, ATmega2560 он писался разработчиками в расчете на то, что будут использованы обычные ардуины. Оригинал кода Вы можете найти тут, так как я менял все на свой вкус:), названия, скобочки.

    Ни когда не нравились, такие конструкции
    Код (Text):

    if (i > 9) t = 0;

    или

    if (i > 9)
      t = 0;
     
    Мне удобнее так, проще читается
    Код (Text):

    if (i > 9)
    {
      t = 0;
    }
     
    А эта конструкция поставила в тупик, пока оставлена, надо будет почитать
    Код (Text):
    if (++UARTTailTX[0] >= TXBufferSize) UARTTailTX[0] = 0;
                USB_Send(USB_CDC_TX,UARTBufferTX[UARTTailTX[0]],1);
    Код привожу полностью, но Вам понадобится Def.h, UART.h, UART.cpp

    Rov .ino
    Код (Text):

    /**************************************************************************************/
    /********************            Основной файл              *************************/
    /**************************************************************************************/

    /**********************************  Библиотеки  **************************************/
    #include "Arduino.h"

    #include "Def.h"

    #include "Timer.h"

    #include "UART.h"
    /**********************************  /Библиотеки  *************************************/

    /******************************** Основные функции ************************************/

    //TODO: Времянка 1
    int ledPin=13;
    int EN = 10;
    int Val;

    uint32_t ps2PreviousT = 0;
    uint32_t ps2T = 1000;
    uint16_t i = 0;

    /// <summary>
    /// Настройка при запуске arduino
    /// </summary>
    void setup()
    {
      //TODO: Времянка 2
      pinMode(ledPin, OUTPUT );

      // RS-485
      pinMode(EN, OUTPUT );
      digitalWrite (EN, HIGH);

      UARTOpen(0, 115200);

      UARTOpen(1, 115200);

      delay(100);

      ps2PreviousT = millis();
    }

    /// <summary>
    /// Основной цикл
    /// </summary>
    void loop()
    {
        if (CheckTimerMillis(ps2PreviousT, ps2T) > 0)
        {
            ps2PreviousT = millis();
     
            digitalWrite (ledPin, !digitalRead(ledPin));

       
            UARTSerialize(0, 'H');
            UARTSerialize(0, 'e');
            UARTSerialize(0, 'l');
            UARTSerialize(0, 'l');
            UARTSerialize(0, 'o');
            UARTSerialize(0, '!');

            UARTSerialize(0,'\n');
            UARTSendData(0);
        }
    }
     
    код береговой станции
    .ino
    Код (Text):

    /**************************************************************************************/
    /********************            Основной файл              *************************/
    /**************************************************************************************/

    /**********************************  Библиотеки  **************************************/
    #include "Arduino.h"

    #include "Def.h"

    #include "Timer.h"

    #include "UART.h"
    /**********************************  /Библиотеки  *************************************/

    /******************************** Основные функции ************************************/

    //TODO: Времянка 1
    int ledPin=13;
    int EN = 10;
    int Val;

    uint32_t ps2PreviousT = 0;
    uint32_t ps2T = 1000;
    uint16_t i = 0;

    /// <summary>
    /// Настройка при запуске arduino
    /// </summary>
    void setup()
    {
      //TODO: Времянка 2
      pinMode(ledPin, OUTPUT );

      // RS-485
      pinMode(EN, OUTPUT );
      digitalWrite (EN, HIGH);

      UARTOpen(0, 115200);

      UARTOpen(1, 115200);

      delay(100);

      ps2PreviousT = millis();
    }

    /// <summary>
    /// Основной цикл
    /// </summary>
    void loop()
    {
        if (CheckTimerMillis(ps2PreviousT, ps2T) > 0)
        {
            ps2PreviousT = millis();
     
            digitalWrite (ledPin, !digitalRead(ledPin));

       
            UARTSerialize(0, 'H');
            UARTSerialize(0, 'e');
            UARTSerialize(0, 'l');
            UARTSerialize(0, 'l');
            UARTSerialize(0, 'o');
            UARTSerialize(0, '!');

            UARTSerialize(0,'\n');
            UARTSendData(0);
        }
    }

    Общие файлы
    Def.h
    Код (Text):

    #ifndef DEF_H_
    #define DEF_H_

    /**************************************************************************************/
    /******************            Класс определений                **********************/
    /**************************************************************************************/

    /*****************************  Определяем тип ардуины  *******************************/
    #if defined(__AVR_ATmega328P__) || defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega2560__)
      #define F_CPU 16000000UL                            // Частота процессора

      // Определяем тип ардуины
      #if defined(__AVR_ATmega328P__)
        // Если ArduinoProMini
        #define ArduinoProMini
      #endif
      #if defined(__AVR_ATmega32U4__)
        // Если ArduinoProMicro
        #define ArduinoProMicro
      #endif
      #if defined(__AVR_ATmega2560__)
        // Если ArduinoMega
        #define ArduinoMega
      #endif
    #endif
    /****************************  /Определяем тип ардуины  *******************************/

    #endif /* DEF_H_ */
     
     
    Последнее редактирование: 13 янв 2015
  6. Alex19

    Alex19 Гуру

    UART.cpp
    Код (Text):

    /**********************************  Библиотеки  **************************************/
    #include "Arduino.h"

    #include "Def.h"

    #include "UART.h"
    /**********************************  /Библиотеки  *************************************/

    /**************************************************************************************/
    /*****************             Класс работы с UART               **********************/
    /**************************************************************************************/

    // UARTHeadRX - буфер RX для хранения "головы масива"
    // UARTTailRX - буфер RX для хранения "хвоста масива"
    static volatile uint8_t UARTHeadRX[UARTNumber],UARTTailRX[UARTNumber];

    // UARTBufferRX - буфер RX для хранения данных
    static uint8_t UARTBufferRX[RXBufferSize][UARTNumber];

    // UARTHeadTX - буфер TX для хранения "головы масива"
    // UARTBufferTX - буфер TX для хранения "хвоста масива"
    static volatile uint8_t UARTHeadTX[UARTNumber],UARTTailTX[UARTNumber];

    // UARTBufferTX - буфер X для хранения данных
    static uint8_t UARTBufferTX[TXBufferSize][UARTNumber];

    /// <summary>
    // Прерывание по опустошению буффера UART
    /// </summary>
    #if defined(ArduinoProMini) || defined(ArduinoMega)
      #if defined(ArduinoProMini)
      ISR(USART_UDRE_vect)
      {
      #endif
      #if defined(ArduinoMega)
      ISR(USART0_UDRE_vect)
      {
      #endif
        uint8_t t = UARTTailTX[0];
        if (UARTHeadTX[0] != t)
        {
          if (++t >= TXBufferSize)
          {
            t = 0;
          }
          UDR0 = UARTBufferTX[t][0];  
          UARTTailTX[0] = t;
        }
        if (t == UARTHeadTX[0])
        {
          UCSR0B &= ~(1<<UDRIE0);
        }
      }
    #endif
    #if defined(ArduinoMega) || defined(ArduinoProMicro)
      ISR(USART1_UDRE_vect)
      {
        uint8_t t = UARTTailTX[1];
        if (UARTHeadTX[1] != t)
        {
          if (++t >= TXBufferSize)
          {
            t = 0;
          }
          UDR1 = UARTBufferTX[t][1];  
          UARTTailTX[1] = t;
        }
        if (t == UARTHeadTX[1])
        {
          UCSR1B &= ~(1<<UDRIE1);
        }
      }
    #endif
    #if defined(ArduinoMega)
      ISR(USART2_UDRE_vect)
      {
        uint8_t t = UARTTailTX[2];
        if (UARTHeadTX[2] != t)
        {
          if (++t >= TXBufferSize)
          {
            t = 0;
          }
          UDR2 = UARTBufferTX[t][2];
          UARTTailTX[2] = t;
        }
        if (t == UARTHeadTX[2]) UCSR2B &= ~(1<<UDRIE2);
      }
      ISR(USART3_UDRE_vect)
      {
        uint8_t t = UARTTailTX[3];
        if (UARTHeadTX[3] != t)
        {
          if (++t >= TXBufferSize)
          {
            t = 0;
          }
          UDR3 = UARTBufferTX[t][3];
          UARTTailTX[3] = t;
        }
        if (t == UARTHeadTX[3])
        {
          UCSR3B &= ~(1<<UDRIE3);
        }
      }
    #endif

    /// <summary>
    // Отправляем данные по UART, включаем прерывание по опустошению буффера UART
    /// </summary>
    /// <param name="port">Номер порта</param>
    void UARTSendData(uint8_t port)
    {
      // UDRIE - Разрешение прерывания при очистке регистра данных UART. Если данный разряд установлен в «1», то при установке флага UDRE в регистра UCSRA  генерируется прерывание.
      #if defined(ArduinoProMini)
        UCSR0B |= (1<<UDRIE0);
      #endif
      #if defined(ArduinoProMicro)
        switch (port)
        {
          case 0:
            while(UARTHeadTX[0] != UARTTailTX[0])
            {
               //TODO: Разобратся с этим if
               if (++UARTTailTX[0] >= TXBufferSize) UARTTailTX[0] = 0;
                 USB_Send(USB_CDC_TX,UARTBufferTX[UARTTailTX[0]],1);
            }
            break;
          case 1: UCSR1B |= (1<<UDRIE1); break;
        }
      #endif
      #if defined(ArduinoMega)
        switch (port)
        {
          case 0: UCSR0B |= (1<<UDRIE0); break;
          case 1: UCSR1B |= (1<<UDRIE1); break;
          case 2: UCSR2B |= (1<<UDRIE2); break;
          case 3: UCSR3B |= (1<<UDRIE3); break;
        }
      #endif
    }

    /// <summary>
    // Инициализируем и открываем UART порт
    /// </summary>
    /// <param name="port">Номер порта</param>
    /// <param name="baud">Скорость работы порта</param>
    void UARTOpen(uint8_t port, uint32_t baud)
    {
      // U2X - Удвоение скорости обмена. Если этот разряд установлен в «1», коэффициент деления предделителя контроллера скорости передачи уменьшается с 16 до 8, удваивая тем самым скорость асинхронного обмена по последовательному каналу. В USART разряд U2X используется только при асинхронном режиме работы. В синхронном режиме он должен быть сброшен.
      // UBRRL  и UBRRH - регистры скорости передачи  
      // RXEN - Разрешение приема. При установке этого разряда в «1» разрешается работа приемника USART/UART и переопределяется функционирование вывода RXD.
      // TXEN - Разрешение передачи. При установке этого разряда в «1» разрешается работа передатчика UART и переопределяется функционирование вывода TXD
      // RXCIE - Разрешение прерывания по завершению приема. Если данный разряд установлен в «1», то при установке флага RXC регистра UCSRA генерируется прерывание.
      uint8_t h = ((F_CPU  / 4 / baud -1) / 2) >> 8;
      uint8_t l = ((F_CPU  / 4 / baud -1) / 2);
      switch (port)
      {
        #if defined(ArduinoProMini)
          case 0: UCSR0A  = (1<<U2X0); UBRR0H = h; UBRR0L = l; UCSR0B |= (1<<RXEN0)|(1<<TXEN0)|(1<<RXCIE0); break;
        #endif
        #if defined(ArduinoProMicro)
          #if (ARDUINO >= 100)
            case 0: UDIEN &= ~(1<<SOFE); break;
          #endif
          case 1: UCSR1A  = (1<<U2X1); UBRR1H = h; UBRR1L = l; UCSR1B |= (1<<RXEN1)|(1<<TXEN1)|(1<<RXCIE1); break;
        #endif
        #if defined(ArduinoMega)
          case 0: UCSR0A  = (1<<U2X0); UBRR0H = h; UBRR0L = l; UCSR0B |= (1<<RXEN0)|(1<<TXEN0)|(1<<RXCIE0); break;
          case 1: UCSR1A  = (1<<U2X1); UBRR1H = h; UBRR1L = l; UCSR1B |= (1<<RXEN1)|(1<<TXEN1)|(1<<RXCIE1); break;
          case 2: UCSR2A  = (1<<U2X2); UBRR2H = h; UBRR2L = l; UCSR2B |= (1<<RXEN2)|(1<<TXEN2)|(1<<RXCIE2); break;
          case 3: UCSR3A  = (1<<U2X3); UBRR3H = h; UBRR3L = l; UCSR3B |= (1<<RXEN3)|(1<<TXEN3)|(1<<RXCIE3); break;
        #endif
      }
    }

    /// <summary>
    // Закрываем UART порт
    /// </summary>
    /// <param name="port">Номер порта</param>
    void UARTClose(uint8_t port)
    {
      // RXEN - Разрешение приема. При установке этого разряда в «1» разрешается работа приемника USART/UART и переопределяется функционирование вывода RXD.
      // TXEN - Разрешение передачи. При установке этого разряда в «1» разрешается работа передатчика UART и переопределяется функционирование вывода TXD
      // RXCIE - Разрешение прерывания по завершению приема. Если данный разряд установлен в «1», то при установке флага RXC регистра UCSRA генерируется прерывание.
      // UDRIE - Разрешение прерывания при очистке регистра данных UART. Если данный разряд установлен в «1», то при установке флага UDRE в регистра UCSRA  генерируется прерывание.  
      switch (port)
      {
        #if defined(ArduinoProMini)
          case 0: UCSR0B &= ~((1<<RXEN0)|(1<<TXEN0)|(1<<RXCIE0)|(1<<UDRIE0)); break;
        #endif
        #if defined(ArduinoProMicro)
          case 1: UCSR1B &= ~((1<<RXEN1)|(1<<TXEN1)|(1<<RXCIE1)|(1<<UDRIE1)); break;
        #endif
        #if defined(ArduinoMega)
          case 0: UCSR0B &= ~((1<<RXEN0)|(1<<TXEN0)|(1<<RXCIE0)|(1<<UDRIE0)); break;
          case 1: UCSR1B &= ~((1<<RXEN1)|(1<<TXEN1)|(1<<RXCIE1)|(1<<UDRIE1)); break;
          case 2: UCSR2B &= ~((1<<RXEN2)|(1<<TXEN2)|(1<<RXCIE2)|(1<<UDRIE2)); break;
          case 3: UCSR3B &= ~((1<<RXEN3)|(1<<TXEN3)|(1<<RXCIE3)|(1<<UDRIE3)); break;
        #endif
      }
    }

    /// <summary>
    // Сохраняем полученные данные в буфер RX
    /// </summary>
    /// <param name="portnum">Номер порта</param>
    void StoreUARTInBuf(uint8_t data, uint8_t portnum)
    {
      // Получаем номер "головы масива" RX
      uint8_t h = UARTHeadRX[portnum];
      // Проверяем, увеличивая номер "головы масива" RX головы на 1 и если номер "головы масива", станет равным или больше размера буфера, обнуляем переменную h в 0
      if (++h >= RXBufferSize)
      {
        h = 0;
      }
      // Проверяем номер "головы масива" RX и номер "хвоста масива" RX если равен, это ошибка
      if (h == UARTTailRX[portnum])
      {
        return;
      }
      // Сохраняем полученный байт в буфер RX для хранения данных
      UARTBufferRX[UARTHeadRX[portnum]][portnum] = data;  
      // Сохраняем новый номер "головы масива" RX
      UARTHeadRX[portnum] = h;
    }

    /// <summary>
    // Прерывание по завершению приема по каналу UART
    /// </summary>
    #if defined(ArduinoProMini)
      ISR(USART_RX_vect)  { StoreUARTInBuf(UDR0, 0); }
    #endif
    #if defined(ArduinoProMicro)
      ISR(USART1_RX_vect)  { StoreUARTInBuf(UDR1, 1); }
    #endif
    #if defined(ArduinoMega)
      ISR(USART0_RX_vect)  { StoreUARTInBuf(UDR0, 0); }
      ISR(USART1_RX_vect)  { StoreUARTInBuf(UDR1, 1); }
      ISR(USART2_RX_vect)  { StoreUARTInBuf(UDR2, 2); }
      ISR(USART3_RX_vect)  { StoreUARTInBuf(UDR3, 3); }
    #endif

    /// <summary>
    // Читаем данные из буфера RX
    /// </summary>
    /// <param name="port">Номер порта</param>
    uint8_t UARTRead(uint8_t port)
    {
      #if defined(ArduinoProMicro)
          #if (ARDUINO >= 100)
            if(port == 0)
            {
              USB_Flush(USB_CDC_TX);
            }
          #endif
          if(port == 0)
          {
            return USB_Recv(USB_CDC_RX);  
          }    
      #endif
      // Получаем номер "хвоста масива" RX
      uint8_t t = UARTTailRX[port];
      // Получаем байт по номеру "хвоста масива" RX
      uint8_t c = UARTBufferRX[t][port];
      // Проверяем номер "головы масива" RX и номер "хвоста масива" RX если не равен
      if (UARTHeadRX[port] != t)
      {
        // Проверяем, увеличивая номер "хвоста масива" RX хвоста на 1 и если номер "хвоста масива", станет равным или больше размера буфера, обнуляем переменную t в 0  
        if (++t >= RXBufferSize)
        {
          t = 0;
        }
        // Сохраняем новый номер "хвоста масива" RX
        UARTTailRX[port] = t;
      }
      return c;
    }

    /// <summary>
    // Получает количество байт доступных для чтения из буфера RX
    /// </summary>
    /// <param name="port">Номер порта</param>
    uint8_t UARTAvailable(uint8_t port)
    {
      #if defined(ArduinoProMicro)
          if(port == 0)
          {
            return USB_Available(USB_CDC_RX);
          }
      #endif
      return ((uint8_t)(UARTHeadRX[port] - UARTTailRX[port]))%RXBufferSize;
    }
     
     
  7. Alex19

    Alex19 Гуру

    Продолжение UART.cpp

    Код (Text):

    /// <summary>
    // // Получает количество байт доступных для отправки в буфере RX
    /// </summary>
    /// <param name="port">Номер порта</param>
    uint8_t UARTUsedTXBuff(uint8_t port)
    {
      return ((uint8_t)(UARTHeadTX[port] - UARTTailTX[port]))%TXBufferSize;
    }

    /// <summary>
    // // Сохраняем отправляемый байт в буфер TX
    /// </summary>
    /// <param name="port">Номер порта</param>
    /// <param name="a">Отправляемый байт</param>
    void UARTSerialize(uint8_t port,uint8_t a)
    {
      uint8_t t = UARTHeadTX[port];
      if (++t >= TXBufferSize)
      {
        t = 0;
      }
      UARTBufferTX[t][port] = a;
      UARTHeadTX[port] = t;
    }

    /// <summary>
    // Сохраняем отправляемый байт в буфер TX и отправляем данные по UART, включаем прерывание по опустошению буффера UART
    /// </summary>
    /// <param name="port">Номер порта</param>
    /// <param name="c">Отправляемый байт</param>
    void UARTWrite(uint8_t port,uint8_t c){
      UARTSerialize(port,c);
      UARTSendData(port);
    }
     
    UART.h
    Код (Text):

    #ifndef UART_H_
    #define UART_H_

    /**************************************************************************************/
    /*****************             Класс работы с UART               **********************/
    /**************************************************************************************/

    // Определяем кол-во UART-тов в зависимости от платы
    #if defined(ArduinoMega)
      // Если ArduinoMega
      #define UARTNumber 4
    #elif defined(ArduinoProMicro)
      // Если ArduinoProMicro
      #define UARTNumber 2
    #else
      // Иначе предполагается ArduinoProMini
      #define UARTNumber 1
    #endif

    // Размер буфера RX
    #define RXBufferSize 128

    // Размер буфера TX
    #define TXBufferSize 128

    /// <summary>
    // Инициализируем и открываем UART порт
    /// </summary>
    /// <param name="port">Номер порта</param>
    /// <param name="baud">Скорость работы порта</param>
    void UARTOpen(uint8_t port, uint32_t baud);

    /// <summary>
    // Закрываем UART порт
    /// </summary>
    /// <param name="port">Номер порта</param>
    void UARTClose(uint8_t port);

    /// <summary>
    // Получает количество байт доступных для чтения из буфера RX
    /// </summary>
    /// <param name="port">Номер порта</param>
    uint8_t UARTAvailable(uint8_t port);

    /// <summary>
    // Читаем данные из буфера RX
    /// </summary>
    /// <param name="port">Номер порта</param>
    uint8_t UARTRead(uint8_t port);

    /// <summary>
    // // Сохраняем отправляемый байт в буфер TX
    /// </summary>
    /// <param name="port">Номер порта</param>
    /// <param name="a">Отправляемый байт</param>
    void UARTSerialize(uint8_t port,uint8_t a);

    /// <summary>
    // // Получает количество байт доступных для отправки в буфере RX
    /// </summary>
    /// <param name="port">Номер порта</param>
    uint8_t UARTUsedTXBuff(uint8_t port);

    /// <summary>
    // Отправляем данные по UART, включаем прерывание по опустошению буффера UART
    /// </summary>
    /// <param name="port">Номер порта</param>
    void UARTSendData(uint8_t port);

    /// <summary>
    // Сохраняем отправляемый байт в буфер TX и отправляем данные по UART, включаем прерывание по опустошению буффера UART
    /// </summary>
    /// <param name="port">Номер порта</param>
    /// <param name="c">Отправляемый байт</param>
    void UARTWrite(uint8_t port,uint8_t c);

    #endif /* UART_H_ */
     

    Timer.cpp
    Код (Text):

    /**********************************  Библиотеки  **************************************/
    #include "Arduino.h"

    #include "Timer.h"
    /**********************************  /Библиотеки  *************************************/

    /**************************************************************************************/
    /**************            Класс работы с таймерами              ********************/
    /**************************************************************************************/

    //TODO: Подумать как сделать оптимальнее

    /// <summary>
    /// Переменная хранящее максимальное значение unsigned long
    /// </summary>
    #define unsignedLongMax 4294967295UL

    /// <summary>
    /// Переменная хранящее 1, для проверки скорости выполнения цикла
    /// </summary>
    #define digitalOne 1UL

    /************ Функции работы с таймерами на основе millis(), micros() *****************/
    /// <summary>
    /// Проверка таймера на основе millis
    /// </summary>
    uint8_t CheckTimerMillis(uint32_t PreviousTimmer, uint32_t Time)
    {
        // Если предыдущие значение, больше 0
        if (PreviousTimmer > 0)
        {
            // Получаем время с момента запуска программы и отнимем значение PreviousTimmer (время с начала запуска таймера). После это проверяем, прошло ли установленное время Time
            if (GetDifferenceULong(PreviousTimmer, millis()) >= Time)
            {
                // Возвращаем true
                return 1;
            }
        }

            return 0;
    }

    /// <summary>
    /// Получение разницы между 2 uint32_t
    /// </summary>
    uint32_t GetDifferenceULong(uint32_t BeginTime, uint32_t EndTime)
    {
      if (EndTime < BeginTime)
      {
        // Защита от переполнения
        return unsignedLongMax - BeginTime + EndTime + digitalOne;
      }
      else
      {
        return EndTime - BeginTime;
      }
    }
    /*********** /Функции работы с таймерами на основе millis(), micros() *****************/
     
    Timer.h
    Код (Text):

    #ifndef TIMER_H_
    #define TIMER_H_

    /**************************************************************************************/
    /**************            Класс работы с таймерами              ********************/
    /**************************************************************************************/

    /// <summary>
    /// Проверка таймера на основе millis
    /// </summary>
    uint8_t CheckTimerMillis(uint32_t PreviousTimmer, uint32_t Time);

    /// <summary>
    /// Получение разницы между 2 uint32_t
    /// </summary>
    uint32_t GetDifferenceULong(uint32_t BeginTime, uint32_t EndTime);

    #endif /* TIMER_H_ */
     
    Возможно кому-то будет полезно.

    Дальше планируются пакеты с проверкой переданной информации, передача RS-485 в обе стороны.

    UPD. Закончил передачу данных пакетами, добавил проверку четности и размера данных. Дальше RS-485, допилить библиотеку прямого доступа к портам, может быть подумать как еще оптимизировать.

    Публикую прищепками, может кому будет полезно, а публиковать весь листинг долго.

    И дальше ковыряться с остальными частями проекта, пока завис с моторами и Rim винтами.
     

    Вложения:

    • GA_Rov_Down.zip
      Размер файла:
      13,9 КБ
      Просмотров:
      465
    • GA_Rov_UP.zip
      Размер файла:
      15,4 КБ
      Просмотров:
      466
    Последнее редактирование: 20 янв 2015
    vvr нравится это.
  8. vvr

    vvr Инженерище

    Спасибо за работу, взял на заметку:)
     
  9. Alex19

    Alex19 Гуру

    Не за что, все помогаем друг, другу по мере сил.

    Сейчас жду модуль RS-485 TTL на замену, один оказался бракованный, дополню отправку передачей в обе стороны по RS-485.

    UPD.
    Что-то у нас в РБ, все болеют и меня не минула данная напасть, в компании где работаю, вообще остановила свою деятельность:(, почти все грипуют.

    Модуль RS-485 TTL увы будет не раньше марта, попал на новый год в Китае, может закажу в РФ, но напрягать знакомых не хочется и мне не к спеху. Нашел пару мелких ошибок, в прищепке исправленный код.
     

    Вложения:

    • GA_Rov.zip
      Размер файла:
      38 КБ
      Просмотров:
      456
    Последнее редактирование: 19 фев 2015