GPS парсер.

5N62V
Offline
Зарегистрирован: 25.02.2016

Приобрел я себе ЖПС приемник BN-880 с тем, чтоб получить 5 Гц апдейт рейт координат в моем роботе.

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

Пришлось писать парсер самому. И тут я уперся в проблему синхронизации работы моего блока управления с этими самыми пятью герцами. И, как человек действия, сначала делаю потом думаю, сделал устройство общения с ЖПС приемником. Это отдельное утройство на аруино мини, которое считывает строки NMEA, парсит их, полученные координаты в виде 19байтной пачки скидывает на блок управленияпо запросу  по i2c. 

Все работает ОК, но принимая во внимание , что я тот еще программист, прошу сообщество глянуть в мой код, и подвергнуть его жесткой критике. Цель - сделать код лучше, а меня - продвинутее :) Добрый глум в сочетании с дельными советами - приветствуется!  Всем бобра!


#include <arduino.h>
#include <Wire.h>
//#include <TinyGPS.h>
#include <SoftwareSerial.h>

#define SLAVE_ADDRESS 4
#define DATA_LENGTH 19
#define DELAY 1

//TinyGPS gps;
SoftwareSerial ss(2, 4);

byte buffer[DATA_LENGTH]; 
//сюда запихиваем переменные для отправки по i2c
float flat, flon, current_course, speed;
unsigned int altitude;
bool fixed_data = 0;
//4 переменные float + 1 unsigned int + 1 bool = 19байт
byte text[100];  
//сюда считываем NMEA строку для последующего парсинга
bool new_data = 0;

void setup() {
  Serial.begin(38400);
  ss.begin(38400); 
  //GPS сконфигурирован под 38400, выдает только RMC и GGA
  Wire.begin(SLAVE_ADDRESS);
  Wire.onRequest(slaveTX);

}

void loop() {
  if (ss.available())  listen_uart();
  if(new_data)data_to_buffer();

}

void slaveTX() {
  //передаем buffer на мастер по i2c
  Wire.write(buffer, DATA_LENGTH);
}

void data_to_buffer() {
  //копируем переменные в buffer
  byte *ptr_flat = (byte *)(&flat);
  byte *ptr_flon = (byte *)(&flon);
  byte *ptr_speed = (byte *)(&speed);
  byte *ptr_current_course = (byte *)(&current_course);
  byte *ptr_altitude = (byte *)(&altitude);
  for (char i = 0; i < 4; ++i) {
    buffer[i] = *(ptr_flat + i);
    buffer[i + 4] = *(ptr_flon + i);
    buffer[i + 8] = *(ptr_speed + i);
    buffer[i + 12] = *(ptr_current_course + i);
  }
  buffer[16] = *ptr_altitude;
  buffer[17] = *(ptr_altitude + 1);
  buffer[18] = fixed_data;
  new_data = 0;
}


void listen_uart() {
  if (ss.available() > 100) {
    while (ss.available())ss.read();
    return;
  }//если больше 100байт - очищаем все
  int i = 0;
  byte buff;

  do {
    buff = ss.read();
  } while (buff != 36);
  //читаем все до знака $

  delay(1);
  do {
    if(i>99)return;
    text[i++] = ss.read();
    delayMicroseconds(100);//ожидание прихода следующего байта
  } while (text[i - 1] != 42);
  //заполняем text[]прока не встретим *
  ss.read(); ss.read();//ложим болт на контрольную сумму

 //for ( int k = 0; k < (i - 1); k++) {    
  //Serial.print((char)text[k]);    
 // Serial.print(" ");  }
  Serial.println();

  new_data = 1;
  if (text[4] == 67) parse_rmc();
  if (text[4] == 65) parse_gga();
}

void parse_rmc() {
  byte count = 0;
  byte i = 0;


  do {
    if (text[i++] == 44) count++;
  } while (count < 2);
  //перебираем ячейки text до второй запятой включительно
  text[i] == 65 ? fixed_data = 1 : fixed_data = 0;
  Serial.print("fixed_data = "); Serial.println(fixed_data);

  do {
    if (text[i++] == 44) count++;
  } while (count < 3);
   //перебираем ячейки text до третьей запятой включительно
  flat = parse_coords(i);
  Serial.print("flat = "); Serial.println(flat, 6);

  do {
    if (text[i++] == 44) count++;
  } while (count < 5);
  flon = parse_coords(i + 1);
  Serial.print("flon = "); Serial.println(flon, 6);

  do {
    if (text[i++] == 44) count++;
  } while (count < 7);
  speed = parse_speed(i);
  speed = speed * 1.852;
  Serial.print("speed = "); Serial.println(speed);

  do {
    if (text[i++] == 44) count++;
  } while (count < 8);
  current_course = parse_speed(i);
  Serial.print("current_course = "); Serial.println(current_course);

}

