概 述

GPS/GPRS/GSM是基于SIMCOM公司SIM548C设计的一款结合GSM/GPRS&GPS功能为一体的通信模块。

可通过GPS功能定位,通过GSM短信、GSM打电话、GPRS的TCP/IP协议将GPS数据或者其他数据信息发送到远端。

兼容Arduino接口规格。

注意:下面程序适用于GPS/GPRS/GSM第二版本。

性能描述

GSM/GPRS指标

-Class 4(2W @ GSM850/900MHz)

-Class 1(1W @ GSM1800/1900MHz)

GPS指标

-无SA/Velocity 0.1 m/s

-无SA/Time 1 μs GPS同步时间

-热启时间:< 1 秒,平均,室外

-温启时间:35 秒,平均,室外

-冷启时间:35 秒,平均,室外

-NMEA-0183(默认)

-SiRF binary

-RTCM SC-104

模块特性

可通过AT命令更改波特率

GSM自动波特率:4800,9600,19200,38400,57600,115200bps

引脚定义

图片

按键切换功能说明

控制端口PD345可更改,换成别的IO

GPS功能

GPS部分与PC机通讯

GPS数据通过串口输出到PC机

主控板选用Arduino 328作为例子说明。

将模块插在328板上,USB线一端接到328,另一端接到PC。(同时利用USB线给328板供电,不外接电源)

硬件连接图片

S1开关拨到EN,即使能下载程序模式,下载下面程序:

 void setup()
 {
    //设置引脚为输出模式
     pinMode(3,OUTPUT);
    pinMode(4,OUTPUT);
 }
 void loop()
 {
    digitalWrite(3,HIGH);//关闭GSM的TX、RX
    digitalWrite(4,LOW);//使能GPS的TX、RX
 }

S1开关拨到Dis,不使能下载程序模式,即使能模块通讯模式

S2开关拨到USB,即选择串口与USB接口通讯

选择波特率:4800bps;数据位:8;停止位:1;校验位:None

选择COM口,打开串口

S3开关拨到ON,给GPS供电,稍后在串口调试软件即可看到GPS数据

串口助手输出数据图片

注意:必须使模块GPS天线露在室外(在室内置于窗台处即可),GPS才能接收到信号,输出GPS定位数据。

GPS部分与Arduino通讯

同上面的硬件连接

