Raspberry PI 3 + OpenCV + Arduino UNO + ......(поледнее решение и вопрос в последнем сообщении)

Тема в разделе "Флудилка", создана пользователем Igor68, 21 ноя 2016.

  1. Igor68

    Igor68 Гуру

    Всё изменилось! Именно время реакции устройства (Arduino UNO на запрос) слишком высоко. Одним словом я получал ответ от предыдущей команды, посылаемой в ардуино.
    Выяснил применением очистки буферов командой tcflush(fd, TCIOFLUSH) приёма и передачи на стороне сервера на малине. Специально порт не перестраивал.
    По стандарту время "молчания" между посылками составляет 3.5 символа/байта.
    Подсчитывал время молчания в микросекундах для символа

    Код (C++):
    symwait     = (int)((1000000.0f / (float)(baudrate)) * 10.0f * (float)(symbols));
    тоесть : (1 / <скорость (бит.с)>) * 10(старт.бит + 8бит данных + стоп.бит) * <количество символов/байт>
    Испытал на скоростях:
    для 9600:
    Код (Bash):
    #!/bin/bash

    echo "...starting Arduino & Raspberry conrol"
    ./arbot -p 8971 -sp /dev/ttyUSB0 9600 50 -wd 50
     
    то есть ожидание между приёмом и передачей в 50 байт
    время бездействия в цикле 50 миллисекунд

    для 19200:
    Код (Bash):
    #!/bin/bash

    echo "...starting Arduino & Raspberry conrol"
    ./arbot -p 8971 -sp /dev/ttyUSB0 19200 70 -wd 70
     
    то есть ожидание между приёмом и передачей в 70 байт
    время бездействия в цикле 70 миллисекунд

    И всё равно на 19200 ошибки проскакивают... но уже другие:
    Код (Bash):
    receive ansver CMD16 CRC error! ...dev: 1  addr: 48  rcount: 7  CRC: 0009  INCRC: 04C5
    receive ansver CMD16 CRC error! ...dev: 1  addr: 48  rcount: 7  CRC: 0009  INCRC: 04C5
    receive ansver CMD16 CRC error! ...dev: 1  addr: 48  rcount: 7  CRC: 0009  INCRC: 04C5
    receive ansver CMD16 CRC error! ...dev: 1  addr: 48  rcount: 7  CRC: 0009  INCRC: 04C5
    receive ansver CMD16 error! ...dev: 1  addr: 48
    receive ansver CMD16 error! ...dev: 1  addr: 48
    receive ansver CMD16 CRC error! ...dev: 1  addr: 48  rcount: 7  CRC: 0009  INCRC: 04C5
    receive ansver CMD16 CRC error! ...dev: 1  addr: 48  rcount: 7  CRC: 0009  INCRC: 04C5
    receive ansver CMD16 CRC error! ...dev: 1  addr: 48  rcount: 7  CRC: 0009  INCRC: 04C5
    Они не частые и допустимые.

    На форумах... включая и этот отвечают, что решили проблему и... отключаются. А пояснения как... ну или указать причину... на пальцах... без примера, а на словах... наверное думают что это авторские права.
    Такое поведение... если очень ласково сказать - козлы. Как это будет если грубо сказать!?

    В моём случае эта связь по USB-SERIAL не с конечным устройством - потому и тормоза. Ведь это устройство (Arduino) работает с другими (тоже с контроллерами типа AVR) по I2C, которые сами управляют приводами
     
  2. Alex19

    Alex19 Гуру

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

    Igor68 Гуру

    Время суток доброе!
    Собственно сразу вопрос. Есть некоторое действие на Си из Modbus(как раз в команде 3):
    Код (C++):
    while(bsreg < bcntreg)
                {  
                    dmrtu.txbuf[cntbytes++] = (uint8_t)(dmotor[bsreg] >> 8);
                    dmrtu.txbuf[cntbytes++] = (uint8_t)(dmotor[bsreg++] & 0xFF);
                }
    Есть желание уменьшить количество телодвижений:
    Код (C++):
     dmrtu.txbuf[cntbytes++] = (uint8_t)(dmotor[bsreg] >> 8);
    Ведь фактически параметр dmotor[bsreg] уже прочитан и находится в паре регистров процессора... надо только его старшее значение (что и есть 8-ми битный регистр)поместить в dmrtu.txbuf[cntbytes] или по его адресу без восьми сдвигов... понятное дело ассемблер... но как правильно оформить ассемблерную вставку (а до этого указать регистр) в Arduino IDE. Ведь только в 16, 32, .... процессорах требуется "выделять" для записи 8-ми битного значения.
    Был бы рад примеру!
    Заранее спасибо!
     
  4. Alex19

    Alex19 Гуру

    Не работал с ассемблером, мне он никогда не требовался.

    Оформляют его обычно в виде макроса, вот пример.
    Код (C++):

    // signed16 * signed16
    // 22 cycles
    // http://mekonik.wordpress.com/2009/03/18/arduino-avr-gcc-multiplication/
    #define MultiS16X16to32(longRes, intIn1, intIn2) \
    asm volatile ( \
    "clr r26 \n\t" \
    "mul %A1, %A2 \n\t" \
    "movw %A0, r0 \n\t" \
    "muls %B1, %B2 \n\t" \
    "movw %C0, r0 \n\t" \
    "mulsu %B2, %A1 \n\t" \
    "sbc %D0, r26 \n\t" \
    "add %B0, r0 \n\t" \
    "adc %C0, r1 \n\t" \
    "adc %D0, r26 \n\t" \
    "mulsu %B1, %A2 \n\t" \
    "sbc %D0, r26 \n\t" \
    "add %B0, r0 \n\t" \
    "adc %C0, r1 \n\t" \
    "adc %D0, r26 \n\t" \
    "clr r1 \n\t" \
    : \
    "=&r" (longRes) \
    : \
    "a" (intIn1), \
    "a" (intIn2) \
    : \
    "r26" \
    )
    Пример был взят из проекта Multiwii, вот ссылка - https://github.com/multiwii/multiwii-firmware/blob/e957a701844a9ecf0d19ac6a7e3ea1e8d81cc43b/IMU.cpp.

    Хотя можно и в функции, подробнее тут - http://www.nongnu.org/avr-libc/user-manual/inline_asm.html.
     
    Igor68 нравится это.
  5. Igor68

    Igor68 Гуру

    А Каково соглашение - пример в Keil чётко определяет :
    int func(int p1, int p2, int p3)
    в регистре r0 - параметр p1,
    в r2 - p2 и так далее, если это касается целых чисел... возвращаемое значение, если это целочисленный параметр в регистре r0. Ссылки непременно посмотрю - время реакции надо уменьшить!
     
  6. Alex19

    Alex19 Гуру

    Тут уже нужно внимательно читать, возможно такого нет, ведь это просто макрос.
    Код (C++):
    #define loop_until_bit_is_clear(port,bit)  \
            __asm__ __volatile__ (             \
            "L_%=: " "sbic %0, %1" "\n\t"      \
                     "rjmp L_%="               \
                     : /* no outputs */      

                     : "I" (_SFR_IO_ADDR(port)),
                       "I" (bit)  
            )
    Не вижу у Вас, чего-то криминального в MRTU_CMD3. Попробую подключить к своей панели и запустить код, мне так проще тестировать, но это уже завтра. Сам перерыв у меня от 14 до 29ms, но скорость у меня 115200.
     
    Igor68 нравится это.
  7. Igor68

    Igor68 Гуру

    Тем не менее на Си контрольная сумма для отправки ответа - вчерашняя задумка - испытал только что:
    Код (C++):
    //контрольная сумма для ответа
    inline void sMRTU_CRCo(uint8_t* data, uint16_t len, uint8_t * crch, uint8_t * crcl)
    {
        uint8_t uchCRCHi = 0xFF;
        uint8_t uchCRCLo = 0xFF;
        uint16_t uIndex ;
        while(len--)
        {
            uIndex = uchCRCHi ^ *data++ ;
            uchCRCHi = uchCRCLo ^ auchCRCHi[uIndex] ;
            uchCRCLo = auchCRCLo[uIndex] ;
        }
        //return (uint16_t)(uchCRCHi | uchCRCLo << 8) ;
        //return (uint16_t)(uchCRCHi | uchCRCLo * 256) ;
        *crch = uchCRCLo;
        *crcl = uchCRCHi;
    }
     
    в функции ркализации команды 3:
    Код (C++):
    /*
    ****************************
    CMD3 - чтение двоичного
    содержания регистров
    ****************************
    */

    inline void    MRTU_CMD3(void)
    {
        uint16_t  crc;             //подсчитанная контрольная сумма
        uint16_t  incrc;            //принятая контрольная сумма
        uint16_t  sreg;            //стартовый регистр
        uint16_t  cntreg;        //количество регистров
        uint8_t   bcntreg;
        uint8_t      cntbytes;        //счётчик байт в поле данных
        uint8_t      bsreg;
        uint8_t   wregcnt;
        //стартовый регистр
        #if(_opt_8 == 0)
            sreg    = (uint16_t)(dmrtu.rxbuf[_ADDR_03_START_REG_H] * 256)
                      | (uint16_t)(dmrtu.rxbuf[_ADDR_03_START_REG_L]);
        #else
            bsreg    = dmrtu.rxbuf[_ADDR_03_START_REG_L];
        #endif
        //количество регистров
        #if(_opt_8 == 0)
            cntreg  = (uint16_t)(dmrtu.rxbuf[_ADDR_03_CNT_REG_H] * 256)
                      | (uint16_t)(dmrtu.rxbuf[_ADDR_03_CNT_REG_L]);
        #else
            bcntreg    = dmrtu.rxbuf[_ADDR_03_CNT_REG_L];
        #endif
        //чтение контрольной суммы
        incrc    = (uint16_t)(dmrtu.rxbuf[_ADDR_03_INCRC_H] * 256)
            | (uint16_t)(dmrtu.rxbuf[_ADDR_03_INCRC_L]);
        crc = sMRTU_CRC(&dmrtu.rxbuf[0], 6);
        if(crc == incrc)
              {
                /*
                ****************************
                проверка границ данных
                ****************************
                */

            #if(_opt_8 == 0)
                bsreg    = (uint8_t)(sreg);
                bcntreg    = (uint8_t)(cntreg);
            #endif
            //проверка предельного размера
            if(bcntreg >= _cntreg)
            {
                dmrtu.txbuf[0] = _MRTU_Addr;
                dmrtu.txbuf[1] = 3 | _CMD_ERR_MODE;
                dmrtu.txbuf[2] = _ILLEGAL_DATA_ADDRESS;
                //crc = sMRTU_CRC(&dmrtu.txbuf[0], 3);
                sMRTU_CRCo(&dmrtu.txbuf[0], 3, &dmrtu.txbuf[3], &dmrtu.txbuf[4]);
                //dmrtu.txbuf[3] = (uint8_t)(crc >> 8);
                //dmrtu.txbuf[4] = (uint8_t)(crc & 0xFF);
                Serial.write(&dmrtu.txbuf[0], 5);
                return;
            }
            //ComMotion
            else if((bsreg >= _ComMotion_RMS) &&
                (bsreg < (_ComMotion_RMS + _ComMotion_SzRM)) &&
                ((bsreg + bcntreg) <= (_ComMotion_RMS + _ComMotion_SzRM)))
            {
                dmrtu.txbuf[_ADDR_MADDR]      = _MRTU_Addr;            //адрес устройства
                dmrtu.txbuf[_ADDR_MCMD]      = 3;                //команда
                dmrtu.txbuf[_ADDR_03_CNT_BYTES]    = bcntreg << 1;            //счётчик байтов для передачи
                //
                bsreg                 -= _ComMotion_RMS;        //стартовый регистр
                cntbytes            = _ADDR_03_DATA;        //счётчик байтов + смещение
                bcntreg                += bsreg;            //количество регистров со смещением
                while(bsreg < bcntreg)
                {  
                    dmrtu.txbuf[cntbytes++] = (uint8_t)(dmotor[bsreg] >> 8);
                    dmrtu.txbuf[cntbytes++] = (uint8_t)(dmotor[bsreg++] & 0xFF);
                }
                //crc = sMRTU_CRC(&dmrtu.txbuf[0], cntbytes);
                //dmrtu.txbuf[cntbytes++] = (uint8_t)(crc >> 8);
                //dmrtu.txbuf[cntbytes++] = (uint8_t)(crc & 0xFF);
                sMRTU_CRCo(&dmrtu.txbuf[0], cntbytes, &dmrtu.txbuf[cntbytes], &dmrtu.txbuf[cntbytes + 1]);
                Serial.write(&dmrtu.txbuf[0], cntbytes + 2);
                return;
            }
            //Multiservo
            else if((bsreg >= _Multiservo_RSS1) &&
                (bsreg < (_Multiservo_RSS1 + _Multiservo_SzRS)) &&
                ((bsreg + bcntreg) <= (_Multiservo_RSS1 + _Multiservo_SzRS)))
            {
                dmrtu.txbuf[_ADDR_MADDR]      =  _MRTU_Addr;            //адрес устройства
                dmrtu.txbuf[_ADDR_MCMD]      =  3;                //команда
                dmrtu.txbuf[_ADDR_03_CNT_BYTES]    = bcntreg << 1;            //счётчик байтов для передачи
                //
                bsreg                 -= _Multiservo_RSS1;        //стартовый регистр
                cntbytes            = _ADDR_03_DATA;        //счётчик байтов + смещение
                bcntreg                += bsreg;            //количество регистров со смещением
                while(bsreg < bcntreg)
                {  
                    dmrtu.txbuf[cntbytes++] = (uint8_t)(dservo[bsreg] >> 8);
                    dmrtu.txbuf[cntbytes++] = (uint8_t)(dservo[bsreg++] & 0xFF);
                }
                //crc = sMRTU_CRC(&dmrtu.txbuf[0], cntbytes);
                //dmrtu.txbuf[cntbytes++] = (uint8_t)(crc >> 8);
                //dmrtu.txbuf[cntbytes++] = (uint8_t)(crc & 0xFF);
                //Serial.write(&dmrtu.txbuf[0], cntbytes);
                sMRTU_CRCo(&dmrtu.txbuf[0], cntbytes, &dmrtu.txbuf[cntbytes], &dmrtu.txbuf[cntbytes + 1]);
                Serial.write(&dmrtu.txbuf[0], cntbytes + 2);
                return;
            }
            else
            {
                dmrtu.txbuf[0] = _MRTU_Addr;
                dmrtu.txbuf[1] = 3 | _CMD_ERR_MODE;
                dmrtu.txbuf[2] = _ILLEGAL_DATA_ADDRESS;
                crc = sMRTU_CRC(&dmrtu.txbuf[0], 3);
                dmrtu.txbuf[3] = (uint8_t)(crc >> 8);
                dmrtu.txbuf[4] = (uint8_t)(crc & 0xFF);
                Serial.write(&dmrtu.txbuf[0], 5);
                return;
            }
        }
    }
     
    Тут указываем где будут ячейки контрольной суммы посылки ответа, но лишние телодвижения не убрал пока... хотя многое пилил приводя к 8-битному виду по мере возможности. Функции тоже без возвращаемых значений!
     
  8. Igor68

    Igor68 Гуру

    Подождите - сейчас кину последний код, точнее кидаю:
    r1_uno_plus.zip
     

    Вложения:

    • r1_uno_plus.zip
      Размер файла:
      22,9 КБ
      Просмотров:
      503
    Alex19 нравится это.
  9. Igor68

    Igor68 Гуру

    Пока аналогично поступил с проверкой контрольной суммы при приёме запроса:
    Код (C++):
    ///контрольная сумма для приёма - результат сравнение: 0 - совпало
    inline uint8_t sMRTU_CRCi(uint8_t* data, uint16_t len, uint8_t * crch, uint8_t * crcl)
    {
        uint8_t uchCRCHi = 0xFF;
        uint8_t uchCRCLo = 0xFF;
        uint16_t uIndex ;
        //uint8_t res;
        while(len--)
        {
            uIndex = uchCRCHi ^ *data++ ;
            uchCRCHi = uchCRCLo ^ auchCRCHi[uIndex] ;
            uchCRCLo = auchCRCLo[uIndex] ;
        }
        //return (uint16_t)(uchCRCHi | uchCRCLo << 8) ;
        //return (uint16_t)(uchCRCHi | uchCRCLo * 256) ;
        //*crch = uchCRCLo;
        //*crcl = uchCRCHi;
        //res = (*crch ^ uchCRCLo) | ( *crcl ^ uchCRCHi);
        return ( (*crch) ^ uchCRCLo) | ( (*crcl) ^ uchCRCHi);
    }
    Применял вот так на примере команды 3:
    Код (C++):
    nline void    MRTU_CMD3(void)
    {
        uint16_t  crc;             //подсчитанная контрольная сумма
        uint16_t  incrc;            //принятая контрольная сумма
        uint16_t  sreg;            //стартовый регистр
        uint16_t  cntreg;        //количество регистров
        uint8_t   bcntreg;
        uint8_t      cntbytes;        //счётчик байт в поле данных
        uint8_t      bsreg;
        uint8_t   wregcnt;
        //стартовый регистр
        #if(_opt_8 == 0)
            sreg    = (uint16_t)(dmrtu.rxbuf[_ADDR_03_START_REG_H] * 256)
                      | (uint16_t)(dmrtu.rxbuf[_ADDR_03_START_REG_L]);
        #else
            bsreg    = dmrtu.rxbuf[_ADDR_03_START_REG_L];
        #endif
        //количество регистров
        #if(_opt_8 == 0)
            cntreg  = (uint16_t)(dmrtu.rxbuf[_ADDR_03_CNT_REG_H] * 256)
                      | (uint16_t)(dmrtu.rxbuf[_ADDR_03_CNT_REG_L]);
        #else
            bcntreg    = dmrtu.rxbuf[_ADDR_03_CNT_REG_L];
        #endif
        //чтение контрольной суммы
        //incrc    = (uint16_t)(dmrtu.rxbuf[_ADDR_03_INCRC_H] * 256)
        //    | (uint16_t)(dmrtu.rxbuf[_ADDR_03_INCRC_L]);
        //crc = sMRTU_CRC(&dmrtu.rxbuf[0], 6);
        //if(crc == incrc)
        if(sMRTU_CRCi(&dmrtu.rxbuf[0], 6, &dmrtu.rxbuf[_ADDR_03_INCRC_H], &dmrtu.rxbuf[_ADDR_03_INCRC_L]) == 0)
              {
                /*
                ****************************
                проверка границ данных
                ****************************
                */

            #if(_opt_8 == 0)
                bsreg    = (uint8_t)(sreg);
                bcntreg    = (uint8_t)(cntreg);
            #endif
            //проверка предельного размера
            if(bcntreg >= _cntreg)
            {
                dmrtu.txbuf[0] = _MRTU_Addr;
                dmrtu.txbuf[1] = 3 | _CMD_ERR_MODE;
                dmrtu.txbuf[2] = _ILLEGAL_DATA_ADDRESS;
                sMRTU_CRCo(&dmrtu.txbuf[0], 3, &dmrtu.txbuf[3], &dmrtu.txbuf[4]);
                Serial.write(&dmrtu.txbuf[0], 5);
                return;
            }
            //ComMotion
    ..... //далее
    Уменьшал количество обращений... пока без ассемблерных вставок.
     
  10. Igor68

    Igor68 Гуру

    Ещё одно дополнение - обход восьми сдвигов вправо... только на Си. (закомментированное заменено на новое):
    Код (C++):
    while(bsreg < bcntreg)
                {  
                    //dmrtu.txbuf[cntbytes++] = (uint8_t)(dservo[bsreg] >> 8);
                    //dmrtu.txbuf[cntbytes++] = (uint8_t)(dservo[bsreg++] & 0xFF);
                    dmrtu.txbuf[cntbytes++] = (*(uint8_t*)(&dservo[bsreg] + 1));
                    dmrtu.txbuf[cntbytes++] = (*(uint8_t*)(&dservo[bsreg++]));
                }
    Описанный код не рабочий - это только идея(задумка)...
     
    Последнее редактирование: 23 дек 2016
  11. Igor68

    Igor68 Гуру

    Странно всё это:
    1) обращаюсь к младшему байту параметра типа int16:
    (*(uint8_t*)(&dservo[bsreg] )) - облом
    2) обращаюсь к старшему байту параметра типа int16:
    (*(uint8_t*)(&dservo[bsreg] + 1)) - облом
    Всю жизнь без проблем!!! А тут что-то не пойму!
    Что не так?
     
    Последнее редактирование: 23 дек 2016
  12. Alex19

    Alex19 Гуру

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

    Тут нет проблем, можете проверить, вот код.
    Код (C++):
    typedef struct _DAT_MRTU
    {
      uint8_t  rxbuf[8];
      uint8_t  txbuf[8];
      uint8_t  adrx;  //указатель на массив буфера приёма
      uint8_t  adtx;  //указатель на массив буфера передачи
    } DAT_MRTU;
    DAT_MRTU  dmrtu;
    uint8_t  txbuf[8];
    uint8_t dservo[8];
    void setup()
    {
      Serial.begin(115200);
      for (byte i = 0; i < 8; i++)
      {
        dmrtu.txbuf[i] = i*1;
        dservo[i] = (i+1)*2;
      }
    }

    void loop()
    {
      static uint8_t cntbytes = 0;
      static uint8_t bsreg = 0;

      Serial.print("txbuf=");
      Serial.print(dmrtu.txbuf[cntbytes++]);
      Serial.print("-cntbytes=");
      Serial.print(cntbytes);
      Serial.print("-dservo=");
      Serial.println(dservo[cntbytes]);
     
      dmrtu.txbuf[cntbytes] = (*(uint8_t*)(&dservo[cntbytes] + 1));
      Serial.print("1txbuf=");
      Serial.print(dmrtu.txbuf[cntbytes]);
      Serial.print("-cntbytes=");
      Serial.print(cntbytes);
      Serial.print("-dservo=");
      Serial.println(dservo[cntbytes]);
     
      delay(1000);
    }
    Сознательно оставил выход за пределы массива:).

    Так, что смотрите в другом месте, тут все работает.
     
    Igor68 нравится это.
  13. Igor68

    Igor68 Гуру

    Что-то пока не вкурю:
    (*(uint8_t*)(&dservo[bsreg] )) //dservo - массив парамеров типа int16_t
    тут я получаю значение размерностью uint8_t по адресу параметра &dservo[bsreg] - то есть младший байт параметра размерностью int16_t. Всегда это было в порядке вещей. Может я что-то не понимаю, но в GAPI для MPX220 при "переносе" игрушки "Elite" именно этим методом пользовался в VS2005. Хоть исходник был для Palm OS и потоки я не применял, а только таймеры системы.
     
  14. Alex19

    Alex19 Гуру

    Доброе утро.

    Вчера видимо от усталости, пропустил, что у Вас int16_t. С ним дела обстоят немного иначе.

    Пример кода.
    Код (C++):

    typedef struct _DAT_MRTU
    {
      uint8_t  rxbuf[8];
      uint8_t  txbuf[8];
      uint8_t  adrx;  //указатель на массив буфера приёма
      uint8_t  adtx;  //указатель на массив буфера передачи
    } DAT_MRTU;
    DAT_MRTU  dmrtu;
    uint8_t  txbuf[8];
    int16_t dservo[8];
    void setup()
    {
      Serial.begin(115200);
      for (byte i = 0; i < 8; i++)
      {
        dmrtu.txbuf[i] = i*1;
        dservo[i] = (i+1)*1000;
      }
      for (byte i = 0; i < 8; i++)
      {
        Serial.println(dservo[i], HEX);
      }
    }

    void loop()
    {
      static uint8_t cntbytes = 0;
      static uint8_t bsreg = 0;
      Serial.print("txbuf=");
      Serial.print(dmrtu.txbuf[cntbytes], HEX);
      Serial.print("-cntbytes=");
      Serial.print(cntbytes);
      Serial.print("-dservo=");
      Serial.println(dservo[cntbytes]);  
      //dmrtu.txbuf[cntbytes] = (*((uint8_t*)(&dservo[cntbytes])));
      dmrtu.txbuf[cntbytes] = (*(((uint8_t*)&dservo[cntbytes]) + 1));
      //dmrtu.txbuf[cntbytes] = (*(uint8_t*)(&dservo[cntbytes] + 1));

      Serial.print("1txbuf=");
      Serial.print(dmrtu.txbuf[cntbytes], HEX);
      Serial.print("-cntbytes=");
      Serial.print(cntbytes);
      Serial.print("-dservo=");
      Serial.println(dservo[cntbytes]);  
      cntbytes++;
      if (cntbytes == 8)
      {
        cntbytes = 0;
      }
      delay(1000);
    }
     
    А теперь пояснение, младший байт.
    Код (C++):
    dmrtu.txbuf[cntbytes] = (*((uint8_t*)(&dservo[cntbytes])));
    Тут все понятно.

    Старший байт.
    Код (C++):
    dmrtu.txbuf[cntbytes] = (*(((uint8_t*)&dservo[cntbytes]) + 1));
    Прибавляем к указателю uint8_t* один, другими словами увеличиваем указатель на размер типа самого указателя. Подробнее тут - http://citforum.ru/programming/c/h17.shtml.

    Если использовать Ваш код
    Код (C++):
    dmrtu.txbuf[cntbytes] = (*(uint8_t*)(&dservo[cntbytes] + 1));
    Мы берем младший бит, следующего элемента, (&dservo[cntbytes] + 1) работает как указатель на int16_t + 1, увеличиваем указатель на размер типа самого указателя.
     
    Igor68 нравится это.
  15. Igor68

    Igor68 Гуру

    Что-то сомнения берут:
    Вот это: &dservo[cntbytes] - адрес размещения (фактическое значение адреса)
    Вот это: &dservo[cntbytes] + 1 - наш адрес увеличили на 1... не на 2 как в случае для двух-байтных чисел.
    Вот это: (*(uint8_t*)(&dservo[cntbytes])) мы обратились к числу типа uint8_t, которое находится по адресу &dservo[cntbytes] в адресном пространстве.
    Вот это: &dservo[cntbytes + 1] адрес сдедующего элемента после cntbytes массива типа int16
    Вот это (*(uint16_t*)(&dservo[cntbytes] )) обращение к полному элементу массива, что соответствует просто dservo[cntbytes]
    Вот это:
    Код (C++):
    while(count < _cnt_regs)
        {
            // в тип int16 из типа uint8
            regs[count] = (*(I16*)(&wbuffrom[addr]));
            addr += 2;  
            count++;
        }
    я копирую в массив регистров значения типа int16 из массива сервера типа uint8. именно эти значения я передаю от клиента серверу по локальной сети в программе связи с ардуино arbot.
    Вот это:
    Код (C++):
    while(count < _cnt_regs)
        {
            (*(I16*)(&wbufto[addr])) = regs[count];
            addr += 2;  
            count++;
        }
    я копирую значения регистров типа int16 в массив типа uint8 в arbot.
    Везде всё работает, вот только со стороны Arduino IDE что-то... не то:
    Код (C++):
    while(bsreg < bcntreg)
                {
                    //dmrtu.txbuf[cntbytes++] = (uint8_t)(dservo[bsreg] >> 8);
                    //dmrtu.txbuf[cntbytes++] = (uint8_t)(dservo[bsreg++] & 0xFF);
                    //--- указатель на старший байт в dservo[bsreg]
                    dmrtu.txbuf[cntbytes++] = (*(uint8_t*)(&dservo[bsreg] + 1));
                    //указатель на младший байт dservo[bsreg], после чего увеличиваю: bsreg++
                    dmrtu.txbuf[cntbytes++] = (*(uint8_t*)(&dservo[bsreg++]));
                }
     
  16. Igor68

    Igor68 Гуру

    Вообще странно всё это. если делать так:
    1) объявляем адрес(тупо) внутри функии:
    Код (C++):
    int    addr;
    2) применяем его как адрес (указатель):
    Код (C++):
    while(bsreg < bcntreg)
                {
                    addr            = (int)(&dservo[bsreg]);//значение адреса
                    dmrtu.txbuf[cntbytes++] = (*(uint8_t*)(addr + 1));
                    dmrtu.txbuf[cntbytes++] = (*(uint8_t*)(addr));
                    bsreg++;
                }
    Всё нормально!
    Но вот это, что вообще-то одно и то же что (но не работает):
    Код (C++):
    while(bsreg < bcntreg)
                {
                    //--- указатель на старший байт в dservo[bsreg]
                    dmrtu.txbuf[cntbytes++] = (*(uint8_t*)(&dservo[bsreg] + 1));
                    //указатель на младший байт dservo[bsreg], после чего увеличиваю: bsreg++
                    dmrtu.txbuf[cntbytes++] = (*(uint8_t*)(&dservo[bsreg++]));
                }
    которое не работает, но зато избавился от >>8 и & 0xFF а это целых 9 лишних операций и обращений к памяти программ. Собственно из-за этого всё было и задуманно.
    Но наверное вот это:
    Код (C++):

    addr            = (int)(&dservo[bsreg]);//значение адреса
    while(bsreg < bcntreg)
                {
                    dmrtu.txbuf[cntbytes++] = (*(uint8_t*)(addr + 1));
                    dmrtu.txbuf[cntbytes++] = (*(uint8_t*)(addr));
                    bsreg++;
                    addr += 2;
                }
    наверное побыстрее будет.
     
    Последнее редактирование: 24 дек 2016
  17. Alex19

    Alex19 Гуру

    Все верно, кроме &dservo[cntbytes] + 1, тут происходит аналогичное этому
    Код (C++):

    int16_t *temp = &dservo[cntbytes];
    temp++;
     
    Это будет работать везде.

    Замените (*(uint8_t*)(&dservo[bsreg]+1)); на (*((uint8_t*)(&dservo[bsreg]))+1)); добавляйте к указателю типа uint8_t.

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

    Если для Вас так критично время операций, зачем Вы вообще их переносите в другой массив. В коде библиотеки ModbusRTU которую давал выше, есть массив uint16_t, который просто заполняется. А если, что-то нужно перекинуть, через константы #define INPUT_Z5 modbusData[32] и в программу double* inputZ5 = &((double&)INPUT_Z5);

    Так же Ваша программа занимает не мало оперативной памяти - Minimum Memory Usage: 1869 bytes (91% of a 2048 byte maximum), советую перенести массивы auchCRCHi и auchCRCLo в EEPROM. Да немного потеряете в производительности, но зато не упретесь в память.

    UPD.
    По переносу расчета контрольной суммы.
    Объявляем массивы auchCRCHi и auchCRCLo.
    Код (C++):
    const uint8_t PROGMEM auchCRCHi[256]
    Читаем
    Код (C++):
    (uint8_t)pgm_read_byte(&auchCRCHi[i]);
    UPD 2. Начал разбираться с MRTU_CMD3, тут придется повозится, у меня Mega + RS485. Да и к тому же, он считает не корректной сумму CRC16 которая приходит от панели HMI компании Weintek.
     
    Последнее редактирование: 24 дек 2016
    Igor68 нравится это.
  18. Igor68

    Igor68 Гуру

    Спорить не имею ни права и ни желания!
    А указатель в переменную размерностью с разрядностью адресного пространства использую очень часто. Фактически это физический адрес - ну и разрядность соответствующая. Тут я уже привык... началось всё с игрушки "Elite", как говорил ранее по GAPI - байтовый массив картинки для отображения на экране. Переносил код для Palm OS в Windows CE. Понятное дело баловство, да и давно это было, но правда! Тут много функций которые можно ускорить например в ComMotion driver for 4 motors (задания для 4-х моторов):
    Код (C++):
    void IndividualMotorControl(int16_t m1, int16_t m2, int16_t m3, int16_t m4)
    {
      Wire.beginTransmission(COMMOTION_ADDR+COMMOTION_OFFS); // Initialize I²C communications with ComMotion shield
      Wire.write(3);              // Specify that data packet is motor control data
      Wire.write(highByte(m1));   // -255 to +255  speed for motor 1
      Wire.write( lowByte(m1));   // negative values reverse direction of travel
      Wire.write(highByte(m2));   // -255 to +255  speed for motor 2
      Wire.write( lowByte(m2));   // negative values reverse direction of travel
      Wire.write(highByte(m3));   // -255 to +255  speed for motor 3
      Wire.write( lowByte(m3));   // negative values reverse direction of travel
      Wire.write(highByte(m4));   // -255 to +255  speed for motor 4
      Wire.write( lowByte(m4));   // negative values reverse direction of travel
      Wire.endTransmission();     // transmit data from I²C buffer to ComMotion shield
    }
     
    Если посмотреть то идёт выделение старшего и младшего байта для передачи по I2C. Вызв данной функции в loop():
    Код (C++):
    IndividualMotorControl(dmotor[0], dmotor[1], dmotor[2], dmotor[3]);
    Одним словом мы читаем данные, вызываем функцию в которой highByte и lowByte по моему аналогичные сдвигу на 8. Думю что:
    Код (C++):
    void mIndividualMotorControl(uint8_t * m1, uint8_t * m2, uint8_t * m3, uint8_t * m4)
    {
      Wire.beginTransmission(COMMOTION_ADDR+COMMOTION_OFFS); // Initialize I²C communications with ComMotion shield
      Wire.write(3);              // Specify that data packet is motor control data
      Wire.write(*(m1 + 1));   // -255 to +255  speed for motor 1
      Wire.write(*m1);   // negative values reverse direction of travel
      Wire.write(*(m2 + 1));   // -255 to +255  speed for motor 2
      Wire.write(*m2);   // negative values reverse direction of travel
      Wire.write(*(m3 + 1));   // -255 to +255  speed for motor 3
      Wire.write(*m3);   // negative values reverse direction of travel
      Wire.write(*(m4 + 1));   // -255 to +255  speed for motor 4
      Wire.write(*m4);   // negative values reverse direction of travel
      Wire.endTransmission();     // transmit data from I²C buffer to ComMotion shield
    }
     
    выгоднее, но с указателями по типам уже побаиваюсь именно для Arduino IDE. потому и сделал как указатель на uint8_t. Ну а вызов соответственно:
    Код (C++):
    mIndividualMotorControl((uint8_t*)&dmotor[0], (uint8_t*)&dmotor[1], (uint8_t*)&dmotor[2], (uint8_t*)&dmotor[3]);
    В надежде несколько освободить ресурс. Ведь надо и для датчика-дальномера что-то предпринять!
     
  19. Igor68

    Igor68 Гуру

    Надо подумать!
     
  20. Alex19

    Alex19 Гуру

    Вроде не спорим, сам скорее практик и читаю документацию, когда ни чего не работает.:)

    Мне просто так легче ориентироваться, глянул объявление и понятно, что там адрес. Так же отправлять в функцию по ссылке.

    Да можно и так, как вариант.

    Но мое мнение, что для такой оптимизации рано, сам бы замерил время работы функций и начал с тех, что выполняются максимально долго. И разбираться в них, убирать задержки, блокирующие циклы и т.д., а уже потом оптимизировать на таком уровне.

    UPD. У меня сейчас аналогичный хоббийный проект ModbusRTU (RS-485), TWI (ADC, FRAM, расширители портов, клавиатуры), Soft SPI и мешок прерываний. Но у меня Mega, на Uno не уместилось. Но пока не вижу необходимости к серьезной оптимизации, тем более ассемблера.
     
    Последнее редактирование: 24 дек 2016