Передача данных DHT датчика с одной ARDUINO на другую посредством радиоканала (433,92) и последующий анализ данных.

archii
Offline
Зарегистрирован: 28.09.2015

Добрый день, уважаемые форумчане.

Не могу преобразовать данные в число для послед. анализа, полученные из буфера другой ардуинки по RC-каналу:

От ардуины с датчиком DHT по радиоканалу на приемник другой ардуинки приходит строка вот в таком виде /22.5/40.8

Далее через сериал порт эта строка посимвольно формируется на экране с помощью след функции: 

	
	uint8_t buf[VW_MAX_MESSAGE_LEN];
    uint8_t buflen = VW_MAX_MESSAGE_LEN;
	
	if (vw_get_message(buf, &buflen)) // Non-blocking
    {
        int i;
  		//Serial.print("Got: ");       
		for (i = 0; i < buflen; i++)
        {
           Serial.print((char)buf[i]);
        }
      Serial.println(" ");
	}

и выглядит точно также:   /22.5/40.8

Собственно вопрос: Как мне создать две float (наверное) переменные со след. значениями:

rcTemp с числовым значением 22.5 и rcHum с числовым значением 40.8, чтоб можно было эти переменные использовать в дальнейшем, например, для включения реле и тп?

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

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015
Действительно, случай тяжёлый:
 
char *s = "/24.5/5.5";
double a = atof(s+1);
double b = atof(s+6);
 
Результат:
a=24.500000 b=5.500000
archii
Offline
Зарегистрирован: 28.09.2015

В том то и дело, не получается присвоить char *rBuf = buf ни так, ни так char *rBuf = 'buf' . Второй вариант, просто стрка из 3 симолов присвается. 

void loop() {
	
	
	
	uint8_t buf[VW_MAX_MESSAGE_LEN];
    uint8_t buflen = VW_MAX_MESSAGE_LEN;
	
	if (vw_get_message(buf, &buflen)) // Non-blocking
    {
        int i;
        digitalWrite(13, true); // Flash a light to show received good message
        // Message with a good checksum received, dump it.
        //Serial.print("Got: ");       
		// for (i = 0; i < buflen; i++)
		char *rBuf = buf;
		double tempBuf = atof(s+1);
		double humBuf = atof(s+6);
		Serial.println(tempBuf);
		Serial.println(humBuf);
		//Serial.println(" ");
        digitalWrite(13, false);
    }
}

В данном варианте ругается на ошибку: 

 
sketch_oct02a:64: error: invalid conversion from 'uint8_t*' to 'char*'
sketch_oct02a:65: error: 's' was not declared in this scope
Вторая говорит о том что не описана переменная масива, а первая, что не может сконвертировать uint8_t в char.
 

 

 

archii
Offline
Зарегистрирован: 28.09.2015

Было бы здорово еще ссылку на мой вопрос, где почитать о конвертации типов данных можно. Гуглу даже вопрос сформировать не получается правильно. Помогите разобраться.

Или может зря отключил цикл for (i = 0; i < buflen; i++

archii
Offline
Зарегистрирован: 28.09.2015

Это наверное мой случай)) Но просто так не сдамся)))

maksim пишет:

 Вы перестаньте дергаться между темами и по нормально во всем разберитесь. Вы выбрали путь когда вам нужно данные с датчика разбить по байтам и отправить. vxl выбрал путь преобразования данных в коды АСКИ и передачи. Скажу сразу первый вариант хоть и сложнее, но более правильный.

blackhand пишет:

это нерабочий код

byte b;
const byte *msg = b;

И так, почему ругается компилятор?
Первая причина в том, что вы пытаетесь присвоить константе переменную. Давайте разберемся, что же не так. Рассмотрим на примере пластилина, то есть его можно как угодно мять. Вы компилятор. Вот у вас два одинаковых куска пластилина. Операция присваивания "=" означает, что нужно взять один кусок пластилина и сделать его такой же формы как и другой. Вам говорят: "приствойте пластилин А к пластилину В"

byte A;
byte B = A;

вы берете и мнете, все нормально, сделали.
Константа - это кусок твердого пластилина, замороженный пластелин. И вам говорят: "сделайте кусок замерзшего пластилина А такой же формы как и В.

byte A;
const byte B = A;

Что же вы ответите на это? Я не могу! Он твердый! Руки больно! Вот и компилятор не может присвоить константе переменную.

Вторая причина - это то что вы пытаетесь указателю присвоить переменную.

byte A;
byte *B = A;

