Это вы батенька их готовить не умеете. Несколько десятков устройств ездит по стране вообще без проблем. Завтра посторяюсь выложить схему соединения nano и sim800 какую я использую - все отлично работает в любых режимах.
Из шести три прекрасно запитались от +5в, живут замечательно (хотя скорее всего это просто over-voltage protection в модулях не работает как надо). Два из них запускаются и живут от 3.3v.
Ещё один от 5в моргает два раза при включении и всё (over-voltage protection сработал). От ~4v работает.
Ещё один от 5в моргает уже не два, а три раза при включении (опять over-voltage protection сработал).
Итого: очень большой разброс, каждый модуль сам по себе.
А в чем суть подбора модуля из шести - работает/не работает овервольтаж? Если есть отлично зарекомендовавший себя способ запитать модуль от 5в через обычный кремниевый диод, и получить на нем 4.2-4.4 вольта, от которых он работает всегда, и без сбоев?
Цели подбора не стояло. Про шесть модулей написано исключительно из соображений личного опыта и ситуации, что "одинаковые" модули на самом деле все разные, какие-то работают прекрасно и от 5в (хотя как бы и не должны), а какие-то не работают вообще ни от скольки.
Небольшая библиотека для работы с Sim800L, функционал:
- прием и отправка SMS
- прием входящих звонков и обработка DTMF нажатий
В проекте добавление следующих действий:
- отправка GET запросов и чтение возвращаемой странички HTML
- пакетная прием-передача данных -> общение с MQTT сервером
Скетч из 4х файлов, первый - пример использования с комментариями, остальные - сама библиотека.
Обработка ответов из модема online - в каждом проходе loop, соответственно категорически не рекомендуется сильно задерживать цикл своими обработчиками.
#include <avr/wdt.h>
#include "sim800lib.h"
unsigned long currentMillis; // главный таймер для запуска операций по времени
s800lib s800l; // объект библиотеки Sim800L
#define period_read_sms 120000UL // каждые 2 минуты читаем СМС
unsigned long timer_read_sms;
#define max_size_sender (byte)16
char sender[max_size_sender]; // отправитель
#define max_size_textsms (byte)32
char textsms[max_size_textsms]; // текст СМС, максимум 255, если необходимо больше - переписывать библиотеку
#define period_send_sms 6003537UL // через 100 минут отправляем тестовую СМС
unsigned long timer_send_sms; byte fl_send_sms = 1; // один раз
uint8_t mcusr_mirror __attribute__ ((section (".noinit")));
void get_mcusr(void) \
__attribute__((naked)) \
__attribute__((used)) \
__attribute__((section(".init3")));
void get_mcusr(void)
{
mcusr_mirror = MCUSR;
MCUSR = 0;
wdt_disable();
}
void setup() {
MCUSR = 0; wdt_disable(); // отключение Watch Dog Timer
// put your setup code here, to run once:
#ifdef USE_SOFTWARESERIAL
Serial.begin(115200); // инициализируем аппаратный UART для вывода сообщений
#endif
s800l.initModem(false); // запуск модема. C использованием GPRS? true/false
wdt_enable(WDTO_8S); // запуск WDT
}
void loop() {
wdt_reset(); // сброс WDT
//Serial.println("Start"); delay(9000); // test WDT
currentMillis = millis(); // присвоим таймеру текущее значение МК
// put your main code here, to run repeatedly:
if (s800l.workModem()) { // модем в работе, что то или пришло или требует внимания программы/пользователя или ошибка
if (s800l.getModemReport() == errTimeOut) { // обрабатываем ошибку модема (таймаут по ответу на команду)
Serial.print("Error timeout on command = "); Serial.println(s800l.getModemCmd(), DEC);
switch (s800l.getModemActions()) { // выбираем реакцию в зависимости от текущего действия
case initATmodem: {
Serial.println("Reset modem."); s800l.resetModem(); s800l.initModem(false); break; // перезапускаем модем
}
case delSMS: {
s800l.clearAction(); break; // продолжаем работать
}
case readSMS: {
s800l.clearAction(); break; // продолжаем работать
}
case sendSMS: {
s800l.clearAction(); break; // продолжаем работать
}
case waitDTMF: {
s800l.clearAction(); break; // продолжаем работать
}
default: {};
}
} else if (s800l.getModemReport() == noGPRS) { // GPRS не поддерживается
Serial.println("GPRS not supported. Reset modem.");
s800l.resetModem(); s800l.initModem(false); // перезагружаемся без поддержки GPRS
} else if (s800l.getModemReport() == oneSMS) { // получили СМС - обрабатываем
Serial.println(sender);
Serial.println(textsms);
} else if (s800l.getModemReport() == keyPressDTMF) { // прилетела нажатая цифра
Serial.print("Pressed key "); Serial.println(s800l.getKeyDTMF()); // обрабатываем нажатую кнопку
} else { // смотрим другие ответы
}
} else { // модем ничем не занят, можно делать что то свое
// отправка СМС, чтение СМС, запрос USSD, отправка GET запроса, вывод в монитор порта каких то своих данных и т.д.
switch (s800l.getModemReport()) { // обрабатываем ответы модема
case initReady: { // успешно запустили модем
Serial.println("Ready");
s800l.deleteAllSMS(); // удалим все СМС при старте
break;
}
case existSMS: { // все СМС прочитаны и обработаны
s800l.deleteAllSMS(); // удалим все СМС
break;
}
case incomingCall: { // входящий звонок
// получаем номер звонящего абонента
Serial.print("Incoming call from "); Serial.println(s800l.getPhoneNumber());
// анализируем номер и решаем что делать дальше или просто игнорируем звонок
s800l.waitPressDTMF(); // снимаем трубку и ждем команд DTMF
break;
}
default: { // делаем что то свое
// --- читаем СМС по таймеру
if ((currentMillis - timer_read_sms) >= period_read_sms) {
timer_read_sms = currentMillis; s800l.readAllSMS(sender, max_size_sender, textsms, max_size_textsms);
}
// --- отправляем СМС по таймеру
if (fl_send_sms) {
if ((currentMillis - timer_send_sms) >= period_send_sms) {
fl_send_sms = 0; timer_send_sms = currentMillis; s800l.sendSimpleSMS((char *)"7900***8478", (char *)"Proba");
}
}
// --- конец своих действий
};
}
}
// делаем что то свое, не задерживаем поток, не рекомендуется использовать здесь вывод чего лобо в монитор порта
}
-
//---sim800lib.h---
#include <arduino.h>
#include "sim800cmd.h"
#define USE_SOFTWARESERIAL // используем программный UART для работы с модемом
//#define SHOW_MODEM_RESPONSE // отображать ответы модема (используется только при отладке если есть проблемы)
#ifdef USE_SOFTWARESERIAL
#include <SoftwareSerial.h>
#define GSM_RX (byte)3 // пин RX на модуле подключаем к указаному пину на Ардуино TX
#define GSM_TX (byte)2 // пин TX на модуле подключаем к указаному пину на Ардуино RX
#endif
#define reset_sim800_pin (byte)4 // pin for reset modem // нога сброса модема
#define dtr_sim800_pin (byte)10 // pin DTR for sleep mode // нога DTR модема
#define modem_speed (word)9600 // скорость обмена с модемом
#define max_size_response_buf (byte)16 // размер буфера ответа от модема, должен быть чуть больше максимальной строки поиска, например SEND OK, ERROR, OK и т.д. для стандартных команд
#define max_size_phone_number (byte)16 // размер буфера телефона абонента входящего звонка
#define max_size_cmd_buf (byte)40 // размер буфера команд модема, должен быть чуть больше максимальной строки команды
#define periodWaitInit 15000UL // сколько дать времени модему на регистрацию в сети после включения или сброса
#define periodSimpleResponse 3000UL // время ожидания простой команды
#define periodReadSMS 30000UL // время ожидания чтения СМС
#define periodSendSMS 30000UL // время ожидания отправки СМС
#define periodWaitDTMF 60000UL // время ожидания сигналов DTMF
// в каком действии сейчас находится модем (начало, инициализация, чтение смс, отправка смс и т д
enum modemActions {waitInit/*ожидание после включения Х секунд*/,
initATmodem/*отправка на модем настроечных AT команд*/,
doNothing/*ничего не делаем - обнуляем после обработки ответа*/,
delSMS/*удаляем все СМС*/,
readSMS/*читаем все смс*/,
sendSMS/*отправка СМС*/,
waitDTMF/*ожидание команд при входящем звонке*/
};
// ответы обработчика
enum modemReport {noReport/*нет ответа - все хорошо*/,
initReady/*Успешная инициализация модема - просто работаем*/,
errTimeOut/*за X время нет успешного ответа на команду*/,
noGPRS/*на SIM ке или не включен или не поддерживается пакетная передача данных*/,
noSMS/*нет SMS*/,
existSMS/*все SMS прочитаны*/,
oneSMS/*получено одно СМС*/,
incomingCall/*входящий звонок*/,
keyPressDTMF/*нажата кнопка DTMF*/
};
class s800lib
{
private:
/* список свойств и методов для использования внутри класса */
bool _use_gprs; // использовать интернет
char resp_buf[max_size_response_buf]; // буфер ответов от модема
char phone_buf[max_size_phone_number]; // буфер телефонного номера
byte pos_buf; // текущая позиция буфера ответов
unsigned long modemMillis; // таймер модема - используется один таймер на все команды
modemActions currentAction; // текущее состояние модема
modemReport currentReport; // текущий ответ после выхода обработчика
void clearRespBuf(); // очистка приемного буфера
byte _current_cmd; // текущая выполняемая команда - команда которую надо запустить - значение 101=выход из пакета команд
byte _next_cmd; // следующая выполняемая команда
void sendATcmd(); // отправка команды модему
bool findResp(char * inStr, byte inByte); // поиск в циклическорм буфере ответа ОК
char * _sms_sender;
byte _max_size_sender;
char * _sms_text;
byte _max_size_sms_text;
byte _sms_count, _sms_step, _ring_step;
bool processSMS(byte inByte); // обработка СМС
byte _inc_ring; // 1 если пришло RING
byte _dtmf_press; // 1 если пришло +DTMF:
char _dtmf_key;
public:
/* список методов доступных другим функциям и объектам программы */
void initModem(bool useGPRS); // начальная инициализация пинов модема, отправка первоначальных команд настройки модема
void resetModem(); // сброс модема
bool workModem(); // основная работа с модемом в loop
modemActions getModemActions(); // возвращает текущую операцию
modemReport getModemReport(); // возвращает ответ операции
byte getModemCmd(); // возвращает номер текущей команды модема
void clearAction(); // сброс текущего действия модема
void deleteAllSMS(); // удалить все СМС
void readAllSMS(char * bufSender, byte maxSender, char * bufText, byte maxText); // прочитать все СМС
void sendSimpleSMS(char * bufSender, char * bufText); // отправка SMS в не PDU фармате
char * getPhoneNumber(); // получить телефонный номер входящего звонка
void waitPressDTMF(); // снимаем трубку при звонке и ждем нажатия кнопок
char getKeyDTMF(); // возвращает нажатую кнопку
protected:
/*список средств, доступных при наследовании*/
};
-
//---sim800lib.cpp---
#include "sim800lib.h"
#ifdef USE_SOFTWARESERIAL
SoftwareSerial gsm(GSM_TX, GSM_RX); // установка контактовGSM_TX->RX и GSM_RX->TX для программного порта
#endif
void s800lib::initModem(bool useGPRS) { // начальная инициализация пинов модема, отправка первоначальных команд настройки модема
#ifdef USE_SOFTWARESERIAL
gsm.begin(modem_speed);
#else
Serial.begin(modem_speed);
#endif
pinMode(LED_BUILTIN, OUTPUT); digitalWrite(LED_BUILTIN, LOW); // гасим встроенный светодиод
pinMode(reset_sim800_pin, INPUT); digitalWrite(reset_sim800_pin, LOW); // ногу сброса отключаем - рабочий режим
pinMode(dtr_sim800_pin, OUTPUT); digitalWrite(dtr_sim800_pin, LOW); // normal mode modem // все модули модема включены
currentAction = waitInit; // ждем как модем зарегестрируется в сети
_use_gprs = useGPRS; // использование GPRS
modemMillis = millis(); // обнулим таймер
_inc_ring = 0; // нет входящего звонка
}
void s800lib::resetModem() { // сброс модема
pinMode(reset_sim800_pin, OUTPUT);
delay(115);
pinMode(reset_sim800_pin, INPUT);
}
void s800lib::clearRespBuf() { // очистка приемного буфера
memset(resp_buf, 0, max_size_response_buf);
pos_buf = 0;
}
bool s800lib::workModem() { // основная работа, возвращает true если что то или пришло или ошибка или все ок, false если нечего модему делать
currentReport = noReport; // сбрасываем ответ при каждом входе
// обрабатваем каждый байт ответа
byte br = 0;
#ifdef USE_SOFTWARESERIAL
if (gsm.available()) br = gsm.read();
#else
if (Serial.available()) br = Serial.read();
#endif
if (br) {
// запись байта в буфер
resp_buf[pos_buf] = br; // записали
++pos_buf; // увеличили счетчик
if (pos_buf >= max_size_response_buf) pos_buf = 0; // если дошло до максимума - обнуляем
}
switch (currentAction) { // отрабатываем все действия раздельно
case waitInit: {
if ((millis() - modemMillis) >= periodWaitInit) { // закончили ожидание регистрации модема - запускаем первые команды инициализации
currentAction = initATmodem; // будем отправлять команды инициализации модема
_current_cmd = 0; // запускаем нулевую команду
s800lib::sendATcmd(); // отправить команду модему
}
break;
}
case initATmodem: {
// проверяем таймаут
if ((millis() - modemMillis) >= periodSimpleResponse) {
currentReport = errTimeOut; return true; // прописываем код ответа и выходим
}
if (br) {
#ifdef SHOW_MODEM_RESPONSE
Serial.write(br);
#endif
if (_use_gprs) { // проверяем работает ли пакетная передача данных
if (_current_cmd == 9) { // на нужной команде ищем подстроку
if (s800lib::findResp((char *)"+CGATT: 0\r\n", br)) {
currentReport = noGPRS; return true; // прописываем код ответа и выходим
}
}
}
if (s800lib::findResp((char *)"OK\r\n", br)) {
if (_next_cmd == 101) { // конец цикла инициализации
if (_use_gprs) { // продолжить команды настройки GPRS ?
if (_current_cmd == 8) { // последняя команда инициализации
_current_cmd = 9; s800lib::sendATcmd(); // запускаем настройку gprs
} else {
currentReport = initReady; s800lib::clearAction(); return false; // успешно настроили модем. обнулили текущее действие и вышли
}
} else {
currentReport = initReady; s800lib::clearAction(); return false; // успешно настроили модем. обнулили текущее действие и вышли
}
} else { // запускаем следующую команду
_current_cmd = _next_cmd; s800lib::sendATcmd();
}
}
}
break;
}
case waitDTMF: { // ждем нажатия кнопок на телефоне
// проверяем таймаут
if ((millis() - modemMillis) >= periodWaitDTMF) {
currentReport = errTimeOut; return true; // прописываем код ответа и выходим
}
if (br) {
#ifdef SHOW_MODEM_RESPONSE
Serial.write(br);
#endif
if (s800lib::findResp((char *)"NO CARRIER\r\n", br)) {
s800lib::clearAction(); return false; // успешно выходим
}
if (s800lib::findResp((char *)"+DTMF: ", br)) { // кнопка нажата
_dtmf_press = 1;
}
if (_dtmf_press) {
if ((isdigit(br)) || (br == '#') || (br == '*')) {
_dtmf_press = 0; _dtmf_key = br;
currentReport = keyPressDTMF; return true;
}
}
}
break;
}
case delSMS: { // операция удаления СМС - тупо ждем ОК и выходим
// проверяем таймаут
if ((millis() - modemMillis) >= periodSimpleResponse) {
currentReport = errTimeOut; return true; // прописываем код ответа и выходим
}
if (br) {
#ifdef SHOW_MODEM_RESPONSE
Serial.write(br);
#endif
if (s800lib::findResp((char *)"OK\r\n", br)) {
s800lib::clearAction(); return false; // успешно выходим
}
}
break;
}
case readSMS: { // операция чтения СМС
// проверяем таймаут
if ((millis() - modemMillis) >= periodReadSMS) {
currentReport = errTimeOut; return true; // прописываем код ответа и выходим
}
if (br) {
#ifdef SHOW_MODEM_RESPONSE
Serial.write(br);
#endif
if (s800lib::findResp((char *)"OK\r\n", br)) {
if (_sms_count) currentReport = existSMS; else currentReport = noSMS;
s800lib::clearAction(); return false; // успешно выходим
} else {
if (s800lib::processSMS(br)) { // обрабатываем поток байтов
currentReport = oneSMS; // СМС закончилась, выходим
}
}
}
break;
}
case sendSMS: { // операция отправки простой СМС
// проверяем таймаут
if ((millis() - modemMillis) >= periodSendSMS) {
currentReport = errTimeOut; return true; // прописываем код ответа и выходим
}
if (_sms_step == 0) { // отправляем в модем телефонный номер
#ifdef USE_SOFTWARESERIAL
gsm.print(_sms_sender); gsm.print("\"\r");
#else
Serial.print(_sms_sender); Serial.print("\"\r");
#endif
++_sms_step; // на следующий шаг
#ifdef SHOW_MODEM_RESPONSE
Serial.print(_sms_sender); Serial.println("\"");
#endif
}
if (br) {
#ifdef SHOW_MODEM_RESPONSE
Serial.write(br);
#endif
if (_sms_step == 1) { // ждем приглашения >
if (br == '>') {
#ifdef USE_SOFTWARESERIAL
gsm.print(_sms_text); gsm.write(26);
#else
Serial.print(_sms_text); Serial.write(26);
#endif
++_sms_step; // на следующий шаг
#ifdef SHOW_MODEM_RESPONSE
Serial.println(_sms_text);
#endif
}
} else if (_sms_step == 2) { // ждем ОК
if (s800lib::findResp((char *)"OK\r\n", br)) {
s800lib::clearAction(); return false; // успешно выходим
}
}
}
break;
}
default: {
#ifdef SHOW_MODEM_RESPONSE
if (br) Serial.write(br);
#endif
// ищем какие либо значимые ответы от модема
if (br) {
if (s800lib::findResp((char *)"RING\r\n", br)) { // ищем входящий звонок
_ring_step = 0; _inc_ring = 1; memset(phone_buf, 0, max_size_phone_number);
}
if (s800lib::findResp((char *)"NO CARRIER\r\n", br)) _inc_ring = 0; // сбросился звонок
if (_inc_ring) { // позвонили
// вытаскиваем телефонный номер
if ((s800lib::findResp((char *)"+CLIP: \"+", br)) && (!_ring_step)) {
_ring_step = 1;
}
if (_ring_step) {
if (br == '\"') { // закончился номер
_ring_step = 0; _inc_ring = 0; currentReport = incomingCall;
} else if (isdigit(br)) {
byte phl = strlen(phone_buf);
if (phl < (max_size_phone_number - 1)) phone_buf[phl] = br;
}
}
}
}
return false; // ничего не обрабатывается
}
}
return true;
}
void s800lib::sendATcmd() {
char cmd_buf[max_size_cmd_buf]; // буфер команд
s800lib::clearRespBuf(); // очищаем приемный буфер
const char * addrStroki = pgm_read_word_near((int)(at_list_cmd + _current_cmd)); // адрес команды в eeprom
strcpy_P(cmd_buf, addrStroki); // достать команду
// отправляем команду в модем
#ifdef USE_SOFTWARESERIAL
gsm.print(cmd_buf);
#else
Serial.print(cmd_buf);
#endif
#ifdef SHOW_MODEM_RESPONSE
Serial.print(cmd_buf);
#endif
// прописать следующую команду при успешном ответе или по условию операции
_next_cmd = pgm_read_byte_near(at_move_cmd + _current_cmd);
modemMillis = millis(); // обнулим таймер
}
bool s800lib::findResp(char * inStr, byte inByte) { // поиск строки в циклическом буфере
byte slen = strlen(inStr); // длина искомой строки
if (inByte == inStr[slen - 1]) { // если последний символ совпадает - продолжаем искать всю строку
byte cfound = 1; // число совпавших символов
byte abpos = pos_buf; // абсолютная позиция в буфере поиска-1 = последнему символу искомой строки
if (!abpos) abpos = max_size_response_buf - 1; else --abpos; // ищем с предпоследнего символа
for ( byte i = 0; i < (slen - 1); ++i) {
if (inStr[slen - 1 - i] != resp_buf[abpos]) return false;
if (!abpos) abpos = max_size_response_buf - 1; else --abpos;
}
} else {
return false;
}
return true;
}
modemActions s800lib::getModemActions() { // возвращает текущую операцию
return currentAction;
}
modemReport s800lib::getModemReport() { // возвращает ответ операции
return currentReport;
}
byte s800lib::getModemCmd() { // возвращает номер текущей команды модема
return _current_cmd;
}
void s800lib::clearAction() { // сброс текущего действия модема
s800lib::currentAction = doNothing;
}
void s800lib::deleteAllSMS() { // удалить все СМС
currentAction = delSMS; _current_cmd = 18; s800lib::sendATcmd();
}
void s800lib::readAllSMS(char * bufSender, byte maxSender, char * bufText, byte maxText) { // прочитать все СМС
s800lib::_sms_count = 0;
s800lib::_sms_step = 0;
s800lib::_sms_sender = bufSender;
s800lib::_max_size_sender = maxSender;
s800lib::_sms_text = bufText;
s800lib::_max_size_sms_text = maxText;
currentAction = readSMS; _current_cmd = 19; s800lib::sendATcmd();
}
bool s800lib::processSMS(byte inByte) { // обработка СМС
switch (_sms_step) {
case 0: {
if (s800lib::findResp((char *)"CMGL:", inByte)) { // найдено начало СМС
++_sms_count; ++_sms_step; // увеличиваем счетчик СМС и переходим на след шаг
memset(_sms_sender, 0, _max_size_sender); memset(_sms_text, 0, _max_size_sms_text); // чистим буферы
}
break;
}
case 1: {
if (s800lib::findResp((char *)",\"", inByte)) ++_sms_step;
break;
}
case 2: {
if (s800lib::findResp((char *)"\",\"+", inByte)) ++_sms_step; // следующий шаг - номер отправителя
break;
}
case 3: {
if (s800lib::findResp((char *)"\",\"\",\"", inByte)) { // номер закончился
++_sms_step; // следующий шаг
} else {
byte lphone = strlen(_sms_sender);
if ((lphone < (_max_size_sender - 1)) && (isdigit(inByte))) _sms_sender[lphone] = inByte; // записываем в строку отправитель
}
break;
}
case 4: {
if (s800lib::findResp((char *)"\"\r\n", inByte)) ++_sms_step; // следующий шаг - текст смс
break;
}
case 5: {
if (s800lib::findResp((char *)"\r\n", inByte)) { // смс закончилась
_sms_step = 0; return true; // выход
} else {
byte ltext = strlen(_sms_text);
if (ltext < (_max_size_sms_text - 1)) _sms_text[ltext] = inByte; // записываем в строку
}
break;
}
default: {}
}
return false;
}
void s800lib::sendSimpleSMS(char * bufSender, char * bufText) { // отправка SMS в не PDU фармате
s800lib::_sms_sender = bufSender;
s800lib::_sms_text = bufText;
s800lib::_sms_step = 0;
currentAction = sendSMS; _current_cmd = 20; s800lib::sendATcmd();
}
char * s800lib::getPhoneNumber() { // получить телефонный номер входящего звонка
return phone_buf;
}
void s800lib::waitPressDTMF() { // снимаем трубку при звонке и ждем нажатия кнопок
s800lib::_dtmf_press = 0;
currentAction = waitDTMF; _current_cmd = 21; s800lib::sendATcmd();
}
char s800lib::getKeyDTMF() { // возвращает нажатую кнопку
return _dtmf_key;
}
-
//---sim800cmd.h---
const char at0cmdAT[] PROGMEM = "AT\r"; // проверка связи
const char at1cmdDDET[] PROGMEM = "AT+DDET=1\r"; // включаем режим распознавания DTMF
const char at2cmdATE0[] PROGMEM = "ATE0\r"; // отключаем возврат команд от модема
const char at3cmdCLIP1[] PROGMEM = "AT+CLIP=1\r"; // включаем АОН
const char at4cmdATS0[] PROGMEM = "ATS0=0\r"; // вручную поднимать трубку при входящем звонке
const char at5cmdATV1[] PROGMEM = "ATV1\r"; // развернутый символьный ответ от модема
const char at6cmdATCMEE2[] PROGMEM = "AT+CMEE=2\r"; // подробный вывод ошибок
const char at7cmdATCMGF1[] PROGMEM = "AT+CMGF=1\r"; // не PDU режим приема и отправки SMS
const char at8cmdCSCLK1[] PROGMEM = "AT+CSCLK=0\r"; // отключаем режим ухода в сон с помощью пина DTR на модеме
const char at9cmdCGATT[] PROGMEM = "AT+CGATT?\r"; // Проверка доступа к услугам пакетной передачи данных
const char at10cmdSAPBR311[] PROGMEM = "AT+SAPBR=3,1,\"CONTYPE\",\"GPRS\"\r";
const char at11cmdSAPBR312[] PROGMEM = "AT+SAPBR=3,1,\"APN\",\"internet\"\r";
const char at12cmdSAPBR313[] PROGMEM = "AT+SAPBR=3,1,\"USER\",\"\"\r";
const char at13cmdSAPBR314[] PROGMEM = "AT+SAPBR=3,1,\"PWD\",\"\"\r";
const char at14cmdCIPMODE[] PROGMEM = "AT+CIPMODE=0\r"; // Командный режим передачи данных
const char at15cmdCIPMUX[] PROGMEM = "AT+CIPMUX=0\r"; // Моносокет
const char at16cmdCIPHEAD[] PROGMEM = "AT+CIPHEAD=1\r"; // Перед блоком данных, принятых от сервера добавлять заголовок формата +IPD,<длина блока данных>
const char at17cmdCIPSRIP[] PROGMEM = "AT+CIPSRIP=0\r"; // При приеме данных не показывать уведомление в виде RECV FROM:<IP адрес отправителя>,<порт>
const char at18cmdDELSMS[] PROGMEM = "AT+CMGDA=\"DEL ALL\"\r"; // удаление всех смс
const char at19cmdREADSMS[] PROGMEM = "AT+CMGL=\"ALL\"\r"; // чтение всех смс
const char at20cmdCMGS[] PROGMEM = "AT+CMGS=\"+"; // begin send sms
const char at21cmdATA[] PROGMEM = "ATA\r"; // hand up
const char * const at_list_cmd[] PROGMEM = { // text command
at0cmdAT, at1cmdDDET, at2cmdATE0, at3cmdCLIP1, at4cmdATS0, at5cmdATV1, at6cmdATCMEE2, at7cmdATCMGF1, at8cmdCSCLK1, // initATmodem
at9cmdCGATT, at10cmdSAPBR311, at11cmdSAPBR312, at12cmdSAPBR313, at13cmdSAPBR314, // init http
at14cmdCIPMODE, at15cmdCIPMUX, at16cmdCIPHEAD, at17cmdCIPSRIP, // init gprs
at18cmdDELSMS, // del sms
at19cmdREADSMS, // read sms
at20cmdCMGS, // send sms
at21cmdATA // ring dtmf
};
const PROGMEM uint8_t at_move_cmd[] = { // step after action cmd
1, 2, 3, 4, 5, 6, 7, 8, 101, // initATmodem
10, 11, 12, 13, 14, // init http
15, 16, 17, 101, // init gprs
101, // del sms
101, // read sms
101, // send sms
101 // ring dtmf
};
-
Скетч использует 6550 байт (21%) памяти устройства. Всего доступно 30720 байт.
Глобальные переменные используют 617 байт (30%) динамической памяти, оставляя 1431 байт для локальных переменных. Максимум: 2048 байт.
Ready
7900***8478
Proba long SMS beach hlam1455&)
Incoming call from 7900***8478
Pressed key 1
Pressed key 6
Pressed key *
Приветствую, вопрос такой, у меня таймер прочьтения смс стоит 1 сек ( ну условно) юзаю без библиотек sim800L. скорость подачи 9600 бадов. чисто вопрос программирования... вот залетел в проверку по времени ну типо пора проверять, типа есть смс... парсю его, а там еще свои таймеры стоят (на проверку количество попыток и прочее...) и свои АТ команды. вот как это работает?!!! он должен каждую строку по коду же прогнать? правильно же понимаю. Но складывается впечатление что если проверять 1 раз в минуту он как бы не цепляет весь код, гдето вылетает и уже к этому не возвращается. А если его каждую сек кормить то иногда проглатывает как надо. Есть ли адекватная причина проверять смс так часто, если мне по сути без разницы 5 минут или 1 минута. И еще с чем связано что АТ команда не всегда корректно обрабатывается? возможна ли причина в питании ? И еще влияет ли вывод в монитор порта на АТ команды ? Неподглюкивает ли ардуино типа время на отправку, а следом уже надо проработать АТ команду СРАЗУ СЛЕДОМ. А там чтото на скоростях 9600 отправляю. Ктонить спатыкался на этом ? И нужно ли использовать специальные библы чтобы этого избежать?
Вы бы для начала сами сели и подумали, вместо того чтоб валить все в кучу и в одном посте задавать 9 (не поленился посчитать) вопросов.
По главному вопросу - проверять СМС раз в секунду совершенно необязательно, можно хоть раз в час. А чтобы ничего не пропустить - надо настроить, чтобы СМС не просто валились в порт ардуины, но и сохранялись в памяти модуля.
Вопрос собственно не совсем в тему, но про SIM800L. Допустим модуль находится в режиме PPP. Как отследить входящий звонок? Хорошо, если на плате распаян выход ring, тогда все проще - при появлении 0, считаем, что звонок поступил (а оно именно так и работает, проверял), переводим модуль в режим AT команд и дальше работаем. А если такой выход не выведен на плате? Как? По uart полный молчок. Если до режима PPP дать команду ATS0=1, то модуль прекрасно снимет трубку при первом звонке, но ничего не скажет об этом. Как?
Подскажите кто нибудь кастельно пина Ring, что он вообще такое и с чем его едят. Во всех описаниях что я нашел - это сигнал входящего вызова, но как он работает?
задача стоит включить "звонок" при поступлении входящего вызова и соответственно выключить его если вызов прекратился или была снята трубка.
Подскажите кто нибудь кастельно пина Ring, что он вообще такое и с чем его едят. Во всех описаниях что я нашел - это сигнал входящего вызова, но как он работает?
задача стоит включить "звонок" при поступлении входящего вызова и соответственно выключить его если вызов прекратился или была снята трубка.
Спасибо. Из мануала понял что легче программно реализовать обработку поступления информации о входящем вызове чем использовать этот пин.
Да и так, и так - не особо сложно, в общем-то. Проблемы засечь длительность импульса - нет, а уже по длительности понимать, что, собственно, произошло. Просто настроить AT-командами выдачу статусов в порт и потом по всяким +CMT: и +RING: понимать, что пришло СМС или входящий звонок - это банально человекопонятней, на то и AT-протокол изначально был заточен (это сейчас из него выросло то, что выросло :)) ).
а зачем собственно возиться с этим пином, если все равно по итогу придется все равно придется программно разбирать "что произошло". Просто слушаем модуль и при поступлении +RING включаем звонок, при подъеме трубки отключаем и ждем следующего вызова. ну там конечно логика процесса будет несколько сложнее но в общем так.
У меня задача достаточно проста - попросили сделать телефон для приколов. старый советский с дисковым номеронабирателем, но чтоб звонил... + бонусом небольшой дисплейчик к нему прикрутить чтоб видеть набираемый номер. Всю обвязку сделал, осталось собственно модуль sim800l раскурить.
Всю обвязку сделал, осталось собственно модуль sim800l раскурить.
Эх, мне б щас вернуться в те времена, когда всё виделось так просто ;) Осталось-то - всего SIM800L раскурить, и всё. Конечно, если опираться на примеры из сети - курить там нехрен, банальный блокирующий код, и то - о коррекции ошибок авторы примеров, как правило, и не слышали.
А вот если асинхронщина - вот это адъ. У меня ушло примерно полтора года на постепенное допиливание конечного автомата, и это при условии, что он, честно говоря - и не претендует (даже близко) на полноту охвата возможностей общения с SIM800L, да и вообще - коряв и некрасив.
Это я к тому, что я до сих пор не могу сказать, что раскурил SIM800L ;)
Да. именно опираясь на примеры из сети я и действую. Да я понимаю что получится коряво и кровь будет течь из глаз ручьями))) но я не унываю и надеюсь заставить это чудо работать. Может (или даже скорее всего) я где-то крупно ошибаюсь. но пока задача видится достаточно простой. набрать номер - отправить его в модуль для осуществления вызова. и соответственно получить от него информацию о входящем вызове и ответить на него. всю остальную информацию тупо обрубаем. во всяком случае на данном этапе. если интерес не угаснет, можно будет продолжить эксперементы. Для меня это не более чем хобби. взлетит - хорошо, не взлетит - значит не судьба. Свой первый проект "для души" а именно наливатор из старого струйника и платы ардуино я делал наощупь имея только небольшие и давно забытые навыки программирования на delphi и к моему удивлению все получилось. часы на ГРИ получились уже вполне на уровне, но там уже разводка платы с атмегой 328 и еще много всего интересного было...
GrSnake , вы главное себе аксиому поставьте в голове "совсем не использовать delay и всегда проверять ответы от модема", и все будет красиво и хорошо :)
GrSnake , вы главное себе аксиому поставьте в голове "совсем не использовать delay и всегда проверять ответы от модема", и все будет красиво и хорошо :)
про проверять ответы это понятно. а вот как без delay - Вы меня заинтриговали. Как я понял в некоторых местах паузу между отправкой команд делать все равно надо.
про проверять ответы это понятно. а вот как без delay - Вы меня заинтриговали. Как я понял в некоторых местах паузу между отправкой команд делать все равно надо.
вы всю ветку эту прочитали? и вообще все примеры из сети смотрели?
ветку всю не читал, скорее пролистал вскользь ища ответ на свой вопрос по поводу пина Ring. возникнут другие - буду искать ответ на них. Примеров в интернете много причем многие достаточно противоречивы хотябы в плане подключения модуля.
Примеры эти видел, пока в них не вчитывался но на заметку касательно этого проекта.
В скетче проблем не видно, проверяйте подключение, пины, уровни сигналов, ограничительные резисторы, пробуйте поменять местами rx tx. Скорость 9600 поставить. Чудес не бывает.
Ну....нечему там ломаться, у меня работает, но я на 2 и 3 пинах лог вывожу, разницы быть не должно. Обновите software serial библиотеку, вдруг ошибка, попробовать на других ножках, тестером проверить все соединения, питание модема отдельное 4 вольта, если включить модем после МК, при регистрации в сети в логе должны быть сообщения из модема и скорость 9600 строго при включении, потом увеличивать будете после отладки
Не правильно, на модеме уровень сигнала 2.8 в ,а у вас 2.5. фильтрации питания нет вообще,на tx резистор зачем. И т д .....
Все плохо, откройте даташит
Задам здесь вопрос к Andycat, как человеку глубоко разобравшемуся в вопросе. Ты используешь брокер clusterfly.ru ? Если да, есть ли у тебя проблемы с этим брокером? После НГ у меня перестало работать SIM800L MQTT на этом брокере. До НГ неделями онлайн нормальный был на том же скетче и железе. Написал в техподдержку - говорят ничего не изменилось на сервере.
Причём не совсем не работает. Происходит так: подключается, работает (как PUB, так и SUB) ровно 30 секунд и выбрасывает с сервера. SIM800 при этом пишет CLOSED. Может подскажешь как выяснить причину выбрасывания? CloudMQTT при этом нормально работает.
добрый день.
в ДШ упоминается PWRKEY пин. но на выводах сим800 такого нету. есть варианты как можно программно его выключать /включать ?
на модулях не выведенно, а программно - вот прямо над вашим постом, который я процитировал.
Спасибо, сообщение видел. Там речь про спящий режим. Меня больше интересует полное отключение через power key
Готовка не обязательно влияет на результат. Пример 6 (шести) модулей - https://www.amazon.de/AZDelivery-⭐⭐⭐⭐⭐-SIM800L-Antenne-Arduino/dp/B07D361WZV/
Из шести три прекрасно запитались от +5в, живут замечательно (хотя скорее всего это просто over-voltage protection в модулях не работает как надо). Два из них запускаются и живут от 3.3v.
Ещё один от 5в моргает два раза при включении и всё (over-voltage protection сработал). От ~4v работает.
Ещё один от 5в моргает уже не два, а три раза при включении (опять over-voltage protection сработал).
Итого: очень большой разброс, каждый модуль сам по себе.
А в чем суть подбора модуля из шести - работает/не работает овервольтаж? Если есть отлично зарекомендовавший себя способ запитать модуль от 5в через обычный кремниевый диод, и получить на нем 4.2-4.4 вольта, от которых он работает всегда, и без сбоев?
Цели подбора не стояло. Про шесть модулей написано исключительно из соображений личного опыта и ситуации, что "одинаковые" модули на самом деле все разные, какие-то работают прекрасно и от 5в (хотя как бы и не должны), а какие-то не работают вообще ни от скольки.
А если из 20+ модемов, подключённых по даташиту работают 100 % это типа не правильно)))
Это охрененно правильно и Вы везунчик (ну или типа того)
Это не везение, а правильное подключение и правильный продавец модемов.
Судя по всему Вы большой специалист по подключению и по выбору продавца. Прямо таки завидую Вам !
Небольшая библиотека для работы с Sim800L, функционал:
- прием и отправка SMS
- прием входящих звонков и обработка DTMF нажатий
В проекте добавление следующих действий:
- отправка GET запросов и чтение возвращаемой странички HTML
- пакетная прием-передача данных -> общение с MQTT сервером
Скетч из 4х файлов, первый - пример использования с комментариями, остальные - сама библиотека.
Обработка ответов из модема online - в каждом проходе loop, соответственно категорически не рекомендуется сильно задерживать цикл своими обработчиками.
-
-
-
-
Приветствую, вопрос такой, у меня таймер прочьтения смс стоит 1 сек ( ну условно) юзаю без библиотек sim800L. скорость подачи 9600 бадов. чисто вопрос программирования... вот залетел в проверку по времени ну типо пора проверять, типа есть смс... парсю его, а там еще свои таймеры стоят (на проверку количество попыток и прочее...) и свои АТ команды. вот как это работает?!!! он должен каждую строку по коду же прогнать? правильно же понимаю. Но складывается впечатление что если проверять 1 раз в минуту он как бы не цепляет весь код, гдето вылетает и уже к этому не возвращается. А если его каждую сек кормить то иногда проглатывает как надо. Есть ли адекватная причина проверять смс так часто, если мне по сути без разницы 5 минут или 1 минута. И еще с чем связано что АТ команда не всегда корректно обрабатывается? возможна ли причина в питании ? И еще влияет ли вывод в монитор порта на АТ команды ? Неподглюкивает ли ардуино типа время на отправку, а следом уже надо проработать АТ команду СРАЗУ СЛЕДОМ. А там чтото на скоростях 9600 отправляю. Ктонить спатыкался на этом ? И нужно ли использовать специальные библы чтобы этого избежать?
Вы бы для начала сами сели и подумали, вместо того чтоб валить все в кучу и в одном посте задавать 9 (не поленился посчитать) вопросов.
По главному вопросу - проверять СМС раз в секунду совершенно необязательно, можно хоть раз в час. А чтобы ничего не пропустить - надо настроить, чтобы СМС не просто валились в порт ардуины, но и сохранялись в памяти модуля.
Да думал попунктно разбить ) но хоть какие нить зацепки получить...
Сесть я сел, но вот с думалкой беда у меня (
смс сохраняется в памяти и только после прочтения его удаляю.
смс сохраняется в памяти и только после прочтения его удаляю.
тогда зачем проверять раз в секунду?
А вообще - показывайте код, как читаете СМС, без кода разговаривать не о чем
Бывает до парсем смс недоходит дело вообще...
Shama - вставьте код по правилам, это сообщение модераторы скоро удалят
Я новенький, пойду почитаю правила )
Я извиняюсь, а где можно правила почитать ?
Господа-товарищи :)
Вопрос собственно не совсем в тему, но про SIM800L. Допустим модуль находится в режиме PPP. Как отследить входящий звонок? Хорошо, если на плате распаян выход ring, тогда все проще - при появлении 0, считаем, что звонок поступил (а оно именно так и работает, проверял), переводим модуль в режим AT команд и дальше работаем. А если такой выход не выведен на плате? Как? По uart полный молчок. Если до режима PPP дать команду ATS0=1, то модуль прекрасно снимет трубку при первом звонке, но ничего не скажет об этом. Как?
Помогите :))
Спасибо.
Попробуйте включить оповещение о состоянии разговорного канала
Доброго времени суток
Подскажите кто нибудь кастельно пина Ring, что он вообще такое и с чем его едят. Во всех описаниях что я нашел - это сигнал входящего вызова, но как он работает?
задача стоит включить "звонок" при поступлении входящего вызова и соответственно выключить его если вызов прекратился или была снята трубка.
Доброго времени суток
Подскажите кто нибудь кастельно пина Ring, что он вообще такое и с чем его едят. Во всех описаниях что я нашел - это сигнал входящего вызова, но как он работает?
задача стоит включить "звонок" при поступлении входящего вызова и соответственно выключить его если вызов прекратился или была снята трубка.
https://img.filipeflop.com/files/download/Datasheet_SIM800L.pdf - раздел 4.6, страница 35.
Спасибо. Из мануала понял что легче программно реализовать обработку поступления информации о входящем вызове чем использовать этот пин.
Спасибо. Из мануала понял что легче программно реализовать обработку поступления информации о входящем вызове чем использовать этот пин.
Да и так, и так - не особо сложно, в общем-то. Проблемы засечь длительность импульса - нет, а уже по длительности понимать, что, собственно, произошло. Просто настроить AT-командами выдачу статусов в порт и потом по всяким +CMT: и +RING: понимать, что пришло СМС или входящий звонок - это банально человекопонятней, на то и AT-протокол изначально был заточен (это сейчас из него выросло то, что выросло :)) ).
а зачем собственно возиться с этим пином, если все равно по итогу придется все равно придется программно разбирать "что произошло". Просто слушаем модуль и при поступлении +RING включаем звонок, при подъеме трубки отключаем и ждем следующего вызова. ну там конечно логика процесса будет несколько сложнее но в общем так.
У меня задача достаточно проста - попросили сделать телефон для приколов. старый советский с дисковым номеронабирателем, но чтоб звонил... + бонусом небольшой дисплейчик к нему прикрутить чтоб видеть набираемый номер. Всю обвязку сделал, осталось собственно модуль sim800l раскурить.
Всю обвязку сделал, осталось собственно модуль sim800l раскурить.
Эх, мне б щас вернуться в те времена, когда всё виделось так просто ;) Осталось-то - всего SIM800L раскурить, и всё. Конечно, если опираться на примеры из сети - курить там нехрен, банальный блокирующий код, и то - о коррекции ошибок авторы примеров, как правило, и не слышали.
А вот если асинхронщина - вот это адъ. У меня ушло примерно полтора года на постепенное допиливание конечного автомата, и это при условии, что он, честно говоря - и не претендует (даже близко) на полноту охвата возможностей общения с SIM800L, да и вообще - коряв и некрасив.
Это я к тому, что я до сих пор не могу сказать, что раскурил SIM800L ;)
Да. именно опираясь на примеры из сети я и действую. Да я понимаю что получится коряво и кровь будет течь из глаз ручьями))) но я не унываю и надеюсь заставить это чудо работать. Может (или даже скорее всего) я где-то крупно ошибаюсь. но пока задача видится достаточно простой. набрать номер - отправить его в модуль для осуществления вызова. и соответственно получить от него информацию о входящем вызове и ответить на него. всю остальную информацию тупо обрубаем. во всяком случае на данном этапе. если интерес не угаснет, можно будет продолжить эксперементы. Для меня это не более чем хобби. взлетит - хорошо, не взлетит - значит не судьба. Свой первый проект "для души" а именно наливатор из старого струйника и платы ардуино я делал наощупь имея только небольшие и давно забытые навыки программирования на delphi и к моему удивлению все получилось. часы на ГРИ получились уже вполне на уровне, но там уже разводка платы с атмегой 328 и еще много всего интересного было...
Извиняюсь за оффтоп)))
и к моему удивлению все получилось.
Не питай иллюзий - это тебя так завлекают :)) Туризм и эмиграция - разные вещи :)))
GrSnake , вы главное себе аксиому поставьте в голове "совсем не использовать delay и всегда проверять ответы от модема", и все будет красиво и хорошо :)
GrSnake , вы главное себе аксиому поставьте в голове "совсем не использовать delay и всегда проверять ответы от модема", и все будет красиво и хорошо :)
про проверять ответы это понятно. а вот как без delay - Вы меня заинтриговали. Как я понял в некоторых местах паузу между отправкой команд делать все равно надо.
про проверять ответы это понятно. а вот как без delay - Вы меня заинтриговали. Как я понял в некоторых местах паузу между отправкой команд делать все равно надо.
вы всю ветку эту прочитали? и вообще все примеры из сети смотрели?
вот выше например
http://arduino.ru/forum/apparatnye-voprosy/vse-o-sim800l-i-vse-chto-s-ni...
примеры с сайта codius.ru не плохи, учиться на них хорошо.
ветку всю не читал, скорее пролистал вскользь ища ответ на свой вопрос по поводу пина Ring. возникнут другие - буду искать ответ на них. Примеров в интернете много причем многие достаточно противоречивы хотябы в плане подключения модуля.
Примеры эти видел, пока в них не вчитывался но на заметку касательно этого проекта.
Здравствуйте. С НОВЫМ ГОДОМ.
Подключила SIM800L к RX TX ардуино, а отладку делаю по SoftwareSerial (подключила UART конвертер)
SIM800 команды не понимает, данные не приходят.
Для проверки подключила конвертер к SIM800, данные отправляются и читаются.
Подключила конвертер к RX TX ардуино - данные отправляются и читаются*
Что не так? (не хватает пинов ардуино, хочу использовать RX TX)
В скетче проблем не видно, проверяйте подключение, пины, уровни сигналов, ограничительные резисторы, пробуйте поменять местами rx tx. Скорость 9600 поставить. Чудес не бывает.
Это уже всё перепробовала. Из-за питания ардуины через юсб может быть такая проблема?
Не может, а будет точно. Питайте правильно
Уже, но безрезультатно, сообщения такого плана CONVERTER.println ("123");
конвертер получает, а с модуля ничего.
Ну....нечему там ломаться, у меня работает, но я на 2 и 3 пинах лог вывожу, разницы быть не должно. Обновите software serial библиотеку, вдруг ошибка, попробовать на других ножках, тестером проверить все соединения, питание модема отдельное 4 вольта, если включить модем после МК, при регистрации в сети в логе должны быть сообщения из модема и скорость 9600 строго при включении, потом увеличивать будете после отладки
Дело в том, что на ардуино есть два резистора на RX TX, и у меня на модуле один на 1 кОм и делитель из двух по 10кОм, поэтому и неработало.
Модуль стал отвечать на АТ, но при этом перезагружается, странно.
Мощности БП не хватает
10 Ампер БП (DPS5020)
Совсем не показатель, подключать осциллограф, смотреть что на шине питания.
При работе по софтсериал, всё норм. А на счёт осциллографа ещё нету, первый раз заказала, не пришел, деньги вернули, надо заказать ещё раз)
Подключите согласно даташита и забудете о проблема с питанием и помехами
Так подключено:
Не правильно, на модеме уровень сигнала 2.8 в ,а у вас 2.5. фильтрации питания нет вообще,на tx резистор зачем. И т д .....
Все плохо, откройте даташит
Задам здесь вопрос к Andycat, как человеку глубоко разобравшемуся в вопросе. Ты используешь брокер clusterfly.ru ? Если да, есть ли у тебя проблемы с этим брокером? После НГ у меня перестало работать SIM800L MQTT на этом брокере. До НГ неделями онлайн нормальный был на том же скетче и железе. Написал в техподдержку - говорят ничего не изменилось на сервере.
Причём не совсем не работает. Происходит так: подключается, работает (как PUB, так и SUB) ровно 30 секунд и выбрасывает с сервера. SIM800 при этом пишет CLOSED. Может подскажешь как выяснить причину выбрасывания? CloudMQTT при этом нормально работает.