S1开关拨到EN,即使能下载程序模式,下载下面程序:

  double Datatransfer(char *data_buf,char num)//数据转换:将字符型数据转换为浮点型数据
  {                                           //*data_buf:要转换的数组;num:小数点的个数
     double temp=0.0;
    unsigned char i,j;

    if(data_buf[0]=='-')//负数的情况
    {
      i=1;
      //数组中的字符型数据转换成整数并累�
       while(data_buf[i]!='.')
        temp=temp*10+(data_buf[i++]-0x30);
      for(j=0;j<num;j++)
        temp=temp*10+(data_buf[++i]-0x30);
      //将转换后的整数转换成浮点数
       for(j=0;j<num;j++)
        temp=temp/10;
      //转换成负数
       temp=0-temp;
    }
    else//正数情况
    {
      i=0;
      while(data_buf[i]!='.')
        temp=temp*10+(data_buf[i++]-0x30);
      for(j=0;j<num;j++)
        temp=temp*10+(data_buf[++i]-0x30);
      for(j=0;j<num;j++)
        temp=temp/10 ;
    }
    return temp;
  }
  char ID()//接收语句的ID
  {
    char i=0;
    char value[6]={
      '$','G','P','G','G','A'  };//要接收的GPS语句的ID内容
    char val[6]={
      '0','0','0','0','0','0'  };

    while(1)
    {
      if(Serial.available())
      {
        val[i] = Serial.read();//接收串口的数据
         if(val[i]==value[i])//对比是否是正确的ID
        {
           i++;
           if(i==6)
           {
             i=0;
             return 1;//接收完毕返回1
           }
        }
        else
          i=0;
      }
    }
  }
  void comma(char num)//接收逗号字符
  {
    char val;
    char count=0;//对接收到的逗号计数

    while(1)
    {
      if(Serial.available())
      {
        val = Serial.read();
        if(val==',')
          count++;
      }
      if(count==num)//数目正确结束接收
        return;
    }
  }
  void UTC()//获取时间信息
  {
    char i;
    char time[9]={
      '0','0','0','0','0','0','0','0','0'
    };
    double t=0.0;

    if( ID())//语句正确
    {
      comma(1);//接收1个逗号
       //读取语句第一个逗号后的数据
       while(1)
      {
        if(Serial.available())
        {
          time[i] = Serial.read();
          i++;
        }
        if(i==9)
        {
          i=0;
          t=Datatransfer(time,2);//转换成浮点型数据
           t=t+80000.00;//将时间转换成北京时间
           Serial.println(t);//输出时间数据
           return;
        }
      }
    }
  }
  void latitude()//获取纬度信息
  {
    char i;
    char lat[10]={
      '0','0','0','0','0','0','0','0','0','0'
    };

    if( ID())
    {
      comma(2);
      //读取语句第二个逗号后的数据
       while(1)
      {
        if(Serial.available())
        {
          lat[i] = Serial.read();
          i++;
        }
        if(i==10)
        {
          i=0;
          Serial.println(Datatransfer(lat,5),5);//输出纬度数据
           return;
        }
      }
    }
  }
  void lat_dir()//获取纬度方向信息
  {
    char i=0,val;

    if( ID())
    {
      comma(3);
      //读取语句第三个逗号后的数据
       while(1)
      {
        if(Serial.available())
        {
          val = Serial.read();
          Serial.println(val,BYTE);//输出方向信息
           i++;
        }
        if(i==1)
        {
          i=0;
          return;
        }
      }
    }
  }
  void longitude()//获取经度信息
  {
    char i;
    char lon[11]={
      '0','0','0','0','0','0','0','0','0','0','0'
    };

    if( ID())
    {
      comma(4);
      //读取语句第四个逗号后的数据
       while(1)
      {
        if(Serial.available())
        {
          lon[i] = Serial.read();
          i++;
        }
        if(i==11)
        {
          i=0;
          Serial.println(Datatransfer(lon,5),5);//输出经度数据
           return;
        }
      }
    }
  }
  void lon_dir()//获取经度方向信息
  {
    char i=0,val;

    if( ID())
    {
      comma(5);
      //读取语句第五个逗号后的数据
       while(1)
      {
        if(Serial.available())
        {
          val = Serial.read();
          Serial.println(val,BYTE);//输出经度方向
           i++;
        }
        if(i==1)
        {
          i=0;
          return;
        }
      }
    }
  }
  void altitude()//获取海拔信息
  {
    char i,flag=0;
    char alt[8]={
      '0','0','0','0','0','0','0','0'
    };

    if( ID())
    {
      comma(9);
      //读取语句第九个逗号后的数据
       while(1)
      {
        if(Serial.available())
        {
          alt[i] = Serial.read();
          if(alt[i]==',')
            flag=1;
          else
            i++;
        }
        if(flag)
        {
          i=0;
          Serial.println(Datatransfer(alt,1),1);//输出海拔数据
           return;
        }
      }
    }
  }
  void setup()
  {
    //设置引脚为输出模式
     pinMode(3,OUTPUT);
    pinMode(4,OUTPUT);

    digitalWrite(3,HIGH);//关闭GSM的TX、RX
    digitalWrite(4,LOW);//使能GPS的TX、RX

    Serial.begin(4800);//设置波特率
    Serial.println("$GPGGA statement information: ");
  }
  void loop()
  {
    while(1)
    {
      Serial.print("UTC:");
      UTC();
      Serial.print("Lat:");
      latitude();
      Serial.print("Dir:");
      lat_dir();
      Serial.print("Lon:");
      longitude();
      Serial.print("Dir:");
      lon_dir();
      Serial.print("Alt:");
      altitude();
      Serial.println(' ');
      Serial.println(' ');
    }
  }

GPS示例代码

/*
 *  created:    2013-08-02
 *  Version:    V0.1
 *  test on Leonardo &XBEE R3
 */

