概 述
GPS/GPRS/GSM是基于SIMCOM公司SIM548C设计的一款结合GSM/GPRS&GPS功能为一体的通信模块。
可通过GPS功能定位,通过GSM短信、GSM打电话、GPRS的TCP/IP协议将GPS数据或者其他数据信息发送到远端。
兼容Arduino接口规格。
注意:下面程序适用于GPS/GPRS/GSM第二版本。
性能描述
GSM/GPRS指标
- 四频GSM 850/900/1800/1900MHz
- GPRS multi-slot Class 10标准
- GPRS mobile station Class B标准
- 满足 GSM 2/2+标准
-Class 4(2W @ GSM850/900MHz)
-Class 1(1W @ GSM1800/1900MHz)
- AT命令控制 (GSM 07.07 ,07.05和SIMCom增强型AT命令集)
- 支持STK
- 支持低功耗模式
- 支持电压范围:3.4…4.5 V
- 正常工作温度:–30°C至+80°C
- 受限运作温度:–40°C至–30°C和+80°C至+85°C
- 存储温度:–45°C至+90°C
GPS指标
- 接收20个通道,L1 1575.42 MHz,C/A 代码 1,023 MHz 芯片率
- 准确定位2.5米CEP
-无SA/Velocity 0.1 m/s
-无SA/Time 1 μs GPS同步时间
- DGPS/SBAS位置:2.0 CEP
- Date WGS-84
- 捕获时间率 (95% TTFF首个当地位置)
-热启时间:< 1 秒,平均,室外
-温启时间:35 秒,平均,室外
-冷启时间:35 秒,平均,室外
- 支持AGPS
- 工作电压:3.3 V DC ±5%
- 低功耗:3.3 V时,160mW
- 协议
-NMEA-0183(默认)
-SiRF binary
-RTCM SC-104
- 晶体振荡器(TCXO),频率稳定的温度±0.5ppm
- Memory: 4 Mb flash and 1Mb SRAM
模块特性
- 通过串口执行AT命令
- GSM串口波特率:300,1200,2400,4800,9600,19200,38400,57600,115200bps(默认115200bps)
可通过AT命令更改波特率
GSM自动波特率:4800,9600,19200,38400,57600,115200bps
- 通过串口输出GPS定位信息
- GPS串口波特率:1200,2400,4800,9600,19200,38400,57600,115200bps(默认4800bps)
- 支持6针翻盖式SIM卡座
- 支持耳机、麦克接口
- 支持4*4矩阵键盘接口
- 模块工作电压:5V
- 模块尺寸:长度82mm,宽度70mm
- 模块重量:
引脚定义
图片
按键切换功能说明
控制端口PD345可更改,换成别的IO
GPS功能
GPS部分与PC机通讯
GPS数据通过串口输出到PC机
- 硬件连接
主控板选用Arduino 328作为例子说明。
将模块插在328板上,USB线一端接到328,另一端接到PC。(同时利用USB线给328板供电,不外接电源)
硬件连接图片
- 下载GPS串口使能程序
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口,打开串口
- 打开GPS电源,输出GPS定位信息
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机。
其他字段信息的读取方法类似。
- 打开GPS电源,GPS开始定位
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供电无法满足。
- 下载GSM串口使能及GSM开机程序
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