打印
[STM32F1]

sim868模块

[复制链接]
71|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
kzlzqi|  楼主 | 2023-5-26 14:29 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
最近使用了SIM868模块做了项目,单片机使用的是STM32F103C8T6,使用串口2与SIM模块通信,实现了打电话、发短信、GPS定位、GPRS发送数据的功能,能够实时定位,1s发送一次定位数据到服务器。
SIM模块代码如下:
#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';                //添加结束符
       
}




使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

68

主题

479

帖子

2

粉丝