не могу понять как работает функция sscanf

timur2008
Offline
Зарегистрирован: 06.03.2013

Здравствуйте. Помогите пожалуйста разобраться с функцией sscanf. Я пытаюсь с помощью этой функции распарсить строку "Raint3dNE;Raint-2dS" У меня должны части этой строки оказаться в разных переменных, а именно t1 = "Rain", temperature1 = "3", dir1 = "NE"  ,t2 = "Cloud", temperature2 = "-2", dir2 = "S" Прочитал описание данной функции, но всеравно ничего не понял :(

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

Вы уверены, что Вам нужна именно sscanf? Я. конечно могу показать как ввести Вашу строку, но эта функция чрезвычайно капризна. Она требует точного соответсвия формату. Любой лишний пробел или буква не втом регистре и всё сломается. Уверены? Да, и, кстати, где Вы там Cloud берёте?

timur2008
Offline
Зарегистрирован: 06.03.2013

аа ,извините немного ввел вас в заблуждение Cloud вместо второго Rain. Raint3dNE;Cloud-2dS Я просто не знаю как по другому распарсить строку такого типа. У меня вообще получается так {тип погоды}t{температура}d{направление ветра}; {тип погоды}t{температура}d{направление ветра} это типо погода утром и вечером. И нужно как то сохранить в переменные эти данные. Но вообще мне нужно как то передать ее на тридня вперед еще я думаю там все это в одну большую строку объеденить и получится чтото вроде:   {тип погоды}t{температура}d{направление ветра}; {тип погоды}t{температура}d{направление ветра}n{тип погоды}t{температура}d{направление ветра}; {тип погоды}t{температура}d{направление ветра}m{тип погоды}t{температура}d{направление ветра}; {тип погоды}t{температура}d{направление ветра}

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

timur2008 пишет:

Raint3dNE;Cloud-2dS

У меня вообще получается так {тип погоды}t{температура}d{направление ветра}; {тип погоды}t{температура}d{направление ветра} это типо погода утром и вечером. 

Ну, тогда, видим не "Raint3dNE;Cloud-2dS", а "Raint3dNE;Cloudt-2dS"

Кроме того, в "типе погоды" никогда не должна встречаться буква 't' - иначе она всё поломает. Например. тип погоды "буря" (Storm) - недопустим.

А скажите, откуда и куда Вы это передаёте. Т.е. откуда эта строка берётся (кто её передаёт) и кто её принимает. Сдайтся мне, что здесь проще вообще обойтись без передачи строк и без парсинга.

timur2008
Offline
Зарегистрирован: 06.03.2013

Я на C# написал прогу которая берет данные с сайта погоды парсит их а передает их ардуине через ком-порт. Там их уже ардуина получает и отображает на светодиодных матрицах. аа да не увидел там действительно t должна быть.

Penni
Penni аватар
Offline
Зарегистрирован: 18.01.2015

Проще и разумнее передавать ардуине уже готовые данные. Например, 1 байт - тип погоды, 2 байт - температура, 3 байт - направление ветра. Потом следующие данные так же и все.

timur2008
Offline
Зарегистрирован: 06.03.2013

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

Попробовал так сделать

char str[80];	
	char * teststring = "Raint3dNE;Raint-2dRain";
	int s = sscanf(teststring, "%st%sd%s;%st%sd%s", str[0], str[1],str[2],str[3],str[4],str[5]);

но чето тоже ничего не выводится :(

Потом дебажу что находится в str[0] , но там пусто :(

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

Памойму, там & нужен, перед переменными, куда пхать. Но могу и ашыбаца.

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

И не должно выводиться. 

Давайте всё-так подумаем, может ну его нафиг - строку передавать. Penni правильно говорит, лучше передавать двоичные данные.

Но если сильно хотите головной боли, могу и sscanf показать, но там всё непросто.

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

timur2008 пишет:

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

И чем же там ограничено число возможных символов?

Поймите, вам советуют, как это сделать легче. Поскольку вы передаете данные от одной программы к другой. вам совершенно незачем делать их "human readable" - то есть читабельными. Можно передавать их в виде байтов. Сначала определенная комбинация байт, означающая начало передачи - т.н. "заголовок", уникальная для вашей программы: например 0x07 0xBB 0x65.

 Приняв эти три байта, Ардуина будет знать, что дальше последуют погодные данные. Например 0x01 0x02 0x18 0x07 - датчик 1 (0x01), тип погоды 1 (0x01), температура 24.7 градусов (0x18 целых 0x07 десятых гр. С)

timur2008
Offline
Зарегистрирован: 06.03.2013

Хорошо давайте попробуем передавать побайтово,а это значит что мне получанные данные нужно будет сконвертировать в byte ? А потом их отправить , а как потом их обратно преобразовать ? ну чтобы понять колько градусов было или там направление ветра ?

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

timur2008 пишет:

Хорошо давайте попробуем передавать побайтово,а это значит что мне получанные данные нужно будет сконвертировать в byte ? А потом их отправить , а как потом их обратно преобразовать ? ну чтобы понять колько градусов было или там направление ветра ?

Обратно их преобразовывать не надо, у вас оператор Serial.read() как раз с байтами и работает

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

Блин, нахрена Вам вообще что-то ковертировать? Чего Вам так неймётся-то?

В каком виде Вы их получаете? Как целые переменные или как что?

timur2008
Offline
Зарегистрирован: 06.03.2013

да как строки из json  запроса. я там получается к вебсервису конекчусь а он мне структуру возвращает с данными строковыми.

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

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

Блин, нахрена Вам вообще что-то ковертировать? Чего Вам так неймётся-то?

Евгений. спокойнее :)

Видите, человек вообще не в зуб ногой. чтотакой байты. а что строки... но при этом программу на С# написал...

Клапауций 112
Клапауций 112 аватар
Offline
Зарегистрирован: 01.03.2017

b707 пишет:

программу на С# написал...

спиздил дохлую лошадь и притащил сюда

timur2008
Offline
Зарегистрирован: 06.03.2013

да нет что такое байты и строки я понимаю вроде , каждый символ представляет собой набор байтов, и все :( Только дальше до меня всеравно не доходит , ну я данные вот так получаю

if (Serial.available() > 0)
	{

		counts++;
		// считываем полученное с порта значение в переменную
		incomingChar = Serial.read();
		full += incomingChar;
	}

когда считывание прекращается срабатывает другая ветка условия где обрабатывается  то что хранится в переменной full

Хмм на шарпе я отправляю данные вот так

currentPort.Write(new byte[] { 0xa0,0xa1,0xa2},0,2); 

а потом получаю в ардуине их вот так

if (incomingChar == 0xa0)
		{
			zero(1, 1);
		}

zero это функция которная ноль рисует на матрице, но у меня почемуто не отрабатывает :( Что я не так делаю? аа все понял не увидел , сравнивал byte а там оказывается в int преобразовалось. Хмм интересно.

MaksVV
Offline
Зарегистрирован: 06.08.2015

хоть я и дилетант, но вдруг поможет. Это как предложил b707 в сообщении #9. Сразу предупреждаю что код быдловатый и не проверен.

Две ардуино общаются по Софт сериалу. Для контроля у обоих всё выводится в хард Сериал монитор. 

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

Скетч передачи 

#include <SoftwareSerial.h>

SoftwareSerial mySerial(7, 8); // RX, TX

byte MessageTx[10] = {0}; // массив передаваемого сообщения 
int Weather = 1;  //тип погоды например



void setup() {
MessageTx[0]= 0x23; // байты заголовка 
MessageTx[1]=0xA1;
MessageTx[2]=0x04;
 
mySerial.begin (9600);
Serial.begin (9600);
}

void loop() {
 
// забиваем в массив нужные параметры, например в байт 3 тип погоды:
 MessageTx[3] = Weather;  // остальное по этому примеру

 // считаем контрольную сумму 
 int CRC = 0;
 for (int i = 0; i < 9; i++) CRC = CRC + MessageTx[i];    
MessageTx[9] = CRC;   // забиваем в последний байт значение контрольной суммы

for (int i = 0; i < 10; i++) { mySerial.write(MessageTx[i]); // отправляем сообщение в софтсериал
Serial.print(MessageTx[i],HEX); Serial.print ("  ");}              // и напечатаем в сериал монитор, что мы отправили
 Serial.println("");

 delay (3000);


}

 Скетч приема. Ждёт пока получит заголовок и далее парсинг. Если в итоге CRC совпадает, чтонибудь делаем. 

#include <SoftwareSerial.h>

SoftwareSerial mySerial(7, 8); // RX, TX

bool MessageParse = 0;     // флаг распарсено ли сообщение
int numberbyte = 0;         //номер байта в массиве
bool MessageEND = 0;       // флаг что все байты записаны в массив
bool MessageBegin = 0;     // флаг принят ли правильный заголовок сообщения
byte byte0 = 0;            // байты заголовка 
byte byte1 = 0;
byte byte2 = 0;

byte MessageRx[7] = {0}; // массив принимаего сообщения, состоящий из 7 байт, т.к. первые три байта это заголовок
int waitbyte = 1;         // задержка в приемё байт, 1 мс, может и не понадобится 


void setup() {
 
mySerial.begin (9600);
Serial.begin (9600);

}

void loop() {

MessageParse = false;
while (!MessageParse) {

// тут определяем наличие заголовка, если наш - то парсим дальше
 if (!MessageBegin) {   
     if (mySerial.read() == 0x23) {byte0=1; delay (waitbyte); }    
     if (mySerial.read() == 0xA1 && byte0) {byte1=1; delay (waitbyte);}
     else byte0=0;
     if (mySerial.read() == 0x04 && byte0 && byte1) {byte2=1; delay (waitbyte);}
     else {byte0=0; byte1=0;}
     if (byte0 && byte1 && byte2) {MessageBegin = true; byte0=0; byte1=0; byte2=0;}
     numberbyte=0;}

 else { // именно тут дальше начинается парсинг, если принят правильный заголовок, то записываем в массив остальные байты

   if (mySerial.available()>0)  { MessageRx[numberbyte] = mySerial.read(); numberbyte++; delayMicroseconds (250);} // задержка может и не понадобиться
      
      if (numberbyte==7) {MessageEND = 1; MessageBegin = false;}
     
     }
      

   if (MessageEND) { 
    int crc =  MessageRx[6]; // контрольной сумма будет это последний байт сообщения
    int CRC = 0xC8; // это сумма первых трех байт "заголовока" ,т.е 0x23+0xA1+0x04 
    for (int i = 0; i < 6; i++) CRC = CRC + MessageRx[i];                 // подсчет контрольной суммы байт от 0 до 5

    Serial.print ("                         Receive:   ");
    for (int i = 0; i < 7; i++) {                     // распечатаем в сериал монитор принятое сообщение 
    Serial.print(MessageRx[i],HEX); Serial.print (" ");}
 

    if (CRC==crc) {Serial.println ("    OK!!!");  // если контрольные суммы совпадают, то делаем нужные нам вещи
    
// Тут что то делаем, если получаем правильное сообщение 

    }
    
  else Serial.println ("    ERROR!!!");   // если сообшение  с ошибкой сообщим в сериал монитор
   MessageEND = false; MessageParse = true; //mySerial.flush();

    for (int i = 0; i < 7; i++) MessageRx[i]=0; // очистка байтов массива
    }}

}