Это отвечает вашей проблеме:
При написании кода GetData()
печатает данные «Device ID», «Mode», «Temp» и «Bat» из ранее полученных данных, а не из самых последних полученных данных. Вот почему ваш первый набор данных - все нули; в первый раз все эти переменные все еще содержат свои исходные неинициализированные значения, которые, поскольку они статически размещаются в «глобальных данных», представляют собой все нули. И через секунду он печатает результаты, полученные из чтения first , что дает неверное значение для «идентификатора устройства» из-за дополнительного нуля в начале потоковый. Наконец, в третий раз он печатает данные, полученные при чтении second , что было хорошо.
Если вы просто переставите часть своего кода, он напечатает данные на основе самый последний образец. Я не пробовал компилировать и запускать его, но мне кажется, что это, вероятно, хорошая переписка, которая объединяет ваши DecodeString()
и GetData()
функции в одну функцию:
void DecodeString()
{
char x;
// scan the incoming data on the RX line
Unit.scanf("%s,",Data);
// translate the data from ASCII into int/float native types
// numbers in brackets is where the data starts in the string
deviceId = Ascii2Char(0);
Mode = Ascii2Char(3);
TempReading = Ascii2Float(6);
x = Ascii2Char(15);
battReading = (float)x/10;
// print the original unprocessed input string
pc.printf("%s,\n\r",Data);
// print what we translated
pc.printf("Device ID = %i\n\r", deviceId);
pc.printf("Mode = %i\n\r", Mode);
pc.printf("Temp = %.1f\n\r", TempReading);
pc.printf("Bat = %.1f\n\n\r", battReading);
}
Вы можете также получите лучшие результаты, если при запуске вы перенаправите sh ваш входящий поток данных (прочитайте и откажитесь от любого существующего буферизованного мусора), что может решить вашу проблему с дополнительным символом при первом чтении. Но если между обоими концами вашей линии связи есть условие запуска при запуске, вы можете обнаружить, что (возможно, иногда) ваш получатель начинает обрабатывать первую выборку в середине символов пакета, и, возможно, операция flu sh отбросила бы Первая часть пакета. Хотя первоначальный грипп sh является хорошей идеей, еще более важно иметь надежный способ проверки каждого пакета.
Это дополнительный комментарий о вашей ситуации:
В своем комментарии MartinJames прав, хотя, возможно, немного туповат. Последовательные потоки данных без четко определенных протокольных пакетов общеизвестно ненадежны, и регистрация данных через такой интерфейс может привести к ошибочным данным, что может иметь серьезные последствия, если вы проводите исследования или разработку результирующего набора данных. Более надежная система сообщений может начинать каждый «пакет» с известного символа или пары символов, так же, как полезный механизм resyn c: если ваш поток байтов выходит из-под синхронизации c, символ resyn c ( или пара) поможет вам быстро и легко вернуться в строй c. В вашем случае, поскольку вы читаете данные ASCII, это '\n'
или "\r\n"
, так что с этой точки зрения вы хороши, если вы действительно что-то делаете для запуска и остановки каждого образца данных на этих границах. Что произойдет, если вы получите образец данных, подобный этому? ...
01,03,CDCC1242,28,
01,03,CDCC1240,27,
01,03,CDCC1241,29,
01,03,CDCC1243,28,
01,03,CDCC123F,2A,
01,03,CD9,
01,03,CDCC1241,29,
01,03,CDCC1241,29,
01,0yĔñvśÄ“3,CDCC1243,28,
01,03,CDCC123F,2A,
01,03,CDCC1242,29,
Сможет ли ваш код повторно синхронизироваться c после примера, в котором пропущено несколько символов? Как насчет того, в котором есть мусор? Ваш код должен иметь возможность разбивать последовательный поток на части, начиная с одного символа (или пары) разделителя и заканчивая непосредственно перед следующим в последовательном потоке. И он должен исследовать символы между ними и проверять, что они «имеют смысл» каким-то образом, и быть способным отклонить любой образец, который не проверяет ОК. То, что он делает, может зависеть от потребностей вашего конечного потребителя данных: возможно, вы можете просто выбросить образец и все еще быть в порядке. Или, может быть, вам следует повторить последний хороший образец, пока не дойдете до следующего хорошего. Или, возможно, вам следует подождать до следующего хорошего и затем линейно интерполировать, чтобы найти разумные оценки того, какими должны быть данные между этими хорошими выборками.
В любом случае, как я уже сказал, вам нужен какой-то способ проверки каждый образец данных. Если длина «пакета» (выборки данных) может варьироваться, то каждый пакет должен содержать некоторое указание относительно количества байтов в нем, поэтому, если вы получаете больше или меньше, вы знаете, что пакет плохой. (Кроме того, если длина неоправданна, вы также знаете, что данные неверны, и вы не позволяете алгоритму сбора данных обмануть ошибочный байт, что ваш следующий пакет равен 1. 8 гигабайт в длину ... что, вероятно, приведет к sh вашей программе, так как ваш буфер приема не такой большой.) Наконец, должна быть какая-то система контрольных сумм для всех данных в пакете; 16-битная аддитивная контрольная сумма будет работать, но CR C будет лучше. Генерируя эти метаданные пакета на отправляющей стороне и проверяя их на принимающей стороне, вы (по крайней мере, с высокой вероятностью) гарантируете достоверность своего набора данных.
Но, как вы сказали, вы не можете контролировать формат передаваемых данных. И это позор; как сказал MartinJames, тот, кто разработал протокол, похоже, не понимал ненадежность простых последовательных потоков. Поскольку вы не можете это изменить, вам просто нужно приложить все усилия, чтобы найти некоторые эвристические методы для проверки данных; возможно, вы заставите свой код запомнить последние 5 выборок в массиве и сравнить каждый новый с последними 5 предполагаемыми действительными выборками; если вы получаете значение, которое находится за пределами разумного изменения из предыдущих примеров, вы выбрасываете его и ждете следующего. Или придумайте свою собственную эвристику. Просто убедитесь, что ваша эвристика не приведет к аннулированию всех будущих выборок, если фактическое измеренное значение изменяется слишком быстро.