//debug
#define DEBUG

#include <Arduino.h>

#define gps_enable()    digitalWrite (4, LOW)
#define gps_disable()   digitalWrite (4, HIGH)

#define gsm_enable()    digitalWrite (3, LOW)
#define gsm_disable()   digitalWrite (3, HIGH)

#define GPS_BUF_SIZE 255
#define GPGGA_NUM 15

char *gpgga_table[GPGGA_NUM] = {
    "Message ID",           //0
    "UTC Time",             //1
    "Latitude",             //2
    "N/S Indicator",        //3
    "Longitude",            //4
    "E/W Indicator",        //5
    "Position Fix Indicator",   //6
    "Satellites Used",      //7
    "HDOP",             //8
    "MSL Altitude",         //9
    "Units(M)",             //10
    "Geoid Separation",         //11
    "Units",            //12
    "Diff.Ref.Station ID",      //13
    "Checksum"};            //14


//save data from GPS
char gps_buf[GPS_BUF_SIZE];

//save pointer of gpgga block
char* gpgga_p[GPGGA_NUM];


// read data to gps_buf[] from GPS
int gps_read () {
    uint32_t start_time = millis ();
    while (!Serial1.available ()) {
        if (millis() - start_time > 1500) {
            #ifdef DEBUG
            Serial.println ("Time out! restart GPS......");
            #endif
            start_gps ();
        }
    }
    for (int i=0; i<GPS_BUF_SIZE; i++) {
        delay (7);
        if (Serial1.available ()) {
            gps_buf [i] = Serial1.read ();
        } else {
            #ifdef DEBUG
            Serial.print ("read ");
            Serial.print (i);
            Serial.println (" character");
            #endif
            return i;
        }
    }
    #ifdef DEBUG
    Serial.println ("error! data is so big!");
    #endif
    return 0;
}

//test head of gps_buf[] if is "$GPGGA" or not
int is_GPGGA () {
    char gpgga_id[7] = "$GPGGA";
    for (int i=0; i<6; i++)
        if (gpgga_id[i] != gps_buf[i])
            return 0;
    return 1;
}

// build gpgga_p[] by gps_buf
void build_gpgga_p () {
    int p,b;
    for (p=b=0; p<GPGGA_NUM && b<GPS_BUF_SIZE; p++,b++) {
        gpgga_p[p] = (gps_buf+b);
        if (gps_buf[b] == ',')
            continue;
        for (b++; b<GPS_BUF_SIZE && gps_buf[b]!=','; b++);
    }

}

//test if fix
int is_fix (void) {
    if (gpgga_p[6][0] == '1')
        return 1;
    else
        return 0;
}

//get UTC second
uint8_t get_utc_ss () {
    return (gpgga_p[1][4]-'0')*10 + gpgga_p[1][5]-'0';
}

//get UTC minute
uint8_t get_utc_mm () {
    return (gpgga_p[1][2]-'0')*10 + gpgga_p[1][3]-'0';
}

//get UTC hour
uint8_t get_utc_hh () {
    return (gpgga_p[1][0]-'0')*10 + gpgga_p[1][1]-'0';
}

/*
//print gpgga data to Serial
void print_gpgga_info () {
    int t=0;    //gpgga_talbe[t]
    int b=0;    //gps_buf[b]
    Serial.print (gpgga_table[t++]);
    Serial.print (": ");
    for (b=0; b<GPS_BUF_SIZE && gps_buf[b] != ','; b++) {
        Serial.print (gps_buf[b]);
    }
    Serial.println ();
    for (b++; b<GPS_BUF_SIZE && gps_buf[b]!=0xd && t<GPGGA_NUM; b++, t++) {
        Serial.print (gpgga_table[t]);
        Serial.print (": ");
        for (; gps_buf[b] != ','; b++) {
            if (gps_buf[b] == 0xd) {
                Serial.println ();
                return;
            }
            Serial.print (gps_buf[b]);
        }
        if (t==6 && gps_buf[b-1] == '0') {
            Serial.print (" \n<can't fix!>\n\n");
            return;
        }
        Serial.println ();
    }
}
*/

