Как правильно соединить char + char? или string + char?

Dr_grizzly
Dr_grizzly аватар
Offline
Зарегистрирован: 07.12.2015

Добрый день! Понимаю что вопрос избитый, но прокопал инет и форумы, так и не прийдя к общему знаменателю... Вообщем работаю с модулем Sim900. Приведу небольшой кусок кода для разбора полета:

const char* Tel[] = {"891257*****", "891297*****", "891958*****" };
char Tel1[13] = "+791257*****";
char Tel2[13] = "+791297*****";
char Tel3[13] = "+791958*****";

byte CheckSignal() {
  byte result = 99;
  char gprsBuffer[21];
  sim900_clean_buffer(gprsBuffer, 21);
  char *s;
  sim900_send_cmd("AT+CSQ\r\n");
  sim900_read_buffer(gprsBuffer, 21, 5);
  if (NULL != ( s = strstr(gprsBuffer, "+CSQ: "))) {
    result = atoi(s + 6);
    sim900_wait_for_resp("OK\r\n", CMD);
  }
  return result;
}

bool sms_text(String txt) {   // А если не String а Char? то дальше как с этим работать?
  Serial.println("AT+CMGS=\"" + String(Tel1) + "\""); //  Можно ли оптимизировать не используя String?
  delay(1000);
  Serial.println(txt);
  delay(200);
  Serial.println((char)26);
  delay(200);
  delay(10000);
  Serial.println("AT+CMGS=\"" + String(Tel2) + "\"");
  delay(200);
  Serial.println(txt);
  delay(200);
  Serial.println((char)26);
}

  if (NULL != (strstr(inputString, "+CLIP:"))) {
    
      numtel = 0;
      if (NULL != (strstr(inputString, Tel1))) {
        numtel = 1;
      }
      if (NULL != (strstr(inputString, Tel2))) {
        numtel = 2;
      }
      if (NULL != (strstr(inputString, Tel3))) {
        numtel = 3;
      }
      if (numtel > 0) {      
        sim900_check_with_cmd("ATA\r\n", "OK\r\n", CMD);
      }
}

 if (digitalRead(pwr_st) == HIGH) {  
        sms_text("Last telephone: " + String(Tel[lastcomm]) + "; 220B OK; SigGSM=" + String(Signal)); // вот тут и возникает проблема, то полностью строка отправляется, то начиная с  "; 220B OK; SigGSM=" а первая часть куда-то теряется
      }

Может для такой задачи есть вариант уйти от String? Микроконтроллер Ardu Mini и думаю что не хватает ему ОЗУ для работы со строками...

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

Ну, во-первых, никогда не передавайте объекты String по значению, за исключением тех случаев, когда Вы точно знаете что делаете и зачем Вам это нужно (подробности в раделе "1. Неоправданная передача параметра функции по значению")! Вам достаточно в строке 20 добавить один символ "&" после слова String, как Вашей памяти сразу и намного полегчает!

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

Dr_grizzly
Dr_grizzly аватар
Offline
Зарегистрирован: 07.12.2015

Хорошая статья, почитаю завтра))  А символ & после String что означает? И если работать только с char, то сильно усложнит код написания?

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

Dr_grizzly пишет:

Хорошая статья, почитаю завтра))  А символ & после String что означает? 

Вот завтра и узнаете.

Dr_grizzly пишет:

И если работать только с char, то сильно усложнит код написания?

"усложнит" - оценочное понятие - кому как. По мне, так существенно  упростит, потому что всё в своих руках и не надо постоянно думать, что там понаписали авторы класса String.

 

Penumbra
Offline
Зарегистрирован: 06.08.2017

вот меня, как юного ардуинщика,  тоже интересует вопрос в из заголовка топика  про char+char

у мну есть функция 

int8_t sendATcommand(char* ATcommand, char* expected_answer, unsigned int timeout)
{..бла бла бла..
}

мне надо ее вызвать чемто типа

sendATcommand("AT+CSTT= \"" + ModemAPN + "\",\"" + ModemUSR + "\",\"" + ModemPWR + "\"", "OK",   30000)

где



char  ModemAPN [20];
char  ModemUSR [10];
char  ModemPWR [10];

PS тяжело переходить с BASCOMAVR на С

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

Ну, разумеется никаких плюсов. Погуглите strcat и strcpy

Penumbra
Offline
Зарегистрирован: 06.08.2017

