#include "sim.h"
#include "delay.h"
#include "string.h"
#include "oled.h"
#include "key.h"
#include "usart.h"
#include "usart2.h"
//SIM868 模块的响应格式为: <回车><换行><响应内容><回车><换行>。 !!!!!!!
//发送的短信内容:SOS!我们在经纬度为39.915403,116.403906的地方遇险,请求帮助!
unsigned char Send_Message[] = "0053004F0053002162114EEC57287ECF7EAC5EA64E3A00330039002E003900310035003400300033002C003100310036002E0034003000330039003000367684573065B990479669FF0C8BF76C425E2E52A9FF01";
unsigned char LBS_Location[30] = {0}; //保存基站定位最近一次读取到的位置信息
unsigned char SNSS_Location[30] = {0}; //保存SNSS定位最近一次读取到的位置信息
unsigned char IPaddr_port[] = "AT+CIPSTART=\"TCP\",\"103.46.128.49\",\"21455\""; //GPRS 连接的外网IP和端口号
unsigned char GPRS_SEND[] = "ID001,39.915403,116.403906"; //GPRS 发送的信息。其中IDxxx为设备的编号,加上纬度,经度
//发送命令后,检测接收到的应答
//p:期待的应答结果
//返回值:0,没有得到期待的应答结果
//返回值:1,得到期待的应答结果
#define SIM_Check_OK 1
#define SIM_Check_ERROR 0
unsigned char SIM_Check(unsigned char *p)
{
if(USART2_RX_STA&0X8000) //判断串口是否接收到一次数据了
{
USART2_RX_BUF[USART2_RX_STA&0X7FFF]=0; //在接收到的字符最后添加结束符
if(strstr((const char*)USART2_RX_BUF,(const char*)p) == NULL) //判断 p 是否为 USART2_RX_BUF 的子串
{
//return 0;
return SIM_Check_ERROR;
}
}
//return 1;
return SIM_Check_OK;
}
//向SIM800C发送命令
//cmd:发送的命令字符串(不需要添加回车了)
//ack:期待的应答结果,如果为空,则表示不需要等待应答
//waittime:等待时间(单位:10ms)
//返回值:0,发送成功(得到了期待的应答结果)
// 1,发送失败
#define SIM_Send_Cmd_OK 0
#define SIM_Send_Cmd_ERROR 1
unsigned char SIM_Send_Cmd(u8 *cmd,u8 *ack,u16 waittime)
{
unsigned char res = SIM_Send_Cmd_OK;
USART2_RX_STA=0; //清空接收到的字符串数组
if((u32)cmd<=0XFF) //发送数字(如发短信的结束符0x1A)
{
while((USART2->SR&0X40)==0); //等待上一次串口数据发送完成
USART2->DR=(u32)cmd;
}
else //发送命令
{
u2_printf("%s\r\n",cmd);//发送命令
}
if(ack&&waittime) //需要等待应答
{
while(--waittime) //等待倒计时
{
delay_ms(10);
if(USART2_RX_STA&0X8000)//接收到期待的应答结果
{
if(SIM_Check(ack)) //判断SIM模块应答是否正常
{
break;
}
USART2_RX_STA=0;
}
}
if(waittime==0)res=SIM_Send_Cmd_ERROR; //超时
}
return res;
}
void SIM_Init() //SIM卡初始化
{
unsigned char flag=1;
while(SIM_Send_Cmd("AT","OK",100)) //检测是否应答AT指令
{
OLED_P8x16Str(0,1, "Sim Fail!");
delay_ms(400);
OLED_P8x16Str(0,1, " ");
delay_ms(300);
}
OLED_P8x16Str(0,1, " ");
OLED_P8x16Str(0,1, "AT is OK!");
SIM_Send_Cmd("ATE0","OK",100);//不回显
delay_ms(200);
while(SIM_Send_Cmd("AT+CPIN?","READY",100)) //检测是否存在SIM卡
{
OLED_P8x16Str(0,1, "No Sim Card!");
delay_ms(400);
OLED_P8x16Str(0,1, " ");
delay_ms(300);
}
OLED_P8x16Str(0,1, "GPS Open...");
while(SIM_Send_Cmd("AT+CGNSPWR=1","OK",100)) //打开gps定位
{
OLED_P8x16Str(0,1, "GPS Open fail!");
delay_ms(400);
OLED_P8x16Str(0,1, " ");
delay_ms(300);
}
OLED_P8x16Str(0,1, "GPRS Init...");
while(flag) //设置GPRS通信
{
flag = 0;
SIM_Send_Cmd("AT+CIPCLOSE=1","ERROR",100); //关闭当前 TCP 连接
SIM_Send_Cmd("AT+CIPSHUT","OK",100); //关闭场景
if(SIM_Send_Cmd("AT+CGCLASS=\"B\"","OK",1000))flag=1; //设置GPRS移动台类别为B,支持包交换和数据交换
if(SIM_Send_Cmd("AT+CGDCONT=1,\"IP\",\"CMNET\"","OK",1000))flag=2; //设置PDP上下文,互联网接协议,接入点等信息
if(SIM_Send_Cmd("AT+CGATT=1","OK",500))flag=3; //附着GPRS业务
if(SIM_Send_Cmd("AT+CIPCSGP=1,\"CMNET\"","OK",500))flag=4; //设置为GPRS连接模式
if(SIM_Send_Cmd("AT+CIPHEAD=1","OK",500))flag=5; //设置接收数据显示IP头(方便判断数据来源)
if(flag)
{
OLED_P8x16Str(0,1, "GPRS ERROR! ");
delay_ms(800);
OLED_P8x16Str(0,1, " ");
delay_ms(300);
}
}
while(SIM_Send_Cmd(IPaddr_port,"OK",500)) //发起GPRS连接
{
OLED_P8x16Str(0,1,"CONNECT FAIL! ");
delay_ms(400);
OLED_P8x16Str(0,1, " ");
delay_ms(300);
}
OLED_P8x16Str(0,1, " ");
OLED_P8x16Str(0,1, "SIM is OK!");
}
//函数功能:
//1.不断读取定位信息,并且将有效的数据存储到GPRS_SEND数组中
//2.将读取到的有效定位数据掉点保存(未实现)
void SIM_ReadData() //不断读取当前的定位信息
{
//获取定位信息
if(SIM_Send_Cmd("AT+CGNSINF","+CGNSINF: 1,1",100) == SIM_Send_Cmd_OK) //定位数据有效则进行记录
{
OLED_P6x8Str(0,5, "SNSS IS OK ");
SNSS_Save_Location(); //记录定位信息
OLED_print(SNSS_Location); //OLED显示定位信息
Change_MessageLocation(SNSS_Location); //修改发送的短信中的定位信息定位信息
}
else
{
OLED_P6x8Str(0,5, "GPS Location...");
}
}
//函数功能:
//将数据发送到固定的端口中
void SIM_GprsSend()
{
if(SIM_Send_Cmd("AT+CIPSEND",">",500)==0) //发送数据
{
//printf("CIPSEND DATA:%s\r\n",p1); //发送数据打印到串口
u2_printf("%s\r\n",GPRS_SEND);
delay_ms(50);
if(SIM_Send_Cmd((u8*)0X1A,"SEND OK",1000)==0)
{
OLED_P6x8Str(0,3,"Data send is ok"); //最长等待10s
}
else
{
OLED_P6x8Str(0,3,"Data send is error");
}
delay_ms(500);
OLED_P8x16Str(0,3," ");
}
else
{
SIM_Send_Cmd((u8*)0X1B,0,0); //ESC,取消发送
}
}
void SIM_SendMessage() //发短信 OK
{
OLED_P8x16Str(0,5, " ");
OLED_P8x16Str(0,5, "Send a Message..");
SIM_Send_Cmd("AT","OK",100);
SIM_Send_Cmd("AT+CMGF=1","OK",100); //设置短信模式为文本模式
SIM_Send_Cmd("AT+CSMP=17,167,1,8","OK",100); //设置短信为中英文模式
SIM_Send_Cmd("AT+CSCS=\"UCS2\"","OK",100); //设置为UCS2字符集编码
SIM_Send_Cmd("AT+CMGS=\"0031 0033 003x003x003x003x003x003x003x003x003x\"",">",500); //设置对方手机号,需要修改
SIM_Send_Cmd(Send_Message,">",1000); //发送短信内容
SIM_Send_Cmd((u8*)0X1A,"+CMGS:",1000);//发送结束符,等待发送完成(最长等待10秒钟,因为短信长了的话,等待时间会长一些)
OLED_P8x16Str(0,5, "Finish Send! ");
delay_ms(500);
OLED_P8x16Str(0,5, " ");
}
void SIM_Call() //打电话 OK
{
unsigned char Key;
unsigned char callbuf[] = "13xxxxxxxxx;"; //预存电话,需要修改
OLED_P8x16Str(0,5, " ");
OLED_P8x16Str(0,5, "Call a phone...");
u2_printf("ATD%s\r\n",callbuf); //拨号
while(1)
{
Key = KEY_Scan(0);
if(Key == KEY2_PRES)
{
u2_printf("ATH\r\n"); //挂电话
OLED_P8x16Str(0,5, "over the phone!");
delay_ms(500);
OLED_P8x16Str(0,5, " ");
break;
}
}
}
//根据模块的基站定位和SNSS定位修改发送的信息和GPRS发送的消息的经纬度
//参数: *p
//LBS_Location表示使用的是基站定位
//SNSS_Location表示的是使用SNSS定位
void Change_MessageLocation(unsigned char p[])
{
unsigned char i;
for(i=12; i<32; i++) //修改报警信息中的经纬度
{
if((i==15)||(i==22)||(i==25)) //小数点不修改
{
continue;
}
Send_Message[i*4-1] = p[i-12];
}
for(i=0; i<20; i++) //修改GPRS发送的经纬度
{
GPRS_SEND[i+6] = p[i];
}
}
void LBS_Save_Location() //保存基站定位最近一次的位置信息, 基站定位是输出 精度,纬度
{
unsigned char i,flag = 0;
if((USART2_RX_BUF[2] == '+')&&(USART2_RX_BUF[9] == '0')) //判断SIM模块是否读取到了地址
{
for(i=11; flag != 2; i++) //SIM模块LBS定位返回来的信息,第11位开始为经纬度信息。注意sim868返回消息的格式
{
if(USART2_RX_BUF[i] == ',')
{
flag++;
}
LBS_Location[i-11] = USART2_RX_BUF[i]; //记录经纬度
}
LBS_Location[i-12] = '\0'; //添加结束符
}
}
void OLED_print(unsigned char p[]) //基站定位和SNSS定位显示经纬度到OLED
{
unsigned char i,Flag = 0;
for(i=0;p[i] != '\0';i++)
{
if(p[i] == ',') //分开经度和纬度
{
p[i] = 0;
Flag = i;
break;
}
}
if(Flag != 0)
{
OLED_P6x8Str(0,6,p);
OLED_P6x8Str(0,7,p+i+1);
p[i] = ',';
}
}
void SNSS_Save_Location() //保存SNSS定位最近一次的位置信息,SNSS定位输出是 纬度,经度
{
unsigned char i,flag = 0;
for(i=35; flag != 2; i++) //SIM模块SNSS定位返回来的信息,第35位开始为经纬度信息。注意sim868返回消息的格式
{
if(USART2_RX_BUF[i] == ',')
{
flag++;
}
SNSS_Location[i-35] = USART2_RX_BUF[i]; //记录经纬度
}
SNSS_Location[i-36] = '\0'; //添加结束符
}