//
void print_gps_buf_gpgga () {
    for (int i=0; i<GPS_BUF_SIZE && gps_buf[i]!=0xd; i++)
        Serial.print (gps_buf[i]);
    Serial.println ();
}

//
void start_gps () {
    digitalWrite (5, HIGH);
    delay (1500);
    digitalWrite (5, LOW);
    delay (1500);

    gsm_enable ();
    gps_disable ();

    delay (2000);
    #ifdef DEBUG
    Serial.println ("waiting for GPS! ");
    #endif

    Serial1.println ("AT");
    #ifdef DEBUG
    Serial.println ("Send AT");
    #endif
    delay (1000);
    Serial1.println ("AT+CGPSPWR=1");
    #ifdef DEBUG
    Serial.println ("Send AT+CGPSPWR=1");
    #endif
    delay (1000);
    Serial1.println ("AT+CGPSRST=1");
    #ifdef DEBUG
    Serial.println ("Send AT+CGPSRST=1");
    #endif
    delay (1000);

    gsm_disable ();
    gps_enable ();

    delay (2000);
    #ifdef DEBUG
    Serial.println ("$GPGGA statement information: ");
    #endif
}

//
void gps_init () {
    pinMode (3, OUTPUT);
    pinMode (4, OUTPUT);
    pinMode (5, OUTPUT);

}

//
void setup () {
    gps_init ();

    Serial.begin (9600);    //serial0 connect computer
    while (!Serial);

    Serial1.begin (9600);   //serial1 connect GPS
    while (!Serial1);
    #ifdef DEBUG
    Serial.println ("start GPS! ");
    #endif

    start_gps ();
}

//
void loop () {
    if (gps_read ()) {  // read data to gps_buf[] from GPS
        if (is_GPGGA ()) {  //test head of gps_buf[] if is "$GPGGA" or not
            //print_gpgga_info ();
            Serial.println ("gpgga raw data:");
            print_gps_buf_gpgga ();
            build_gpgga_p ();   // build *gpgga_p[] by gps_buf
            Serial.print ("UTC hour:\t");
            Serial.println (get_utc_hh (), DEC);
            Serial.print ("UTC minute:\t");
            Serial.println (get_utc_mm (), DEC);
            Serial.print ("UTC second:\t");
            Serial.println (get_utc_ss (), DEC);
            #ifdef DEBUG
            if (is_fix ())
                Serial.println ("ok! is fix!");
            else
                Serial.println ("can't fix! please go outside!");
            for (int i=0; i<GPGGA_NUM; i++) {
                Serial.print (i);
                Serial.print (": ");
                Serial.print (gpgga_table[i]);
                Serial.print (":\t");
                for (int j=0; gpgga_p[i][j]!=',' && gpgga_p[i][j]!=0xd; j++)
                    Serial.print (gpgga_p[i][j]);
                Serial.println ();
            }
            #endif
        } else {
            #ifdef DEBUG
            Serial.println ("data is error!");
            Serial.println ("error message :");
            Serial.println (gps_buf);
            Serial.println ("...message end...");
            #endif
        }
    }
    Serial.println ();
}

程序说明:Arduino328读取模块GPS定位信息中的GPGGA字段信息,为了验证读取的信息,328将读取到的信息输出到PC机。

其他字段信息的读取方法类似。

S3开关拨到ON,给GPS供电。

S1开关拨到Dis,不使能下载程序模式,即使能模块通讯模式

S2开关拨到USB,即选择串口与USB接口通讯

选择波特率:4800bps;数据位:8;停止位:1;校验位:None

选择COM口,打开串口

稍后在串口调试软件即可看到GPS信息中的GPGGA字段信息。

NMEA-0183语句字段

GPS部分默认的协议:NMEA-0183

上面输出的GPS定位信息,都是NMEA-0183语句字段,每个字段详细解释请参考:常用NMEA-0183语句字段定义解释

GSM功能

GSM与PC机通讯

将SIM卡插到模块的卡槽�

图片

