B4R Tutorial GSM / GPRS - Control the Arduino with SMS messages

SS-2016-05-11_13.27.00.jpg


The GSM shield allows the Arduino to connect to cellular networks. This opens the door for many interesting outdoor solutions.

There are all kinds of shields available. Make sure that the shield you are using is configured to work with pins other than 0 and 1 (which are used for programming the Arduino). We will use SoftwareSerial with AsyncStreams to communicate with the GSM module.

The GSM shield is controlled with AT commands. There are many online resources about the supported commands. Here is a one: http://www.codeproject.com/Articles/85636/Introduction-to-AT-commands-and-its-uses

The GSM code module, included in the attached example, implements the most common commands.

- Sending and receiving SMS messages.
- Making phone calls (the speaker part is not implemented).
- Incoming phone calls.
- Checking the registration status.

Only one task can be done at a time. So there is a "busy" flag that is set and cleared to make sure that commands do not mix.

In this specific example the led is controlled with SMS messages. The button sends a "click!!!" message:
B4X:
Sub btn_StateChanged (State As Boolean)
   If State = False Then
     GSM.SendSMS(phoneNumber, "Click!!!")
   End If
End Sub

Sub MessageArrived(msg() As Byte)
   If msg = "On" Then
     led.DigitalWrite(True)
   Else if msg = "Off" Then
     led.DigitalWrite(False)
   Else
     Log("error: ", msg)
   End If
End Sub

Useful information about these shields:
http://www.seeedstudio.com/wiki/GPRS_Shield_V1.0
http://www.seeedstudio.com/wiki/GPRS_Shield_V2.0
 

Attachments

  • GSM_Example.zip
    2.3 KB · Views: 1,598
Last edited:

Beja

Expert
Licensed User
Longtime User
Hi Erel,
I am just wondering if this code can be ported to GPS/GPRS modem + B4J, and what modifications are necessary if that's possible.
 

JOANORSKY

Member
Licensed User
Longtime User
This might be a slightly off topic but... i have always wondered how do some companies change their caller ID when sending SMS. I know that this can be done using an Asterisk PBX.. but wouldn't this great if done inside a microcontroller such as the Arduino's ATMEGA ?

This can be called as a spoof and can have a lot of uses.. such as publicity to the customers of a certain shop, and for that purpose it is legal as far as i know (it is legal over here in Portugal as well as in all EU countries and US generally speaking).

I know for a fact that this can be done without the carrier manipulating the data.. i just don't know how. As far as i recall on my old days of GSM.. the SMS can be manipulated (in a more hardcore point of view) by changing some details when on PDU mode (please check : http://www.smartposition.nl/resources/sms_pdu.html) which could be a task for the ATMEGA... and the sending could be done using the AT commands of the GSM modem. I have tried many times.. just for some reason i never was able to output the data.. so.. that project was taken to backside of the barn and shoot dead.

But now... this new IDE just reminded me of that.. and.. oh well.. old habits are hard to let go i guess.. ^_^

Just imagine a SMS distribution system implemented using an arduino.. a gsm modem (such as the shield on the topic above) .. and PDU manipulation code. I believe that many shop owners would like such an application... (specially because many carriers are giving free SMS on their plans).

What do you guys think... ?

Again.. sorry for the offtopic.. but i guess it maybe be a close fit..
 

quique

Member
Licensed User
Longtime User
Hi!

Something most unusual had happened to me with this code: I downloaded it and successfully tried it "as is" a couple of days ago.

Today, I decided to try it again, same code base, same boards, same gsm chip, etc. but adding a bit more of functionality:

I added a DHT11 temp & humidity sensor on pin 4 and a solid relay on pin 6.

The resulting code received SMS just fine but It refused to send SMS.

After about an hour of debugging, I found the following:

Inside the GSM.bas code, at the beginning of the SendSMS sub, the first line of code:

B4X:
If busy Then Return False

... was triggering, thus shorting out the sub execution and returning with FALSE.

I commented out that line of code and my program runs just fine sending SMS.