void parse_gga() {
  byte count = 0;
  byte i = 0;

  do {
    if (text[i++] == 44) count++;
  } while (count < 9);

  int n = -1;

  do {
    n++;
  } while (text[i++] != 46);

  i = i - n - 1;
  altitude = parse_value(i, n);
  //for( byte l = 0; l<n; l++)altitude+=(text[l+i]-48)*(unsigned int)(pow(10, n-l-1)+0.5);
  Serial.println(altitude);
}

long parse_value(byte i, byte n) {
  long value = 0;
  for (byte j = 0; j < n; j++) value = value * 10 + (text[i + j] - '0');
  return value;
}

float parse_coords( byte i) {
  float coord = 0;
  coord = parse_value(i, 2);
  float minutes = parse_value(i + 2, 2);
  float after_dot = parse_value(i + 5, 4);
  minutes = minutes + after_dot / 10000.;
  coord = coord + minutes / 60.;

  return coord;
}

float parse_speed(byte i) {
  if (text[i] == 44)return 0;

  int n = -1;
  float res = 0;
  byte j = i;

  do {
    n++;
  } while (text[j++] != 46);
  res = parse_value(i, n);
  res = res + (text[i + n + 1] - '0') / 10.;
  return res;
}

 

b707
Offline
Зарегистрирован: 26.05.2017

Прошу не обижаться., но текст - классический "антимотиватор". :)  Если у вас и так все работает, нафига мне тратить время на улучшение вашего кода? :) тем более что вы даже приблизительно не обозначили, в какую сторону двигаться? - уменьшить размер скетча? освободить память переменных?увеличить скорость работы?

Код открывать не стал.

С уважением к автору.

5N62V
Offline
Зарегистрирован: 25.02.2016

b707 пишет:

 Если у вас и так все работает, нафига мне тратить время на улучшение вашего кода? :) 

Ок, предположим, код не работает. Нафига Вам было бы тратить время на поиск ошибки? Тренировать свои скилы? Сомневаюсь. Демонстрировать свой профессионализм? Скорее всего. :) Не обижайтесь, но это является мотиватором для большинства перцев, не только в сфере программирования микроконтроллеров.

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

В первую очередь размер интересен, т.к. одной из причин выноса парсера на отдельное устройство стал дифицит памяти.  Но если еще  попутно и скорость возрастет, то вау! :)

С уважением.

sadman41
Offline
Зарегистрирован: 19.10.2016

5N62V пишет:

В первую очередь размер интересен, т.к. одной из причин выноса парсера на отдельное устройство стал дифицит памяти.  Но если еще  попутно и скорость возрастет, то вау! :)

Какой памяти, сколько надо... Не инициализируйте Serial - вот вам уже память. Избавьтесь от float - вот вам и память и скорость. 

А "делать красиво" - это как перед костром сидеть. До бесконечности можно. Ну, или пока с голоду набок не завалишься.

b707
Offline
Зарегистрирован: 26.05.2017

ну что, нормальный код . Сойдет для сельской местности...^)

Вот вам первое улучшение - так покороче будет.

void data_to_buffer() {
  //копируем переменные в buffer
memcpy(buffer, &flat, 4);
memcpy(buffer+4, &flon, 4);
memcpy(buffer+8, &speed, 4);
memcpy(buffer+12, &current_course, 4);
memcpy(buffer+16, &altitude, 2);

buffer[18] = fixed_data;
  new_data = 0;
}

А дальше пусть еще кто-нить выскажется

 

b707
Offline
Зарегистрирован: 26.05.2017

А вообще правильнее было бы обьединить все ваши данные - flat, flon, altitude и тд - в структуру и работать с ней как единым блоком. Тогда не надо было бы ничего копировать из одного места памяти в другое, буфер был бы не нужен, отправляли бы их по i2c непосредственно, а на другой стороне не надо было бы парсить отдельные байты

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