Указатель это всего лишь адрес массива. Вам говорят сделайте пластилин формой Россия г. Москва, ул.Тверская дом 1. Вы понимаете что такое форма куба, форма шара и т.д. но как форма может быть адресом??? Это как вообще такое возможно??? Да никак. Вот по этой причине и ругается компилятор. 

Что бы привоить массиву переменную нужно обратиться к элементу массива

byte A;
byte *B;

где нибудь в функции:

B[0] = A;

Или можно указателю присвоить адрес переменной

byte A;
byte *B = &A;

 

 

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

archii пишет:

В том то и дело, не получается присвоить char *rBuf = buf ни так, ни так char *rBuf = 'buf' . Второй вариант, просто стрка из 3 симолов присвается. 

void loop() {
	
	
	
	uint8_t buf[VW_MAX_MESSAGE_LEN];
    uint8_t buflen = VW_MAX_MESSAGE_LEN;
	
	if (vw_get_message(buf, &buflen)) // Non-blocking
    {
        int i;
        digitalWrite(13, true); // Flash a light to show received good message
        // Message with a good checksum received, dump it.
        //Serial.print("Got: ");       
		// for (i = 0; i < buflen; i++)
		char *rBuf = buf;
		double tempBuf = atof(s+1);
		double humBuf = atof(s+6);
		Serial.println(tempBuf);
		Serial.println(humBuf);
		//Serial.println(" ");
        digitalWrite(13, false);
    }
}

В данном варианте ругается на ошибку: 

 
sketch_oct02a:64: error: invalid conversion from 'uint8_t*' to 'char*'
sketch_oct02a:65: error: 's' was not declared in this scope
Вторая говорит о том что не описана переменная масива, а первая, что не может сконвертировать uint8_t в char.
Не понимаю проблемы. Вместо 
char *rBuf = buf;

Пишем

char *rBuf = (char *) buf;

и всего делов. Только не понимаю для чего это. Почему не использовать прямо buf в atof. Там можно точно также преобразовать тип, как я здесь написал.

Ну, а про s - правильно, откуда у Вас s, если она у Вас называется rBuf?

 

archii
Offline
Зарегистрирован: 28.09.2015

Спасибо за наводку, Евгений.  Теперь я получил 2 значения температуры и влажности вот таким образм. (эквивалент Вашему, выше предложенному варианту) вот такой строкой:

char s1[5] = {buf[1], buf[2], buf[3], buf[4], '\0'} ;
char s2[5] = {buf[6], buf[7], buf[8], buf[9], '\0'} ;
Serial.println(s1);
Serial.println(s2);

В итоге я получил строку s1 с символами пусть 22.2 и строку s2 с символами 33.3 

Как мне получить  s1+s1=44.4 или s1+s2=55.5? Компилятор не даст выполнить эту операцию со строками, как я понимаю. Как мне char (строку) перевести в цифру 22.2, чтоб я cмог дальше выполнить след условие.: 

if (s1>0)
{digitalWrite(ledPin, HIGH);}
else
{digitalWrite(ledPin, LOW);}

 

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

archii пишет:

Спасибо за наводку, Евгений.  Теперь я получил 2 значения температуры и влажности вот таким образм. (эквивалент Вашему, выше предложенному варианту) вот такой строкой:

char s1[5] = {buf[1], buf[2], buf[3], buf[4], '\0'} ;
char s2[5] = {buf[6], buf[7], buf[8], buf[9], '\0'} ;
Serial.println(s1);
Serial.println(s2);

В итоге я получил строку s1 с символами пусть 22.2 и строку s2 с символами 33.3 

Как мне получить  s1+s1=44.4 или s1+s2=55.5? Компилятор не даст выполнить эту операцию со строками, как я понимаю. Как мне char (строку) перевести в цифру 22.2, чтоб я cмог дальше выполнить след условие.: 

if (s1>0)
{digitalWrite(ledPin, HIGH);}
else
{digitalWrite(ledPin, LOW);}

Какой эе это эквивалент? Я же Вам писал как преобразовать их к числам, а не к строкам

double as1 = atof((char *) buf+1);
double as2 = atof((char *) buf+6);

Теперь as1 и as2 - числа, а не строки. Надо Вам их сложить, ну и складывайте as1+as2

 

archii
Offline
Зарегистрирован: 28.09.2015

ДА! То, что доктор прописал. Спасибо!

double as1 = atof((char *) buf+1);
double as2 = atof((char *) buf+6);
float as3 = as1 + as2;

Serial.println(as1);
Serial.println(as2);
Serial.println(as3);