将模块插在328板上,USB线一端接到328,另一端接到PC。

5节电池组给328板供电

硬件连接图片

注意:必须外接电源,模块GSM部分工作实际瞬态电流可达2A,USB供电无法满足。

S1开关拨到EN,即使能下载程序模式,下载下面程序:

 void setup()
 {
    //设置引脚为输出模式
    pinMode(3,OUTPUT);
   pinMode(5,OUTPUT);
   pinMode(4,OUTPUT);
   //GSM开机时序
   digitalWrite(5,HIGH);
   delay(1500);
   digitalWrite(5,LOW);
 }
 void loop()
 {
    digitalWrite(3,LOW);//使能GSM的TX、RX
    digitalWrite(4,HIGH);//关闭GPS的TX、RX
 }

程序功能:让GSM模块开机,使能GSM模块通讯

此时模块上面的STAT灯保持亮,说明GSM模块开机

开机后起初NET灯以64ms on/800ms off闪烁,即没有找到网络;

稍后NET灯以64ms on/3000ms off闪烁,即找到网络。

S1开关拨到Dis,不使能下载程序模式,即使能模块通讯模式

S2开关拨到USB,即选择串口与USB接口通讯

S3开关拨到off,即关闭GPS

选择波特率:115200bps;数据位:8;停止位:1;校验位:None

选择COM口,打开串口

将串口调试软件面板上,发送新行框内打√

在串口调试软件字符串输入框输入:AT

点击发送,即发送AT到模块GSM

GSM会返回OK,显示在软件接收区,即GSM模块与PC机通讯成功

输入AT命令:

AT+CMGF=1(设置短消息的格式为文本格式)点击发送

AT+CMGS="XXXXX"(xxxx为目的地的电话号码)点击发送

出现“>”,在后面输入短信内容,输入完成后按‘ctrl+z’即短信发送

图片

插上耳机和麦克

输入AT命令:

ATDXXXXXXX; 拨号

接通电话后,即可通话

ATH 挂机命令

ATA 接电话

通话音量大小调节:AT+CLVL=n(n范围1~100,值越大声音越大)

调节麦克风音量大小:AT+CMIC=n(n范围1~15,值越大分贝越大)

例如:默认波特率为115200bps,此时改为9600bps

AT+IPR=9600&W

修改波特率为9600bps并保存修改的值

GSM部分还有很多不同功能的AT命令具体可参考:SIM548C_ATC_V1.00(1).pdf

GSM与Arduino通讯

同上面硬件连接

S1开关拨到EN,即使能下载程序模式,下载下面程序:

  void setup()
  {
      //端口模式设置
      pinMode(3,OUTPUT);
      pinMode(4,OUTPUT);
      pinMode(5,OUTPUT);
     //GSM开机时序
     digitalWrite(5,HIGH);
     delay(1500);
     digitalWrite(5,LOW);

     //使能GSM串口
     digitalWrite(3,LOW);
     digitalWrite(4,HIGH);
     delay(2000);
     //设置波特率
     Serial.begin(9600);
     //等待call ready
     delay(5000);
     delay(5000);
     delay(5000);
  }
  void loop()
  {
     //发送AT命令同步
     Serial.println("AT");
     delay(2000);
     Serial.println("AT");
     delay(2000);

     //发送短信
     Serial.println("AT+CMGF=1");
     delay(1000);
     Serial.println("AT+CMGS=\"xxxxxxxxxxx\"");//xxx为电话号码
     delay(1000);
     Serial.print("TEST");
     delay(1000);
     Serial.print(26,BYTE);

     //打电话
     //Serial.println("ATDxxxxxxxxxxx;");

     while(1);
  }

程序说明:Arduino328发送命令给模块,让模块发短信、打电话。

其他功能类似。

AT命令表

上述程序中,大家可以看到用到发短信、打电话AT命令等。

除了上述用到的AT命令,还有好多各种功能的AT命令,具体可参考SIM548C_ATC_V1.00(1).pdf

购买地址

<File:nextredirectltr.png>购买 GPS/GPRS/GSM三合一模块V1.0 (SKU: TEL0050)