Пересылка данных со знаком по I2С. Как реализовать?

Тема в разделе "Arduino & Shields", создана пользователем Zorg_79, 30 мар 2014.

  1. Zorg_79

    Zorg_79 Нуб

    Доброго дня.
    Есть три ведомые платы, одна ведущая. Все связаны по i2c

    По запросу от ведущей ведомые возвращают данные: от одного до десяти целых чисел в диапазоне от -100 до 100. (Длина пакета разная для трех плат, но в ходе работы не меняется. Т.е. например набор 3 числа от платы 1,3 от платы 2,10 от платы 3. Задается при первоначальном программировании)

    Как корректно передавать данные? Иными словами - как сформировать пакет байт на стороне ведомого и как корректно востановить из пакета байт целые числа на стороне ведущего?

    Киньтесь ссылкой если уже обсуждалось.

    Спасибо.
     
  2. Zorg_79

    Zorg_79 Нуб

    Эту библиотеку я смотрел. Насколько я понял - что бы она работала - необходима одинаковая длина пакета на всех платах. У меня - длина пакета разная на разных платах.
     
  3. Zorg_79

    Zorg_79 Нуб

    Со стороны передатчика (слэйв I2C)написан код:
    Код (Text):

    void setup() {
    Wire.begin(2);  
    Serial.begin(9600);Wire.onRequest(requestEvent);
    }
    void loop() {
    sensorValue = analogRead(analogInPin);  
    outputValue = map(sensorValue, 0, 1023, -100, 100);
    //приводим к диапазону -100 100
    void requestEvent()
    Serial.println(outputValue);
    {
    // Wire.write(outputValue);
    Wire.write(lowByte(outputValue));
    Wire.write(highByte(outputValue));
    }
    }
     
    Со стороны приемника (мастер I2C) написан код:

    Код (Text):

    #include <Wire.h>
    #include <LiquidCrystal.h>
    int data = 0;
    LiquidCrystal lcd(10, 4, 5, 6, 7, 8);

    void setup() {
     
    lcd.begin(16, 4);
    lcd.print("OK");

    Wire.begin();  
    Serial.begin(9600);
    }

    void loop() {
    lcd.setCursor(0, 1);
    lcd.print(millis()/1000);


    Wire.requestFrom(2, 2);  
    byte i = 0;
    byte buffer[2] = {0, 0};
    while(Wire.available())  
    {
    buffer[i] =Wire.read();
    i++;
    data = 0;
    data |=buffer[1] & 0xFF;
    data =data << 8;
    data |=buffer[2] & 0xFF;
    }
    Serial.print("Data=");
    Serial.println(data);  
    lcd.setCursor(-4,3);
    lcd.print(data);
    delay(500);
    }
     
    Выдает на стороне мастера неправильное значение... То -88 то -4, но ни разу не то что подается слэйвом.

    Что я делаю не так?
     
  4. acos

    acos Официальный гик Администратор

    Код (Text):
    outputValue = map(sensorValue, 0, 1023, -100, 100);
    А почему бы это не делать со стороны мастера?
     
  5. Zorg_79

    Zorg_79 Нуб

    Это - частный случай.
    Просто сделал так для отладки. Кручу потенциометр - смотрю что шлется.

    В общем случае - у меня будут пересылаться не только данные с сенсора но и отрицательные числа, получаемые расчетным путем. Как двухбайтного хранения - целые, так и четырехбайтные - float.

    В любом случае - как их правильно пересылать - важно разобраться.
    Пока у меня не получается.
     
  6. Tomasina

    Tomasina Сушитель лампочек Модератор

    Вы все-таки определитесь с размерностью, от этого и реализация будет зависеть, потому как диапазоны -100...+100 и -398,20...+400,37 нужно кодировать совершенно по-разному.
     
  7. Zorg_79

    Zorg_79 Нуб

    Базовым типом будет float. Т.е. положительные и отрицательные, с десятичной точкой.
     
  8. Tomasina

    Tomasina Сушитель лампочек Модератор

    предельные значения какие? Число знаков после точки?
     
  9. Zorg_79

    Zorg_79 Нуб

    Знаков после точки шесть. Предельные значения -360 + 360. Передаваться будут географические координаты, курс, скорость.... Для координат - шесть знаков после запятой, курс - хватит одного знака. Сдужебная информация - и вовсе целыми числами будет кодироваться.

    Разрабатываю навигационно -управляющую систему для катера и хочу проверить несколько идей с разнесенными приемниками. Каждая платка обрабатывает свой приемник и потом мастеру по запросу данные передает.
     
  10. Unixon

    Unixon Оракул Модератор

    Про фиксированную точку опять незаслуженно забыли.
     
  11. Zorg_79

    Zorg_79 Нуб

    Я в общем то электромеханикой больше занимался всю жизнь. А не программированием. По этому и спрашиваю как сделать....

    Ежели ткнете носом в пример кода аль толковый учебник - буду благодарен.

    ежели ткнете в рабочий код пересылающий три числа, скажем 160.123456 -80.654321 255 по I2C - так и вовсе счастлив буду...
     
  12. NR55RU

    NR55RU Гик

    На самом деле если вы желаете передать допустим число с плавающей точкой как целочисленные значения а потом его собрать.
    Можно использовать объединения.
    Вот демонстрационный код:

    Код (Text):
    #include <iostream>

    int main( void )
    {
        union mixValue
        {
            float floatValue;
            char charValue[ 4 ];
        };
     
        mixValue mV;
        mV.floatValue = 12.74;
     
        std::cout << mV.floatValue << std::endl;
        mV.floatValue = 0;
        std::cout << mV.floatValue << std::endl;
     
        mV.charValue[0] = 10;
        mV.charValue[1] = -41;
        mV.charValue[2] = 75;
        mV.charValue[3] = 65;
     
        std::cout << mV.floatValue << std::endl;
     
        return 0;
    }
    Вывод:
    Код (Text):
    12.74
    0
    12.74
    Таким образом достаточно передать 4 байта данных а на другом конце вставить их на свои места в такое же объединение.

    У меня в системе для float отводилось 4 байта. отсюда и размер массива char.
    Главное как я понимаю что бы порядок хранения байтов в памяти совпадал у задействованных МК, в противном случае придется это решать :)

    Если вы не совсем поняли как работает объединение, то прочитайте о нем и все сразу станет понятно :)
    Фактически это кусочек памяти который можно интерпретировать по разному получая доступ к тому что там записано либо как к float либо как в массиву char и тд и тп.
     
  13. Zorg_79

    Zorg_79 Нуб

    Стало еще непонятнее.

    Добавил коментарии в ваш пример.

    Код (Text):

    #include <iostream>

    int main( void )
    {
    union mixValue
    {
    float floatValue;
    char charValue[ 4 ];
    };

    mixValue mV;
    mV.floatValue = 12.74;   *ИСХОДНОЕ ЧИСЛО*

    std::cout << mV.floatValue << std::endl;  *СИЛЬНОЕ КОЛДУНСТВО*
    mV.floatValue = 0;
    std::cout << mV.floatValue << std::endl;

    mV.charValue[0] = 10;   *А ВОТ ЭТИ ПРИСВОЕНИЯ ЗАЧЕМ???*
    mV.charValue[1] = -41;
    mV.charValue[2] = 75;
    mV.charValue[3] = 65;

    std::cout << mV.floatValue << std::endl;

    return 0;
    }
     
     
  14. Zorg_79

    Zorg_79 Нуб

    В принципе - математика с фиксированной точкой мне подходит.
    Базовые чипы в системе - Mega8

    Главное, что бы работало с числами вида S XXXX.YYYYYY где
    S знак плюс или минус
    XXXX целая часть числа до 9999 (мне хватит за глаза)
    YYYY дробная часть числа

    По большому счету - даже не нужно пересылать несколько подобных чисел за один пакет.


    В любом случае буду реализовывать диалоговую систему - т.е писать протокол запрос - ответ.
    На человеческом языке примерно такая логика
    Что то вроде: М=Мастер С=слэйв
    М: С1, сообщить статус
    С1: 111.222222 /Все работает/
    М: С1, скорость?
    С1: 30.250000
    М: С1, курс
    С1: 135.200000
    М:С1, широта
    С1:-60.234567
    М:С1, дистанция до точки
    C1: 2300.100000


    Как протокол реализовать - это в примерах Ардуины более менее понятно написано. Как с GPS работать - тоже.

    А вот пересылка данных - уже третий день вою от напряга мозга :)

    Главное - отработать код для пересылки 1 числа указанного формата....

    А это - не получается пока....