5N62V пишет:

прошу сообщество глянуть в мой код, и подвергнуть его жесткой критике

Ну, давайте начнём, помолясь. Только … это … Вы сами просили :)

1.  С буфером для передачи данных так работать нельзя

Вот смотрите. Функция slaveX вызывается по прерыванию, т.е. она может быть вызвана в любой момент. Теперь преставьте, что у Вас работает функция data_to_buffer. Часть данных она уже успела скопировать, а часть нет. Более того, она находится в процессе копирования конкретного числа (т.е. часть числа скопировалось, а часть ещё нет) и в этот самый момент прилетает прерывание. Что происходит? А ничего. Функция slaveTX радостно передаёт своему мастеру «полускопированные» данные. Мастер их получает этот сивокобылий бред и долго удивляется что курит Ваш скетч и какая зараза ему это продала. Проблема понятна?

2. Ну, кто так копирует данные в буфер?

Что это за функция data_to_buffer такая в полскетча? Вам достаточно А) удалить строку 13; Б) вместо строк 15-18 описать структуру типа такой

struct {
	float flat, flon, current_course, speed;
	unsigned int altitude;
	bool fixed_data = 0;
} buffer;

далее В) в строке 40 прописать

Wire.write((byte *) & buffer, sizeof(buffer));

далее  Г) везде, где Вы используете переменные flat, flon, current_course, speed, altitude и fixed_data заменить их на buffer.flat, buffer.flon, buffer.current_course, buffer.speed, buffer.altitude и buffer.fixed_data соответственно. Эти переменные даже не надо выискивать по тексту, просто запустите компиляцию, и компилятор радостно начнёт тыкать Вас в них носом, т.к. после нашего действия (Б) они окажутся неописанными. 

Когда Вы всё это проделаете, Ваша функция data_to_buffer перестала быть нужной вовсе. Можете выбрасывать и её саму и её вызов, но не всё так гладко, см. ниже.

Дело в том, что мы решили проблему №2 – убрали ужасную функцию и сократили размер и скорость работы программы, но мы не решили проблему №1. По-прежнему прерывание может прилететь в момент, когда наш новый буфер в раздрае со всеми вытекающими.

Решать её можно 100500 способами. Самый простой, это снова завести буфер для передачи. Описать его надо после описания структуры и выглядеть он может так:

byte buffer_to_send [sizeof(buffer)];

Тогда нынешнюю строку 40 запишем как

Wire.write(buffer_to_send, sizeof(buffer_to_send));

и вернём на место вызов функции data_to_buffer. Сама же функция data_to_buffer теперь будет вовсе не такой ужасной, как была у Вас, а всего лишь:

void data_to_buffer(void) {
    cli();
    memcpy(buffer_to_send, & buffer, sizeof(buffer_to_send));
    sei();
}

Вот и все дела. Скобки cli() - sei() предохраняют нас то того, чтобы отдать мастеру полуготовый буфер. Проблема №1 теперь тоже решена.

---------------

От 63-её строки и ниже я не смотрел. Поправьте пока то, о чём я написал, тогда и посмотрим.

b707
Offline
Зарегистрирован: 26.05.2017

ЕвгенийП - идеи те же, только лень было расписывать так подробно :)

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

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Это само собой - на той стороне также. Но здесь более критична проблема №1, а она от структуры не зависит. А сломать может всю систему на раз.

5N62V
Offline
Зарегистрирован: 25.02.2016

Други, спасибо, уже ушел курить структуры  и прочие неизвестные мне доселе memcpy, cli(), sei()

 

ЕвгенийП пишет:

1.  С буфером для передачи данных так работать нельзя

Вот смотрите. Функция slaveX вызывается по прерыванию, т.е. она может быть вызвана в любой момент. Теперь преставьте, что у Вас работает функция data_to_buffer. Часть данных она уже успела скопировать, а часть нет. Более того, она находится в процессе копирования конкретного числа (т.е. часть числа скопировалось, а часть ещё нет) и в этот самый момент прилетает прерывание. Что происходит? А ничего. Функция slaveTX радостно передаёт своему мастеру «полускопированные» данные. Мастер их получает этот сивокобылий бред и долго удивляется что курит Ваш скетч и какая зараза ему это продала. Проблема понятна?

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