For the life of me, I cannot detect HOW did I cause that to happen.

I suspect something a bit more obscure may be happening: Could some other variable (perhaps one var also called "busy") at library level (specifically on the DHT library) mix up in some way?

Below you will find my slighty customized code. There is also the GSM.bas code which has the conflictive line of code commented out.

B4X:
Private Sub AppStart
[INDENT]Serial1.Initialize(115200)
Log("AppStart")
GSM.Init(7, 8)
pip.Initialize( "ledblink",1000)
pip.Enabled=True
DHT11pin.Initialize(4,DHT11pin.MODE_INPUT)   
led.Initialize(2, led.MODE_OUTPUT)
btn.Initialize(3, btn.MODE_INPUT_PULLUP)
btn.AddListener("btn_StateChanged")
rele.Initialize(6, rele.MODE_OUTPUT)[/INDENT]
EndSub

Sub ledblink()
[INDENT]led.DigitalWrite(Not(led.digitalread)) [/INDENT]
EndSub



Sub btn_StateChanged (State As Boolean)
[INDENT]If State = False Then
[INDENT]GSM.SendSMS(phoneNumber, "Click!!!")[/INDENT]
EndIf[/INDENT]
EndSub



Sub MessageArrived(msg() As Byte)
[INDENT]If msg = "On" Then
[INDENT]rele.DigitalWrite(True)
GSM.SendSMS(phoneNumber, "On")[/INDENT]
else if msg= "Off" Then
[INDENT]rele.DigitalWrite(False)
GSM.SendSMS(phoneNumber, "Off")[/INDENT]
else if msg= "Info" Then
[INDENT]GSM.SendSMS(phoneNumber,dht11result)[/INDENT]
Else
[INDENT]Log("error: ", msg)[/INDENT]
EndIf[/INDENT]
EndSub



Sub dht11result() As String
[INDENT]Dim texto As String
DHT11sensor.Read11(DHT11pin.PinNumber)            'Reading the DHT11 measure
humidity=DHT11sensor.GetHumidity                'Get humidity from readed measure
temperature=DHT11sensor.GetTemperature            'Get temperature from readed measure
mytext= JoinStrings(Array As String("Humidity ",humidity,"% Temp ",temperature,"c"))[/INDENT]
Return mytext
EndSub
 

Erel

B4X founder
Staff member
Licensed User
Longtime User
I suspect something a bit more obscure may be happening: Could some other variable (perhaps one var also called "busy") at library level (specifically on the DHT library) mix up in some way?
No. A library variable cannot affect your variables. However it is possible that for some reason a task never completed which caused the busy flag to remain true.
 

Tayfur

Well-Known Member
Licensed User
Longtime User
Hello @Erel & @rbghongade

I recived my GPRS shield. it s same your shield.

Connceted like under below. ( ı used diffrent rx tx port on shiled)

GSM TX --->> Wemos D5
GSM RX --->> Wemos D6
GSM VCC 5V--->> Wemos 5V port
GSM VCC gnd--->> Wemos GND port

I cant recive data from Shield.
"AStream_NewData" cant run.??? Please help me....

Log...>>>
---APPStart
---sub init
---sub Eneblasmsevent
---sub sendcommand


res1.jpg



B4X:
Region Project Attributes
    #AutoFlushLogs: True
    #CheckArrayBounds: True
    #StackBufferSize: 1000
#End Region

Sub Process_Globals
    Public Serial1 As Serial
    Private led As Pin
    Private btn As Pin
    Private wemos As D1Pins
     Private Timer1 As Timer
     Private durum As Boolean
    Private phoneNumber As String = "+905331234567"
End Sub

Private Sub AppStart
    Serial1.Initialize(115200)
    Log("AppStart")
    'GSM.Init(7, 8)
    GSM.Init(wemos.D5, wemos.D6)
    led.Initialize(wemos.D2, led.MODE_OUTPUT)
    btn.Initialize(wemos.D3, btn.MODE_INPUT_PULLUP)
    btn.AddListener("btn_StateChanged")
    Timer1.Initialize("Timer1_Tick", 20000) '1000ms = 1 second
   Timer1.Enabled = True
   durum=False
