Правильное форматирование данных для I2C (Wire.write) - PullRequest
0 голосов
/ 28 декабря 2018

Я соединяю несколько модулей Arduino Mega вместе, чтобы создать банк ввода-вывода, полностью управляемый ведущим на шине I2C.

Я работал с подчиненным, заполняя строку с состоянием аналоговых входови т. д. каждый разделен двоеточием.Строка будет затем зациклена с Wire.write.

Начальный reqNo сообщит мастеру, какая партия возвращалась.Например, партия 0 будет аналоговой 0 - 5, партия 1 будет аналоговой 6 - 11 и т. Д.

Все это работало, пока дальнейшее чтение не привело меня к статье, которая выступала против использования строк из-за использования памяти и связанных с нимипроблемы.Я попытался изменить свой код, чтобы избежать использования строк, но теперь я получаю строки вроде этого:

: ⸮: ⸮: ⸮: ⸮: ⸮: ⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮W

вернулось вместо ожидаемого результата.

Я думаю, что это проблема кодирования или подобное?Может кто-нибудь, пожалуйста, дать совет о том, что я делаю неправильно или другой способ достижения этого, пожалуйста.Очень важно, чтобы устройство функционировало в течение очень длительного периода времени без перезагрузок или каких-либо проблем, поэтому я очень заинтересовался удалением строк, если это может вызвать проблемы.

Основной код:

int i=0;
char res[32]="";
while(Wire.available()){
    char c=Wire.read();
    Serial.print(c);
    res[i]=c;
    i++;
}

Код ведомого:

void requestStatus(){
    int i;
    Wire.write(reqNo);

    if(reqNo==0){
        for(i=0;i<6;i++){
            Wire.write(':');
            Wire.write(analogRead(i));
        }
    }else if(reqNo==1){
        for(i=6;i<12;i++){
            Wire.write(':');
            Wire.write(analogRead(i));
        }
    }else if(reqNo==2){
        for(i=12;i<16;i++){
            Wire.write(':');
            Wire.write(analogRead(i));
        }
    }
    reqNo++;
    if(reqNo==3){
        reqNo=0;
    }
}

Ответы [ 4 ]

0 голосов
/ 28 декабря 2018

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

Я предполагаю, что речь шла о String объекты, а не c-строки (массивы символов с нулевым символом в конце).
Те, которые используют динамическое распределение памяти и вызывают фрагментацию кучи.C-строки обычно статически размещаются (char res[32];) и очищаются из стека, если они определены внутри функции.

write принимает только один байт, массив байтов (или chars) с явной длиной или c-строкой.
Передавая его, int преобразует его только в байт и сохраняет только младшие 8 бит.

Вам нужен метод «print».Он конвертирует целые числа в символы на лету.Он не использует String или c-строки.

Вы должны заменить все свои Wire.write на Wire.print.

Кроме того, в вашем мастер-коде вы не завершаете nul.массив res char, который вызовет проблемы, поскольку нет явного конца строки.Вы также должны убедиться, что вы не записали в него более 31 символа (nul terminator также считается символом) и вызовете переполнение буфера.

0 голосов
/ 28 декабря 2018

Есть две проблемы с вашим кодом, во-первых:

...
// master side
char c=Wire.read();
...
// slave side            
Wire.write(analogRead(i));

вы рассматриваете целочисленные значения, как если бы они были ASCII закодированы, это не так.Вы должны преобразовать их в ASCII в какой-то момент (например, со стороны мастера).Рассмотрите возможность использования sscanf или snprintf для конвертации.

Во-вторых, вы не NUL заканчиваете строкой C.

0 голосов
/ 28 декабря 2018

Вы должны ввести reqNo в char при передаче его в функции Wire.write, например

Wire.write((char)(reqNo));
0 голосов
/ 28 декабря 2018

Wire.write(reqNo); например, напишет символ кода 0 1 или 2, а не символ «0» или «1» или «2», если это то, что вы ожидали

...