1. Пиков в 2 ампера я не заметил на всем промежутки работы модуля (10 минут)
2. Стандартный ток в модуле - 20 мА
3. При регистрации в сети ток - 100мА, никакими 2А там и не пахнет.
3. Как я и говорил проблема не в питании, сейчас обеспечил абсолютно стабильные 4В 2А, результат нулевой. Прошу если и высказываться, то конструктивно, имхо даже с студенту 1-2 курса понятно что при нагрузках в виде регистрации в сети и отправки 3-4 сообщений по юарту в секунду модуль не сможет физически жрать 2А.
Ага, и даташиты дураки пишут, и на форумах бараны, которые с запасом БП делают, живите дальше в своей розовой вселенной и делайте г... устройства :(
А на счет используемого вами БП на 1 А меня терзают смутные сомнения, что он подойдет, ведь по даташиту модуль кушает 2 А, и как он работает от силы тока в два раза меньше мне решительно непонятно. Очевидно, человек не читал даташит, и, я надеюсь, не доказывает всем, что тот, кто не читал даташит делает "г... устройства"
А если по конструктиву, то: паял обвязку в виде ножек и антенны я сам, косяков там не может быть. Возможно что-то с пайкой модуля, но перепаять я его не могу, имея паяльник и фен. Есть ли у кого-то соображения пока ко мне идет 3 модуля и мои платы под этот модуль с китая?
Проблема с модулем Sim800l. Через какой-то промежуток времени перестает работать. Светодиод не мигает. Перезапуск не помогает. Может включиться на следующий день. Контакты пропаяны хорошо, нигде не отходит.
Питание от компьютерного блока питания, шина +12в, через DC-DC LM2596S, на выходе 4.1В. Модуль подключаю к Нано, RX-TX через резисторный делитель. Скетч брал отсюда
История такова. Схема запускалась, скетч работал, все АТ команды проходили на УРА, сообщения на телефон получал. После оставил на какое-то время всё в покое. Через какое-то время модуль отключился. Отключал питание, DTR садил на землю. Ничего не помогало его включить. На следующий день попытался опять , и он включился. Через определённое время всё повторилось.
Отключал питание, DTR садил на землю. Ничего не помогало его включить.
Так может модуль бракованный? другой не пробовали? Я встречался что у SIM800L зависает радио модуль, но это бывает у единиц и через 1.5 - 2 месяца непрерывной работы. И на AT команды он все равно отвечает. И все соединения к модулю крайне рекомендуется паять.
Так может модуль бракованный? другой не пробовали? Я встречался что у SIM800L зависает радио модуль, но это бывает у единиц и через 1.5 - 2 месяца непрерывной работы. И на AT команды он все равно отвечает. И все соединения к модулю крайне рекомендуется паять.
Весьма вероятно . У меня с 50 модулей , очень много брака оказалось . Какие сразу не работали , а какие работали потом переставали вовсе. По прозвонке , с нормальными , выяснил закономерность в виде плохих прозванивающихся пинов. Видимо китайцы плохо припаяли модули.
В след. раз буду брать только SIM800C , у них необходимые пины по сторонам модуля , а не под ним где не увидишь качество пайки. У SIM800C разве что пин управления питания немного по другой логике работает.
Питание от компьютерного блока питания, шина +12в, через DC-DC LM2596S, на выходе 4.1В. Модуль подключаю к Нано, RX-TX через резисторный делитель. Скетч брал отсюда
История такова. Схема запускалась, скетч работал, все АТ команды проходили на УРА, сообщения на телефон получал. После оставил на какое-то время всё в покое. Через какое-то время модуль отключился. Отключал питание, DTR садил на землю. Ничего не помогало его включить. На следующий день попытался опять , и он включился. Через определённое время всё повторилось.
Приобрёл модуль Sim800C. Пару дней с ним ковыряюсь, пока всё работает. Такой вопрос. Попалась статья, где указано, что необходимо согласовывать с модулем подключаемую антенну. Нашел схему в даташите, но там не указываются номиналы елементов. Какие надо, и надо ли вообще?
Подскажите кто знает как сделать что бы когда Sim800L ответила на входящий звонок по белому списку номеров и передачи DTMF сигналов с мобильного телефона в динамике Sim800L не было слышно как раз этих сигналов DTMF ? А то подаёшь команду и слышишь её , мне просто для проекта это не нужно .
добавлю свои пять копеек по поводу питания и 2 ампер в пике.
Обнаружил что в SIM800L стоит самый настоящий УМЗЧ собраный по мостовой схеме для увеличения выходной мощности. Усилитель тоже жрет и довольно много. поэтому предположения что если подключить достаточно низкоомную нагрузку и выставить CLVL=100 (громкость) то ток потребления увеличится. А если нагрузки нет то ни о каких 2 ампер даже и близко речи не может быть.
простой конденсатор по питанию превратит из пикового значения в RMS.
Ещё один не верующий в даташит :(
Уважаемый, не вводите людей в заблуждение, если вы это не видели, это не значит что этого нет.
ЗЫ. Сам видел нагрузку высокую, да иногда не предсказуемо, но она есть.
Собрал не менее десятка устройств, по моим проектам тысячи и я вас уверяю - тестировали очень много прежде чем выбрать правильный БП.
я не ввожу в заблуждение, а пытаюсь разобраться. там в даташит указано что может пиковая нагрузка быть, а в каких условиях она может быть вот один из вариантов я и предполагаю следующее.
выходная мощность УМЗЧ 1 вт. с хвостиком. КПД усилителя АВ не более 50%, из этого следует что потребляет он более 2 вт только на динамик и эта мощность не пиковая а RMS. отсюда вывод если нет динамика то можеш сразу 0.5 А сразу удалить. а то и больше. (прям совсем топорный анализ)
даташит стр 36 усилитель АВ. гуглим КПД 50%. в идеальных условиях и при максимальной мощности может достигать 70%. это все еще RMS.
опять топорный подсчет. на выходе усилителя АВ амплитуда может достигать питания 4 в (схема усилителя мостом). при нагрузки динамика 8 ом ток пиковый через динамик составит 0.5 А если еще прикинуть КПД 70% то реальное потребление еще чутка больше. я просто указываю что реально достаточно много жрет. ловить меня на точных подсчетах ненужно, это просто топорный подсчет.
если динамика нет то и нагрузки нет, значит и ток через 8 ом не потечет значит и потреблять меньше будет (это просто аксиома) нет нагрузки нет тока.
Alex_Mn , sim800l может потреблять более 1.5 ампер без всяких динамиков на выходе и это факт, подтвержденный практикой. Быть теоретиком это хорошо, но когда вам нужно стабильно работающее устройство, это совсем другое.
даташит стр 36 усилитель АВ. гуглим КПД 50%. в идеальных условиях и при максимальной мощности может достигать 70%. это все еще RMS.
1. Так все-таки, 50% или 70%? Это как бы не одно и от же.
2. О каком дэйташите Вы говорите. На физические формулы нет дэйташитов. Если уж ссылаться, то на страницу учебника, а не дэйташита.
3. Максимальный КПД усилителя класса В (на синусоидальном сигнале без искажений) составляет 78.5%. Для класса АВ - совпадает (с указанной точностью) с этим значением.
Цитата:
если динамика нет то и нагрузки нет, значит и ток через 8 ом не потечет значит и потреблять меньше будет (это просто аксиома) нет нагрузки нет тока.
Это не аксиома, это - логическая ошибка: из того, что средний ток будет меньше, никак не следует, что максимальный ток также будет меньше.
1. Пиков в 2 ампера я не заметил на всем промежутки работы модуля (10 минут)
2. Стандартный ток в модуле - 20 мА
3. При регистрации в сети ток - 100мА, никакими 2А там и не пахнет.
3. Как я и говорил проблема не в питании, сейчас обеспечил абсолютно стабильные 4В 2А, результат нулевой. Прошу если и высказываться, то конструктивно, имхо даже с студенту 1-2 курса понятно что при нагрузках в виде регистрации в сети и отправки 3-4 сообщений по юарту в секунду модуль не сможет физически жрать 2А.
конструктивно высказываю свои мысли. хотя тебе может уже не актуально, но другим может и позновательно.
даташит на SIM800L указывает что ток в пике может достигать 2 ампер длительность этого импульса весьма микроскопична (даташит только оговаривает на саму сборку). и указывает что нужно устанавливать конденсатор минимум 100 мкф. то что ты мериш уже собраный макет и в котором уже стоит эта емкость, отсюда ты никогда не увидиш эти 2 ампера.
плюс еще там стоит усилитель НЧ который работает на 8 омную нагрузку, который жрет (мои предположения больше чем усилитель ВЧ). усилитель ВЧ нагружен на антену 50 ом. поэтому мои предположения что если не использовать динамик то апетит этого модуля куда скромнее 2 ампер. и не обращай внимание на аналитиков которые техническую литературу рассматривают как журнал "мурзилка" (картинки)
ключевое слово!
Спорить не буду, понял что бесполезно, у вас свои учебники из другой вселенной, когда соберете устройство со слабеньким БП на модем миллиампер на 300....и сможете добиться uptime стабильной непрерывной работы/звонки/СМС/GPRS на пару месяцев - тогда и поговорим :)
ключевое слово!
Спорить не буду, понял что бесполезно, у вас свои учебники из другой вселенной, когда соберете устройство со слабеньким БП на модем миллиампер на 300....и сможете добиться uptime стабильной непрерывной работы/звонки/СМС/GPRS на пару месяцев - тогда и поговорим :)
что у вас за манера высказывать что одни вы правы и вы один дартаньян, есть что по делу то говорите. на то и форум искать компромис мнений. чел искал пиковый ток и не смог его обнаружить, я подсказал свое мнение почему его нет.
там стоит усилитель НЧ который работает на 8 омную нагрузку, который жрет (мои предположения больше чем усилитель ВЧ).
Где вы там увидели 8-омную нагрузку? Даже если предположить что она в готовом устройстве действительно есть, то динамик участвует только при вызовах, а до этого, как минимум, модуль должен зарегистрироваться в сети, чего у большинства как раз и не происходит при некачественном питании. Т.е. до возрастания потребления модулем из-за УНЧ и низкоомного динамика еще ой как далеко...
там стоит усилитель НЧ который работает на 8 омную нагрузку, который жрет (мои предположения больше чем усилитель ВЧ).
Где вы там увидели 8-омную нагрузку? Даже если предположить что она в готовом устройстве действительно есть, то динамик участвует только при вызовах, а до этого, как минимум, модуль должен зарегистрироваться в сети, чего у большинства как раз и не происходит при некачественном питании. Т.е. до возрастания потребления модулем из-за УНЧ и низкоомного динамика еще ой как далеко...
конечно там и нет нагрузки (динамика), ну так я там и не увидел 2 ампер потребления, и там как раз приводится эксперемент что при регистрации потребления возрастает до 100 ма. кто-нибудь хоть видел на приборе пиковый ток в 2 ампера? реально видеть не что что бабушка сказала. да что там 2 ампера, хоть приведите факт реальный в 1 ампер.
что у вас за манера высказывать что одни вы правы и вы один дартаньян, есть что по делу то говорите. на то и форум искать компромис мнений. чел искал пиковый ток и не смог его обнаружить, я подсказал свое мнение почему его нет.
да пожалуйста, подумаешь.....сами то можете привести факты - график потребления хотя бы за пару суток со схемой подключения?
Впрочем не важно, не отвечайте, не интересно :)
ЗЫ. Новичков жалко, начитаются таких комментариев, потом подключают питание sim800l например от самой arduino UNO и удивляются че это у них не работает :(
что у вас за манера высказывать что одни вы правы и вы один дартаньян, есть что по делу то говорите. на то и форум искать компромис мнений. чел искал пиковый ток и не смог его обнаружить, я подсказал свое мнение почему его нет.
да пожалуйста, подумаешь.....сами то можете привести факты - график потребления хотя бы за пару суток со схемой подключения?
Впрочем не важно, не отвечайте, не интересно :)
ЗЫ. Новичков жалко, начитаются таких комментариев, потом подключают питание sim800l например от самой arduino UNO и удивляются че это у них не работает :(
хорошо как-нибудь будет время попробую, не обещаю на ради эксперимента постараюсь сгородить некий стенд. но ни о каких 2 суток не может быть и речи. максимум некоторые моменты продолжительностью в несколько секунд. ибо такие замеры адекватно проводить на осцилографе. ни один мультиметр не способен ловить пики.
некоторые моменты продолжительностью в несколько секунд. ибо такие замеры адекватно проводить на осцилографе. ни один мультиметр не способен ловить пики.
смешно.......и нафиг не надо, и при чем тут мультиметр? в даташите черным по английски на 20 странице написано что при передаче может быть сильное падение напряжения и БП должен обеспечивать ток нагрузки до 2 ампер. Лично мне не нужны никакие доказательства, если вы уперлись и хотите сообществу что там доказать - соберите стенд с электронным логированием потребляемого тока в разных режимах работы - тогда и поговорим.
измерения проводил осцилографом. в разрыв питания поставил резистор 0.125 ом (точность 1%).
желтый луч показывает напряжения на этом резисторе пульсация достигала даже чутка более 160 мв. что в переводе на ток 0.16/0.125 = 1.28 ампер и это прям на скорую руку думаю если еще грузануть то можно еще больше ток увидить.
так что снимаю шляпу действительно ток в 1.5 А думаю в импульсе запросто жрет.
такие импульсы не всегда, когда в сети регистрируется кратковременно кидают импульсы, когда идет дозвон на этот номер тож хорошие импульсы.
источник питания брал китайский блок питания стабилизатор на микрухе LM2596S. напряжения 4.05 вольта.
Итак я вернулся! Овации господа! И я готов отстаивать свое мнение. За плечами у меня 4 рабочих модуля, отправленные СМС и ИСТИНА. Истиной готов поделиться. При регистрации модуля в сети пиковая нагрузка 4V 0,2A вкуснейшего постоянного напряжения. Ни о каких 2А речи идти не может, после регистрации при переходе в режим ожидания модуль жрет от 0,01 до 0,05 ампер заявленного напряжения. При отсутствии же законченной регистрации он с периодичностью в 20-30 секунд пытается зарегистрироваться в сети. Моя проблема была не в проводах, ни тем более в электричестве. Все оказалось весьма банально, однако никто мне по этому поводу советов не дал. НЕ ИСПОЛЬЗУЙТЕ КАРТЫ ТЕЛЕ-2, у меня они НЕ ПАШУТ с модулем. Заблокированную МТС видит, рабочую МТС видит. В качестве теста отправил сообщение. Оборудование БП (указан выше, переходник USB-UART, ноут, симка МТС). Спасибо за внимание
P.S. andycat, учите матчасть (не даташиты а физику)
Абсолютно с вами согласен, коллега практик, у меня вышло 200 мА пик, больше не жрало, я думаю если все функции применить в модуле одновременно может там и будет ток около 1А но явно это не причина не работы просто подключенного модуля, что я пытался доказать господам выше и был послан
Итак я вернулся! Овации господа! И я готов отстаивать свое мнение. За плечами у меня 4 рабочих модуля, отправленные СМС и ИСТИНА. Истиной готов поделиться. При регистрации модуля в сети пиковая нагрузка 4V 0,2A вкуснейшего постоянного напряжения. Ни о каких 2А речи идти не может, после регистрации при переходе в режим ожидания модуль жрет от 0,01 до 0,05 ампер заявленного напряжения. При отсутствии же законченной регистрации он с периодичностью в 20-30 секунд пытается зарегистрироваться в сети. Моя проблема была не в проводах, ни тем более в электричестве. Все оказалось весьма банально, однако никто мне по этому поводу советов не дал. НЕ ИСПОЛЬЗУЙТЕ КАРТЫ ТЕЛЕ-2, у меня они НЕ ПАШУТ с модулем. Заблокированную МТС видит, рабочую МТС видит. В качестве теста отправил сообщение. Оборудование БП (указан выше, переходник USB-UART, ноут, симка МТС). Спасибо за внимание
P.S. andycat, учите матчасть (не даташиты а физику)
Да мне насрать на ваше мнение)
Я сторонник верить даташитам.
И да, когда будет у вас несколько тысяч! устройств на sim800 с бп 500 мА и uptime несколько месяцев, тогда и поговорим....а так это просто пшик ни о чем.
... И я готов отстаивать свое мнение. За плечами у меня ...
ждем когда начнеш отстаивать, только еще пиши чем и как мерил пиковые нагрузки.
выше я скрин осцилографа выложил, падения напряжения на резисторе 0.125 ом (точность резистора 1%).
значение пиковое и среднеквадратичное они разные. а то если считать по значению RMS там как раз 36 мв. в переводе на ток 0.036/0.125 и получим твои 0.288 А.
Интересно, вам не надоело повторять как заведенному историю про даташиты и кучи ваших устройств? Я смотрю за столько времени ваша риторика так и не сменилась. При чем кое-где вы пишете что-то про то, что вы практик при этом не прикладывая к своим словам никакой информации. По-моему вы обычный словоблуд, который не может принять факт того, что был неправ в течении уже 3?4? месяцев. Вам уже и графики приводят и фотки скидывают, и проблема уже решилась, а вы все про свой даташит пишете. Можете не отвечать, это последнее сообщение в ветке, где мне не смогли помочь, зато давали "дельные" советы в тех местах, где проблем не было, что тоже о многом говорит.
P.S. Про ваше личное качество может говорить и то, что вы делаете свои поделки на копеечном модуле и ардуине. Поверьте, серьезные проекты делают не на них, и хоть миллионы их штук дело не изменят) Вы не смогли найти проблему имея тысячу этих модулей, о чем нам с вами говорить?)
на практике я и намерил пиковый ток в 1.28 ампер и это просто пустой модуль. и это проводилось просто на скорую руку, еще УНЧ нагрузить получим еще больше.
на практике я и намерил пиковый ток в 1.28 ампер и это просто пустой модуль. и это проводилось просто на скорую руку, еще УНЧ нагрузить получим еще больше.
Alex, я не вам писал свое последнее сообщение, а телу выше) Ваш график я видел, что вполне может соответствовать правде, однако вопрос то в начале у меня был несколько иной, да и сомневаюсь что он сможет долго жрать 1,5А
Библиотека для работы GPRS с модемом SIM800L.
MK и модем подключены через аппаратный UART, соотвественно на 0 и 1 пины МК.
Пин Arduino TX1 подключается через резисторный делитель (понизить с 5 вольт до ~2.8 вольт) на пин RX модема.
Пин Arduino RX0 подключается напрямую на пин TX модема.
Пин Arduino A1 подключается через резистор 30....70 Ом на пин RST модема.
Для вывода лога в консоль использую внешний TTL-USB переходник, подключенный через пины 2 и 3 МК, работает через библиотеку SoftwareSerial. В итоговом работающем устройстве рекомендую вывод каких либо данных в консоль через эту библиотеку не использовать!
Поскольку обработка данных от модема идет в online режиме анализом каждого входящего байта данных, крайне не рекомендуется в своих задачах использовать delay и любой долго задерживающий loop код!
В дальнейшем напишу библиотеку работы с MQTT, буду выкладывать по мере готовности.
Пример работы с HTTP сервером
#define USESOFTUARTLOG // если будем выводить ответы из модема или какие то сообщения программы в SoftwareSerial, закоментировать при ненадобности
#include <avr/pgmspace.h>
#include <avr\wdt.h> // стандартная библиотека работы с WDT
#include "sim800gprs.h" // библиотека работы с модемом SIM800L
#ifdef USESOFTUARTLOG
unsigned char pinSwUART_TX = 2, pinSwUART_RX = 3; // пины куда подключаем USB-TTL переходник для вывода лога
#include <SoftwareSerial.h> // стандартная библиотека работы с SoftwareSerial
SoftwareSerial swuart(pinSwUART_RX, pinSwUART_TX); // установка контактов
void showResponseModem(unsigned char inByte) { // обработчик вывода ответа от модема
swuart.write(inByte); // выводим в програмный UART
}
#endif /*USESOFTUARTLOG*/
Sim800GPRS myModem; // объект класса модем
// инициализация WDT (код из даташита + из форума)
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
wdt_disable(); // отключение WDT
#ifdef USESOFTUARTLOG
swuart.begin(115200);
swuart.println(F("Start!"));
myModem.setCallbackRespnseByte(showResponseModem); // прописываем обработчик вывода ответов
#endif /*USESOFTUARTLOG*/
// put your setup code here, to run once:
myModem.initUART(); // инициализация порта
myModem.startInit(); // и запуск
wdt_enable(WDTO_1S); // включение WDT
}
const unsigned char serverName[] PROGMEM = {"arduino.ru"}; // адрес сервера
const unsigned short serverPort = 80; // порт TCP сервера HTTP
const unsigned char getHTTP[] PROGMEM = {"GET / HTTP/1.1\r\n\
Host: arduino.ru\r\n\
User-Agent: Mozilla/5.0 (X11; U; Linux i686; ru; rv:1.9b5) Gecko/2008050509 Firefox/3.0b5\r\n\
Accept: text/html\r\n\
Connection: keep-alive\r\n\r\n"
}; // запрос HTTP GET
void processHTTPclient(void) { // пример работы HTTP клиента
static _Bool needConnectTCPserver = true; // необходимо подключиться к серверу
static unsigned long timerSendHttpGet = 0; // таймер соединения с сервером и отправки GET запроса
if (needConnectTCPserver) { // еще не соеденялись с вервером
if ((millis() - timerSendHttpGet) >= 90000UL) { // Каждые 90 секунд соединяемся с сервером
needConnectTCPserver = false; // сбросили флаг соединения
myModem.connectToTCPsocket((unsigned char *) serverName, serverPort); // соединяемся с сервером
}
} else { // ждем соединения
if (myModem.getStatusGPRS() == gprsConnected) { // успешно соеденились, надо отправить HTTP GET запрос
myModem.sendDataToServer((unsigned char *) getHTTP); // отправили данные на сервер
// далее ждем статус успешной отправки
// при ошибке действуем по ситуации
// при нормальной отправке вылавливаем данные приходящие от сервера тут showResponseModem(unsigned char inByte)
// или тупо ничего не делаем и через некоторое время повторно шлем HTTP GET запрос
timerSendHttpGet = millis(); // сбросили таймер для след отправки
needConnectTCPserver = true; // опять отправим данные, предварительно соеденившись с сервером
}
}
}
void loop() {
wdt_reset(); // сброс WDT
myModem.loopSIM800modem(); // циклическая работа с модемом
// put your main code here, to run repeatedly:
if ((myModem.getGlobalModemStatus() == modemInit) || (myModem.getGlobalModemStatus() == modemRegSIM)) { // идет первоначальная инициализация модема
// что то тут делаем
} else if (myModem.getGlobalModemStatus() == modemNeedRestart) { // все плохо
// как минимум перезагрузить модем, можно еще и весь МК
myModem.modemReset();
myModem.startInit(); // и запуск
} else if (myModem.getGlobalModemStatus() == modemReady) { // инициализация прошла
#ifdef USESOFTUARTLOG
static unsigned char flagFirstStart = 1; // для тестовой надписи что модем успешно инициализировали
if (flagFirstStart) { // один раз
flagFirstStart = 0; swuart.println(F("Modem ready")); // выведем надпись
}
#endif /*USESOFTUARTLOG*/
processHTTPclient(); // пример работы HTTP клиента
// что то дальше делаем
}
}
/*Скетч использует 7448 байт (24%) памяти устройства. Всего доступно 30720 байт.
Глобальные переменные используют 516 байт (25%) динамической памяти, оставляя 1532 байт для локальных переменных. Максимум: 2048 байт.*/
- sim800gprs.h
// sim800gprs.h by andycat2013@yandex.ru
// библиотека работы с модемом SIM800L
// используется аппаратный UART пины 0 и 1 Atmega328p
#pragma once
#define _speed_modem 9600 // скорость порта работы с модемом
#define _wait_period_init_cmd 5000UL // время ожидания ответа на команды начальной инициализации модема и кратких команд интернета
#define _wait_power_start_modem 5000UL // время ожидания начла инициализациии после включения питания, проснуться модему
#define _period_wait_registration_modem 5000UL // каждый этот период спрашивается зарегестрировался ли модем
#define _period_ready_modem 45000UL // общее время, которое дается на регистрацию в сети, иначе перезагрузка модема
#define _period_connect_gprs_ready 180000UL // общее время подключения к серверу, 3 минуты, поскольку на некоторые команды ответ по даташиту больше минуты требуется, иначе перезагрузка модема
#define _period_wait_send_ok 15000UL // время ожидания успешной отправки данных
#define _size_response_buf ((unsigned char)16) // размер циклического буфера приема данных от модема
#define _pinResetModem A1 // пин сброс модема
enum globalModemStatus {modemInit = 0 /*начальная инициализация*/, modemNeedRestart /*модем совсем не отвечает - требуется перезагрузка*/,
modemReady /*начальная инициализация прошла успешно*/, modemRegSIM /*регистрация СИМки у оператора сотовой связи*/
}; // глобальные статусы модема
enum modesGPRSstatus {gprsNone /*ничего не делаем, начало*/, gprsGetStatus /*запрос статуса интернет сессии*/,
gprsWaitOKcmd /*ожидание ответа ОК на команду*/, gprsConnectTimeout /*не смогли подключиться за время*/,
gprsWaitStatus /*ждем и анализируем статус сессии*/, gprsWaitOKstatus /*ожидание ответа ОК на запрос статуса*/,
gprsWaitCIICRcmd /*ожидание активации контекста*/, gprsWaitCIPSTARTcmd /*ожидание подключения*/,
gprsConnected /*успешно подключились к серверу*/, gprsWaitRNcmd /*ожидание строки вывода*/,
gprsWaitSENDOK /*ожидаем успешной отправки*/, gprsTimeoutSend /*не дождались успешной отправки*/,
gprsSendDataOK /*успешно отправились данные*/, gprsWaitPromtSend /*ожидание приглашения модема на отправку данных*/
}; // статусы работы с GPRS, часть из них служебные, на часть из них будет вызываться callback функция основной программе
class Sim800GPRS { // класс модема
private:
unsigned char _show_modem_response; // выводить ли ответы от модема
void (*_callback_show_byte)(unsigned char); // внешний обработчик вывода байта ответа модема
void showResponseByte(unsigned char outByte); // вывод в лог ответного байта от модема
enum globalModemStatus currentGlobalStatusModem; // текущий глобальный статус
enum modesGPRSstatus currentGprsMode; // текущий статус интернета
unsigned char mainBufResp[_size_response_buf]; // приемный буфер
unsigned char posRespBuf; // текущая позиция приемного буфера
unsigned char stepByCurrentStatus; // текущее действие в рабочем статусе модема
unsigned long timerByCurrentStatus; // timer в рабочем статусе модема
unsigned long timerWaitConnectTCP; // таймер ожидания коннекта к серверу
_Bool flagRegModem; // флаг регистрации модема в сети оператора
unsigned long timerRegModem; // ожидание времени регистрации модема в сети оператора
void workModemInit(_Bool flIn, unsigned char inBr); // инициализация модема
void workRegSIM(_Bool flIn, unsigned char inBr); // инициализация модема
void clearResponseBuf(void); // очистка приемного буфера
_Bool findOKfromBuf(const unsigned char inByte); // поиск OK\r\n в циклическом буфере
_Bool processCREG(const unsigned char inBt); // парсинг ответа модема на команду AT+CREG
_Bool findRespFromBuf(char * inStr, const unsigned char inByte); // поиск строки в циклическом буфере
void workGPRS(_Bool flIn, unsigned char inBr); // работа с интернетом
void processCIPstatus(unsigned char inByte); // обработка входящих данных / статуса CIP GPRS сессии
unsigned char * gprsSRVname; // имя/адрес сервера
unsigned short gprsSRVport; // порт сервера
unsigned char * gprsSendData; // данные для отправки серверу
void sendToUARTstringPGM(unsigned char * inPGMstring); // отправка в UART модема PROGMEM строки
public:
Sim800GPRS(void); // конструктор
void setCallbackRespnseByte(void (*inFuncShowByte)(unsigned char)); // установка обработчика ответов от модема
void initUART(void); // инициализация порта
void startInit(void); // запуск инициализации модема
globalModemStatus getGlobalModemStatus(void); // вывод текущего статуса модема
void loopSIM800modem(void); // циклическая работа с модемом
void modemReset(void); // сброс модема
void connectToTCPsocket(unsigned char * inSRVname, unsigned short inSRVport); // соединяемся с сервером
modesGPRSstatus getStatusGPRS(void); // вывод текущего статуса соединения
void sendDataToServer(unsigned char * inPGMdata); // отправка данных на сервер
protected:
};
- sim800gprs.cpp
// sim800gprs.cpp by andycat2013@yandex.ru
// библиотека работы с модемом SIM800L
// используется аппаратный UART пины 0 и 1 Atmega328p
#include <avr/pgmspace.h>
#include <Arduino.h>
#include "sim800gprs.h" // подключен заголовочный файл
Sim800GPRS::Sim800GPRS(void) { // конструктор
this->_show_modem_response = 0; // не выводим ответы от модема
this->_callback_show_byte = NULL; // нет обработчика вывода ответов от модема
}
void Sim800GPRS::initUART(void) { // инициализация порта и запуск
Serial.begin(_speed_modem); // запускаем аппаратный UART
}
void Sim800GPRS::setCallbackRespnseByte(void (*inFuncShowByte)(unsigned char)) { // установка обработчика ответов от модема
this->_callback_show_byte = inFuncShowByte; // прописываем обработчик
this->_show_modem_response = 1; // выводим ответы от модема
}
void Sim800GPRS::showResponseByte(unsigned char outByte) { // вывод в лог ответного байта от модема
if (this->_show_modem_response) if (this->_callback_show_byte) this->_callback_show_byte(outByte); // если лог включен - выводим
}
globalModemStatus Sim800GPRS::getGlobalModemStatus(void) { // вывод текущего статуса модема
return this->currentGlobalStatusModem;
}
void Sim800GPRS::loopSIM800modem(void) { // циклическая работа с модемом
unsigned char br = 0; // переменная куда падает входящий байт из модема
_Bool flbr = false; // влаг что пришедший байт не равен нулю
if (Serial.available()) { // если что то пришло из модема
br = Serial.read(); // считали из модема байт
if (br) { // если он больше нуля
if (this->posRespBuf >= _size_response_buf) this->posRespBuf = 0;
this->mainBufResp[this->posRespBuf] = br; // добавляем пришедший байт в круговой буфер
++this->posRespBuf;
this->showResponseByte(br); // выводим его в лог
flbr = true; // ставим флаг что надо обработать данные
}
}
// работа по статусам модема
switch (this->currentGlobalStatusModem) {
case modemInit: {
this->workModemInit(flbr, br);
break;
}
case modemRegSIM: {
this->workRegSIM(flbr, br);
break;
}
case modemReady: {
if (this->currentGprsMode != gprsNone) this->workGPRS(flbr, br); // работа с интернет сессией
break;
}
default: {}
}
}
void Sim800GPRS::startInit(void) { // запуск инициализации модема
this->currentGlobalStatusModem = modemInit; // начнем с глобальной инициализации
this->clearResponseBuf(); // обнуляем входной буфер
this->stepByCurrentStatus = 0; // начнем сначала
this->timerByCurrentStatus = millis(); // начнем сначала
digitalWrite(_pinResetModem, LOW); // инициализация пина сброса модема
pinMode(_pinResetModem, INPUT); // инициализация пина сброса модема
this->timerRegModem = millis(); // сбросили таймер регистрации
this->currentGprsMode = gprsNone; // интернет не подключали
}
void Sim800GPRS::workModemInit(_Bool flIn, unsigned char inBr) { // инициализация модема
switch (this->stepByCurrentStatus) {
case 0: { // ждем пока модем проснется
if ((millis() - this->timerByCurrentStatus) >= _wait_power_start_modem) ++this->stepByCurrentStatus;
break;
}
case 1: {
Serial.print(F("AT\r")); // проверка связи
++this->stepByCurrentStatus;
this->timerByCurrentStatus = millis();
break;
}
case 2: {
if ((millis() - this->timerByCurrentStatus) >= _wait_period_init_cmd) { // если время ожидания ответа на команду вышло
this->currentGlobalStatusModem = modemNeedRestart; // проблема
} else if (flIn) if (this->findOKfromBuf(inBr)) { // если прилетело ОК
Serial.print(F("ATE0\r")); // отключение ЭХО, т е модем в обратку не дублирует команды
++this->stepByCurrentStatus;
this->timerByCurrentStatus = millis();
}
break;
}
case 3: {
if ((millis() - this->timerByCurrentStatus) >= _wait_period_init_cmd) { // если время ожидания ответа на команду вышло
this->currentGlobalStatusModem = modemNeedRestart; // проблема
} else if (flIn) if (this->findOKfromBuf(inBr)) { // если прилетело ОК
Serial.print(F("ATV1\r")); // развернутый подробный ответ от модема
++this->stepByCurrentStatus;
this->timerByCurrentStatus = millis();
}
break;
}
case 4: {
if ((millis() - this->timerByCurrentStatus) >= _wait_period_init_cmd) { // если время ожидания ответа на команду вышло
this->currentGlobalStatusModem = modemNeedRestart; // проблема
} else if (flIn) if (this->findOKfromBuf(inBr)) { // если прилетело ОК
Serial.print(F("AT+CMEE=2\r")); // вывод подробных описаний ошибок
++this->stepByCurrentStatus;
this->timerByCurrentStatus = millis();
}
break;
}
case 5: {
if ((millis() - this->timerByCurrentStatus) >= _wait_period_init_cmd) { // если время ожидания ответа на команду вышло
this->currentGlobalStatusModem = modemNeedRestart; // проблема
} else if (flIn) if (this->findOKfromBuf(inBr)) { // если прилетело ОК
Serial.print(F("AT+CIPSHUT\r")); // закрыть все интернет сессии
++this->stepByCurrentStatus;
this->timerByCurrentStatus = millis();
}
break;
}
case 6: {
if ((millis() - this->timerByCurrentStatus) >= _wait_period_init_cmd) { // если время ожидания ответа на команду вышло
this->currentGlobalStatusModem = modemNeedRestart; // проблема
} else if (flIn) if (this->findOKfromBuf(inBr)) { // если прилетело ОК
Serial.print(F("AT+CLIP=0\r")); // отключение АОН
++this->stepByCurrentStatus;
this->timerByCurrentStatus = millis();
}
break;
}
case 7: {
if ((millis() - this->timerByCurrentStatus) >= _wait_period_init_cmd) { // если время ожидания ответа на команду вышло
this->currentGlobalStatusModem = modemNeedRestart; // проблема
} else if (flIn) if (this->findOKfromBuf(inBr)) { // если прилетело ОК
Serial.print(F("AT+CMGF=1\r")); // обычный режим вывода СМСе
++this->stepByCurrentStatus;
this->timerByCurrentStatus = millis();
}
break;
}
case 8: {
if ((millis() - this->timerByCurrentStatus) >= _wait_period_init_cmd) { // если время ожидания ответа на команду вышло
this->currentGlobalStatusModem = modemNeedRestart; // проблема
} else if (flIn) if (this->findOKfromBuf(inBr)) { // если прилетело ОК
Serial.print(F("AT+CSCLK=0\r")); // отключение работы энергосберегающего режима через пин DTR
++this->stepByCurrentStatus;
this->timerByCurrentStatus = millis();
}
break;
}
case 9: {
if ((millis() - this->timerByCurrentStatus) >= _wait_period_init_cmd) { // если время ожидания ответа на команду вышло
this->currentGlobalStatusModem = modemNeedRestart; // проблема
} else if (flIn) if (this->findOKfromBuf(inBr)) { // если прилетело ОК
Serial.print(F("AT+CIPHEAD=0\r")); // не добавлять заголовок при приеме данных
++this->stepByCurrentStatus;
this->timerByCurrentStatus = millis();
}
break;
}
case 10: {
if ((millis() - this->timerByCurrentStatus) >= _wait_period_init_cmd) { // если время ожидания ответа на команду вышло
this->currentGlobalStatusModem = modemNeedRestart; // проблема
} else if (flIn) if (this->findOKfromBuf(inBr)) { // если прилетело ОК
Serial.print(F("AT+CIPRXGET=0\r")); // автоматический вывод принятых данных
++this->stepByCurrentStatus;
this->timerByCurrentStatus = millis();
}
break;
}
case 11: {
if ((millis() - this->timerByCurrentStatus) >= _wait_period_init_cmd) { // если время ожидания ответа на команду вышло
this->currentGlobalStatusModem = modemNeedRestart; // проблема
} else if (flIn) if (this->findOKfromBuf(inBr)) { // если прилетело ОК
Serial.print(F("AT+CIPSRIP=0\r")); // не показывать данные отправителя при приеме данных
++this->stepByCurrentStatus;
this->timerByCurrentStatus = millis();
}
break;
}
case 12: {
if ((millis() - this->timerByCurrentStatus) >= _wait_period_init_cmd) { // если время ожидания ответа на команду вышло
this->currentGlobalStatusModem = modemNeedRestart; // проблема
} else if (flIn) if (this->findOKfromBuf(inBr)) { // если прилетело ОК
// переходим в логику регистрации СИМ карты у оператора сотовой связи
this->stepByCurrentStatus = 0; // начнем сначала
this->timerByCurrentStatus = millis(); // начнем сначала
this->currentGlobalStatusModem = modemRegSIM;
}
break;
}
default: {}
}
}
void Sim800GPRS::clearResponseBuf(void) { // очистка приемного буфера
memset(this->mainBufResp, 0, _size_response_buf); // обнуляем входной буфер
this->posRespBuf = 0; // обнуляем входной буфер
}
void Sim800GPRS::modemReset(void) { // сброс модема
pinMode(_pinResetModem, OUTPUT);
delay(115);
pinMode(_pinResetModem, INPUT);
}
_Bool Sim800GPRS::findOKfromBuf(const unsigned char inByte) { // поиск OK\r\n в циклическом буфере
const char inStr[] = "OK\r\n"; // искомая строка
byte slen = 4; // длина искомой строки
if (inByte == inStr[slen - 1]) { // если последний символ совпадает - продолжаем искать всю строку
byte abpos = this->posRespBuf; // абсолютная позиция в буфере поиска-1 = последнему символу искомой строки
if (!abpos) abpos = _size_response_buf - 1; else --abpos; // ищем с предпоследнего символа
for ( byte i = 0; i < (slen - 1); ++i) { // цикл по оставшимся символам
if (inStr[slen - 1 - i] != this->mainBufResp[abpos]) return false; // если не сопадабт символы - выходим
if (!abpos) abpos = _size_response_buf - 1; else --abpos; // уменьшаем счетчики
}
} else {
return false;
} return true;
}
void Sim800GPRS::workRegSIM(_Bool flIn, unsigned char inBr) { // инициализация модема
if ((millis() - this->timerRegModem) >= _period_ready_modem) { // если за время отведенное не зарегестрировались
this->currentGlobalStatusModem = modemNeedRestart; // проблема
return; // выходим
}
switch (this->stepByCurrentStatus) {
case 0: {
this->flagRegModem = false; // пока не зарегестрировались в сети
Serial.print(F("AT+CREG?\r")); // запрос статуса регистрации
++this->stepByCurrentStatus;
this->timerByCurrentStatus = millis();
break;
}
case 1: {
if ((millis() - this->timerByCurrentStatus) >= _wait_period_init_cmd) { // если время ожидания ответа на команду вышло
this->currentGlobalStatusModem = modemNeedRestart; // проблема
} else if (flIn) { // что то прилетело
if (this->processCREG(inBr)) this->flagRegModem = true; // парсим строку - если зарегестрировались - ставим флаг
if (this->findOKfromBuf(inBr)) { // ищем ответ ОК
if (this->flagRegModem) { // если успешно зарегестрировались
this->currentGlobalStatusModem = modemReady; // закончили регистрацию
} else { // если так и не смогли зарегестрироваться
++this->stepByCurrentStatus; // через время periodWaitRegistrationModem опять отправляем команду для проверки зарегестрировалась ли СИМ карта
this->timerByCurrentStatus = millis();
}
}
}
break;
}
case 2: {
if ((millis() - this->timerByCurrentStatus) >= _period_wait_registration_modem) { // время для повторного запроса регистрации вышло
this->stepByCurrentStatus = 0; // заново будем запрашивать статус регистрации
}
break;
}
default: {}
}
}
_Bool Sim800GPRS::processCREG(const unsigned char inBt) { // парсинг ответа модема на команду AT+CREG
static unsigned char stepCREG = 0; // текущий шаг
switch (stepCREG) {
case 100: { // ждем цифру
if (isdigit((char)inBt)) ++stepCREG; else stepCREG = 0; // если да - переходим на другой шаг
break;
}
case 101: { // ждем запятую
if (inBt == ',') ++stepCREG; else stepCREG = 0; // если да - переходим на другой шаг
break;
}
case 102: { // ждем цифру регистрации в домашней сети или в роуминге
if ((inBt == '1') || (inBt == '5')) {
stepCREG = 0; return true; // если да - положительно выходим
} else {
stepCREG = 0;
}
break;
}
default: {
if (this->findRespFromBuf((char *) "+CREG: ", inBt)) stepCREG = 100; // ждем строку +CREG И начинаем пошагово обрабатывать символы
}
}
return false; // иначе выходим с отрицательным результатом
}
_Bool Sim800GPRS::findRespFromBuf(char * inStr, const unsigned char inByte) { // поиск строки в циклическом буфере
byte slen = strlen((const char *)inStr); // длина искомой строки
if (inByte == inStr[slen - 1]) { // если последний символ совпадает - продолжаем искать всю строку
byte abpos = this->posRespBuf; // абсолютная позиция в буфере поиска-1 = последнему символу искомой строки
if (!abpos) abpos = _size_response_buf - 1; else --abpos; // ищем с предпоследнего символа
for ( byte i = 0; i < (slen - 1); ++i) { // цикл по оставшимся символам
if (inStr[slen - 1 - i] != this->mainBufResp[abpos]) return false; // если не сопадабт символы - выходим
if (!abpos) abpos = _size_response_buf - 1; else --abpos; // уменьшаем счетчики
}
} else {
return false;
} return true;
}
void Sim800GPRS::processCIPstatus(unsigned char inByte) { // обработка входящих данных / статуса CIP GPRS сессии
if (this->findRespFromBuf((char *) "IP INITIAL\r\n", inByte)) { // начальный статус
Serial.print(F("AT+CSTT=\"internet\"\r")); // прописали APN
this->timerByCurrentStatus = millis();
this->currentGprsMode = gprsWaitOKcmd; // ждем ОК на команду
} else if (this->findRespFromBuf((char *) "IP START\r\n", inByte)) {
Serial.print(F("AT+CIICR\r")); // активируем контекст
this->timerByCurrentStatus = millis();
this->currentGprsMode = gprsWaitCIICRcmd; // ждем ОК на команду
} else if (this->findRespFromBuf((char *) "IP GPRSACT\r\n", inByte)) {
Serial.print(F("AT+CIFSR\r")); // получить IP
this->timerByCurrentStatus = millis();
this->currentGprsMode = gprsWaitRNcmd; // ждем RN на команду
} else if (this->findRespFromBuf((char *) "IP STATUS\r\n", inByte)) {
Serial.print(F("AT+CIPSTART=\"TCP\",\""));
this->sendToUARTstringPGM(this->gprsSRVname);
Serial.print(F("\",\""));
char strPort[6];
itoa(this->gprsSRVport, (char *)strPort, 10);
Serial.print((char *)strPort);
Serial.print(F("\"\r"));
this->timerByCurrentStatus = millis();
this->currentGprsMode = gprsWaitCIPSTARTcmd; // ждем ОК на команду
} else if (this->findRespFromBuf((char *) "CONNECT OK\r\n", inByte)) { // успешно подключились
this->currentGprsMode = gprsConnected;
} else if (this->findRespFromBuf((char *) "TCP CONNECTING\r\n", inByte)) { // в процессе подключения
this->currentGprsMode = gprsGetStatus; // снова запрашиваем статус
} else if (this->findRespFromBuf((char *) "IP CONFIG\r\n", inByte)) { // в процессе подключения
this->currentGprsMode = gprsGetStatus; // снова запрашиваем статус
} else if (this->findRespFromBuf((char *) "TCP CLOSING\r\n", inByte)) { // в процессе подключения
this->currentGprsMode = gprsGetStatus; // снова запрашиваем статус
} else if (this->findRespFromBuf((char *) "TCP CLOSED\r\n", inByte)) { // отключился от сервера
Serial.print(F("AT+CIPSHUT\r")); // гасим сессию
this->timerByCurrentStatus = millis();
this->currentGprsMode = gprsWaitOKcmd; // ждем ОК на команду
} else if (this->findRespFromBuf((char *) "PDP DEACT\r\n", inByte)) { // все плохо, коннекта не будет
this->currentGprsMode = gprsConnectTimeout; // ставим статус ошибки
this->currentGlobalStatusModem = modemNeedRestart; // надо полностью сбросить модем
} else if (this->findRespFromBuf((char *) "CONNECT FAIL\r\n", inByte)) { // ошибка соединения
Serial.print(F("AT+CIPSHUT\r")); // гасим сессию
this->currentGprsMode = gprsConnectTimeout; // ставим статус ошибки
}
}
void Sim800GPRS::workGPRS(_Bool flIn, unsigned char inBr) { // работа с интернетом
switch (this->currentGprsMode) { // Работаем по шагам
case gprsGetStatus: {
Serial.print(F("AT+CIPSTATUS\r")); // запрос статуса сессии
this->timerByCurrentStatus = millis();
this->currentGprsMode = gprsWaitOKstatus;
break;
}
case gprsWaitOKstatus: {
if ((millis() - this->timerByCurrentStatus) >= _wait_period_init_cmd) { // если время ожидания ответа на команду вышло
this->currentGlobalStatusModem = modemNeedRestart; // проблема
} else if ((millis() - this->timerWaitConnectTCP) >= _period_connect_gprs_ready) { // время соединения с сервером вышло
this->currentGprsMode = gprsConnectTimeout; // прописали статус
} else if (flIn) if (this->findOKfromBuf(inBr)) this->currentGprsMode = gprsWaitStatus; // пришло ОК, будем ждать статус
break;
}
case gprsWaitStatus: {
if ((millis() - this->timerWaitConnectTCP) >= _period_connect_gprs_ready) { // время соединения с сервером вышло
this->currentGprsMode = gprsConnectTimeout; // прописали статус
} else if (flIn) this->processCIPstatus(inBr); // обрабатываем статус сессии
break;
}
case gprsWaitOKcmd: {
if ((millis() - this->timerByCurrentStatus) >= _wait_period_init_cmd) { // если время ожидания ответа на команду вышло
this->currentGlobalStatusModem = modemNeedRestart; // проблема
} else if ((millis() - this->timerWaitConnectTCP) >= _period_connect_gprs_ready) { // время соединения с сервером вышло
this->currentGprsMode = gprsConnectTimeout; // прописали статус
} else if (flIn) if (this->findOKfromBuf(inBr)) this->currentGprsMode = gprsGetStatus; // пришло ОК, будем запрашивать новый статус
break;
}
case gprsWaitCIICRcmd: {
if ((millis() - this->timerByCurrentStatus) >= 85000UL) { // если время ожидания ответа на команду вышло
this->currentGlobalStatusModem = modemNeedRestart; // проблема
} else if ((millis() - this->timerWaitConnectTCP) >= _period_connect_gprs_ready) { // время соединения с сервером вышло
this->currentGprsMode = gprsConnectTimeout; // прописали статус
} else if (flIn) if (this->findOKfromBuf(inBr)) this->currentGprsMode = gprsGetStatus; // пришло ОК, будем запрашивать новый статус
break;
}
case gprsWaitCIPSTARTcmd: {
if ((millis() - this->timerByCurrentStatus) >= 75000UL) { // если время ожидания ответа на команду вышло
this->currentGlobalStatusModem = modemNeedRestart; // проблема
} else if ((millis() - this->timerWaitConnectTCP) >= _period_connect_gprs_ready) { // время соединения с сервером вышло
this->currentGprsMode = gprsConnectTimeout; // прописали статус
} else if (flIn) if (this->findOKfromBuf(inBr)) this->currentGprsMode = gprsGetStatus; // пришло ОК, будем запрашивать новый статус
break;
}
case gprsWaitRNcmd: {
if ((millis() - this->timerByCurrentStatus) >= _wait_period_init_cmd) { // если время ожидания ответа на команду вышло
this->currentGlobalStatusModem = modemNeedRestart; // проблема
} else if ((millis() - this->timerWaitConnectTCP) >= _period_connect_gprs_ready) { // время соединения с сервером вышло
this->currentGprsMode = gprsConnectTimeout; // прописали статус
} else if (flIn) if (this->findRespFromBuf((char *)"\r\n", inBr)) this->currentGprsMode = gprsGetStatus; // пришла строка, будем запрашивать новый статус
break;
}
case gprsWaitSENDOK: {
if ((millis() - this->timerByCurrentStatus) >= _period_wait_send_ok) { // если время ожидания ответа на команду вышло
this->currentGprsMode = gprsTimeoutSend; // прописали статус
} else if (flIn) if (this->findRespFromBuf((char *)"SEND OK\r\n", inBr)) this->currentGprsMode = gprsSendDataOK; // пришла строка успешно
break;
}
case gprsWaitPromtSend: {
if ((millis() - this->timerByCurrentStatus) >= _wait_period_init_cmd) { // если время ожидания ответа на команду вышло
this->currentGlobalStatusModem = modemNeedRestart; // проблема
} else if (flIn) if (inBr == '>') {
this->sendToUARTstringPGM(this->gprsSendData);
Serial.write(0x1A); // конец отправляемой строки
this->timerByCurrentStatus = millis();
this->currentGprsMode = gprsWaitSENDOK; // будем ждать успешной отправки
}
break;
}
default: { // проверяем ответ сервера закрытия сессии при других статусах
if (flIn) if (this->findRespFromBuf((char *)"CLOSED\r\n", inBr)) { // ждем отключения от сервера
this->currentGprsMode = gprsNone; // прописали начальный статус
}
}
}
}
void Sim800GPRS::connectToTCPsocket(unsigned char * inSRVname, unsigned short inSRVport) { // соединяемся с сервером
this->gprsSRVname = inSRVname;
this->gprsSRVport = inSRVport;
this->currentGprsMode = gprsGetStatus; // начало - запрашиваем статус сессии
this->timerWaitConnectTCP = millis(); // сбросили таймер ожидания коннекта к серверу
}
modesGPRSstatus Sim800GPRS::getStatusGPRS(void) { // вывод текущего статуса соединения
return this->currentGprsMode;
}
void Sim800GPRS::sendDataToServer(unsigned char * inPGMdata) { // отправка данных на сервер
this->gprsSendData = inPGMdata;
Serial.print(F("AT+CIPSEND\r")); // запрос статуса сессии
this->timerByCurrentStatus = millis();
this->currentGprsMode = gprsWaitPromtSend;
}
void Sim800GPRS::sendToUARTstringPGM(unsigned char * inPGMstring) { // отправка в UART модема PROGMEM строки
unsigned short i = 0;
while (unsigned char inChar = pgm_read_byte_near(inPGMstring + i)) {
Serial.write(inChar);
++i;
}
}
не знаю, нет такого модуля, не пробовал, судя по даташиту sim800_series_at_command_manual_v1.01, там общая система команд. Возможно различия в сбросе модема, например для SIM800L просто пином RST сбрасывается, то для SIM800C другой ногой в определенной комбинации делается сброс.
Продолжение http://arduino.ru/forum/apparatnye-voprosy/vse-o-sim800l-i-vse-chto-s-nim-svyazano?page=5#comment-652617
Работа с MQTT брокером через GPRS модем SIM800L.
Поддержание постоянной связи с брокером посредством каманд PINGREQ/PINGRESP.
При реконнекте с брокером не производиться автоматическое подписание на SUBSCRIBE топики, сделано осознано, на практике рабочих проектов при сбоях обычно запускается другая логика/топики. Если понадобиться - допишу как нибудь. Т е по хорошему в основной программе необходимо проверять статус подключения и в случае сбоя ставить флаг - повторное подписание на топики.
- тестовый код
#define USESOFTUARTLOG // если будем выводить ответы из модема или какие то сообщения программы в SoftwareSerial, закоментировать при ненадобности
#include <avr/pgmspace.h>
#include <avr\wdt.h> // стандартная библиотека работы с WDT
#include "sim800mqtt.h"
const unsigned char mqttSrvName[] PROGMEM = {"***.cloudmqtt.com"}; // адрес сервера
const unsigned short mqttSrvPort = 14769; // порт сервера
const unsigned char mqttUser[] PROGMEM = {"*******"}; // пользователь MQTT брокера
const unsigned char mqttPass[] PROGMEM = {"********"}; // пароль MQTT брокера
const unsigned char mqttIDclient[] PROGMEM = {"fuvgiu787hnl"}; // уникальный для каждого! подключения/устройства - идентификатор клиента MQTT
// поскольку работа с модемом происходит online обработкой каждого входящего байта
// идет борьба за быстродействие, соотвественно в PROGMEM подписываемые топики засунуть нельзя
// и чем больше топиков тем больше скетч занимает оперативку МК
// длина буфера описана в sim800mqtt.h, соотвественно длина входящих данных вместе с длиной самого топика не должна превышать данного значения!
// максимально количество топиков прописывается в _mqtt_max_count_subscribe_topics в файле sim800mqtt.h
// в обработчике getInputPubTopic приходят ID подписных топиков
const unsigned char * mqttSubTopics[] = {(unsigned char *)"AT41/key"/*id0*/, (unsigned char *)"AT41/temp1"/*id1*/, (unsigned char *)""}; // топики, на которые подписываемся, последний обязательно должен быть пустой строкой
// топики с отправкой данных брокеру
const unsigned char pub1t[] PROGMEM = {"AT41/data1test"};
const unsigned char pub2t[] PROGMEM = {"AT41/tesy2temp"};
const unsigned char pub3t[] PROGMEM = {"AT41/hlam3"};
const unsigned char pub4t[] PROGMEM = {"AT41/good4FCST"};
const unsigned char * mqttPubTestTopics[] = {pub1t, pub2t, pub3t, pub4t};
Sim800MQTT myMQTT; // object
#ifdef USESOFTUARTLOG
unsigned char pinSwUART_TX = 2, pinSwUART_RX = 3; // пины куда подключаем USB-TTL переходник для вывода лога
#include <SoftwareSerial.h> // стандартная библиотека работы с SoftwareSerial
SoftwareSerial swuart(pinSwUART_RX, pinSwUART_TX); // установка контактов
#endif /*USESOFTUARTLOG*/
void showResponseModem(unsigned char inByte) { // обработчик вывода ответа от модема
myMQTT.mqttGetDataFromModem(inByte); // "заворачиваем" весь вывод из модема в MQTT объект
// свой код обработки данных от модема если требуется
// закончили обрабатывать входящие данные
#ifdef USESOFTUARTLOG
if ((inByte < 0x20) || (inByte >= 0x7F)) {
swuart.print("x");
if (inByte < 0x10) swuart.write('0');
swuart.print(inByte, HEX);
}
swuart.write(inByte); // выводим в програмный UART
#endif /*USESOFTUARTLOG*/
}
void getInputPubTopic(unsigned char inIdTopic /*ID топика на который подписывались*/, unsigned char * inDataTopic /*пришедшие данные топика*/) { // обработчик данных входящих publish топиков
// своя обработка данных
// закончили обрабатывать SUBSCRIBE TOPIC
#ifdef USESOFTUARTLOG
swuart.print("Topic ID "); swuart.print(inIdTopic, DEC); swuart.print(" -> "); swuart.println((char *)inDataTopic);
#endif /*USESOFTUARTLOG*/
}
// инициализация WDT (код из даташита + из форума)
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
wdt_disable(); // отключение WDT
#ifdef USESOFTUARTLOG
swuart.begin(115200);
swuart.println(F("Start!"));
#endif /*USESOFTUARTLOG*/
myMQTT.setCallbackResponseByte(showResponseModem); // прописываем обработчик вывода ответов, обязательно для использования с MQTT!
myMQTT.setCallbackPubTopic(getInputPubTopic); // прописываем обработчик входящих топиков с данными
// put your setup code here, to run once:
myMQTT.mqttStart((unsigned char *)mqttSrvName, mqttSrvPort, (unsigned char *)mqttUser, (unsigned char *)mqttPass, (unsigned char *)mqttIDclient);
wdt_enable(WDTO_1S); // включение WDT
}
void loop() {
wdt_reset(); // сброс WDT
myMQTT.loopMQTTgprs();
// put your main code here, to run repeatedly:
// подписываемся на топики
static _Bool firstStart = true; // один раз при старте
if ((firstStart) && (!myMQTT.mqttIsBUSY())) { // если брокер не занят
myMQTT.mqttSubscribeTopics(mqttSubTopics); // подписываемся на топики
firstStart = false; // сбросим флаг что бы больше не запускалось
}
// подписались, свой код, можно по событиям отправлять данные на брокер
static unsigned long timerPubTopic = 0; // тестовый таймер будем по времени отправлять данные брокеру
if ((!firstStart) && (!myMQTT.mqttIsBUSY()) && ((millis() - timerPubTopic) >= 139097UL)) { // если брокер не занят, каждые 139 секунд будем слать
static unsigned char orderTopic = 0; // по очереди топики слать
timerPubTopic = millis(); // сбросим таймер
static unsigned char dataTopic[20]; // отправляемые данны, обязательно должно быть прописано static!
itoa(millis() / 1000, (char *) dataTopic, 10); // для теста будем просто отправлять время в секундах
myMQTT.sendPublishTopic((unsigned char *) mqttPubTestTopics[orderTopic], (unsigned char *) dataTopic); // отправляем данные
if ((++orderTopic) /*след топик слать*/ >= 4) orderTopic = 0; // начнем с первого топика когда отправили наши четыре тестовых
}
}
/*Скетч использует 9906 байт (32%) памяти устройства. Всего доступно 30720 байт.
Глобальные переменные используют 740 байт (36%) динамической памяти, оставляя 1308 байт для локальных переменных. Максимум: 2048 байт.*/
- sim800gprs.h
// sim800gprs.h by andycat2013@yandex.ru
// библиотека работы с модемом SIM800L
// используется аппаратный UART пины 0 и 1 Atmega328p
#pragma once
#include <Arduino.h>
#define _speed_modem 9600 // скорость порта работы с модемом
#define _wait_period_init_cmd 5000UL // время ожидания ответа на команды начальной инициализации модема и кратких команд интернета
#define _wait_power_start_modem 5000UL // время ожидания начла инициализациии после включения питания, проснуться модему
#define _period_wait_registration_modem 5000UL // каждый этот период спрашивается зарегестрировался ли модем
#define _period_ready_modem 45000UL // общее время, которое дается на регистрацию в сети, иначе перезагрузка модема
#define _period_connect_gprs_ready 180000UL // общее время подключения к серверу, 3 минуты, поскольку на некоторые команды ответ по даташиту больше минуты требуется, иначе перезагрузка модема
#define _period_wait_send_ok 15000UL // время ожидания успешной отправки данных
#define _size_response_buf ((unsigned char)16) // размер циклического буфера приема данных от модема
#define _pinResetModem A1 // пин сброс модема
enum globalModemStatus {modemInit = 0 /*начальная инициализация*/, modemNeedRestart /*модем совсем не отвечает - требуется перезагрузка*/,
modemReady /*начальная инициализация прошла успешно*/, modemRegSIM /*регистрация СИМки у оператора сотовой связи*/
}; // глобальные статусы модема
enum modesGPRSstatus {gprsNone /*ничего не делаем, начало*/, gprsGetStatus /*запрос статуса интернет сессии*/,
gprsWaitOKcmd /*ожидание ответа ОК на команду*/, gprsConnectTimeout /*не смогли подключиться за время*/,
gprsWaitStatus /*ждем и анализируем статус сессии*/, gprsWaitOKstatus /*ожидание ответа ОК на запрос статуса*/,
gprsWaitCIICRcmd /*ожидание активации контекста*/, gprsWaitCIPSTARTcmd /*ожидание подключения*/,
gprsConnected /*успешно подключились к серверу*/, gprsWaitRNcmd /*ожидание строки вывода*/,
gprsWaitSENDOK /*ожидаем успешной отправки*/, gprsTimeoutSend /*не дождались успешной отправки*/,
gprsSendDataOK /*успешно отправились данные*/, gprsWaitPromtSend /*ожидание приглашения модема на отправку данных*/
}; // статусы работы с GPRS, часть из них служебные, на часть из них будет вызываться callback функция основной программе
class Sim800GPRS { // класс модема
private:
unsigned char mainBufResp[_size_response_buf]; // приемный буфер
unsigned char posRespBuf; // текущая позиция приемного буфера
unsigned char stepByCurrentStatus; // текущее действие в рабочем статусе модема
unsigned long timerByCurrentStatus; // timer в рабочем статусе модема
unsigned long timerWaitConnectTCP; // таймер ожидания коннекта к серверу
_Bool flagRegModem; // флаг регистрации модема в сети оператора
unsigned long timerRegModem; // ожидание времени регистрации модема в сети оператора
void workModemInit(_Bool flIn, unsigned char inBr); // инициализация модема
void workRegSIM(_Bool flIn, unsigned char inBr); // инициализация модема
void clearResponseBuf(void); // очистка приемного буфера
_Bool findOKfromBuf(const unsigned char inByte); // поиск OK\r\n в циклическом буфере
_Bool processCREG(const unsigned char inBt); // парсинг ответа модема на команду AT+CREG
_Bool findRespFromBuf(char * inStr, const unsigned char inByte); // поиск строки в циклическом буфере
void workGPRS(_Bool flIn, unsigned char inBr); // работа с интернетом
void processCIPstatus(unsigned char inByte); // обработка входящих данных / статуса CIP GPRS сессии
unsigned char * gprsSRVname; // имя/адрес сервера
unsigned short gprsSRVport; // порт сервера
unsigned char * gprsSendData; // данные для отправки серверу PROGMEM
unsigned char * gprsStringData; // данные для отправки серверу Char
unsigned char lenGprsStringData; // длина отправляемой Char строки
void sendToUARTstringPGM(unsigned char * inPGMstring); // отправка в UART модема PROGMEM строки
void sendToUARTstringChar(void); // отправка в UART модема Char строки
unsigned char _show_modem_response; // выводить ли ответы от модема
void (*_callback_show_byte)(unsigned char); // внешний обработчик вывода байта ответа модема
void showResponseByte(unsigned char outByte); // вывод в лог ответного байта от модема
public:
Sim800GPRS(void); // конструктор
void setCallbackResponseByte(void (*inFuncShowByte)(unsigned char)); // установка обработчика ответов от модема
void initUART(void); // инициализация порта
void startInit(void); // запуск инициализации модема
globalModemStatus getGlobalModemStatus(void); // вывод текущего статуса модема
void loopSIM800modem(void); // циклическая работа с модемом
void modemReset(void); // сброс модема
void connectToTCPsocket(unsigned char * inSRVname, unsigned short inSRVport); // соединяемся с сервером
modesGPRSstatus getStatusGPRS(void); // вывод текущего статуса соединения
void sendDataToServer(unsigned char * inPGMdata); // отправка данных на сервер
protected:
enum globalModemStatus currentGlobalStatusModem; // текущий глобальный статус
enum modesGPRSstatus currentGprsMode; // текущий статус интернета
void sendStringToServer(unsigned char * inCharData, unsigned char inLenStr); // отправка данных на сервер
};
- sim800gprs.cpp
// sim800gprs.cpp by andycat2013@yandex.ru
// библиотека работы с модемом SIM800L
// используется аппаратный UART пины 0 и 1 Atmega328p
#include <avr/pgmspace.h>
#include <Arduino.h>
#include "sim800gprs.h" // подключен заголовочный файл
Sim800GPRS::Sim800GPRS(void) { // конструктор
this->_show_modem_response = 0; // не выводим ответы от модема
this->_callback_show_byte = NULL; // нет обработчика вывода ответов от модема
}
void Sim800GPRS::initUART(void) { // инициализация порта и запуск
Serial.begin(_speed_modem); // запускаем аппаратный UART
}
void Sim800GPRS::setCallbackResponseByte(void (*inFuncShowByte)(unsigned char)) { // установка обработчика ответов от модема
this->_callback_show_byte = inFuncShowByte; // прописываем обработчик
this->_show_modem_response = 1; // выводим ответы от модема
}
void Sim800GPRS::showResponseByte(unsigned char outByte) { // вывод в лог ответного байта от модема
if (this->_show_modem_response) if (this->_callback_show_byte) this->_callback_show_byte(outByte); // если лог включен - выводим
}
globalModemStatus Sim800GPRS::getGlobalModemStatus(void) { // вывод текущего статуса модема
return this->currentGlobalStatusModem;
}
void Sim800GPRS::loopSIM800modem(void) { // циклическая работа с модемом
unsigned char br = 0; // переменная куда падает входящий байт из модема
_Bool flbr = false; // влаг что пришедший байт не равен нулю
if (Serial.available()) { // если что то пришло из модема
br = Serial.read(); // считали из модема байт
if (br) { // если он больше нуля
if (this->posRespBuf >= _size_response_buf) this->posRespBuf = 0;
this->mainBufResp[this->posRespBuf] = br; // добавляем пришедший байт в круговой буфер
++this->posRespBuf;
this->showResponseByte(br); // выводим его в лог
flbr = true; // ставим флаг что надо обработать данные
}
}
// работа по статусам модема
switch (this->currentGlobalStatusModem) {
case modemInit: {
this->workModemInit(flbr, br);
break;
}
case modemRegSIM: {
this->workRegSIM(flbr, br);
break;
}
case modemReady: {
if (this->currentGprsMode != gprsNone) this->workGPRS(flbr, br); // работа с интернет сессией
break;
}
default: {}
}
}
void Sim800GPRS::startInit(void) { // запуск инициализации модема
this->currentGlobalStatusModem = modemInit; // начнем с глобальной инициализации
this->clearResponseBuf(); // обнуляем входной буфер
this->stepByCurrentStatus = 0; // начнем сначала
this->timerByCurrentStatus = millis(); // начнем сначала
digitalWrite(_pinResetModem, LOW); // инициализация пина сброса модема
pinMode(_pinResetModem, INPUT); // инициализация пина сброса модема
this->timerRegModem = millis(); // сбросили таймер регистрации
this->currentGprsMode = gprsNone; // интернет не подключали
}
void Sim800GPRS::workModemInit(_Bool flIn, unsigned char inBr) { // инициализация модема
switch (this->stepByCurrentStatus) {
case 0: { // ждем пока модем проснется
if ((millis() - this->timerByCurrentStatus) >= _wait_power_start_modem) ++this->stepByCurrentStatus;
break;
}
case 1: {
Serial.print(F("AT\r")); // проверка связи
++this->stepByCurrentStatus;
this->timerByCurrentStatus = millis();
break;
}
case 2: {
if ((millis() - this->timerByCurrentStatus) >= _wait_period_init_cmd) { // если время ожидания ответа на команду вышло
this->currentGlobalStatusModem = modemNeedRestart; // проблема
} else if (flIn) if (this->findOKfromBuf(inBr)) { // если прилетело ОК
Serial.print(F("ATE0\r")); // отключение ЭХО, т е модем в обратку не дублирует команды
++this->stepByCurrentStatus;
this->timerByCurrentStatus = millis();
}
break;
}
case 3: {
if ((millis() - this->timerByCurrentStatus) >= _wait_period_init_cmd) { // если время ожидания ответа на команду вышло
this->currentGlobalStatusModem = modemNeedRestart; // проблема
} else if (flIn) if (this->findOKfromBuf(inBr)) { // если прилетело ОК
Serial.print(F("ATV1\r")); // развернутый подробный ответ от модема
++this->stepByCurrentStatus;
this->timerByCurrentStatus = millis();
}
break;
}
case 4: {
if ((millis() - this->timerByCurrentStatus) >= _wait_period_init_cmd) { // если время ожидания ответа на команду вышло
this->currentGlobalStatusModem = modemNeedRestart; // проблема
} else if (flIn) if (this->findOKfromBuf(inBr)) { // если прилетело ОК
Serial.print(F("AT+CMEE=2\r")); // вывод подробных описаний ошибок
++this->stepByCurrentStatus;
this->timerByCurrentStatus = millis();
}
break;
}
case 5: {
if ((millis() - this->timerByCurrentStatus) >= _wait_period_init_cmd) { // если время ожидания ответа на команду вышло
this->currentGlobalStatusModem = modemNeedRestart; // проблема
} else if (flIn) if (this->findOKfromBuf(inBr)) { // если прилетело ОК
Serial.print(F("AT+CIPSHUT\r")); // закрыть все интернет сессии
++this->stepByCurrentStatus;
this->timerByCurrentStatus = millis();
}
break;
}
case 6: {
if ((millis() - this->timerByCurrentStatus) >= _wait_period_init_cmd) { // если время ожидания ответа на команду вышло
this->currentGlobalStatusModem = modemNeedRestart; // проблема
} else if (flIn) if (this->findOKfromBuf(inBr)) { // если прилетело ОК
Serial.print(F("AT+CLIP=0\r")); // отключение АОН
++this->stepByCurrentStatus;
this->timerByCurrentStatus = millis();
}
break;
}
case 7: {
if ((millis() - this->timerByCurrentStatus) >= _wait_period_init_cmd) { // если время ожидания ответа на команду вышло
this->currentGlobalStatusModem = modemNeedRestart; // проблема
} else if (flIn) if (this->findOKfromBuf(inBr)) { // если прилетело ОК
Serial.print(F("AT+CMGF=1\r")); // обычный режим вывода СМСе
++this->stepByCurrentStatus;
this->timerByCurrentStatus = millis();
}
break;
}
case 8: {
if ((millis() - this->timerByCurrentStatus) >= _wait_period_init_cmd) { // если время ожидания ответа на команду вышло
this->currentGlobalStatusModem = modemNeedRestart; // проблема
} else if (flIn) if (this->findOKfromBuf(inBr)) { // если прилетело ОК
Serial.print(F("AT+CSCLK=0\r")); // отключение работы энергосберегающего режима через пин DTR
++this->stepByCurrentStatus;
this->timerByCurrentStatus = millis();
}
break;
}
case 9: {
if ((millis() - this->timerByCurrentStatus) >= _wait_period_init_cmd) { // если время ожидания ответа на команду вышло
this->currentGlobalStatusModem = modemNeedRestart; // проблема
} else if (flIn) if (this->findOKfromBuf(inBr)) { // если прилетело ОК
Serial.print(F("AT+CIPHEAD=0\r")); // не добавлять заголовок при приеме данных
++this->stepByCurrentStatus;
this->timerByCurrentStatus = millis();
}
break;
}
case 10: {
if ((millis() - this->timerByCurrentStatus) >= _wait_period_init_cmd) { // если время ожидания ответа на команду вышло
this->currentGlobalStatusModem = modemNeedRestart; // проблема
} else if (flIn) if (this->findOKfromBuf(inBr)) { // если прилетело ОК
Serial.print(F("AT+CIPRXGET=0\r")); // автоматический вывод принятых данных
++this->stepByCurrentStatus;
this->timerByCurrentStatus = millis();
}
break;
}
case 11: {
if ((millis() - this->timerByCurrentStatus) >= _wait_period_init_cmd) { // если время ожидания ответа на команду вышло
this->currentGlobalStatusModem = modemNeedRestart; // проблема
} else if (flIn) if (this->findOKfromBuf(inBr)) { // если прилетело ОК
Serial.print(F("AT+CIPSRIP=0\r")); // не показывать данные отправителя при приеме данных
++this->stepByCurrentStatus;
this->timerByCurrentStatus = millis();
}
break;
}
case 12: {
if ((millis() - this->timerByCurrentStatus) >= _wait_period_init_cmd) { // если время ожидания ответа на команду вышло
this->currentGlobalStatusModem = modemNeedRestart; // проблема
} else if (flIn) if (this->findOKfromBuf(inBr)) { // если прилетело ОК
// переходим в логику регистрации СИМ карты у оператора сотовой связи
this->stepByCurrentStatus = 0; // начнем сначала
this->timerByCurrentStatus = millis(); // начнем сначала
this->currentGlobalStatusModem = modemRegSIM;
}
break;
}
default: {}
}
}
void Sim800GPRS::clearResponseBuf(void) { // очистка приемного буфера
memset(this->mainBufResp, 0, _size_response_buf); // обнуляем входной буфер
this->posRespBuf = 0; // обнуляем входной буфер
}
void Sim800GPRS::modemReset(void) { // сброс модема
pinMode(_pinResetModem, OUTPUT);
delay(115);
pinMode(_pinResetModem, INPUT);
}
_Bool Sim800GPRS::findOKfromBuf(const unsigned char inByte) { // поиск OK\r\n в циклическом буфере
const char inStr[] = "OK\r\n"; // искомая строка
byte slen = 4; // длина искомой строки
if (inByte == inStr[slen - 1]) { // если последний символ совпадает - продолжаем искать всю строку
byte abpos = this->posRespBuf; // абсолютная позиция в буфере поиска-1 = последнему символу искомой строки
if (!abpos) abpos = _size_response_buf - 1; else --abpos; // ищем с предпоследнего символа
for ( byte i = 0; i < (slen - 1); ++i) { // цикл по оставшимся символам
if (inStr[slen - 1 - i] != this->mainBufResp[abpos]) return false; // если не сопадабт символы - выходим
if (!abpos) abpos = _size_response_buf - 1; else --abpos; // уменьшаем счетчики
}
} else {
return false;
} return true;
}
void Sim800GPRS::workRegSIM(_Bool flIn, unsigned char inBr) { // инициализация модема
if ((millis() - this->timerRegModem) >= _period_ready_modem) { // если за время отведенное не зарегестрировались
this->currentGlobalStatusModem = modemNeedRestart; // проблема
return; // выходим
}
switch (this->stepByCurrentStatus) {
case 0: {
this->flagRegModem = false; // пока не зарегестрировались в сети
Serial.print(F("AT+CREG?\r")); // запрос статуса регистрации
++this->stepByCurrentStatus;
this->timerByCurrentStatus = millis();
break;
}
case 1: {
if ((millis() - this->timerByCurrentStatus) >= _wait_period_init_cmd) { // если время ожидания ответа на команду вышло
this->currentGlobalStatusModem = modemNeedRestart; // проблема
} else if (flIn) { // что то прилетело
if (this->processCREG(inBr)) this->flagRegModem = true; // парсим строку - если зарегестрировались - ставим флаг
if (this->findOKfromBuf(inBr)) { // ищем ответ ОК
if (this->flagRegModem) { // если успешно зарегестрировались
Serial.print(F("AT+CMGDA=\"DEL ALL\"\r")); // удалить все SMS из SIM карты
this->timerByCurrentStatus = millis();
this->stepByCurrentStatus = 112; // последней операцией ждем удаление всех СМС
} else { // если так и не смогли зарегестрироваться
++this->stepByCurrentStatus; // через время periodWaitRegistrationModem опять отправляем команду для проверки зарегестрировалась ли СИМ карта
this->timerByCurrentStatus = millis();
}
}
}
break;
}
case 2: {
if ((millis() - this->timerByCurrentStatus) >= _period_wait_registration_modem) { // время для повторного запроса регистрации вышло
this->stepByCurrentStatus = 0; // заново будем запрашивать статус регистрации
}
break;
}
case 112: {
if ((millis() - this->timerByCurrentStatus) >= 20000UL) { // если время ожидания ответа на команду вышло
this->currentGlobalStatusModem = modemNeedRestart; // проблема
} else if (flIn) if (this->findOKfromBuf(inBr)) { // если прилетело ОК
this->currentGlobalStatusModem = modemReady; // закончили регистрацию
}
break;
}
default: {}
}
}
_Bool Sim800GPRS::processCREG(const unsigned char inBt) { // парсинг ответа модема на команду AT+CREG
static unsigned char stepCREG = 0; // текущий шаг
switch (stepCREG) {
case 100: { // ждем цифру
if (isdigit((char)inBt)) ++stepCREG; else stepCREG = 0; // если да - переходим на другой шаг
break;
}
case 101: { // ждем запятую
if (inBt == ',') ++stepCREG; else stepCREG = 0; // если да - переходим на другой шаг
break;
}
case 102: { // ждем цифру регистрации в домашней сети или в роуминге
if ((inBt == '1') || (inBt == '5')) {
stepCREG = 0; return true; // если да - положительно выходим
} else {
stepCREG = 0;
}
break;
}
default: {
if (this->findRespFromBuf((char *) "+CREG: ", inBt)) stepCREG = 100; // ждем строку +CREG И начинаем пошагово обрабатывать символы
}
}
return false; // иначе выходим с отрицательным результатом
}
_Bool Sim800GPRS::findRespFromBuf(char * inStr, const unsigned char inByte) { // поиск строки в циклическом буфере
byte slen = strlen((const char *)inStr); // длина искомой строки
if (inByte == inStr[slen - 1]) { // если последний символ совпадает - продолжаем искать всю строку
byte abpos = this->posRespBuf; // абсолютная позиция в буфере поиска-1 = последнему символу искомой строки
if (!abpos) abpos = _size_response_buf - 1; else --abpos; // ищем с предпоследнего символа
for ( byte i = 0; i < (slen - 1); ++i) { // цикл по оставшимся символам
if (inStr[slen - 1 - i] != this->mainBufResp[abpos]) return false; // если не сопадабт символы - выходим
if (!abpos) abpos = _size_response_buf - 1; else --abpos; // уменьшаем счетчики
}
} else {
return false;
} return true;
}
void Sim800GPRS::processCIPstatus(unsigned char inByte) { // обработка входящих данных / статуса CIP GPRS сессии
if (this->findRespFromBuf((char *) "IP INITIAL\r\n", inByte)) { // начальный статус
Serial.print(F("AT+CSTT=\"internet\"\r")); // прописали APN
this->timerByCurrentStatus = millis();
this->currentGprsMode = gprsWaitOKcmd; // ждем ОК на команду
} else if (this->findRespFromBuf((char *) "IP START\r\n", inByte)) {
Serial.print(F("AT+CIICR\r")); // активируем контекст
this->timerByCurrentStatus = millis();
this->currentGprsMode = gprsWaitCIICRcmd; // ждем ОК на команду
} else if (this->findRespFromBuf((char *) "IP GPRSACT\r\n", inByte)) {
Serial.print(F("AT+CIFSR\r")); // получить IP
this->timerByCurrentStatus = millis();
this->currentGprsMode = gprsWaitRNcmd; // ждем RN на команду
} else if (this->findRespFromBuf((char *) "IP STATUS\r\n", inByte)) {
Serial.print(F("AT+CIPSTART=\"TCP\",\""));
this->sendToUARTstringPGM(this->gprsSRVname);
Serial.print(F("\",\""));
char strPort[6];
itoa(this->gprsSRVport, (char *)strPort, 10);
Serial.print((char *)strPort);
Serial.print(F("\"\r"));
this->timerByCurrentStatus = millis();
this->currentGprsMode = gprsWaitCIPSTARTcmd; // ждем ОК на команду
} else if (this->findRespFromBuf((char *) "CONNECT OK\r\n", inByte)) { // успешно подключились
this->currentGprsMode = gprsConnected;
} else if (this->findRespFromBuf((char *) "TCP CONNECTING\r\n", inByte)) { // в процессе подключения
this->currentGprsMode = gprsGetStatus; // снова запрашиваем статус
} else if (this->findRespFromBuf((char *) "IP CONFIG\r\n", inByte)) { // в процессе подключения
this->currentGprsMode = gprsGetStatus; // снова запрашиваем статус
} else if (this->findRespFromBuf((char *) "TCP CLOSING\r\n", inByte)) { // в процессе подключения
this->currentGprsMode = gprsGetStatus; // снова запрашиваем статус
} else if (this->findRespFromBuf((char *) "TCP CLOSED\r\n", inByte)) { // отключился от сервера
Serial.print(F("AT+CIPSHUT\r")); // гасим сессию
this->timerByCurrentStatus = millis();
this->currentGprsMode = gprsWaitOKcmd; // ждем ОК на команду
} else if (this->findRespFromBuf((char *) "PDP DEACT\r\n", inByte)) { // все плохо, коннекта не будет
this->currentGprsMode = gprsConnectTimeout; // ставим статус ошибки
this->currentGlobalStatusModem = modemNeedRestart; // надо полностью сбросить модем
} else if (this->findRespFromBuf((char *) "CONNECT FAIL\r\n", inByte)) { // ошибка соединения
Serial.print(F("AT+CIPSHUT\r")); // гасим сессию
this->currentGprsMode = gprsConnectTimeout; // ставим статус ошибки
}
}
void Sim800GPRS::workGPRS(_Bool flIn, unsigned char inBr) { // работа с интернетом
switch (this->currentGprsMode) { // Работаем по шагам
case gprsGetStatus: {
Serial.print(F("AT+CIPSTATUS\r")); // запрос статуса сессии
this->timerByCurrentStatus = millis();
this->currentGprsMode = gprsWaitOKstatus;
break;
}
case gprsWaitOKstatus: {
if ((millis() - this->timerByCurrentStatus) >= _wait_period_init_cmd) { // если время ожидания ответа на команду вышло
this->currentGlobalStatusModem = modemNeedRestart; // проблема
} else if ((millis() - this->timerWaitConnectTCP) >= _period_connect_gprs_ready) { // время соединения с сервером вышло
this->currentGprsMode = gprsConnectTimeout; // прописали статус
} else if (flIn) if (this->findOKfromBuf(inBr)) this->currentGprsMode = gprsWaitStatus; // пришло ОК, будем ждать статус
break;
}
case gprsWaitStatus: {
if ((millis() - this->timerWaitConnectTCP) >= _period_connect_gprs_ready) { // время соединения с сервером вышло
this->currentGprsMode = gprsConnectTimeout; // прописали статус
} else if (flIn) this->processCIPstatus(inBr); // обрабатываем статус сессии
break;
}
case gprsWaitOKcmd: {
if ((millis() - this->timerByCurrentStatus) >= _wait_period_init_cmd) { // если время ожидания ответа на команду вышло
this->currentGlobalStatusModem = modemNeedRestart; // проблема
} else if ((millis() - this->timerWaitConnectTCP) >= _period_connect_gprs_ready) { // время соединения с сервером вышло
this->currentGprsMode = gprsConnectTimeout; // прописали статус
} else if (flIn) if (this->findOKfromBuf(inBr)) this->currentGprsMode = gprsGetStatus; // пришло ОК, будем запрашивать новый статус
break;
}
case gprsWaitCIICRcmd: {
if ((millis() - this->timerByCurrentStatus) >= 85000UL) { // если время ожидания ответа на команду вышло
this->currentGlobalStatusModem = modemNeedRestart; // проблема
} else if ((millis() - this->timerWaitConnectTCP) >= _period_connect_gprs_ready) { // время соединения с сервером вышло
this->currentGprsMode = gprsConnectTimeout; // прописали статус
} else if (flIn) if (this->findOKfromBuf(inBr)) this->currentGprsMode = gprsGetStatus; // пришло ОК, будем запрашивать новый статус
break;
}
case gprsWaitCIPSTARTcmd: {
if ((millis() - this->timerByCurrentStatus) >= 75000UL) { // если время ожидания ответа на команду вышло
this->currentGlobalStatusModem = modemNeedRestart; // проблема
} else if ((millis() - this->timerWaitConnectTCP) >= _period_connect_gprs_ready) { // время соединения с сервером вышло
this->currentGprsMode = gprsConnectTimeout; // прописали статус
} else if (flIn) if (this->findOKfromBuf(inBr)) this->currentGprsMode = gprsGetStatus; // пришло ОК, будем запрашивать новый статус
break;
}
case gprsWaitRNcmd: {
if ((millis() - this->timerByCurrentStatus) >= _wait_period_init_cmd) { // если время ожидания ответа на команду вышло
this->currentGlobalStatusModem = modemNeedRestart; // проблема
} else if ((millis() - this->timerWaitConnectTCP) >= _period_connect_gprs_ready) { // время соединения с сервером вышло
this->currentGprsMode = gprsConnectTimeout; // прописали статус
} else if (flIn) if (this->findRespFromBuf((char *)"\r\n", inBr)) this->currentGprsMode = gprsGetStatus; // пришла строка, будем запрашивать новый статус
break;
}
case gprsWaitSENDOK: {
if ((millis() - this->timerByCurrentStatus) >= _period_wait_send_ok) { // если время ожидания ответа на команду вышло
this->currentGprsMode = gprsTimeoutSend; // прописали статус
} else if (flIn) if (this->findRespFromBuf((char *)"SEND OK\r", inBr)) this->currentGprsMode = gprsSendDataOK; // пришла строка успешно
break;
}
case gprsWaitPromtSend: {
if ((millis() - this->timerByCurrentStatus) >= _wait_period_init_cmd) { // если время ожидания ответа на команду вышло
this->currentGlobalStatusModem = modemNeedRestart; // проблема
} else if (flIn) if (inBr == '>') {
if (this->gprsSendData) { // или отправляем строку данных из PROGMEN
this->sendToUARTstringPGM(this->gprsSendData);
} else if (this->gprsStringData) { // или отправляем Char строку
this->sendToUARTstringChar();
}
Serial.write(0x1A); // конец отправляемой строки
this->timerByCurrentStatus = millis();
this->currentGprsMode = gprsWaitSENDOK; // будем ждать успешной отправки
}
break;
}
default: { // проверяем ответ сервера закрытия сессии при других статусах
if (flIn) {
if (this->findRespFromBuf((char *)"CLOSED\r", inBr)) { // ждем отключения от сервера
this->currentGprsMode = gprsNone; // прописали начальный статус
}
}
}
}
}
void Sim800GPRS::connectToTCPsocket(unsigned char * inSRVname, unsigned short inSRVport) { // соединяемся с сервером
this->gprsSRVname = inSRVname;
this->gprsSRVport = inSRVport;
this->currentGprsMode = gprsGetStatus; // начало - запрашиваем статус сессии
this->timerWaitConnectTCP = millis(); // сбросили таймер ожидания коннекта к серверу
}
modesGPRSstatus Sim800GPRS::getStatusGPRS(void) { // вывод текущего статуса соединения
return this->currentGprsMode;
}
void Sim800GPRS::sendDataToServer(unsigned char * inPGMdata) { // отправка данных на сервер
this->gprsStringData = NULL;
this->gprsSendData = inPGMdata;
Serial.print(F("AT+CIPSEND\r")); // запрос статуса сессии
this->timerByCurrentStatus = millis();
this->currentGprsMode = gprsWaitPromtSend;
}
void Sim800GPRS::sendStringToServer(unsigned char * inCharData, unsigned char inLenStr) { // отправка данных на сервер
this->gprsStringData = inCharData;
this->gprsSendData = NULL;
this->lenGprsStringData = inLenStr;
Serial.print(F("AT+CIPSEND\r")); // запрос статуса сессии
this->timerByCurrentStatus = millis();
this->currentGprsMode = gprsWaitPromtSend;
}
void Sim800GPRS::sendToUARTstringPGM(unsigned char * inPGMstring) { // отправка в UART модема PROGMEM строки
unsigned short i = 0;
while (unsigned char inChar = pgm_read_byte_near(inPGMstring + i)) {
Serial.write(inChar);
++i;
}
}
void Sim800GPRS::sendToUARTstringChar(void) { // отправка в UART модема Char строки
for (unsigned char i = 0; i < this->lenGprsStringData; ++i) Serial.write(this->gprsStringData[i]);
}
- sim800mqtt.h
// sim800mqtt.h by andycat2013@yandex.ru
// библиотека работы с MQTT сервером через библиотеку sim800gprs.h
#pragma once
#include "sim800gprs.h"
#define _mqtt_period_save_connection_broker 250 // время в секундах, сколько брокер держит соединение без активности, 255 секунд максимум
#define _mqtt_period_send_ping_req 237000UL // периодичность в миллисекундах отправки брокеру пакета PINGREQ, должно быть меньше время сохранения соединения без активности
#define _mqtt_period_broker_connected 7000UL // время ожидания подключения к брокеру т е ответа на CONNECT PACKET
#define _mqtt_period_ping_response 3000UL // время ожидания PINGRESP packet
#define _mqtt_period_subscribe_topic 4000UL // время ожидания ответа на подписываемый топик и отправляемы топик
#define _mqtt_max_count_subscribe_topics 10 // максимальное количество подписываемых топиков
#define _mqtt_size_send_buf 64 // размер буфера отправляемой строки брокеру
#define _mqtt_size_buf_pub_topic 32 // размер буфера с пришедшими данныеми на подписанные топики
enum stepMqttModes {mqttNone = 0 /*ничего не сделано, начало*/, mqttConnectToSocket /*соединяемся с сервером TCP сокет*/,
mqttWaitConnectonToSocket /*ждем успешного подключения к сокету брокера*/,
mqttWaitConnectBroker /*ожидание подключения к брокеру*/, mqttToReconnect /*проблема, ждем время и переподключаемся*/,
mqttWaitReconect /*ждем время переподключения*/, mqttBrokerConnected /*успешно подключились к брокеру*/,
mqttWaitRespPing /*ожидание пинг ответа*/, mqttWaitPubTopic /*ожидание успешной отправыки PUB*/,
mqttSendSubTopic /*отправка подписываемого топика*/, mqttWaitSubTopic /*ожидание успешного ответа на подписание к топику*/
}; // режимы работы с сервером MQTT
class Sim800MQTT : public Sim800GPRS {
private:
enum stepMqttModes currentMQTTstatus; // режим работы с сервером MQTT
void mainWorkMQTT(void); // основной процесс работы с брокером
unsigned char * mqttServerName;
unsigned short mqttServerPort;
unsigned char * mqttUserName;
unsigned char * mqttPassword;
unsigned char * mqttClient;
unsigned char mqttLenStrUserName;
unsigned char mqttLenStrPassword;
unsigned char mqttLenStrClient;
unsigned long mqttTimerWait; // рабочий таймер
unsigned char mqttStepWork; // рабочий шаг
unsigned long mqttTimerPingReq; // таймер отправки PINGREQ packet
_Bool mqttFlagBusy; // флаг занятости
const unsigned char ** mqttTopicsSubscribe; // подписные топики
unsigned char mqttCountSubTopics; // число топиков подписки
unsigned char mqttCurrentSubTopic; // текущий топик с которым работаем
_Bool mqttReadySubTopics; // флаг успешной подписи топиков
unsigned char mqttLenSubTopics[_mqtt_max_count_subscribe_topics]; // длины строк топиков
unsigned char getLenStringPGM(unsigned char * inPGMstring); // получение длины PROGMEM строки
unsigned char mqttToUARTstringPGM(unsigned char * inPGMstring, unsigned char inPosBuf); // отправка в буфер модема PROGMEM строки
void (*_callback_pub_topic)(unsigned char, unsigned char *); // внешний обработчик входящих топиков
public:
Sim800MQTT(void): Sim800GPRS() {}
void sendPublishTopic(unsigned char * outPubTopic, unsigned char * outDataPub); // отправка PUBLISH TOPIC
void setCallbackPubTopic(void (*inFuncPubTopic)(unsigned char, unsigned char *)); // установка обработчика входящих топиков
void mqttGetDataFromModem(unsigned char inByte); // обработчик полученных от модема данных
void mqttStart(unsigned char * inSrvName, unsigned short inSrvPort, unsigned char * inUser, unsigned char * inPass, unsigned char * inClient); // запуск
void loopMQTTgprs(void); // циклическая работа с сервером MQTT
_Bool mqttIsBUSY(void); // идет работа с брокером, ожидается подтверждение/коннект или другое любое действие, пока занят - не рекомендуется ничего отправлять
void mqttSubscribeTopics(const unsigned char ** inSubTopics); // подписываемся на топики
protected:
};
- sim800mqtt.cpp
// sim800mqtt.cpp by andycat2013@yandex.ru
// библиотека работы с MQTT сервером через библиотеку sim800gprs.h
#include "sim800mqtt.h"
unsigned char mqttStringToSend[_mqtt_size_send_buf]; // динамически собираемая строка для отправки брокеру
unsigned char mqttPubStringTopic[_mqtt_size_buf_pub_topic]; // входящие данные на подписанные топики
_Bool Sim800MQTT :: mqttIsBUSY(void) { // идет работа с брокером, ожидается подтверждение/коннект или другое любое действие, пока занят - не рекомендуется ничего отправлять
return this->mqttFlagBusy;
}
unsigned char Sim800MQTT :: mqttToUARTstringPGM(unsigned char * inPGMstring, unsigned char inPosBuf) { // отправка в буфер модема PROGMEM строки
unsigned char i = 0;
while (unsigned char inChar = pgm_read_byte_near(inPGMstring + i)) {
mqttStringToSend[inPosBuf + i] = inChar;
++i;
}
return (inPosBuf + i);
}
unsigned char Sim800MQTT :: getLenStringPGM(unsigned char * inPGMstring) { // получение длины PROGMEM строки
unsigned char i = 0;
while (pgm_read_byte_near(inPGMstring + i)) ++i;
return i;
}
void Sim800MQTT :: mqttGetDataFromModem(unsigned char inByte) { // обработчик полученных от модема данных
switch (this->currentMQTTstatus) { // будем обработывать данные в зависимости от текущего режима работы
case mqttWaitConnectBroker: { // ждем последовательность байт 0x02 0x01 CONNACK packet
if ((inByte == 0x02) && (mqttStepWork == 0)) {
this->mqttStepWork = 1;
} else if ((inByte == 0x01) && (mqttStepWork == 1)) {
this->currentMQTTstatus = mqttBrokerConnected; // подключились успешно
this->mqttFlagBusy = false;
} else if ((millis() - mqttTimerWait) >= _mqtt_period_broker_connected) { // время подключения вышло
this->currentMQTTstatus = mqttToReconnect; // будем переподключаться
}
break;
}
case mqttWaitRespPing: {
if (inByte == 0xD0) { // прилетел PINGRESP
this->currentMQTTstatus = mqttBrokerConnected;
this->mqttFlagBusy = false;
} else if ((millis() - this->mqttTimerWait) >= _mqtt_period_ping_response) { // время ожидани PINGRESP вышло
this->currentMQTTstatus = mqttToReconnect; // будем переподключаться
}
break;
}
case mqttWaitSubTopic: {
if (inByte == 0x90) { // прилетел SUBACK Packet fixed header
++this->mqttCurrentSubTopic; // следующий топик
if (this->mqttCurrentSubTopic < mqttCountSubTopics) { // отправляем след топик
this->currentMQTTstatus = mqttSendSubTopic;
} else { // если нет следующего топика - закончили отправку
this->mqttReadySubTopics = true; // успешно подписались на все топики
this->currentMQTTstatus = mqttBrokerConnected;
this->mqttFlagBusy = false;
}
} else if ((millis() - this->mqttTimerWait) >= _mqtt_period_subscribe_topic) { // время ожидания вышло
this->currentMQTTstatus = mqttToReconnect; // будем переподключаться
}
break;
}
case mqttWaitPubTopic: { // поскольку на PUB пакет при QoS=0 ничего не приходит в ответ
if (this->getStatusGPRS() == gprsSendDataOK) { // будем просто ждать успешной отправки пакета
this->currentMQTTstatus = mqttBrokerConnected; // освободим брокер
this->mqttFlagBusy = false;
} else if ((millis() - this->mqttTimerWait) >= _mqtt_period_subscribe_topic) { // время ожидания вышло
this->currentMQTTstatus = mqttToReconnect; // будем переподключаться
}
break;
}
default: {}
}
if ((this->mqttReadySubTopics) && (this->mqttCountSubTopics)) { // если успешно подписаны на топики
static unsigned char mqttStepProcessPub = 0; // статус обработки входящих данных PUB топиков
static unsigned char _fullLenPacket; // общая длина данных
static unsigned char _lenPubPacket; // длина топика
static unsigned char _accBytes; // счетчик байтов
static unsigned char _foundIdPubTopic; // ID найденного совпадающего топика
static unsigned char _lenDataTopic; // длина данных топика
switch (mqttStepProcessPub) {
case 100: {
if (inByte >= _mqtt_size_buf_pub_topic) { // если длина пакета больше размера массива - выходим
mqttStepProcessPub = 0; // все сначала
} else {
_fullLenPacket = inByte;
mqttStepProcessPub = 101; // будем ждать длину топика
}
break;
}
case 101: {
if (inByte >= _fullLenPacket) { // левые данные
mqttStepProcessPub = 0; // все сначала
} else { // если длина топика меньше общей длины пакеты
_lenPubPacket = inByte;
_Bool flBr = false; // флаг поиска
for (unsigned char i = 0; i < this->mqttCountSubTopics; ++i) { // цикл по всем топикам
if (_lenPubPacket == this->mqttLenSubTopics[i]) { // нашлась длина
flBr = true;
break;
}
}
if (flBr) { // есть топик такой длины
mqttStepProcessPub = 102; // считать байты
_accBytes = 0; // сбросили счетчик
} else { // не нашли подходящую длину, пришло что то другое
mqttStepProcessPub = 0; // все сначала
}
}
break;
}
case 102: {
mqttPubStringTopic[_accBytes] = inByte; // заносим входящий байт в массив
++_accBytes;
if (_accBytes == _lenPubPacket) { // пришел весь топик - ищем в списке топиков
_Bool flBr = false; // флаг поиска
for (unsigned char i = 0; i < mqttCountSubTopics; ++i) { // цикл по всем топикам
if (_lenPubPacket == mqttLenSubTopics[i]) { // нашлась длина
if (memcmp((char *)mqttPubStringTopic, (char *)mqttTopicsSubscribe[i], _lenPubPacket) == 0) { // нашелся топик
_foundIdPubTopic = i;
flBr = true;
break;
}
}
}
if (flBr) { // нашелся топик
_lenDataTopic = _fullLenPacket - _lenPubPacket - 2; // посчитали длину данных
_accBytes = 0; // сбросили счетчик
mqttStepProcessPub = 103; // считать приходящие данные
} else { // нет такого топика
mqttStepProcessPub = 0; // все сначала
}
}
break;
}
case 103: {
mqttPubStringTopic[_accBytes] = inByte; // заносим входящий байт в массив
++_accBytes;
if (_accBytes == _lenDataTopic) { // пришли все данные
mqttPubStringTopic[_accBytes] = 0; // конец строки
mqttStepProcessPub = 0; // все сначала
this->_callback_pub_topic(_foundIdPubTopic, (unsigned char *)mqttPubStringTopic); // вызываем внешний обработчик
}
break;
}
default: { // 0 - ищем ИД пакета
if (inByte == 0x30) { // прилетел топик с QoS = 0
mqttStepProcessPub = 100; // будем ждать длину пакета
}
}
}
}
}
void Sim800MQTT :: mqttStart(unsigned char * inSrvName, unsigned short inSrvPort, unsigned char * inUser, unsigned char * inPass, unsigned char * inClient) { // запуск
this->mqttCountSubTopics = 0; // нет подписанных топиков
this->mqttReadySubTopics = false; // нет подписанных топиков
this->mqttFlagBusy = true;
this->mqttServerName = inSrvName;
this->mqttServerPort = inSrvPort;
this->mqttUserName = inUser;
this->mqttLenStrUserName = this->getLenStringPGM(this->mqttUserName);
this->mqttPassword = inPass;
this->mqttLenStrPassword = this->getLenStringPGM(this->mqttPassword);
this->mqttClient = inClient;
this->mqttLenStrClient = this->getLenStringPGM(mqttClient);
this->currentMQTTstatus = mqttNone; // начало
this->initUART(); // инициализация порта
this->startInit(); // и запуск
}
void Sim800MQTT :: mainWorkMQTT(void) { // основной процесс работы с брокером
switch (this->currentMQTTstatus) {
case mqttNone: {
this->mqttCountSubTopics = 0; // нет подписанных топиков
this->mqttReadySubTopics = false; // нет подписанных топиков
this->mqttFlagBusy = true;
this->currentMQTTstatus = mqttConnectToSocket;
break;
}
case mqttConnectToSocket: {
this->connectToTCPsocket(mqttServerName, mqttServerPort);
this->currentMQTTstatus = mqttWaitConnectonToSocket;
break;
}
case mqttWaitConnectonToSocket: {
if (this->currentGprsMode == gprsConnected) { // успешный коннект с сокетом
// будет отправлять пакет соединения с брокером
// подготовка строки для брокера
mqttStringToSend[0] = 0x10; // MQTT Control Packet type 0001 connect, reserved 0000
mqttStringToSend[1] = 16 + this->mqttLenStrUserName + this->mqttLenStrPassword + this->mqttLenStrClient; // Remaining Length is the length of the variable header (10 bytes) plus the length of the Payload.
// Variable header
mqttStringToSend[2] = 0x00; // Length MSB (0)
mqttStringToSend[3] = 0x04; // Length LSB (4)
mqttStringToSend[4] = 'M';
mqttStringToSend[5] = 'Q';
mqttStringToSend[6] = 'T';
mqttStringToSend[7] = 'T';
mqttStringToSend[8] = 0x04; // Protocol Level byte
mqttStringToSend[9] = 0xC0; // Connect Flag bits, login and pass enable
mqttStringToSend[10] = 0x00; // Keep Alive MSB (0)
mqttStringToSend[11] = (unsigned char)_mqtt_period_save_connection_broker; // Keep Alive LSB (0)
// payload
mqttStringToSend[12] = 0x00; // Keep Alive MSB (0)
mqttStringToSend[13] = mqttLenStrClient; // Length LSB (4) - device
unsigned char slen = mqttToUARTstringPGM(this->mqttClient, 14); // client/device ID
mqttStringToSend[slen] = 0x00; // Keep Alive MSB (0)
mqttStringToSend[slen + 1] = mqttLenStrUserName; // Length LSB (4) - user
slen = mqttToUARTstringPGM(this->mqttUserName, slen + 2); // user
mqttStringToSend[slen] = 0x00; // Keep Alive MSB (0)
mqttStringToSend[slen + 1] = mqttLenStrPassword; // Length LSB (4) - pass
slen = mqttToUARTstringPGM(this->mqttPassword, slen + 2); // pass
// отправка строки брокеру
this->sendStringToServer((unsigned char *)mqttStringToSend, slen);
this->mqttTimerWait = millis(); // сбросим таймер ожидания коннекта
this->currentMQTTstatus = mqttWaitConnectBroker; // будем ждать успешного соединения с брокером
this->mqttStepWork = 0; // сброс рабочего флага
} else if ((this->currentGprsMode == gprsNone) || (this->currentGprsMode == gprsConnectTimeout)) { // проблема с подключением
// пробуем бесконечно подключиться - повтор
this->currentMQTTstatus = mqttToReconnect; // будем переподключаться
}
break;
}
case mqttToReconnect: {
this->mqttTimerWait = millis();
this->currentMQTTstatus = mqttWaitReconect;
break;
}
case mqttWaitReconect: {
if ((millis() - this->mqttTimerWait) >= 5000UL) this->currentMQTTstatus = mqttNone; // время вышло, все сначала
break;
}
case mqttSendSubTopic: {
// fixed header
mqttStringToSend[0] = 0x82; // MQTT Control Packet type (8) 0100, reserved 0010
mqttStringToSend[1] = 5 + this->mqttLenSubTopics[this->mqttCurrentSubTopic]; // Remaining Length is the length of the variable header (10 bytes) plus the length of the Payload.
// Variable header
mqttStringToSend[2] = 0x00; // Packet Identifier MSB (0)
mqttStringToSend[3] = 0x0A; // Packet Identifier LSB (10)
// payload
mqttStringToSend[4] = 0x00; // Length MSB (0)
mqttStringToSend[5] = this->mqttLenSubTopics[this->mqttCurrentSubTopic]; // Length LSB (size line)
unsigned char i = 0; // позиция в строке
while (unsigned char inCh = mqttTopicsSubscribe[mqttCurrentSubTopic][i]) {
mqttStringToSend[i + 6] = inCh; // отправили строку
++i;
}
mqttStringToSend[i + 6] = 0x00; // Requested QoS(0)
// отправка строки брокеру
this->sendStringToServer((unsigned char *)mqttStringToSend, i + 7);
this->mqttTimerWait = millis(); // сбросим таймер
this->currentMQTTstatus = mqttWaitSubTopic;
break;
}
default: { // mqttBrokerConnected ничего не делаем
if ((this->currentGprsMode == gprsNone) || (this->currentGprsMode == gprsConnectTimeout) ||
(this->currentGprsMode == gprsTimeoutSend)) { // смотри статусы GPRS
this->currentMQTTstatus = mqttToReconnect; // будем переподключаться
} else if ((currentMQTTstatus == mqttBrokerConnected) && ((millis() - mqttTimerPingReq) >= _mqtt_period_send_ping_req) && (!mqttFlagBusy)) { // пришло время отправки PINGREQ
this->mqttFlagBusy = true;
mqttStringToSend[0] = 0xC0; // MQTT Control Packet type (12) 1100 ping, reserved 0000
mqttStringToSend[1] = 0x00; // Remaining Length
this->sendStringToServer((unsigned char *)mqttStringToSend, 2);
this->mqttTimerPingReq = millis();
currentMQTTstatus = mqttWaitRespPing;
this->mqttTimerWait = millis();
}
}
}
}
void Sim800MQTT :: loopMQTTgprs(void) { // циклическая работа с сервером MQTT
this->loopSIM800modem();
if (this->currentGlobalStatusModem == modemNeedRestart) { // все плохо
this->modemReset(); // как минимум перезагрузить модем, можно еще и весь МК
this->startInit(); // и запуск
} else if (this->currentGlobalStatusModem == modemReady) { // инициализация прошла - работаем
this->mainWorkMQTT();
}
}
void Sim800MQTT :: mqttSubscribeTopics(const unsigned char ** inSubTopics) { // подписываемся на топики
this->mqttFlagBusy = true; // займем работу с брокером
this->mqttReadySubTopics = false; // нет подписанных топиков
this->mqttTopicsSubscribe = inSubTopics;
this->mqttCountSubTopics = 0;
while (inSubTopics[this->mqttCountSubTopics][0]) ++this->mqttCountSubTopics; // посчитали количество топиков
for (unsigned char i = 0; i < this->mqttCountSubTopics; ++i) { // цикл по всем топикам
this->mqttLenSubTopics[i] = 0; // длина строки топика
while (this->mqttTopicsSubscribe[i][this->mqttLenSubTopics[i]]) ++this->mqttLenSubTopics[i]; // посчитали длину строки
}
this->mqttCurrentSubTopic = 0; // начнем с нулевого топика
this->currentMQTTstatus = mqttSendSubTopic;
}
void Sim800MQTT :: setCallbackPubTopic(void (*inFuncPubTopic)(unsigned char, unsigned char *)) { // установка обработчика входящих топиков
this->_callback_pub_topic = inFuncPubTopic;
}
void Sim800MQTT :: sendPublishTopic(unsigned char * outPubTopic, unsigned char * outDataPub) { // отправка PUBLISH TOPIC
this->mqttFlagBusy = true; // займем работу с брокером
unsigned char lenTopic = getLenStringPGM(outPubTopic);
unsigned char lenData = strlen((const char *)outDataPub);
// fixed header
mqttStringToSend[0] = 0x30; // MQTT Control Packet type 0011, DUP QoS Retain 0000 flags
mqttStringToSend[1] = 4 + lenTopic + lenData; // Remaining Length is the length of the variable header (10 bytes) plus the length of the Payload.
// Variable header
mqttStringToSend[2] = 0x00; // Length MSB (0)
mqttStringToSend[3] = lenTopic; // Length LSB
unsigned char slen = mqttToUARTstringPGM(outPubTopic, 4); // pub topic
mqttStringToSend[slen] = 0x00; // Packet Identifier MSB (0)
mqttStringToSend[slen + 1] = 0x0A; // Packet Identifier LSB (10)
// payload
unsigned char i = 0; // позиция в строке
while (unsigned char inCh = outDataPub[i]) {
mqttStringToSend[slen + 2 + i] = inCh; // отправили строку
++i;
}
// отправка строки брокеру
this->sendStringToServer((unsigned char *)mqttStringToSend, slen + 2 + lenData);
this->mqttTimerWait = millis();
this->currentMQTTstatus = mqttWaitPubTopic;
}
Итак, господа:
1. Пиков в 2 ампера я не заметил на всем промежутки работы модуля (10 минут)
2. Стандартный ток в модуле - 20 мА
3. При регистрации в сети ток - 100мА, никакими 2А там и не пахнет.
3. Как я и говорил проблема не в питании, сейчас обеспечил абсолютно стабильные 4В 2А, результат нулевой. Прошу если и высказываться, то конструктивно, имхо даже с студенту 1-2 курса понятно что при нагрузках в виде регистрации в сети и отправки 3-4 сообщений по юарту в секунду модуль не сможет физически жрать 2А.
Ага, и даташиты дураки пишут, и на форумах бараны, которые с запасом БП делают, живите дальше в своей розовой вселенной и делайте г... устройства :(
Заменил все провода на 0,5мм2, AT+CREG? Теперь выдает 1,0, 1,2; 1,1 добиться все также не могу. Ток в рамках моего сообщения выше
Осталось питание на модуль РАСПАЯТЬ !
Ещё очень часто сам модуль криво напаян на плату ... Видимо у вас именно этот случай...
В какое место мне его распаять?
Видимо на плату, хотя бы монтажную распаять. Многократно уже люди попадали на косяки при сборке устройства на sim800 на проводочках.
Пример стабильно работающей схемы подключения / питания
http://arduino.ru/forum/apparatnye-voprosy/vse-o-sim800l-i-vse-chto-s-ni...
Не очень понял, открыв схему (http://arduino.ru/forum/apparatnye-voprosy/vse-o-sim800l-i-vse-chto-s-ni...) я увидел висящий в воздухе L2, на месте БП возле вышеупомянутого L2 пустое место, как я догадываюсь.
А на счет используемого вами БП на 1 А меня терзают смутные сомнения, что он подойдет, ведь по даташиту модуль кушает 2 А, и как он работает от силы тока в два раза меньше мне решительно непонятно. Очевидно, человек не читал даташит, и, я надеюсь, не доказывает всем, что тот, кто не читал даташит делает "г... устройства"
А если по конструктиву, то: паял обвязку в виде ножек и антенны я сам, косяков там не может быть. Возможно что-то с пайкой модуля, но перепаять я его не могу, имея паяльник и фен. Есть ли у кого-то соображения пока ко мне идет 3 модуля и мои платы под этот модуль с китая?
4.2 - 4.3 В пробуйте
Не очень понял, открыв схему (http://arduino.ru/forum/apparatnye-voprosy/vse-o-sim800l-i-vse-chto-s-ni...) я увидел висящий в воздухе L2, на месте БП возле вышеупомянутого L2 пустое место, как я догадываюсь.
Сайт глючит, не все показывает. Полная схема:
Проблема с модулем Sim800l. Через какой-то промежуток времени перестает работать. Светодиод не мигает. Перезапуск не помогает. Может включиться на следующий день. Контакты пропаяны хорошо, нигде не отходит.
В uart модема что нибудь есть?
1 проблема с питанием
2 модем ушёл в спящий режим
Схемы нет, скетча нет, говорит не о чем.
Питание от компьютерного блока питания, шина +12в, через DC-DC LM2596S, на выходе 4.1В. Модуль подключаю к Нано, RX-TX через резисторный делитель. Скетч брал отсюда
http://codius.ru/articles/GSM_%D0%BC%D0%BE%D0%B4%D1%83%D0%BB%D1%8C_SIM80...
История такова. Схема запускалась, скетч работал, все АТ команды проходили на УРА, сообщения на телефон получал. После оставил на какое-то время всё в покое. Через какое-то время модуль отключился. Отключал питание, DTR садил на землю. Ничего не помогало его включить. На следующий день попытался опять , и он включился. Через определённое время всё повторилось.
И ещё. В скетче добавил команду отключения спящего режима AT+CSCLK=0.
Отключал питание, DTR садил на землю. Ничего не помогало его включить.
Так может модуль бракованный? другой не пробовали? Я встречался что у SIM800L зависает радио модуль, но это бывает у единиц и через 1.5 - 2 месяца непрерывной работы. И на AT команды он все равно отвечает. И все соединения к модулю крайне рекомендуется паять.
Так может модуль бракованный? другой не пробовали? Я встречался что у SIM800L зависает радио модуль, но это бывает у единиц и через 1.5 - 2 месяца непрерывной работы. И на AT команды он все равно отвечает. И все соединения к модулю крайне рекомендуется паять.
Весьма вероятно . У меня с 50 модулей , очень много брака оказалось . Какие сразу не работали , а какие работали потом переставали вовсе. По прозвонке , с нормальными , выяснил закономерность в виде плохих прозванивающихся пинов. Видимо китайцы плохо припаяли модули.
В след. раз буду брать только SIM800C , у них необходимые пины по сторонам модуля , а не под ним где не увидишь качество пайки. У SIM800C разве что пин управления питания немного по другой логике работает.
Спасибо. Буду покупать другой модуль.
Питание от компьютерного блока питания, шина +12в, через DC-DC LM2596S, на выходе 4.1В. Модуль подключаю к Нано, RX-TX через резисторный делитель. Скетч брал отсюда
http://codius.ru/articles/GSM_%D0%BC%D0%BE%D0%B4%D1%83%D0%BB%D1%8C_SIM80...
История такова. Схема запускалась, скетч работал, все АТ команды проходили на УРА, сообщения на телефон получал. После оставил на какое-то время всё в покое. Через какое-то время модуль отключился. Отключал питание, DTR садил на землю. Ничего не помогало его включить. На следующий день попытался опять , и он включился. Через определённое время всё повторилось.
Приобрёл модуль Sim800C. Пару дней с ним ковыряюсь, пока всё работает. Такой вопрос. Попалась статья, где указано, что необходимо согласовывать с модулем подключаемую антенну. Нашел схему в даташите, но там не указываются номиналы елементов. Какие надо, и надо ли вообще?
Подскажите кто знает как сделать что бы когда Sim800L ответила на входящий звонок по белому списку номеров и передачи DTMF сигналов с мобильного телефона в динамике Sim800L не было слышно как раз этих сигналов DTMF ? А то подаёшь команду и слышишь её , мне просто для проекта это не нужно .
Доброго времени, дабы не плодить темы спрошу тут. Кто-нибудь знает как попасть на сайт через sim800l, если на сайте стоит .htpasswd ?
Или это не как не влияет на POST / GET запросы ?
добавлю свои пять копеек по поводу питания и 2 ампер в пике.
Обнаружил что в SIM800L стоит самый настоящий УМЗЧ собраный по мостовой схеме для увеличения выходной мощности. Усилитель тоже жрет и довольно много. поэтому предположения что если подключить достаточно низкоомную нагрузку и выставить CLVL=100 (громкость) то ток потребления увеличится. А если нагрузки нет то ни о каких 2 ампер даже и близко речи не может быть.
простой конденсатор по питанию превратит из пикового значения в RMS.
Ещё один не верующий в даташит :(
Уважаемый, не вводите людей в заблуждение, если вы это не видели, это не значит что этого нет.
ЗЫ. Сам видел нагрузку высокую, да иногда не предсказуемо, но она есть.
Собрал не менее десятка устройств, по моим проектам тысячи и я вас уверяю - тестировали очень много прежде чем выбрать правильный БП.
но почему сразу не верю очень даже верю.
я не ввожу в заблуждение, а пытаюсь разобраться. там в даташит указано что может пиковая нагрузка быть, а в каких условиях она может быть вот один из вариантов я и предполагаю следующее.
выходная мощность УМЗЧ 1 вт. с хвостиком. КПД усилителя АВ не более 50%, из этого следует что потребляет он более 2 вт только на динамик и эта мощность не пиковая а RMS. отсюда вывод если нет динамика то можеш сразу 0.5 А сразу удалить. а то и больше. (прям совсем топорный анализ)
КПД усилителя АВ не более 50%
Это откуда такое?
вывод если нет динамика то можеш сразу 0.5 А сразу удалить.
Откуда такой вывод?
даташит стр 36 усилитель АВ. гуглим КПД 50%. в идеальных условиях и при максимальной мощности может достигать 70%. это все еще RMS.
опять топорный подсчет. на выходе усилителя АВ амплитуда может достигать питания 4 в (схема усилителя мостом). при нагрузки динамика 8 ом ток пиковый через динамик составит 0.5 А если еще прикинуть КПД 70% то реальное потребление еще чутка больше. я просто указываю что реально достаточно много жрет. ловить меня на точных подсчетах ненужно, это просто топорный подсчет.
если динамика нет то и нагрузки нет, значит и ток через 8 ом не потечет значит и потреблять меньше будет (это просто аксиома) нет нагрузки нет тока.
Alex_Mn , sim800l может потреблять более 1.5 ампер без всяких динамиков на выходе и это факт, подтвержденный практикой. Быть теоретиком это хорошо, но когда вам нужно стабильно работающее устройство, это совсем другое.
даташит стр 36 усилитель АВ. гуглим КПД 50%. в идеальных условиях и при максимальной мощности может достигать 70%. это все еще RMS.
1. Так все-таки, 50% или 70%? Это как бы не одно и от же.
2. О каком дэйташите Вы говорите. На физические формулы нет дэйташитов. Если уж ссылаться, то на страницу учебника, а не дэйташита.
3. Максимальный КПД усилителя класса В (на синусоидальном сигнале без искажений) составляет 78.5%. Для класса АВ - совпадает (с указанной точностью) с этим значением.
если динамика нет то и нагрузки нет, значит и ток через 8 ом не потечет значит и потреблять меньше будет (это просто аксиома) нет нагрузки нет тока.
Это не аксиома, это - логическая ошибка: из того, что средний ток будет меньше, никак не следует, что максимальный ток также будет меньше.
...
ну как скажеш ошибка так ошибка.
понял одно что я гуглить не умею ))
Итак, господа:
1. Пиков в 2 ампера я не заметил на всем промежутки работы модуля (10 минут)
2. Стандартный ток в модуле - 20 мА
3. При регистрации в сети ток - 100мА, никакими 2А там и не пахнет.
3. Как я и говорил проблема не в питании, сейчас обеспечил абсолютно стабильные 4В 2А, результат нулевой. Прошу если и высказываться, то конструктивно, имхо даже с студенту 1-2 курса понятно что при нагрузках в виде регистрации в сети и отправки 3-4 сообщений по юарту в секунду модуль не сможет физически жрать 2А.
конструктивно высказываю свои мысли. хотя тебе может уже не актуально, но другим может и позновательно.
даташит на SIM800L указывает что ток в пике может достигать 2 ампер длительность этого импульса весьма микроскопична (даташит только оговаривает на саму сборку). и указывает что нужно устанавливать конденсатор минимум 100 мкф. то что ты мериш уже собраный макет и в котором уже стоит эта емкость, отсюда ты никогда не увидиш эти 2 ампера.
плюс еще там стоит усилитель НЧ который работает на 8 омную нагрузку, который жрет (мои предположения больше чем усилитель ВЧ). усилитель ВЧ нагружен на антену 50 ом. поэтому мои предположения что если не использовать динамик то апетит этого модуля куда скромнее 2 ампер. и не обращай внимание на аналитиков которые техническую литературу рассматривают как журнал "мурзилка" (картинки)
мои предположения
ключевое слово!
Спорить не буду, понял что бесполезно, у вас свои учебники из другой вселенной, когда соберете устройство со слабеньким БП на модем миллиампер на 300....и сможете добиться uptime стабильной непрерывной работы/звонки/СМС/GPRS на пару месяцев - тогда и поговорим :)
мои предположения
ключевое слово!
Спорить не буду, понял что бесполезно, у вас свои учебники из другой вселенной, когда соберете устройство со слабеньким БП на модем миллиампер на 300....и сможете добиться uptime стабильной непрерывной работы/звонки/СМС/GPRS на пару месяцев - тогда и поговорим :)
что у вас за манера высказывать что одни вы правы и вы один дартаньян, есть что по делу то говорите. на то и форум искать компромис мнений. чел искал пиковый ток и не смог его обнаружить, я подсказал свое мнение почему его нет.
там стоит усилитель НЧ который работает на 8 омную нагрузку, который жрет (мои предположения больше чем усилитель ВЧ).
Где вы там увидели 8-омную нагрузку? Даже если предположить что она в готовом устройстве действительно есть, то динамик участвует только при вызовах, а до этого, как минимум, модуль должен зарегистрироваться в сети, чего у большинства как раз и не происходит при некачественном питании. Т.е. до возрастания потребления модулем из-за УНЧ и низкоомного динамика еще ой как далеко...
там стоит усилитель НЧ который работает на 8 омную нагрузку, который жрет (мои предположения больше чем усилитель ВЧ).
Где вы там увидели 8-омную нагрузку? Даже если предположить что она в готовом устройстве действительно есть, то динамик участвует только при вызовах, а до этого, как минимум, модуль должен зарегистрироваться в сети, чего у большинства как раз и не происходит при некачественном питании. Т.е. до возрастания потребления модулем из-за УНЧ и низкоомного динамика еще ой как далеко...
конечно там и нет нагрузки (динамика), ну так я там и не увидел 2 ампер потребления, и там как раз приводится эксперемент что при регистрации потребления возрастает до 100 ма. кто-нибудь хоть видел на приборе пиковый ток в 2 ампера? реально видеть не что что бабушка сказала. да что там 2 ампера, хоть приведите факт реальный в 1 ампер.
тупо чистые замеры. факт в студию!!!
что у вас за манера высказывать что одни вы правы и вы один дартаньян, есть что по делу то говорите. на то и форум искать компромис мнений. чел искал пиковый ток и не смог его обнаружить, я подсказал свое мнение почему его нет.
да пожалуйста, подумаешь.....сами то можете привести факты - график потребления хотя бы за пару суток со схемой подключения?
Впрочем не важно, не отвечайте, не интересно :)
ЗЫ. Новичков жалко, начитаются таких комментариев, потом подключают питание sim800l например от самой arduino UNO и удивляются че это у них не работает :(
что у вас за манера высказывать что одни вы правы и вы один дартаньян, есть что по делу то говорите. на то и форум искать компромис мнений. чел искал пиковый ток и не смог его обнаружить, я подсказал свое мнение почему его нет.
да пожалуйста, подумаешь.....сами то можете привести факты - график потребления хотя бы за пару суток со схемой подключения?
Впрочем не важно, не отвечайте, не интересно :)
ЗЫ. Новичков жалко, начитаются таких комментариев, потом подключают питание sim800l например от самой arduino UNO и удивляются че это у них не работает :(
хорошо как-нибудь будет время попробую, не обещаю на ради эксперимента постараюсь сгородить некий стенд. но ни о каких 2 суток не может быть и речи. максимум некоторые моменты продолжительностью в несколько секунд. ибо такие замеры адекватно проводить на осцилографе. ни один мультиметр не способен ловить пики.
некоторые моменты продолжительностью в несколько секунд. ибо такие замеры адекватно проводить на осцилографе. ни один мультиметр не способен ловить пики.
смешно.......и нафиг не надо, и при чем тут мультиметр? в даташите черным по английски на 20 странице написано что при передаче может быть сильное падение напряжения и БП должен обеспечивать ток нагрузки до 2 ампер. Лично мне не нужны никакие доказательства, если вы уперлись и хотите сообществу что там доказать - соберите стенд с электронным логированием потребляемого тока в разных режимах работы - тогда и поговорим.
провел эксперемент на скорую руку.
измерения проводил осцилографом. в разрыв питания поставил резистор 0.125 ом (точность 1%).
желтый луч показывает напряжения на этом резисторе пульсация достигала даже чутка более 160 мв. что в переводе на ток 0.16/0.125 = 1.28 ампер и это прям на скорую руку думаю если еще грузануть то можно еще больше ток увидить.
так что снимаю шляпу действительно ток в 1.5 А думаю в импульсе запросто жрет.
такие импульсы не всегда, когда в сети регистрируется кратковременно кидают импульсы, когда идет дозвон на этот номер тож хорошие импульсы.
источник питания брал китайский блок питания стабилизатор на микрухе LM2596S. напряжения 4.05 вольта.
LM2596S проверенный многими поколениями понижайка для sim800l - надёжно и просто, но великоват для компактных схем.
Хочу питать и ардуино и SIM800 от 4 Вольт. Делитель по RX рассчитывать примерно на 2,5 Вольт?
Или правильнее раздельное питание?
Использую LM2596
Итак я вернулся! Овации господа! И я готов отстаивать свое мнение. За плечами у меня 4 рабочих модуля, отправленные СМС и ИСТИНА. Истиной готов поделиться. При регистрации модуля в сети пиковая нагрузка 4V 0,2A вкуснейшего постоянного напряжения. Ни о каких 2А речи идти не может, после регистрации при переходе в режим ожидания модуль жрет от 0,01 до 0,05 ампер заявленного напряжения. При отсутствии же законченной регистрации он с периодичностью в 20-30 секунд пытается зарегистрироваться в сети. Моя проблема была не в проводах, ни тем более в электричестве. Все оказалось весьма банально, однако никто мне по этому поводу советов не дал. НЕ ИСПОЛЬЗУЙТЕ КАРТЫ ТЕЛЕ-2, у меня они НЕ ПАШУТ с модулем. Заблокированную МТС видит, рабочую МТС видит. В качестве теста отправил сообщение. Оборудование БП (указан выше, переходник USB-UART, ноут, симка МТС). Спасибо за внимание
P.S. andycat, учите матчасть (не даташиты а физику)
Абсолютно с вами согласен, коллега практик, у меня вышло 200 мА пик, больше не жрало, я думаю если все функции применить в модуле одновременно может там и будет ток около 1А но явно это не причина не работы просто подключенного модуля, что я пытался доказать господам выше и был послан
Итак я вернулся! Овации господа! И я готов отстаивать свое мнение. За плечами у меня 4 рабочих модуля, отправленные СМС и ИСТИНА. Истиной готов поделиться. При регистрации модуля в сети пиковая нагрузка 4V 0,2A вкуснейшего постоянного напряжения. Ни о каких 2А речи идти не может, после регистрации при переходе в режим ожидания модуль жрет от 0,01 до 0,05 ампер заявленного напряжения. При отсутствии же законченной регистрации он с периодичностью в 20-30 секунд пытается зарегистрироваться в сети. Моя проблема была не в проводах, ни тем более в электричестве. Все оказалось весьма банально, однако никто мне по этому поводу советов не дал. НЕ ИСПОЛЬЗУЙТЕ КАРТЫ ТЕЛЕ-2, у меня они НЕ ПАШУТ с модулем. Заблокированную МТС видит, рабочую МТС видит. В качестве теста отправил сообщение. Оборудование БП (указан выше, переходник USB-UART, ноут, симка МТС). Спасибо за внимание
P.S. andycat, учите матчасть (не даташиты а физику)
Да мне насрать на ваше мнение)
Я сторонник верить даташитам.
И да, когда будет у вас несколько тысяч! устройств на sim800 с бп 500 мА и uptime несколько месяцев, тогда и поговорим....а так это просто пшик ни о чем.
... И я готов отстаивать свое мнение. За плечами у меня ...
ждем когда начнеш отстаивать, только еще пиши чем и как мерил пиковые нагрузки.
выше я скрин осцилографа выложил, падения напряжения на резисторе 0.125 ом (точность резистора 1%).
значение пиковое и среднеквадратичное они разные. а то если считать по значению RMS там как раз 36 мв. в переводе на ток 0.036/0.125 и получим твои 0.288 А.
Интересно, вам не надоело повторять как заведенному историю про даташиты и кучи ваших устройств? Я смотрю за столько времени ваша риторика так и не сменилась. При чем кое-где вы пишете что-то про то, что вы практик при этом не прикладывая к своим словам никакой информации. По-моему вы обычный словоблуд, который не может принять факт того, что был неправ в течении уже 3?4? месяцев. Вам уже и графики приводят и фотки скидывают, и проблема уже решилась, а вы все про свой даташит пишете. Можете не отвечать, это последнее сообщение в ветке, где мне не смогли помочь, зато давали "дельные" советы в тех местах, где проблем не было, что тоже о многом говорит.
P.S. Про ваше личное качество может говорить и то, что вы делаете свои поделки на копеечном модуле и ардуине. Поверьте, серьезные проекты делают не на них, и хоть миллионы их штук дело не изменят) Вы не смогли найти проблему имея тысячу этих модулей, о чем нам с вами говорить?)
...
на практике я и намерил пиковый ток в 1.28 ампер и это просто пустой модуль. и это проводилось просто на скорую руку, еще УНЧ нагрузить получим еще больше.
...
на практике я и намерил пиковый ток в 1.28 ампер и это просто пустой модуль. и это проводилось просто на скорую руку, еще УНЧ нагрузить получим еще больше.
Alex, я не вам писал свое последнее сообщение, а телу выше) Ваш график я видел, что вполне может соответствовать правде, однако вопрос то в начале у меня был несколько иной, да и сомневаюсь что он сможет долго жрать 1,5А
Библиотека для работы GPRS с модемом SIM800L.
MK и модем подключены через аппаратный UART, соотвественно на 0 и 1 пины МК.
Пин Arduino TX1 подключается через резисторный делитель (понизить с 5 вольт до ~2.8 вольт) на пин RX модема.
Пин Arduino RX0 подключается напрямую на пин TX модема.
Пин Arduino A1 подключается через резистор 30....70 Ом на пин RST модема.
Для вывода лога в консоль использую внешний TTL-USB переходник, подключенный через пины 2 и 3 МК, работает через библиотеку SoftwareSerial. В итоговом работающем устройстве рекомендую вывод каких либо данных в консоль через эту библиотеку не использовать!
Поскольку обработка данных от модема идет в online режиме анализом каждого входящего байта данных, крайне не рекомендуется в своих задачах использовать delay и любой долго задерживающий loop код!
В дальнейшем напишу библиотеку работы с MQTT, буду выкладывать по мере готовности.
Пример работы с HTTP сервером
- sim800gprs.h
- sim800gprs.cpp
-
Библиотека для работы GPRS с модемом SIM800L.
для модуля SIM800A подойдёт?
для модуля SIM800A подойдёт?
не знаю, нет такого модуля, не пробовал, судя по даташиту sim800_series_at_command_manual_v1.01, там общая система команд. Возможно различия в сбросе модема, например для SIM800L просто пином RST сбрасывается, то для SIM800C другой ногой в определенной комбинации делается сброс.
Продолжение http://arduino.ru/forum/apparatnye-voprosy/vse-o-sim800l-i-vse-chto-s-nim-svyazano?page=5#comment-652617
Работа с MQTT брокером через GPRS модем SIM800L.
Поддержание постоянной связи с брокером посредством каманд PINGREQ/PINGRESP.
При реконнекте с брокером не производиться автоматическое подписание на SUBSCRIBE топики, сделано осознано, на практике рабочих проектов при сбоях обычно запускается другая логика/топики. Если понадобиться - допишу как нибудь. Т е по хорошему в основной программе необходимо проверять статус подключения и в случае сбоя ставить флаг - повторное подписание на топики.
- тестовый код
- sim800gprs.h
- sim800gprs.cpp
- sim800mqtt.h
- sim800mqtt.cpp
-
Здравствуйте.