ура! спасибо великому гуглу! танцам с бубном и паре выкуренных сигарет из мануалов

    char str1[70];
    strcpy (str1, "AT+CSTT=\"");
    strcat (str1, ModemAPN);
    strcat (str1, "\",\"");
    strcat (str1, ModemUSR);
    strcat (str1, "\",\"");
    strcat (str1, ModemPWR);
    strcat (str1, "\"");
sendATcommand2(str1, "OK",  30000);

работает))

brokly
brokly аватар
Offline
Зарегистрирован: 08.02.2014

Penumbra пишет:

ура! спасибо великому гуглу! танцам с бубном и паре выкуренных сигарет из мануалов

    char str1[70];
    strcpy (str1, "AT+CSTT=\"");
    strcat (str1, ModemAPN);
    strcat (str1, "\",\"");
    strcat (str1, ModemUSR);
    strcat (str1, "\",\"");
    strcat (str1, ModemPWR);
    strcat (str1, "\"");
sendATcommand2(str1, "OK",  30000);

работает))

А теперь почитайте что нить про p_strcpy.

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

brokly пишет:

А теперь почитайте что нить про p_strcpy.

а чем strcpy плоха

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

Penumbra пишет:

ура! спасибо великому гуглу! танцам с бубном и паре выкуренных сигарет из мануалов

    char str1[70];
    strcpy (str1, "AT+CSTT=\"");
    strcat (str1, ModemAPN);
    strcat (str1, "\",\"");
    strcat (str1, ModemUSR);
    strcat (str1, "\",\"");
    strcat (str1, ModemPWR);
    strcat (str1, "\"");
sendATcommand2(str1, "OK",  30000);

работает))

Учитывая, что и strcpy, и strcat вовращаю адрес получившейся строки, можно написать тоже самое  и так (не уверен. что это лучше, но просто, чтобы Вы знали):

strcat(strcat(strcat(strcat(strcat(strcat(strcpy(str1, 
     "AT+CSTT=\""), ModemAPN), "\",\""), ModemUSR), "\",\""), ModemPWR), "\"");

 

Penumbra
Offline
Зарегистрирован: 06.08.2017

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

Penumbra пишет:

ура! спасибо великому гуглу! танцам с бубном и паре выкуренных сигарет из мануалов

    char str1[70];
    strcpy (str1, "AT+CSTT=\"");
    strcat (str1, ModemAPN);
    strcat (str1, "\",\"");
    strcat (str1, ModemUSR);
    strcat (str1, "\",\"");
    strcat (str1, ModemPWR);
    strcat (str1, "\"");
sendATcommand2(str1, "OK",  30000);

работает))

Учитывая, что и strcpy, и strcat вовращаю адрес получившейся строки, можно написать тоже самое  и так (не уверен. что это лучше, но просто, чтобы Вы знали):

strcat(strcat(strcat(strcat(strcat(strcat(strcpy(str1, 
     "AT+CSTT=\""), ModemAPN), "\",\""), ModemUSR), "\",\""), ModemPWR), "\"");

 

а это я знаю)) просто у меня чуть мозг не сфихнулся от подсчитывания скобочек )) в столбик наглянее))

а вот про p_strcpy  я нефига не нашел...

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

Penumbra пишет:

а вот про p_strcpy  я нефига не нашел...

Это у коллеги опечатка. Правильно strcpy_P (правда, сейчас Atmel рекоммендует использовать strcpy_PF).

Это функции для копирования строк из PROGMEM.

Вообще, сделайте закладку на атмеловскую документацию - не раз поможет. В первый раз прочитайте более или менее всё, чтобы знать что там есть, а потом используйте как справочник.

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

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

Это у коллеги опечатка. Правильно strcpy_P

ну вот, а я тоже полГугля перерыл. Кстати, есть такая p_strcpy или pstrcpy в некоторых версиях Си - та же самая strcpy, только "безопасная" - проверяет результат на переполнение, вроде

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

b707 пишет:

только "безопасная" - проверяет результат на переполнение, вроде

стандартная безопасная функция здесь strcpy_s

Dr_grizzly
Dr_grizzly аватар
Offline
Зарегистрирован: 07.12.2015

Если я правильно понял, то у меня получилось такая фукнция:

bool sms_text(String& txt) {

}

Передаю в нее строковое значение

sms_text("Power 220B OK!");  

на что получаю сообщение компилятора:

invalid initialization of non-const reference of type 'String&' from an rvalue of type 'const char*'

1) В чем разница между String& и String* ?

2) Как лучше обойти ошибку компилятора? привести к char или оставить строку?

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

Dr_grizzly пишет:

1) В чем разница между String& и String* ?

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

Dr_grizzly пишет:

2) Как лучше обойти ошибку компилятора? привести к char или оставить строку?

Непонятно что Вам надо. Передать ссылку, ну так создайте объект и передавайте.

String kaka = "Power 220B OK!";
sms_text(kaka);

 

 

Dr_grizzly
Dr_grizzly аватар
Offline
Зарегистрирован: 07.12.2015

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

Сейчас переписал функции таким образом:

bool sms_text(char* txt) {
  
  digitalWrite(13, HIGH);

  sim900_send_cmd("AT+CMGS=\"");
  sim900_send_cmd(Tel1);
  sim900_send_cmd("\"");
  
  delay(1000);
  Serial.println(txt);
  delay(200);
  Serial.println((char)26);
  delay(200);
  delay(10000);
  sim900_send_cmd("AT+CMGS=\"");
  sim900_send_cmd(Tel2);
  sim900_send_cmd("\"");
  delay(200);
  Serial.println(txt);
  delay(200);
  Serial.println((char)26);
  delay(200);
  digitalWrite(13, LOW);
}

void loop {
........
 if ((digitalRead(pwr_st)==HIGH) && (SendSmsSt==false))  { // Если от сети
  if (GPRSOnline==true) {
   char pwm="Power 220B OK!";
   sms_text(pwm);    
   SendSmsSt=true;
  }
 }
.............
if ((digitalRead(pwr_st)==LOW) && (SendSmsA==false))  { // Если от сети
  if (GPRSOnline==true) {
   char alm1="Alarm!!! HET 220B!";
   sms_text(alm1);    
   SendSmsA=true;
  }
 }
..........
  if (GPRSOnline==true) {
      char flsend[60];
      strcpy (flsend, "Last telephone: "); 
      strcpy (flsend, Tel[lastcomm]); 
      strcpy (flsend, "; 220B OK; SigGSM=");       
      if (digitalRead(pwr_st) == HIGH) {
        strcpy (flsend, "; 220B OK; SigGSM="); 
      } else {
        strcpy (flsend, "; HET 220B; SigGSM="); 
      }
      strcpy (flsend, Signal); 
      sms_text(flsend);
    }

}

Вот таким образом следуя инструкциям, вроде все объявления переменных заключены в скобках {}, если я правильно все понял, то после закрытия скобок память будет освобождаться. Вот только еще момент - объявил переменную char flsend[60];  указав размер 60, чуть больше чем требуется, + 5-7 байт. Этот хвост не помешает правильному выполнению? Мусора там не будет? И хочется еще раз Ваше заключение )

P.S. нашел книгу Страуструпа "Программирование. Принципы и практика с использованием C++" это про нее Вы говорите?

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

Dr_grizzly пишет:

На столько озадачен экономией ОЗУ у Мини, что хочется выбрать код,чтобы сэкономить эту память.

В таком случае от String избавляйтесь целиком и полностью. Если не поможет, можно символьные константы перенести в память программы (если её хватает).

Ваш код не полный и я, например, не вижу как описана переменная Signal, которая используется в 54 строке.

Dr_grizzly пишет:

чуть больше чем требуется, + 5-7 байт. Этот хвост не помешает правильному выполнению? 

Не помешает.

Dr_grizzly пишет:

Мусора там не будет?

Будет, но не помешает.

Dr_grizzly пишет:

P.S. нашел книгу Страуструпа "Программирование. Принципы и практика с использованием C++" это про нее Вы говорите?

Я имел в виду вот эту.

Не понял строк 46-48 и 50б 52 и 54.

Во них всех Вы копируете в начало массива flsend, т.е. в строке 47 Вы затираете то, что записали в строке 46, в строке 48 затираете то, что записали в строке 47 и т.п.

 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Как говорится научи д***а молится , так он и голову разобъет. http://cppstudio.com/post/695/

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

ПС: Извините что влез в ваш обучающий процесс.

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

Dr_grizzly пишет:

объявил переменную char flsend[60];  указав размер 60, чуть больше чем требуется, + 5-7 байт. 

зачем?