Действительно все работает. 

Но подозреваю, что при передаче вместо строки /22.2/33.3 , с которой Вы помогли мне разобраться, например /-2.2/33.3 или /2.2/33.3 меня ждет сюрприз?))) Из-за того что температура будет не в десятках, т.е. не двухзначным числом, а односзначным. А с минусом и предположить сложно )))... НО все-равно спасибо, помогли новичку. 2 выходных убил изучая типы данных, но так и не осилил.

Возникли вопросы: 

1. Почему double , а не float

2. С этой строкой не все понятно. Про atof прочел на вики, а вот ((char *) buf+1) ???

Как я понимаю char* сформировал строку с некотороми символами неопределенной длины, допустим 0123456789... buf+1 указывает на то, что мне нужно начать читать эту строку со второго символа (и читает он ее так 123456789...), а как он определил длину в 4 символа? Именно тип данных double определил, что это будет 4 символа (4 байта это 1234), так 

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

archii пишет:
Но подозреваю, что при передаче вместо строки /22.2/33.3 , с которой Вы помогли мне разобраться, например /-2.2/33.3 или /2.2/33.3 меня ждет сюрприз?)))

Никаких сюрпризов, всё как должно быть:

/-2.2/33.3 – результат -2,2 и 33,3

/2.2/33.3 – результат 2,2 и 3,3

Обратите внимание на второй результат. Вы, видимо не этого хотите.

Пераметр функции atof – адрес с которого начинается число. В случае второго примера число 33,3 начинается с пятого символа, а мы пишем шестой, значит первая тройка будет проигнорирована.

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

archii пишет:
1. Почему double , а не float

Потому что результат функции atof – double. Можете написать float – преобразуется. При этом компилятор может, конечно ругнуться на потерю точности, но это будет предупреждение, а не ошибка. Чтобы не ругался надо преобразовать тип явно.

archii пишет:

2. С этой строкой не все понятно. Про atof прочел на вики, а вот ((char *) buf+1) ???

Как я понимаю char* сформировал строку с некотороми символами неопределенной длины, допустим 0123456789... buf+1 указывает на то, что мне нужно начать читать эту строку со второго символа (и читает он ее так 123456789...), а как он определил длину в 4 символа? Именно тип данных double определил, что это будет 4 символа (4 байта это 1234), так ? 

Нет.

buf+1 – означает, что Вас интересует строка, начиная с первого символа (они с нулевого нумеруются).

buf+6 – означает, что Вас интересует строка, начиная с шестого символа (они с нулевого нумеруются).

 (char *) ничего не формирует. Он вообще ничего не делает. У Вас ведь buf имеет тип uint8_t *. Так? А функции atof нужен тип char *. Если ничего не делать, то компилятор ругается на несоответсвие типов – Вы это видели.Так вот выражение (char *) не делает ничего, оно лишь говорит компилятору, что мол «знаю, что тебе нужен тип char * - так вот не парься и считай, что там char * и есть». Компилятор это проглатывает и спокойно работает.

Длину в 4 символа никто никак не определял. atof читает столько символов, сколько есть, пока там идёт что-то похожее на число. Как только там встретится то, что не может быть числом – она останавливается. Попробуйте 1234.56789A – она благополучно схавает до 9 включительно, а на A останвится. Результат: 1234.56789

archii
Offline
Зарегистрирован: 28.09.2015

Спасибо... Буду двигаться дальше. Все вопросы буду задавать в этой теме.

archii
Offline
Зарегистрирован: 28.09.2015

Все собрал, выяснилась следующая проблема:

Радиус действия совсем маленький. В прямой видимости данные передаются максимум на 2 метра. Это с припаянными антенками по 17,3 см. Как я понимаю на ресивер и на приемник можно подать большее напряжение (на трансмиттер - 12В, а на ресивер 5В), чтоб увеличить дальность?

Питание на трансмитер и ресивер подаю только с самой ардуины. Наверное этого не достаточно.

Подчищу код и выложу сюда оба скетча (R/T). Возможно там накосячил.

vitalikost
Offline
Зарегистрирован: 28.11.2014

Игрался с этим чудом, больше 2 метров по прямой не работало. Стабильно работало, то расстояние не больше 50 см. что очень мало. Подавать больше питания пока не пробивал, если у Вас есть возможность — это сделать, то о результате отпишитесь. Спасибо!

archii
Offline
Зарегистрирован: 28.09.2015

Ок, но в городе и в поле - разница доже должна быть. 433 частота там чище, в поле)) Тему буду продолжать.