End Sub
Private Sub Timer1_Tick
    Log(">>>Timer1")
    If durum = False Then
        GSM.SendSMS(phoneNumber, "Click!!!")
        durum=True
    End If
End Sub
Sub btn_StateChanged (State As Boolean)
    If State = False Then
        GSM.SendSMS(phoneNumber, "Click!!!")
    End If
End Sub

Sub MessageArrived(msg() As Byte)
    If msg = "On" Then
        led.DigitalWrite(True)
    Else if msg = "Off" Then
        led.DigitalWrite(False)
    Else
        Log("error: ", msg)
    End If
End Sub
 

rbghongade

Active Member
Licensed User
Longtime User
You have not declared/initialized asyncstream object. Hence the event is not triggered.
 

Tayfur

Well-Known Member
Licensed User
Longtime User
You have not declared/initialized asyncstream object. Hence the event is not triggered.
thank you for feedback.

I used same code GSM example files in message #1 (erels eample)

I cant recie data from gsm. Where is problem??

B4X:
Region Project Attributes
    #AutoFlushLogs: True
    #CheckArrayBounds: True
    #StackBufferSize: 1000
#End Region
'****** MAIN   MODULE****************
Sub Process_Globals
    Public Serial1 As Serial
    Private led As Pin
    Private btn As Pin
    Private wemos As D1Pins
     Private Timer1 As Timer
     Private durum As Boolean
    Private phoneNumber As String = "+905331234567"
End Sub

Private Sub AppStart
    Serial1.Initialize(115200)
    Log("AppStart")
    'GSM.Init(7, 8)
    GSM.Init(wemos.D5, wemos.D6)
    led.Initialize(wemos.D2, led.MODE_OUTPUT)
    btn.Initialize(wemos.D3, btn.MODE_INPUT_PULLUP)
    btn.AddListener("btn_StateChanged")
    Timer1.Initialize("Timer1_Tick", 20000) '1000ms = 1 second
   Timer1.Enabled = True
   durum=False
End Sub
Private Sub Timer1_Tick
    Log(">>>Timer1")
    If durum = False Then
        GSM.SendSMS(phoneNumber, "Click!!!")
        durum=True
    End If
End Sub
Sub btn_StateChanged (State As Boolean)
    If State = False Then
        GSM.SendSMS(phoneNumber, "Click!!!")
    End If
End Sub

Sub MessageArrived(msg() As Byte)
    If msg = "On" Then
        led.DigitalWrite(True)
    Else if msg = "Off" Then
        led.DigitalWrite(False)
    Else
        Log("error: ", msg)
    End If
End Sub


B4X:
'********  GMS  MODULE ****************
Sub Process_Globals
    Private serial As SoftwareSerial
    Private bc As ByteConverter
    Private astream As AsyncStreams
    Private EOL() As Byte = Array As Byte(13)
    Private busy As Boolean
    Private messageToSend(160) As Byte
    Private SMSSlot(4) As Byte
    Private retryEmptyMessages As Byte
End Sub

Public Sub Init(rx As Byte, tx As Byte)
    serial.Initialize(9600, rx, tx)
    astream.Initialize(serial.Stream, "astream_NewData", Null)
    astream.WaitForMoreDataDelay = 100 'make sure that we receive full messages
    busy = False
    EnableSMSEvents
End Sub


Public Sub EnableSMSEvents As Boolean
    Return SendCommand("AT+CNMI=2,1", True)
End Sub

'PhoneNumber - should start with + and include country code.
Public Sub Call (PhoneNumber() As Byte) As Boolean
    If busy Then Return False
    busy = True
    astream.Write("ATD").Write(PhoneNumber).Write(";").Write(EOL)
    Return True
End Sub

