SMS_flash_send_format_PDU_UCS2_Cyrillic_and_Latin_Arduino_2021_01_22
arduino-IDE v 1.6.12 Pro_Mini
отправка SMS сообщений, в формате PDU / UCS2 - (кириллице и латинице), ("обычное-SMS" или "flash-SMS - флэш-SMS")
SMS_flash_send_PDU_UCS2_Cyrillic_Arduino_2021_01_22.ino
https://drive.google.com/drive/folders/16xi9JyQo0KEzg2WB3aBVJbdbUruo7uw9?usp=sharing https://drive.google.com/drive/folders/1cNVe7wQF4HhTadJbO_yAMLIoJPae52A4 Ссылка на видео:
https://youtu.be/wDkHl6TE5c0 отправка возможна;
1.) через (монитор порта).
2.) через CMD - bat файл. (кириллицу настроить не удалось, пока только на латинице)
3.) в коде, через передачу параметров в функцию. (проблемы с arduino-IDE v...)
строка для отправки SMS, может состоять из 3 значений, разделённых символом '~', символ '#' конца строки.
'#' символ конца строки,
'~' символ разделения частей строки
Идентификатор части строки 'N' для номера телефона в виде 79150011712
Идентификатор части строки 'F' для выбора типа SMS (0="обычное-SMS" или 1="flash-SMS")(не обязателен по умолчанию "обычное-SMS"
Идентификатор части строки '$' для текста SMS сообщения, максимум 70 символов
пример строки;
79150011712N~1F~Тест флэш-SMS! Test flash-SMS!$#
79150011712N~0F~Тест обычное-SMS! Test - SMS!$#
79150011712N~АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдеёжзийклмнопрстуфхцчшщъыьэюя№ DU$#
79150011712N~Тест SMS PDU UCS2 кириллица латиница Test SMS PDU UCS2 Cyrillic Latin$#
*/
/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
#include <SoftwareSerial.h> // библиотека для программного Serial - UART
SoftwareSerial mySerial(2, 3); // Соединяем (RX *SIM800L* TX) с (3-Pin *Arduino* 2-Pin)
#define SERIAL_BAUD 9600 // скорость Serial
/* ###################################### */
/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
// Препроцессорная компиляция кода.
// Препроцессор выполняет предварительную настройку кода, перед передачей компилятору (загрузкой в Arduino)
#define DEBUG_PRINT_SERIAL HIGH // (ВЫБЕРИТЕ!) режим тестирования устройства
// #define DEBUG_PRINT_SERIAL LOW // (ВЫБЕРИТЕ!) режим эксплуатации устройства
// для экономии памяти микроконтроллера, в режиме эксплуатации устройства, эти строки не будут загружаться в микроконтроллер
#if DEBUG_PRINT_SERIAL == HIGH
#define DEBUG_SERIAL_BEGIN(x) Serial.begin(x);
#define DEBUG_SERIAL_PRINT(x) Serial.print(x);
#define DEBUG_SERIAL_PRINTLN(x) Serial.println(x);
#define DEBUG_SERIAL_WRITE(x) Serial.write(x);
#else
#define DEBUG_SERIAL_BEGIN(x)
#define DEBUG_SERIAL_PRINT(x)
#define DEBUG_SERIAL_PRINTLN(x)
#define DEBUG_SERIAL_WRITE(x)
#endif
/* ###################################### */
// для отладки кода, выводим название функции, номер строки начала функции, и другую информацию.
#define DEBUG_FUNCTION_LINE \
DEBUG_SERIAL_PRINT(__PRETTY_FUNCTION__); \
DEBUG_SERIAL_PRINT(F("\t""LINE""\t")); \
DEBUG_SERIAL_PRINT(__LINE__); \
DEBUG_SERIAL_PRINT(F("\t")); \
DEBUG_SERIAL_PRINTLN(__COUNTER__);
// ###########################################
// AT команды - для настройки SIM800L
#define FACTORY_RESET_SIM800L "AT&F" // Сброс настроек SIM800L до заводских
#define RESTART_SIM800L "AT+CFUN=1,1" // перезагружаем - SIM800L
#define SETUP_SMS_PDU_MODE "AT+CMGF=0;&W" // Включаем PDU режим SMS (PDU mode) и сохраняем значение (AT&W)!
#define SMS_DEL_ALL R"(AT+CMGDA="DEL ALL")" // удаляем все SMS.
#define SETUP_SMS_CENTER_NUMBER_MTS R"(AT+CSCA="+79168999100")" // установить номер центра отправки SMS сообщений MTS.
// ###########################################
/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
#define SIZE_ARR_SERIAL_READ 95
char arrSerialRead[SIZE_ARR_SERIAL_READ + 2] = {0}; // массив char для хранения входящей сырой строки
char arrPhoneNumber[13] = {"XXXXXXXXXXXF"}; // массив для номера телефона
char arrPduPacket[29] = {"0001000B91XXXXXXXXXXXF0008XX"}; // массив PDU пакета
// максимальная длина отправляемого сообщения в PDU-формате 70 символов
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
// Прототипы функций: нужны - чтобы все функции были видны компилятору, вне зависимости от их расположения в коде
void FOO_serialReadStr(); // клавиши Ctrl + L (Перейти к строке) № 219
void FOO_parsingString(char * ); // (Перейти к строке) № 254
bool FOO_SMS_PDU_send(char * , char * , char); // функция для отправки SMS в PDU-формате // (Перейти к строке) № 324
/* ################################## */
void setup() {
Serial.begin(SERIAL_BAUD); // Скорость обмена данными с компьютером
mySerial.begin(SERIAL_BAUD); // Скорость обмена данными с SIM800L
mySerial.setTimeout(9000); // время ожидания данных, поступающих от (SIM800L)
DEBUG_FUNCTION_LINE
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, HIGH);
// while (1) {
// if (mySerial.available())Serial.write(mySerial.read());
// if (Serial.available())mySerial.write(Serial.read());
// }
// while (1);
/*
Префикс R"( позволяет избавиться от "\" - обратная косая черта - Экранирующий символ
Префикс (F( разместить строку Serial.println во флэш-памяти Serial.println(F("OK"));
Префикс (PSTR разместить строку передаваемую в функцию, во флэш-памяти FOO_responseMySerial(PSTR("AT"), PSTR("OK"));
*/
mySerial.println((char)27); // на всякий случай ! выходим из состояния (ожидание ввода текста SMS сообщения)
// if (mySerial.find("OK"));
Serial.println(F("START SETUP SIM800L"));
/*
do {
mySerial.println(F(FACTORY_RESET_SIM800L)); // Сброс настроек до заводских - SIM800L
DEBUG_SERIAL_PRINTLN(F("FACTORY_RESET_SIM800L" "\t" FACTORY_RESET_SIM800L));
} while (!mySerial.find("OK"));
do {
mySerial.println(F(RESTART_SIM800L)); // программная перезагрузка SIM800
DEBUG_SERIAL_PRINTLN(F("RESTART_SIM800L" "\t" RESTART_SIM800L));
} while (!mySerial.find("OK"));
do {
mySerial.println(F("AT")); // ждем пока SIM800 заработает, только Потом отправляем AT команды
DEBUG_SERIAL_PRINTLN(F("! SIM800 Start !"));
} while (!mySerial.find("OK")); // ожидаем ответа "OK" waitTime минут, долбим AT командой
*/
do {
mySerial.println(F(SETUP_SMS_PDU_MODE));
DEBUG_SERIAL_PRINTLN(F("SETUP_SMS_PDU_MODE" "\t" SETUP_SMS_PDU_MODE));
} while (!mySerial.find("OK"));
// это необязательно! если на sim-карте номер SMS центра записан правильно то этого делать не надо
// установить номер центра отправки SMS. оператора МТС
do {
mySerial.println(F(SETUP_SMS_CENTER_NUMBER_MTS));
DEBUG_SERIAL_PRINTLN(F("SETUP_SMS_CENTER_NUMBER_MTS" "\t" SETUP_SMS_CENTER_NUMBER_MTS));
} while (!mySerial.find("OK"));
DEBUG_SERIAL_PRINTLN(F("END SETUP"));
digitalWrite(LED_BUILTIN, LOW);
/*
внимание! начиная с версии приблизительно arduino-IDE v 1.5 устроили проблему, с символами кириллицы.
если нажать кнопку сохранить, и загрузить код в микроконтроллер, в машинном коде цифровое значение символов кириллицы
изменится.
если в коде сделать какое-нибудь изменение, хоть сдвинуть в право или влево комментарии, в микроконтроллер загрузится
правильные значения, даже размер кода изменится.
итог; (если в коде используются символы кириллицы) перед каждой загрузкой кода, сдвинуть в право или влево комментарии.
Если отправлять строку с символами кириллицы через (монитор порта), проблем не будет.
*/
// FOO_SMS_PDU_send("79150011712F", "Тест флэш-SMS! Test flash-SMS!", '1');
while (1) {
if (Serial.available())FOO_serialReadStr();
if (mySerial.available())Serial.write(mySerial.read());
}
}
/* ################################## */
void loop() {}
/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
void FOO_serialReadStr() { // функция для принятия сырой строки по Serial - UART
DEBUG_FUNCTION_LINE
unsigned long timeout = (millis() + 2000); // таймер ожидания следующего байта
int indexArrIn = -1; // счетчик индексов массива
char inChar = NULL;
while (1) { // стоим на месте / зависаем
if (Serial.available()) { // если в буфере Serial есть данные
timeout = (millis() + 1000); // сохраняем время таймера максимальное Время ожидания следующего байта
inChar = (char)Serial.read();
arrSerialRead[++indexArrIn] = inChar; // сохраняем поступившие сырые данные в массив
}
if (indexArrIn > SIZE_ARR_SERIAL_READ)return; // защита от переполнения массива, - выходим из функции
if ((inChar == '#') || (millis() > timeout))break; // если обнаружен символ конца строки, или истекло время ожидания, выходим
}
arrSerialRead[(indexArrIn + 1)] = NULL; // ставим флаг конца строки в c++
FOO_parsingString(arrSerialRead); // передаём указатель на массив / строку, в функции FOOparsingString
}
/* ############################################## */
/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
void FOO_parsingString(char * arrInStr) { // функция для сортировки данных, в принятой строке
DEBUG_FUNCTION_LINE
DEBUG_SERIAL_PRINTLN(arrInStr);
char SMSflash = '0'; // статус flash-SMS - по умолчанию "обычное-SMS" = 0
int strlenArrInStr = strlen(arrInStr); // сохраняем индекс - полезную длину строки / массива
arrInStr[strlenArrInStr - 1] = '~'; // заменяем '#' символ конца строки, на '~' символ разделения частей строки
int partStart = 0; // сохраняем индекс последнего элемента части строки, для вычисления первого элемента, следующей части строки
for (int indexInStr = 0; indexInStr < strlenArrInStr; indexInStr++) {
if (arrInStr[indexInStr] == '~') { // если обнаружен символ разделения частей строки
char dataTypes = arrInStr[(indexInStr - 1)]; // сохраняем символ идентификации, части строки
arrInStr[indexInStr - 1] = NULL; // заменяем символ идентификации части строки, на флаг конца строки c++
if (dataTypes == 'N') { // если символ идентификации части строки 'N', данные для "номера телефона"
if ((indexInStr - partStart) != 12) { // если длина номера телефона не равна 11, выходим из функции
DEBUG_SERIAL_PRINTLN(F("ERROR size phone Number. (11) return"));
return; // выходим из функции
}
// сохраняем номер телефона в массив arrPhoneNumber
for (int i = 0; i < (indexInStr - (partStart + 1)); i++)arrPhoneNumber[i] = (arrInStr[(partStart + i)]);
DEBUG_SERIAL_PRINTLN((String)"arrPhoneNumber" + '\t' + arrPhoneNumber + '\t' + "size " + ((indexInStr - partStart) - 1));
}
else if (dataTypes == 'F') { // если символ идентификации части строки 'F', параметр для flash-SMS
if ((arrInStr[partStart] == '0') || (arrInStr[partStart] == '1')) { // фильтруем на допустимый диапазон значений (0 или 1)
SMSflash = arrInStr[partStart]; // устанавливаем, полученное значение, (1 = flash-SMS) - (0 = обычное SMS).
DEBUG_SERIAL_PRINTLN((String)"flash-SMS parametr" + '\t' + (arrInStr + partStart));
}
else { // если не правильный, допустимый диапазон значений, выходим из функции.
DEBUG_SERIAL_PRINTLN((String)"ERROR flash-SMS parameter" + '\t' + (arrInStr + partStart) + '\t' + "only (0 or 1) return");
return;
}
}
else if (dataTypes == '$') { // если символ идентификации части строки '$', данные для "текста SMS"
if ((indexInStr - partStart) > 71) { // если длина "текста для SMS" больше 70 , выходим из функции
DEBUG_SERIAL_PRINTLN(F("ERROR size SMS text. max (70) return"));
return; // выходим из функции
}
DEBUG_SERIAL_PRINTLN((String)"SMS text size" + '\t' + ((indexInStr - partStart) - 1));
// передаём стартовый индекс как указатель на массив с текстом для SMS
FOO_SMS_PDU_send(arrPhoneNumber, arrInStr + partStart, SMSflash);
return;
}
partStart = (indexInStr + 1); // запоминаем стартовый индекс, индекс начала для следующей части строки
}
}
}
/* ############################################## */
/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
// функция для отправки SMS сообщений в PDU формате: принимает 3 параметра номер телефона, текст для SMS , статус flash-SMS
bool FOO_SMS_PDU_send(char * numberPhone, char * textMessage, char flashSMS) {
DEBUG_FUNCTION_LINE
digitalWrite(LED_BUILTIN, HIGH);
arrPduPacket[24] = flashSMS; // устанавливаем статус flash-SMS
byte lenTextSms = strlen(textMessage); // длина текста SMS сообщения
DEBUG_SERIAL_PRINTLN((String)"number " + numberPhone + " text " + textMessage + ": strlen " + lenTextSms + " flash " + flashSMS);
for (int i = 0; i <= 10; i += 2) { // копируем номер телефона, в часть массива arrPduPacket
arrPduPacket[i + 10] = numberPhone[i + 1]; // и меняем местами, каждую пару цифр номера телефона
arrPduPacket[i + 11] = numberPhone[i];
}
// Функция преобразования числового значения байта в шестнадцатеричное (HEX)
// длина текста SMS сообщения для arrPduPacket
String intTOcharHEX = String(lenTextSms * 2, HEX); // количество символов в тексте SMS сообщения умножаем на 2
if (intTOcharHEX.length() == 1) intTOcharHEX = "0" + intTOcharHEX; // сохраняем в тип данных char, в формате HEX
arrPduPacket[26] = intTOcharHEX[0]; // результат копируем в конец массива arrPduPacket
arrPduPacket[27] = intTOcharHEX[1];
DEBUG_SERIAL_PRINTLN((String)"AT+CMGS=" + (((lenTextSms * 4) + 26) / 2) + '\t' + "wait Response >");
mySerial.print(F("AT+CMGS=")); // отправляем в модем команду AT+CMGS=
mySerial.println((((lenTextSms * 4) + 26) / 2)); // и длину PDU-пакета в байтах без учета поля SCA.
if (mySerial.find('>')); // и ждём ответа символ ">" для ввода текста SMS
// внимание! после разрешающего ответа для ввода текста SMS, символом " > " модем как бы зависает,
// перестает реагировать на AT команды, интерпретируя их как текст для SMS сообщения.
// (char)27 выводит из состояния (ожидание отправки SMS сообщения)
mySerial.print(arrPduPacket); // сначала отправляем в SIM800 arrPduPacket
DEBUG_SERIAL_PRINTLN(arrPduPacket);
// 1 символ UCS2 PDU занимает 2 байта, каждый байт в HEX-формате. итого 1 символ занимает 4 знака .
for (int i = 0; i < lenTextSms; i ++) { // отправляем в SIM800, текст SMS сообщения, в формате PDU.
if (textMessage[i] < 0) { // если код буквы кириллица
if (textMessage[i] == -72)textMessage[i] = 1; // исключение для буквы "ё"
else if (textMessage[i] == -88) { // исключение для буквы "Ё"
mySerial.print(F("0401"));
continue; // возвращаемся к циклу for
}
else if (textMessage[i] == -71) { // исключение для символа "№"
mySerial.print(F("2116"));
continue; // возвращаемся к циклу for
}
textMessage[i] += 80; // преобразуем код буквы кириллица в формат UCS2 PDU
mySerial.print(F("04")); // отправляем первую часть (2 байта) символа UCS2, кода буквы кириллицы в HEX формате
DEBUG_SERIAL_PRINT(F("04"));
}
else { // если код буквы латиница
mySerial.print(F("00")); // отправляем первую часть (2 байта) символа UCS2, кода буквы латиницы в HEX формате
DEBUG_SERIAL_PRINT(F("00"));
}
mySerial.print(textMessage[i], HEX); // отправляем вторую часть (2 байта) символа UCS2, кода буквы латиницы или кириллицы в HEX
#if DEBUG_PRINT_SERIAL == HIGH
Serial.print(textMessage[i], HEX);
#endif
}
mySerial.println();
DEBUG_SERIAL_PRINTLN();
if (mySerial.find('>')); // ждём ответа, о завершении ввода текст SMS сообщения, символ ">"
mySerial.println((char)26); // внимание отправляем в модем "невидимый" символ, для Отправки SMS (char)26 .
DEBUG_SERIAL_PRINTLN(F("wait Response +CMGS: SMS_SENT_?"));
if (mySerial.find("+CMGS:")) { // ждём ответа об успешной отправки SMS, если получили ответ +CMGS:
DEBUG_SERIAL_PRINTLN(F("RESPONSE SENT SMS message OK")); // SMS отправлена успешно
}
else {
DEBUG_SERIAL_PRINTLN(F("ERROR SMS_SENT")); // SMS не отправлена
}
mySerial.println((char)27); // на всякий случай ! повторно выходим из состояния (ожидание отправки SMS сообщения)
// Serial.println('', DEC); // увидеть в десятичном формате символ для выхода из состояния (ожидание отправки SMS сообщения)
digitalWrite(LED_BUILTIN, LOW);
}
/* ###################################### */
// BAT.FILE
/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
/*
set SMS_Text='79150011712N~1F~Test flash-SMS!$#' & :: переменная для отправки SMS Text
@chcp 1251 & :: чтобы .bat файл понимал русские буквы (кириллицу)
set /a SERIAL_BAUD=9600 & :: создаём переменную SERIAL_BAUD скорость на которой работает Arduino
set /a COM_PORT=10 & :: переменная для номер COM-порта
powershell "$port=new-Object System.IO .Ports.SerialPort COM%COM_PORT%,(%SERIAL_BAUD%),None,8,one; $port.open(); $port.Write(%SMS_Text%); $port.Close();"
@: пример строки;
@: set SMS_Text='79150011712N~1F~Test flash-SMS!$#'
@: set SMS_Text='79150011712N~0F~Test - SMS!$#'
@: set SMS_Text='79150011712N~Test SMS PDU UCS2$#'
TIMEOUT /T 10
pause
goto start
// начало комментария
pause
// конец комментария
:start
*/
/* ###################################### */
Присоединяйтесь — мы покажем вам много интересного
Присоединяйтесь к ОК, чтобы подписаться на группу и комментировать публикации.
Нет комментариев