Но I`ll be back! :)

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

5N62V пишет:

Ничего ужастного не происходит, проверено. 

Нет, не проверено. Для того, чтобы что-то ужасное произошло, нужно чтобы точно совпало время прерывания и работы с буффером. Это может происходить раз в неделю или в месяц, но происходить обязательно будет.

5N62V
Offline
Зарегистрирован: 25.02.2016

ЕвгенийП пишет:

Нет, не проверено. Для того, чтобы что-то ужасное произошло, нужно чтобы точно совпало время прерывания и работы с буффером. Это может происходить раз в неделю или в месяц, но происходить обязательно будет.

Я когда размышлял над этим, думал так:

пусть в худшем случае у нас функция slaveTX вызовется прямо во время копирования данных в buffer. Тогда часть буфера отправится с обновленными данными, а часть - со старыми. В силу небольшой скорости моего робота, изменение его координат за 0,2 секунды большим не будет, проэтому просохатить одно обновление координат ( одной или нескольких) вполне допустимо без печальных последствий, ДАЖЕ если прерывание произошло посередине копирования переменной. Возможно ли прерывание посередине копирования одного байта , что повалило бы целостность переменнойб я не знаю.

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

b707
Offline
Зарегистрирован: 26.05.2017

ЕвгенийП пишет:

Это само собой - на той стороне также. Но здесь более критична проблема №1, а она от структуры не зависит. А сломать может всю систему на раз.

К стыду. я проблему №1 даже не заметил. Для меня это дело новое, я с неатомарными операциями имел дело только в базах данных.

Не очень понимаю, как прерывание может помешать отправке константного (в масштабе времени передачи) буфера? Каазалось бы - ну прилетит в момент отправки буфера прерывание, отправка прервется на десяток микросекунд, а потом возобновится снова, разве не так? Вот если бы буфер за это время изменился - возникла бы проблема, а так не понимаю, в чем опасность.

b707
Offline
Зарегистрирован: 26.05.2017

5N62V пишет:

пусть в худшем случае у нас функция slaveTX вызовется прямо во время копирования данных в buffer.

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

5N62V
Offline
Зарегистрирован: 25.02.2016

b707 пишет:

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

Эмммм.....  кажется slaveTX  вызывается приходом запроса от мастера, то есть это абсолютно асинхронно с основным потоком.

b707 пишет:

Не очень понимаю, как прерывание может помешать отправке константного (в масштабе времени передачи) буфера? Каазалось бы - ну прилетит в момент отправки буфера прерывание, отправка прервется на десяток микросекунд, а потом возобновится снова, разве не так? Вот если бы буфер за это время изменился - возникла бы проблема, а так не понимаю, в чем опасность.

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

5N62V
Offline
Зарегистрирован: 25.02.2016

ЕвгенийП пишет:

От 63-её строки и ниже я не смотрел. Поправьте пока то, о чём я написал, тогда и посмотрим.

Я конечно талантлив, но с такими подробными инструкциями сложно было накосячить :))

Код теперь занимает на 118 байт меньше. Все работает! :))


#include <arduino.h>
#include <Wire.h>
//#include <TinyGPS.h>
#include <SoftwareSerial.h>

#define SLAVE_ADDRESS 4
#define DATA_LENGTH 19
#define DELAY 1

SoftwareSerial ss(2, 4); 

struct {
    float flat, flon, current_course, speed;
    unsigned int altitude;
    byte fixed_data = 0;
} buffer;

byte buffer_to_send [sizeof(buffer)];

byte text[100];  
//сюда считываем NMEA строку для последующего парсинга
bool new_data = 0;

void setup() {
  Serial.begin(38400);
  ss.begin(38400); 
  //GPS сконфигурирован под 38400, выдает только RMC и GGA
  Wire.begin(SLAVE_ADDRESS);
  Wire.onRequest(slaveTX);

}

void loop() {
  if (ss.available())  listen_uart();
  if(new_data)data_to_buffer();

}

void slaveTX() {
  //передаем buffer на мастер по i2c
  Wire.write(buffer_to_send, sizeof(buffer_to_send));
}

void data_to_buffer() {
  cli();
  memcpy(buffer_to_send, & buffer, sizeof(buffer_to_send));
  sei();
  new_data = 0;
}


void listen_uart() {
  if (ss.available() > 100) {
    while (ss.available())ss.read();
    return;
  }//если больше 100байт - очищаем все
  int i = 0;
  byte buff;

  do {
    buff = ss.read();
  } while (buff != 36);
  //читаем все до знака $

  delay(1);
  do {
    if(i>99)return;
    text[i++] = ss.read();
    delayMicroseconds(100);//ожидание прихода следующего байта
  } while (text[i - 1] != 42);
  //заполняем text[]прока не встретим *
  ss.read(); ss.read();//ложим болт на контрольную сумму

 for ( int k = 0; k < (i - 1); k++) {    Serial.print((char)text[k]);    Serial.print(" ");  }
  Serial.println();
//  ss.flush();
  new_data = 1;
  if (text[4] == 67) parse_rmc();
  if (text[4] == 65) parse_gga();
}

void parse_rmc() {
  byte count = 0;
  byte i = 0;


  do {
    if (text[i++] == 44) count++;
  } while (count < 2);
  text[i] == 65 ? buffer.fixed_data = 1 : buffer.fixed_data = 0;
  Serial.print("fixed_data = "); Serial.println(buffer.fixed_data);

  do {
    if (text[i++] == 44) count++;
  } while (count < 3);
  buffer.flat = parse_coords(i);
  Serial.print("flat = "); Serial.println(buffer.flat, 6);

  do {
    if (text[i++] == 44) count++;
  } while (count < 5);
  buffer.flon = parse_coords(i + 1);
  Serial.print("flon = "); Serial.println(buffer.flon, 6);

  do {
    if (text[i++] == 44) count++;
  } while (count < 7);
  buffer.speed = parse_speed(i);
  buffer.speed = buffer.speed * 1.852;
  Serial.print("speed = "); Serial.println(buffer.speed);

  do {
    if (text[i++] == 44) count++;
  } while (count < 8);
  buffer.current_course = parse_speed(i);
  Serial.print("current_course = "); Serial.println(buffer.current_course);

}

void parse_gga() {
  byte count = 0;
  byte i = 0;

  do {
    if (text[i++] == 44) count++;
  } while (count < 9);

  int n = -1;

  do {
    n++;
  } while (text[i++] != 46);

  i = i - n - 1;
  buffer.altitude = parse_value(i, n);
  //for( byte l = 0; l<n; l++)altitude+=(text[l+i]-48)*(unsigned int)(pow(10, n-l-1)+0.5);
  Serial.println(buffer.altitude);
}

long parse_value(byte i, byte n) {
  long value = 0;
  for (byte j = 0; j < n; j++) value = value * 10 + (text[i + j] - '0');
  return value;
}

float parse_coords( byte i) {
  float coord = 0;
  coord = parse_value(i, 2);
  float minutes = parse_value(i + 2, 2);
  float after_dot = parse_value(i + 5, 4);
  minutes = minutes + after_dot / 10000.;
  coord = coord + minutes / 60.;

  return coord;
}

float parse_speed(byte i) {
  if (text[i] == 44)return 0;

  int n = -1;
  float res = 0;
  byte j = i;

  do {
    n++;
  } while (text[j++] != 46);
  res = parse_value(i, n);
  res = res + (text[i + n + 1] - '0') / 10.;
  return res;
}

Только я в объявлении структуры bool  fixed_data = 0; заменил на byte. 

 

5N62V
Offline
Зарегистрирован: 25.02.2016

sadman41 пишет:

Избавьтесь от float - вот вам и память и скорость. 

Обязательно этим займусь, но позже. Просто на главном блоке управления тоже работала TinyGPS.h , пока я не стал менять приемник ЖПС. Теперь я ее выкинул, выгрызя из нее две интересующие меня функции : distanceBetween и directionTo .  А они сами float, и аргументы у них 4 штуки  float, вобщем надо будет засесть за математику, когда соберусь с духом.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

b707 пишет:

Не очень понимаю, как прерывание может помешать отправке константного (в масштабе времени передачи) буфера? Каазалось бы - ну прилетит в момент отправки буфера прерывание, отправка прервется на десяток микросекунд, а потом возобновится снова, разве не так? Вот если бы буфер за это время изменился - возникла бы проблема, а так не понимаю, в чем опасность.

Беда не в том, что прерывание прилетит во время отправки. Там все наоборот - отправка делается по прерыванию.

теперь представим себе было у нас честное целое число 255 (b0000000011111111). Теперь оно возросло на 1 и стало 256 (b0000000100000000). пошла перезапись буфера. Млаший байт успел перезаписаться, а старший не успел - прилетело прерывание и отправило буфер (с этим числом) мастеру. Что получит мастер? Совместим младший байт нового число и старший байт старого - правильно - 0 он получит. Нехилый такой скачок получился.

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

5N62V пишет:
ДАЖЕ если прерывание произошло посередине копирования переменной

Ну, Вам виднее к чему критичны Ваши алгоритмы, а к чему - нет. Посмотрите пост #17, я там привёл реалистичный пример большого скачка за раз.

5N62V
Offline
Зарегистрирован: 25.02.2016

ЕвгенийП пишет:

Ну, Вам виднее к чему критичны Ваши алгоритмы, а к чему - нет. Посмотрите пост #17, я там привёл реалистичный пример большого скачка за раз.

Да, я понял. Скорее всего это даже проявлялось в подергивании органов управления. Я замечал, было очень редко, но присутствовало. Будет прикольно, если проблема именно в этом! :)

sadman41
Offline
Зарегистрирован: 19.10.2016

Пожалуй, что работу с UART я бы изобразил как-то так (пишу по памяти, у ЕвгенияП наверняка кровь из глаз пойдет):

...
if (ss.available())
  buff = ss.read();
  case (buff) {
    switch '$':
      i = 0;
      break;
                     
    switch '*':
      if (text[4] == 'C') { parse_rmc(); }
      if (text[4] == 'A') { parse_gga(); } 
      break; 

    default:
      text[i] = buff;
      if (i < sizeof(text)) { i++; }   
  }
...

Справитесь с неблокирующим чтением порта - можно будет перейти к парсингу с использованием меньшего буфера. Ну и так, итерационно, пока от килограмма кода у вас не останется сияющая бриллиантовая однобайтовая инструкция, которая будет делать ВСЁ за один такт МК. 

b707
Offline
Зарегистрирован: 26.05.2017

ЕвгенийП пишет:

Беда не в том, что прерывание прилетит во время отправки. Там все наоборот - отправка делается по прерыванию.

 

Понятно. Спасибо за обьяснения.

Решение на поверхности - мастером должен быть передатчик :), тогда никакие половинки буфера не полетят :)

5N62V
Offline
Зарегистрирован: 25.02.2016

b707 пишет:

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

Так и есть. Код на приемнике стал короче раз в пять. Какая полезная штука эти структуры. :) ЕвгенийП, b707 - спасибо за дельные советы! 

void get_gps_data(){
 byte * ptr_coords = (byte *)(&coords);
//coords - имя структуры
   Wire.requestFrom(GPS_ADDR, sizeof(coords));
   delay(2);
   for (char i = 0; i<sizeof(coords); i++)  *(ptr_coords+i) = Wire.read();
}
sadman41
Offline
Зарегистрирован: 19.10.2016

5N62V пишет:

   for (char i = 0; i<sizeof(coords); i++) *(ptr_coords+i) = Wire.read();

Вопрос: что вы наловите в coords и куда поедет ваш боевой человекоподобный робот, eсли i2c-передатчик зависнет или отвлечется в процессе передачи (представьте, что в буфер Wire успела попасть только треть посылки).

5N62V
Offline
Зарегистрирован: 25.02.2016

Вопрос в каком контексте? Реализован ли у меня резервный канал приема координат, или знаком ли я с регулярным отвлечением передатчика i2c от выполнения своих обязанностей? По второму - нет , не знаком. Буду благодарен, если просветите. Вообще-то у меня блок управления общается ещё с пятью устройствами по этой же шине. Пока траблов не замечалось, хотя, как выясняется, организовываю я обмен далеко не наилучшим образом, мягко говоря. Касательно первого- да, дублирующий канал есть, пока только в железе, общаться будут по uart.

5N62V
Offline
Зарегистрирован: 25.02.2016

А, я понял, Вы про то, что в цикле тупо считывается 19 байт без проверки их наличия. Ну да, надо вставить проверку наличия именно 19 байт, если в течении какого-то времени их нет, то не принимаем и очищаем буфер. Спасибо!

sadman41
Offline
Зарегистрирован: 19.10.2016

Вопрос в контексте доверия к принятым данным. А точнее -  способа реализации приема при помощи for(). Загляните в Wire::read() - там несложно, представьте что будет, если в буфер Wire не успели попасть данные целиком, а вы уже их начали запрашивать этой функцией.