STM32 GPS/GPRS通讯功能实现 - (第二十九讲)
视频讲解如下:
工程源码下载:GPS定位系统系列教程源码下载
工程源码中,A9G.c 文件的源代码如下,具体的工程源码,可直接去上面的链接下载。
#include <string.h>
#include <stdlib.h>
#include "delay.h"
#include "stdio.h"
#include "usart3.h"
#include "A9G.h"
#include "GpsCoord.h"
char A9G_Receive[700]={0}; // AT当前命令的反馈数据
// 等待A9G启动
void A9G_Start(void)
{
u8 GpsBuff[700]=""; // 开辟一点空间,用来读取串口数据,经过测试,GPS单次数据包最大有547个字节,我这里直接开辟300字节的缓存空间
int siz = 0;
while(1) // 如果检测不通过,是不能退出循环的,只能重启设备
{
delay_ms(500); // 等待500ms,给串口中断留一些数据接收的时间
siz = 0;
memset(GpsBuff,0,sizeof(GpsBuff)); // 清空缓存数据
siz = usart3_Receive(GpsBuff, sizeof(GpsBuff)); // 接收串口数据
if(siz <= 0) continue;
// 解析串口数据,如果A9G模块启动完成,串口应该是能接收到带有“”字符的字符串的
// 相当于下位机模拟器中 ComReadData()函数里面的 “A9G复位信息检测”代码
if(strstr((char *)GpsBuff,"NO SIM CARD") != 0)
{
printf("未检测到SIM卡...\r\n");
}
if(strstr((char *)GpsBuff,"+CREG:") != 0)
{
printf("A9G启动成功...\r\n");
break;
}
}
}
// 通用AT命令发送接口
// Order:需要发送的命令
// succeed:该命令对应的正确反馈
// oTime:等待超时时间(秒)
// 成功返回0,失败返回-1
int SendAT(char *Order, char *succeed, int oTime)
{
int i = 0;
int siz = 0;
// 发送AT命令
printf("发送:%s\r\n", Order);
usart3_Send((u8 *)Order,strlen(Order));
// 等待接收,超时时间:oTime(秒)
for(i = 0;i < oTime * 5; i++)
{
delay_ms(200); // 等待200ms,给串口中断留一些数据接收的时间
memset(A9G_Receive,0,sizeof(A9G_Receive)); // 清空缓存数据
siz = usart3_Receive((u8 *)A9G_Receive, sizeof(A9G_Receive)); // 接收串口数据
if(siz <= 0) continue;
printf("接收:%s\r\n", A9G_Receive);
// 解析串口数据,如果接收到指定的字符串了,则认为命令发送成功了
if(strstr((char *)A9G_Receive,(char *)succeed) != 0)
{
// 接收关键字符串了,退出检测代码,继续执行下一步
return 0;
}
}
return -1;
}
// 初始化GPS
void A9G_Init_GPS(void)
{
int order = 0; // 下发命令跳转控制
while(1) // 如果配置不通过,是不能退出循环的,只能重启设备
{
delay_ms(500); // 每次命令,间隔500ms,也不知道A9G能支持多快的命令速度,我这里直接按500ms一个命令的速度进行下发,同时也给串口中断留一些数据接收的时间
// 通过switch的方式来控制每次需要下发哪种命令
switch(order)
{
case 0: // 设置为GPS模式(AT+GPSMD=1)/GPS+BD模式(AT+GPSMD=2),命令反馈3秒超时
if(SendAT("AT+GPSMD=2\r\n", "OK", 3) == 0) {
order++; // 命令下发成功,继续下一个命令
}
break;
case 1: // 设置GPS每三秒输出一次定位信息,命令反馈3秒超时,也不要太快,给程序留点处理数据的时间
if(SendAT("AT+GPSRD=3\r\n", "OK", 3) == 0) {
return;// GPS初始化完成
}
break;
default: break;
}
}
}
// 启动GPS
void A9G_Start_GPS(void)
{
while(1) // 如果启动不通过,是不能退出循环的,只能重启设备
{
printf("启动GPS...\r\n");
delay_ms(1000);
if(SendAT("AT+GPS=1\r\n", "OK", 3) == 0) {
break;
}
}
}
// 停止GPS
void A9G_Stop_GPS(void)
{
while(1) // 如果停止不通过,是不能退出循环的,只能重启设备
{
printf("停止GPS...\r\n");
delay_ms(1000);
if(SendAT("AT+GPS=0\r\n", "OK", 3) == 0) {
break;
}
}
}
// 初始化GPRS
// IP:服务器公网IP
// port:服务器公网端口
void A9G_Init_GPRS(char IP[30], char port[30])
{
char CIPSTART[255]= "AT+CIPSTART=\"TCP\",\"";
char str1[30]="\",";
char str2[30]="\r\n";
int order = 0; // 下发命令跳转控制
strcat(CIPSTART, IP);
strcat(CIPSTART, str1);
strcat(CIPSTART, port);
strcat(CIPSTART, str2);
printf("GPS Server:%s\r\n", CIPSTART);
while (1)
{
delay_ms(500); // 每次命令,间隔500ms,也不知道A9G能支持多快的命令速度,我这里直接按500ms一个命令的速度进行下发,同时也给串口中断留一些数据接收的时间
switch (order)
{
case 0: // 查询SIM ,序列号唯一,可以用来判断卡是否正常
if (SendAT("AT+CCID\r\n", "OK", 3) == 0)
{
order++; // 命令下发成功,继续下一个命令
}
break;
case 1: // 第一个参数1表示允许注册入网;第二个参数5表示已注册,处于漫游状态,如果是1的话,表示已注册本地网络,出现其他参数表示不正常
if (SendAT("AT+CREG?\r\n", "+CREG: 1,1", 3) == 0)
{
order++; // 命令下发成功,继续下一个命令
}
break;
case 2: // 查询信号强度 第一个参数为信号强度值,
if (SendAT("AT+CSQ\r\n", "OK", 5) == 0)
{
// 在这里可以将 A9G_Receive 中的信号强度数据解析出来,C语言写这个太麻烦了,我就不写了,解析思路可以参考模拟器中的算法。。。。
printf("%s\r\n",A9G_Receive);
order++; // 命令下发成功,继续下一个命令
}
break;
case 3: // 附着网络,如果需要上网,这条指令是必选的
if (SendAT("AT+CGATT=1\r\n", "OK", 3) == 0)
{
order++; // 命令下发成功,继续下一个命令
}
break;
case 4: // 设置PDP参数
if (SendAT("AT+CGDCONT=1,\"IP\",\"CMNET\"\r\n", "OK", 3) == 0)
{
order++; // 命令下发成功,继续下一个命令
}
break;
case 5: // 激活PDP,正确激活以后就可以上网了
if (SendAT("AT+CGACT=1,1\r\n", "OK", 3) == 0)
{
order++; // 命令下发成功,继续下一个命令
}
break;
case 6: // 连接TCP服务器
if (SendAT(CIPSTART, "CONNECT OK", 3) == 0)
{
order++; // 命令下发成功,继续下一个命令
}
break;
case 7:
// 查询透传默认参数
if (SendAT("AT+CIPHMODE=1\r\n", "OK", 3) == 0)
{
printf("GPRS初始化完成!\r\n");
return;// GPRS所有设置完成,退出
}
break;
default: break;
}
}
}
// 启动GPRS
void A9G_Start_GPRS(void)
{
while(1) // 这里的逻辑和模拟器还是有些差异的,模拟器是手动控制命令下发,所以不需要循环,但是下位机是自动的,如果命令不成功,只能不停的尝试,或者重启设备
{
printf("启动GPRS...\r\n");
delay_ms(1000);
if(SendAT("AT+CIPTMODE=1\r\n", "OK", 3) == 0) {
printf("启动GPRS...OK\r\n");
break;
}
}
}
// 停止GPRS
void A9G_Stop_GPRS(void)
{
// 停止命令有点奇葩,只有第一次的时候会返回OK,第二次的时候就没有OK了,所以这里不能用循环,只能祈祷停止命令一次性发送成功吧~~
printf("停止GPRS...\r\n");
if (SendAT("+++", "OK", 3) == 0)
{
printf("停止GPRS...OK\r\n");
}
else
{
printf("停止GPRS...Error\r\n");
}
}
A9G.h 文件的源代码如下:
#ifndef __A9G_H_
#define __A9G_H_
#include "sys.h"
void A9G_Start(void);
void A9G_Init_GPS(void);
void A9G_Start_GPS(void);
void A9G_Stop_GPS(void);
void A9G_Init_GPRS(char IP[30], char port[30]);
void A9G_Start_GPRS(void);
void A9G_Stop_GPRS(void);
#endif