Урок 22. Модуль SIM800L



  • Цель урока

    Привет! Сегодня мы познакомимся с отличным модулем SIM800L и научимся принимать SMS-сообщения (рисунок 1).

    Рисунок 1

    Этот урок научит: обмениваться данными по UART с модулем; производить инициализацию и конфигурацию модуля; получать и читать текстовые SMS.

    Краткая справка

    • Назначение: применяют получения услуг сотовой связи
    • Сфера применения: сельское хозяйство, умный дом и другие
    • Интерфейс подключения: UART2 (MBUS)
    • Напряжение питания: от 3.4 до 4.4 В
    • Совместимость: M5STACK и M5FIRE (со снятым GO-модулем)
    • Форм-фактор: STACK

    Краткий обзор

    SIM800L — один из большого семейства дополнительных модулей (MODULES), предназначенных прежде всего для М5STACK. Поставляется данный модуль в пластиковом футляре (рисунок 2).

    Рисунок 2

    На лицевой стороне модуля имеется вилка шины MBUS, слот для MicroSIM, канавка под антенну-пружинку (рисунок 3).

    Примечание: контакты: G5 -> RST, G16 -> TXD, G17 -> RXD (Serial2).

    Рисунок 3

    Примечание: если модуль присоединён к М5, то вставить и извлечь SIM-карту нельзя.

    На обратной стороне модуля имеется розетка шины MBUS, модуль SIM800L, антенна-пружинка на GSM-диапазон, разъём (3.5 мм mini-jack) для подключения наушников и встроенный микрофон (рисунок 4).

    Рисунок 4

    Начнём!

    Blockly (UI Flow)

    Для того, чтобы приступить к использованию нашего модуля необходимо его инициализировать (рисунок 5). Это займет некоторое время (приблизительно около 1 минуты). В это время нельзя беспокоить модем и выполнять какие-либо операции с ним, поэтому мы временно окрасим LED BAR красным цветом. С помощью функции InitSIM800L мы сообщим модему некоторые параметры работы, которые интересны нам в будущем. Обратите внимание на переменную isMessage, которая принимает значение 0. Для чего она нужна - рассмотрим далее.

    Рисунок 5

    Для того, чтобы модем начал реагировать на внешние команды после подачи питания ему потребуется приблизительно 10 секунд. Далее нам необходимо инициализировать UART-интерфейс на соответсвующих контактах устройства с помощью блока set UART.

    Обратите внимание: TX 17, RX 16

    Затем с помощью блока read UART available в цикле убедимся, что есть какой-то мусор в UART-буфере и считаем его посимвольно с помощью блока read UART. Отлично! Порт готов к работе. Теперь перезагрузим модуль, отправив команду AT+CFUN=1,1\r с помощью блока write. Дадим модему на нормальный запуск 45 секунд. Выключим ЭХО с помощью ATE0\r. Установим GSM-кодировку текстового режима AT+CSCS="GSM"\r. Включим текстовый режим AT+CMGF=1\r. Очистим память сообщений AT+CMGD=1,4\r. Попросим модуль читать входящие сообщения при получении AT+CNMI=1,2,2,1,0\r. Опять очистим буфер от возможного мусора. Всё, на этом модуль полностью готов к работе (рисунок 5.1).

    Рисунок 5.1

    Функция LiveSIM800L будет постоянно вызываться из цикла Loop (рисунок 5.2). В ней мы будем смотреть если ли входящие данные от модуля. Если есть, то считаем и приведем их к строковому виду. Теперь посмотрим есть ли флаг CMT:, если есть, то это входящее сообщение поставим флаг isMessage в состояние 1, это нам необходимо для того, чтобы прочесть текст сообщения. Помните функцию parseString, которую мы писали в прошлых уроках для Arduino IDE? Она отлично нам пригодится здесь. Я её перевел на MicroPython, а Вам её необходимо просто скопировать и вставить в Ваш проект ;)

    def parseString(idSeparator, separator, str2):
        global parseStringGlobalVar1
        parseStringGlobalVar1 = ''
        separatorCount = 0
        for i in range(len(str2)):
            if str2[i] == separator:
                separatorCount += 1
            else:
                if separatorCount == idSeparator:
                    parseStringGlobalVar1 += str2[i]
                elif separatorCount > idSeparator:
                    break
        return parseStringGlobalVar1
    

    Для тех, кто не помнит или не читал прошлые уроки - функция parseString принимает три аргумента и возращает участок строки, расположенный между разделителями: idSeparator (int), separator (char), str2 (String). Где idSeparator - порядковый номер разделителя; separator - разделитель; str2 - строка из которой извлекаем подстроку.

    Например:

    cmtStr = '+CMT: "+7XXXXXX0001","","01/01/01,09:30:00+12"\r\n';
    print(parseStr(1, '"', cmtStr))
    

    Будет выведено:

    +7XXXXXX0001
    

    А если сделать так:

    print(parseStr(3, '"', cmtStr))
    

    То будет выведено:

    01/01/01,09:30:00+12
    

    Рисунок 5.2

    К сожалению Blockly не позволяет сегодня нам нормально реализовать нашу функцию, но ничего страшного - есть обходной вариант сделать MicroPython-вставку (рисунок 5.3.1).

    Рисунок 5.3

    Рисунок 5.3.1

    Когда будут приходить SMS будет вызываться функция-событие IncomingSms. А номер отправителя и текст сообщения будет находиться в глобальных переменных IncomingSmsPhone и IncomingSmsMessage, соответственно.

    Рисунок 5.4

    На этом урок закончен! :)

    MicroPython (UI Flow)

    from m5stack import *
    from m5ui import *
    import machine
    clear_bg(0xffffff)
    
    
    rgb = RGB_Bar()
    btnA = M5Button(name="ButtonA", text="ButtonA", visibility=False)
    btnB = M5Button(name="ButtonB", text="ButtonB", visibility=False)
    btnC = M5Button(name="ButtonC", text="ButtonC", visibility=False)
    label1 = M5TextBox(18, 90, "...", lcd.FONT_DejaVu24, 0x000000)
    label2 = M5TextBox(22, 192, "...", lcd.FONT_DejaVu18, 0x000000)
    title0 = M5Title(title="SIM800L Module", fgcolor=0xFFFFFF, bgcolor=0x000000)
    label4 = M5TextBox(24, 48, "Phone number:", lcd.FONT_DejaVu24, 0x000000)
    label3 = M5TextBox(48, 145, "Message:", lcd.FONT_DejaVu24, 0x000000)
    
    from numbers import Number
    
    idSeparator = None
    separator = None
    str2 = None
    parseStringGlobalVar1 = None
    IncomingSmsPhone = None
    uart = None
    buf = None
    IncomingSmsMessage = None
    isMessage = None
    
    def parseString(idSeparator, separator, str2):
        global parseStringGlobalVar1
        parseStringGlobalVar1 = ''
        separatorCount = 0
        for i in range(len(str2)):
            if str2[i] == separator:
                separatorCount += 1
            else:
                if separatorCount == idSeparator:
                    parseStringGlobalVar1 += str2[i]
                elif separatorCount > idSeparator:
                    break
        return parseStringGlobalVar1
    
    def IncomingSms():
      global idSeparator, separator, str2, parseStringGlobalVar1, IncomingSmsPhone, uart, buf, IncomingSmsMessage, isMessage
      label1.setText(str(IncomingSmsPhone))
      label2.setText(str(IncomingSmsMessage))
      speaker.volume(1)
      for count in range(4):
        rgb.set_all(0x00cccc)
        speaker.sing(659, 1/8)
        wait(0.125)
        rgb.set_all(0x000000)
        wait(0.125)
    
    def InitSIM800L():
      global idSeparator, separator, str2, parseStringGlobalVar1, IncomingSmsPhone, uart, buf, IncomingSmsMessage, isMessage
      wait(10)
      uart = machine.UART(1, tx=17, rx=16)
      uart.init(115200, bits=8, parity=None, stop=1)
      while uart.any():
        if uart.read(1):
          pass
      uart.write('AT+CFUN=1,1\r')
      wait(45)
      uart.write('ATE0\r')
      wait(1)
      uart.write('AT+CSCS="GSM"\r')
      wait(1)
      uart.write('AT+CMGF=1\r')
      wait(1)
      uart.write('AT+CMGD=1,4\r')
      wait(1)
      uart.write('AT+CNMI=1,2,2,1,0\r')
      wait(1)
      while uart.any():
        if uart.read(1):
          pass
    
    def LiveSIM800L():
      global idSeparator, separator, str2, parseStringGlobalVar1, IncomingSmsPhone, uart, buf, IncomingSmsMessage, isMessage
      if uart.any():
        buf = str((uart.readline()))
        if isMessage == 0:
          if buf.count('CMT:') == 1:
            isMessage = (isMessage if isinstance(isMessage, Number) else 0) + 1
            IncomingSmsPhone = parseString(1, '"', buf)
        else:
          if buf.count('\\x') == 0:
            isMessage = (isMessage if isinstance(isMessage, Number) else 0) + 0
            buf = buf[2:-5]
            if buf.count('CMT:') == 0 and len(buf) != 0:
              IncomingSmsMessage = buf
              IncomingSms()
        wait(1)
    
    
    
    rgb.set_all(0xff0000)
    InitSIM800L()
    rgb.set_all(0x000000)
    isMessage = (isMessage if isinstance(isMessage, Number) else 0) + 0
    while True:
      LiveSIM800L()
      wait(0.001)
    

    C & C++ (Arduino IDE)

    Пример ещё не написан ^_^

    Downloads

    Увы, тут сегодня ничего нет :)