Dr_grizzly
Dr_grizzly аватар
Offline
Зарегистрирован: 07.12.2015
Цитата:
Не понял строк 46-48 и 50б 52 и 54.

Во них всех Вы копируете в начало массива flsend, т.е. в строке 47 Вы затираете то, что записали в строке 46, в строке 48 затираете то, что записали в строке 47 и т.п.

Как я понял из примера выше strcat соединяет char строки в один массив... разве не? )) (тогда пример был не верен??)Я попытался у себя реализовать это же. Объявить массив, собрать в него данные в зависимости от текущих состояний портов, и послать их в виде смс.


byte Signal = 0; //запись уровня сигнала в глобальную

 Signal = CheckSignal(); // вызов в loop цикле

byte CheckSignal() {
  byte result = 99;
  char gprsBuffer[21];
  sim900_clean_buffer(gprsBuffer, 21);
  char *s;
  sim900_send_cmd("AT+CSQ\r\n");
  sim900_read_buffer(gprsBuffer, 21, 5);
  if (NULL != ( s = strstr(gprsBuffer, "+CSQ: "))) {
    result = atoi(s + 6);
    sim900_wait_for_resp("OK\r\n", CMD);
  }
  return result;
}

Т.е в массиве flsend я жду строку "Last telephone: +79128111111; 220B OK; SigGSM=15,6"

 

Пока писал увидел косяк )) 48 строка лишняя )))))

Dr_grizzly
Dr_grizzly аватар
Offline
Зарегистрирован: 07.12.2015

Клапауций 112 пишет:

Dr_grizzly пишет:

объявил переменную char flsend[60];  указав размер 60, чуть больше чем требуется, + 5-7 байт. 

зачем?

На всякий пожарный )) мало ли что там Sim вернет ))

Dr_grizzly
Dr_grizzly аватар
Offline
Зарегистрирован: 07.12.2015

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

Во них всех Вы копируете в начало массива flsend, т.е. в строке 47 Вы затираете то, что записали в строке 46, в строке 48 затираете то, что записали в строке 47 и т.п.

Почему я затираю массив?

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

Dr_grizzly пишет:

Почему я затираю массив?

подсказка: на всякий случай(с) :D

Dr_grizzly
Dr_grizzly аватар
Offline
Зарегистрирован: 07.12.2015

Получается "смотрю в книгу - вижу фигу"? )) В описании фукнции strcat скачано что она призвана объединять строки. Пример приведет в таком же виде, что у меня. Где собака зарыта тогда? )))

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

Dr_grizzly пишет:

Как я понял из примера выше strcat соединяет char строки в один массив... разве не? )
 
А теперь открываем пост #16, берём лупу и ищем в указанных мною строках (46-54) strcat.
 
А раз его там нет, то о чём вообще разговор?

Dr_grizzly пишет:

Почему я затираю массив?

Ну, откуда мне знать почему? Возможно перепутали strcat и strcpy, а может так и хотели. В общем, не знаю я почему, но затираете - факт.

 
Dr_grizzly
Dr_grizzly аватар
Offline
Зарегистрирован: 07.12.2015

Ёшкин кот!!!! Вот это бревно у меня в глазу видать! Спасибо большое!)))

Dr_grizzly
Dr_grizzly аватар
Offline
Зарегистрирован: 07.12.2015

Решил потестить мой скеч MemoryExplorer'ом. Запихнул в каждую функцию, и в таймер в loop вывод информации о состоянии памяти(Тестирую на Mega2560. А прототип собран на Mini). Вот что получил:

Стартанул (в Setup после открытия Serial):

---- Memory report: POINT #0
HEAP:@083E(2110)-@210E(8462);
Unallocated from:@083E(2110);
Stack pointer: @218E(8590)
Free List: EMPTY

В ходе программы получаю такие данные:

вход в процедуру:

---- Memory report: POINT Sim_wait_resp #0
HEAP:@083E(2110)-@20F9(8441);
Unallocated from:@083E(2110);
Stack pointer: @2179(8569)
Free List: EMPTY
-----

После выхода из процедуры:

---- Memory report: POINT Sim_wait_resp #3
HEAP:@083E(2110)-@20F9(8441);
Unallocated from:@083E(2110);
Stack pointer: @2179(8569)
Free List: EMPTY

На таймере в Loop: - каждый раз эти же показания:

---- Memory report: POINT Timer #0
HEAP:@083E(2110)-@210E(8462);
Unallocated from:@083E(2110);
Stack pointer: @218E(8590)
Free List: EMPTY

Самые маленькие значения были

Вход в процедуру:

---- Memory report: POINT Sim_read_buf #0
HEAP:@083E(2110)-@20F6(8438);
Unallocated from:@083E(2110);
Stack pointer: @2176(8566)
Free List: EMPTY
-----

Выход из процедуры:
---- Memory report: POINT Sim_read_buf #1
HEAP:@083E(2110)-@210E(8462);
Unallocated from:@083E(2110);
Stack pointer: @218E(8590)
Free List: EMPTY
-----

Free List: EMPTY - везде, и не меняется.

Unallocated from:@083E(2110); - везде и не меняется.

Можно ли сделать вывод, что у меня нет утечек памяти в скетче?

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

Ну, судя по всему, да, Вы вообще не пользуеесь кучей, а только стеком

Dr_grizzly
Dr_grizzly аватар
Offline
Зарегистрирован: 07.12.2015

А исходя из этого заключения может быть так, что скетч работает на меге, но начинает глючить на мини? К примеру зависает отправка смс, и она постоянно отправляет их. Или не хочет брать трубку, как-будто не распознает входящий. Хотя в отладке все вижу. Подключил через мегу - на первый порт Мини, на второй Сим, а на нулевом Монитор компа. И вижу все что ходит между ними. Когда идет входящий то это отображается на мониторе, но Мини иногда просто игнорирует. Хотя на Меге такого не происходит... уже всю голову сломал

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

Может стек переполняется. Можете на мини такую же печать поставить?

Dr_grizzly
Dr_grizzly аватар
Offline
Зарегистрирован: 07.12.2015

Попробовал поднять на Мини софтварный порт и получил:

Скетч использует 10398 байт (36%) памяти устройства. Всего доступно 28672 байт.
Глобальные переменные используют 1603 байт (78%) динамической памяти, оставляя 445 байт для локальных переменных. Максимум: 2048 байт.
Недостаточно памяти, программа может работать нестабильно.

 

а до него - использовал 45% для глобальных переменных... и оставлял 1100байт для локальных

Dr_grizzly
Dr_grizzly аватар
Offline
Зарегистрирован: 07.12.2015

При старте:

---- Memory report: POINT #0
HEAP:@0743(1859)-@0810(2064);
Unallocated from:@0743(1859);
Stack pointer: @0890(2192)
Free List: EMPTY
-----

на таймере:

---- Memory report: POINT Timer #0
HEAP:@0743(1859)-@0810(2064);
Unallocated from:@0743(1859);
Stack pointer: @0890(2192)
Free List: EMPTY

на входе в процедуру

---- Memory report: POINT Sim_read_buf #0
HEAP:@0743(1859)-@07F5(2037);
Unallocated from:@0743(1859);
Stack pointer: @0875(2165)
Free List: EMPTY
-----

на выходе:

---- Memory report: POINT Sim_read_buf #3
HEAP:@0743(1859)-@0810(2064);
Unallocated from:@0743(1859);
Stack pointer: @0890(2192)
Free List: EMPTY
-----

Вот что получаю ))

 

это самые маленькие значения:

HEAP:@0743(1859)-@07F5(2037);
Unallocated from:@0743(1859);
Stack pointer: @0875(2165)

На что нужно обращать внимание? А точнее что искать при анализе данных?))

 

Dr_grizzly
Dr_grizzly аватар
Offline
Зарегистрирован: 07.12.2015

без виртуального сериал порта:

Скетч использует 6114 байт (21%) памяти устройства. Всего доступно 28672 байт.
Глобальные переменные используют 928 байт (45%) динамической памяти, оставляя 1120 байт для локальных переменных. Максимум: 2048 байт.
 

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

И всё равно не работает?

Dr_grizzly
Dr_grizzly аватар
Offline
Зарегистрирован: 07.12.2015

Как надо - неа )) начинает норм, а потом, то трубку не берет, то сигнала сети нет, то рестартит шилду по алгоритму - отправить AT если нет ответа - рестарт. То берет трубу, но не реагирует на DTMF сигналы. Хаос какой-то непредсказуемый получается... Наверное придется выложить мою схему подключения и весь код программы? Может не там ищу )

Dr_grizzly
Dr_grizzly аватар
Offline
Зарегистрирован: 07.12.2015

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