'PhoneNumber - should start with + and include country code.
Public Sub SendSMS(PhoneNumber() As Byte, message() As Byte) As Boolean
    If busy Then Return False
    busy = True
    astream.Write("AT+CMGS=""").Write(PhoneNumber).Write("""").Write(EOL)
    'copy the message to the global variable
    bc.ArrayCopy(message, messageToSend)
    Return True
End Sub

Private Sub SendSMSPart2
    busy = True
    astream.Write(messageToSend).Write(Array As Byte(0x1a))
End Sub

Private Sub SendSMSPart3
    Log("Message was sent successfully")
End Sub

Public Sub Hangup As Boolean
    Return SendCommand("ATA", False)
End Sub

Private Sub SendCommand (cmd() As Byte, ResponseExpected As Boolean) As Boolean
    If busy Then Return False
    busy = ResponseExpected
    astream.Write(cmd).Write(EOL)
    Return True
End Sub

Public Sub CheckRegistered
    SendCommand("AT+CREG?", True)
End Sub

Private Sub CheckRegisteredResult (buffer() As Byte)
    If bc.IndexOf(buffer, "+CREG: 0,1") > -1 Or bc.IndexOf(buffer, "+CREG: 0,5") > -1 Then
        Log("Registered")
    Else
        Log("Not registered")
    End If
End Sub

Private Sub SMSArrived1(buffer() As Byte)
    Dim i As Int = bc.IndexOf(buffer, ",") 
    Dim slot() As Byte = bc.SubString(buffer, i + 1)
    bc.ArrayCopy(slot, SMSSlot)
    Log("SMS received, slot = ", SMSSlot)
    retryEmptyMessages = 0
    Delay(200)
    astream.Write("AT+CMGR=").Write(slot).Write(EOL)
    busy = True
End Sub

Private Sub SMSArrived2(Buffer() As Byte)
    busy = True
    Dim afterCMGR As Boolean = False
    Dim emptyMessage As Boolean = True
    'Log("buffer: ", Buffer)
    For Each line() As Byte In bc.Split(Buffer, Array As Byte(13, 10))
        If afterCMGR Then
            If line.Length = 0 Or bc.StartsWith(line, "OK") Then Continue
            Log("Msg: ", line)
            If emptyMessage Then
                Main.MessageArrived(line)
                emptyMessage = False
            End If
        Else If bc.StartsWith(line, "+CMGR") Then
            Dim counter As Int = 0
            For Each s() As Byte In bc.Split(line, """")
                If counter = 3 Then
                    Log("From: ", s)
                Else If counter = 7 Then
                    Log("Date: ", s)
                End If
                counter = counter + 1
            Next
            afterCMGR = True
        End If
    Next
    If emptyMessage And retryEmptyMessages < 3 Then
        retryEmptyMessages = retryEmptyMessages + 1
        Log("Trying to read message again.")
        Delay(200)
        astream.Write("AT+CMGR=").Write(SMSSlot).Write(EOL)
    Else
        'delete the SMS
        astream.Write("AT+CMGD=").Write(SMSSlot).Write(EOL)
    End If
End Sub

Private Sub Ring(Buffer() As Byte)
    Dim clip() As Byte = "+CLIP: """
    Dim callingNumber() As Byte = "unknown"
    Dim i1 As Int = bc.IndexOf(Buffer, clip)
    If i1 > -1 Then
        Dim i2 As Int = bc.IndexOf2(Buffer, """", i1 + clip.Length)
        If i2 > -1 Then
            callingNumber = bc.SubString2(Buffer, i1 + clip.Length, i2)
        End If
    End If
    Log("Ring... Number: ", callingNumber)
    'hangup up the call
    Hangup
End Sub

Sub AStream_NewData (Buffer() As Byte)
    busy = False
    Select True
        Case bc.IndexOf(Buffer, "+CREG:") > -1
            CheckRegisteredResult(Buffer)
        Case bc.IndexOf(Buffer, "RING") > -1
            Ring(Buffer)
        Case bc.IndexOf(Buffer, "AT+CMGS") > -1
            SendSMSPart2
        Case bc.IndexOf(Buffer, "+CMGS:") > -1
            SendSMSPart3
        Case bc.IndexOf(Buffer, "+CMTI:") > -1
            SMSArrived1(Buffer)
        Case bc.IndexOf(Buffer, "+CMGR:") > -1
            SMSArrived2(Buffer)
        Case Else
            Log("****************")
            Log(Buffer)
    End Select
End Sub
 

Tayfur

Well-Known Member
Licensed User
Longtime User
@Erel
İ fixed some problems.

GPRS001.jpg

http://www.geeetech.com/wiki/index.php/Arduino_GPRS_Shield

I used for RX + TX + GND pins on UARTof SIM900 .

Now I reading GPRS shileds.
Stage 1 complated.

(I cant understand otherher pins connections for your Sample)

I recived SMS. but it s PDU format. is it normal? can i recive text format?


Stage 2. SENDING SMS
Your code runs...
  1. sub sendsms (ok)
  2. sub AstreamNewData (>> returnde data..2 lines.)
      • AT+CMGS="+905321111111"
      • ERROR
  3. sub SendSmsPart2 (ok)
  4. sub AstreamNewData (>>> returned data...
  • click!!!
and waiting code....
Where is problem? I cant recive error or data?
 
Last edited:

Tayfur

Well-Known Member
Licensed User
Longtime User
tayfur selam...
benimde benzer projem var bende bizimpiyasadan gndteknik in ürettiği gsm modulü aldım arduino ile bir türlü başarılı olamadım halende kafam ona takık ama vakit katbetmemek için raspberry pi ile yaptım projeyi

text formatında sms göndermen için ;

AT+CMGF=1 komutunu başlangıcta gönder...

şimdi cıkmak zorundayım başka sorun olursa yaz...

kolay gelsin
EYVALLAH KARDEŞİM SAOL. DENEDİM ÇALIŞTI. SIKINTI GÖZÜKMÜYOR ŞİMDİİLİK.
MSJ GİDİYOR GELİYOR, ARTIK GERİSİ FANTEZİ KISMINI KALDI. BİRDE DEVLETİM SAĞOLSUN HEMEN IMEI NUMARASINI KAYDET DİYE MSJ ATTI :)

YAKINDA BİR BANANA Pİ SİPARİŞİ VERİCEM, ORDA TAKILIRRSAM KAPINI ÇALARIM
 

Tayfur

Well-Known Member
Licensed User
Longtime User

Tayfur

Well-Known Member
Licensed User
Longtime User
SS-2016-05-11_13.27.00.jpg


The GSM shield allows the Arduino to connect to cellular networks. This opens the door for many interesting outdoor solutions.

There are all kinds of shields available. Make sure that the shield you are using is configured to work with pins other than 0 and 1 (which are used for programming the Arduino). We will use SoftwareSerial with AsyncStreams to communicate with the GSM module.

The GSM shield is controlled with AT commands. There are many online resources about the supported commands. Here is a one: http://www.codeproject.com/Articles/85636/Introduction-to-AT-commands-and-its-uses

The GSM code module, included in the attached example, implements the most common commands.

- Sending and receiving SMS messages.
- Making phone calls (the speaker part is not implemented).
- Incoming phone calls.
- Checking the registration status.

Only one task can be done at a time. So there is a "busy" flag that is set and cleared to make sure that commands do not mix.

In this specific example the led is controlled with SMS messages. The button sends a "click!!!" message:
B4X:
Sub btn_StateChanged (State As Boolean)
   If State = False Then
     GSM.SendSMS(phoneNumber, "Click!!!")
   End If
End Sub

Sub MessageArrived(msg() As Byte)
   If msg = "On" Then
     led.DigitalWrite(True)
   Else if msg = "Off" Then
     led.DigitalWrite(False)
   Else
     Log("error: ", msg)
   End If
End Sub

B4R v1.00 BETA #10+ is required: https://www.b4x.com/android/forum/threads/b4r-beta-is-available-for-download.65651/

Useful information about these shields:
http://www.seeedstudio.com/wiki/GPRS_Shield_V1.0
http://www.seeedstudio.com/wiki/GPRS_Shield_V2.0

could you share full project? (I need other pins actions.)
 
Top