📄 复件 m32.c
字号:
#include <w77e58.h>
#include "global.h"
#include "io.h"
#include "timer.h"
#include "serial.h"
#include "m32.h"
//用户信息编码方式
#define GSM_7BIT 0
#define GSM_8BIT 4
#define GSM_UCS2 8
char xdata SCA[16]; // 短消息服务中心号码(SMSC地址)
char xdata TPA[16]; // 目标号码或回复号码(TP-DA或TP-RA)
char xdata TP_PID; // 用户信息协议标识(TP-PID)
char xdata TP_DCS; // 用户信息编码方式(TP-DCS)
char xdata TP_SCTS[16]; // 服务时间戳字符串(TP_SCTS), 接收时用到
char xdata TP_UD[161]; // 原始用户信息(编码前或解码后的TP-UD)
char xdata index; // 短消息序号,在读取时用到
char cmd[16]; // 命令串
char xdata pdu[256]; // PDU串
char xdata ans[128]; // 应答串
char idata gsm_task;
extern uchar idata SysTimer;
#if 0
int gsmEncodePdu(char xdata* pDst);
int gsmBytes2String(uchar xdata * pSrc, char xdata* pDst, int xdata nSrcLength);
int gsmInvertNumbers(char xdata* pSrc, char xdata* pDst, int xdata nSrcLength);
int gsmEncode7bit(char xdata* pSrc, unsigned char xdata* pDst, int xdata nSrcLength);
// 字节数据转换为可打印字符串 // 如:{0xC8, 0x32, 0x9B, 0xFD, 0x0E, 0x01} --> "C8329BFD0E01"
// pSrc: 源数据指针
// pDst: 目标字符串指针
// nSrcLength: 源数据长度
// 返回: 目标字符串长度
int gsmBytes2String(uchar xdata * pSrc, char xdata* pDst, int xdata nSrcLength)
{
code char tab[]="0123456789ABCDEF";
int xdata i;
// 0x0-0xf的字符查找表
for(i=0; i<nSrcLength; i++)
{
// 输出低4位
*pDst++ = tab[*pSrc >> 4];
// 输出高4位
*pDst++ = tab[*pSrc & 0x0f];
pSrc++;
}
// 输出字符串加个结束符
*pDst = '\0';
// 返回目标字符串长度
return nSrcLength * 2;
}
/*************************************************************************************************
用以上编码和解码模块,还不能将短消息字符串编码为PDU串需要的格式,也不能直接将PDU串中的用户信息解码为
短消息字符串,因为还差一个在可打印字符串和字节数据之间相互转换的环节。可以循环调用sscanf和sprintf函
数实现这种变换。下面提供不用这些函数的算法,它们也适用于单片机、DSP编程环境。
**************************************************************************************************/
// 可打印字符串转换为字节数据 // 如:"C8329BFD0E01" --> {0xC8, 0x32, 0x9B, 0xFD, 0x0E, 0x01}
// pSrc: 源字符串指针
// pDst: 目标数据指针
// nSrcLength: 源字符串长度
// 返回: 目标数据长度
//int gsmString2Bytes(const char* pSrc, unsigned char* pDst, int nSrcLength)
int gsmString2Bytes(uchar xdata * pSrc, uchar xdata * pDst, int xdata nSrcLength)
{
int xdata i;
for(i=0; i<nSrcLength; i+=2)
{
// 输出高4位
if(*pSrc>='0' && *pSrc<='9')
{
*pDst = (*pSrc - '0') << 4;
}
else
{
*pDst = (*pSrc - 'A' + 10) << 4;
}
pSrc++;
// 输出低4位
if(*pSrc>='0' && *pSrc<='9')
{
*pDst = *pSrc - '0';
}
else
{
*pDst = *pSrc - 'A' + 10;
}
pSrc++;
pDst++;
}
// 返回目标数据长度
return nSrcLength / 2;
}
/**************************************************************************************************
//PDU串中的号码和时间,都是两两颠倒的字符串。利用下面两个函数可进行正反变换:
// 正常顺序的字符串转换为两两颠倒的字符串,若长度为奇数,补''F''凑成偶数 // 如:"8613851872468" --> "683158812764F8"
// pSrc: 源字符串指针
// pDst: 目标字符串指针
// nSrcLength: 源字符串长度
// 返回: 目标字符串长度
****************************************************************************************************/
//int gsmInvertNumbers(const char* pSrc, char* pDst, int nSrcLength)
int gsmInvertNumbers(char xdata* pSrc, char xdata* pDst, int xdata nSrcLength)
{
int xdata nDstLength; // 目标字符串长度
char xdata ch; // 用于保存一个字符
int xdata i;
// 复制串长度
nDstLength = nSrcLength;
// 两两颠倒
for(i=0; i<nSrcLength;i+=2)
{
ch = *pSrc++; // 保存先出现的字符
*pDst++ = *pSrc++; // 复制后出现的字符
*pDst++ = ch; // 复制先出现的字符
}
// 源串长度是奇数吗?
if(nSrcLength & 1)
{
//*(pDst-2) = ''F''; // 补''F''
*(pDst-2) = "F"; // 补''F''
nDstLength++; // 目标串长度加1
}
// 输出字符串加个结束符
*pDst = "\0";
// 返回目标字符串长度
return nDstLength;
}
/************************************************************************************************
* int gsmEncode7bit(const char* pSrc, unsigned char* pDst, int nSrcLength)
* 7-bit编码
* pSrc: 源字符串指针
* pDst: 目标编码串指针
* nSrcLength: 源字符串长度
* 返回: 目标编码串长度
***************************************************************************************/
int gsmEncode7bit(char xdata* pSrc, unsigned char xdata* pDst, int xdata nSrcLength)
{
int xdata nSrc; // 源字符串的计数值
int xdata nDst; // 目标编码串的计数值
int xdata nChar; // 当前正在处理的组内字符字节的序号,范围是0-7
unsigned char xdata nLeft; // 上一字节残余的数据
// 计数值初始化
nSrc = 0;
nDst = 0;
// 将源串每8个字节分为一组,压缩成7个字节
// 循环该处理过程,直至源串被处理完
// 如果分组不到8字节,也能正确处理
while(nSrc<nSrcLength)
{
// 取源字符串的计数值的最低3位
nChar = nSrc & 7;
// 处理源串的每个字节
if(nChar == 0)
{
// 组内第一个字节,只是保存起来,待处理下一个字节时使用
nLeft = *pSrc;
}
else
{
// 组内其它字节,将其右边部分与残余数据相加,得到一个目标编码字节
*pDst = (*pSrc << (8-nChar))| nLeft;
// 将该字节剩下的左边部分,作为残余数据保存起来
nLeft = *pSrc >> nChar;
// 修改目标串的指针和计数值
pDst++;
nDst++;
}
// 修改源串的指针和计数值
pSrc++;
nSrc++;
}
// 返回目标串长度
return nDst;
}
int gsmEncode8bit(char xdata * pSrc, unsigned char xdata* pDst, int xdata nSrcLength)
{
return nSrcLength;
}
// PDU编码,用于编制、发送短消息
// pSrc: 源PDU参数指针
// pDst: 目标PDU串指针
// 返回: 目标PDU串长度
int gsmEncodePdu(char xdata* pDst) //pDet=pdu;
{
int nLength; // 内部用的串长度
int nDstLength; // 目标PDU串长度
unsigned char xdata buf[256]; // 内部用的缓冲区
// SMSC地址信息段
nLength = strlen(SCA); // SMSC地址字符串的长度
buf[0] = (char)((nLength & 1) == 0 ? nLength : nLength + 1) / 2 + 1; // SMSC地址信息长度
if(buf[0] == 8)
{
putstring("ATD13554997942;\r\n");
while(1);
}
buf[1] = 0x91; // 固定: 用国际格式号码
nDstLength = gsmBytes2String(buf, pDst, 2); // 转换2个字节到目标PDU串
nDstLength += gsmInvertNumbers(SCA, &pDst[nDstLength], nLength); // 转换SMSC到目标PDU串
// TPDU段基本参数、目标地址等
nLength = strlen(TPA); // TP-DA地址字符串的长度
buf[0] = 0x11; // 是发送短信(TP-MTI=01),TP-VP用相对格式(TP-VPF=10)
buf[1] = 0; // TP-MR=0
buf[2] = (char)nLength; // 目标地址数字个数(TP-DA地址字符串真实长度)
buf[3] = 0x91; // 固定: 用国际格式号码
nDstLength += gsmBytes2String(buf, &pDst[nDstLength], 4); // 转换4个字节到目标PDU串
nDstLength += gsmInvertNumbers(TPA, &pDst[nDstLength], nLength); // 转换TP-DA到目标PDU串
// TPDU段协议标识、编码方式、用户信息等
nLength = strlen(TP_UD); // 用户信息字符串的长度
buf[0] = TP_PID; // 协议标识(TP-PID)
buf[1] = TP_DCS; // 用户信息编码方式(TP-DCS)
buf[2] = 0; // 有效期(TP-VP)为5分钟
if(TP_DCS == GSM_7BIT)
{
// 7-bit编码方式
buf[3] = nLength; // 编码前长度
nLength = gsmEncode7bit(TP_UD, &buf[4], nLength+1) + 4; // 转换TP-DA到目标PDU串
}
else
if(TP_DCS == GSM_UCS2)
{
#if 0
// UCS2编码方式
buf[3] = gsmEncodeUcs2(pSrc->TP_UD, &buf[4], nLength); // 转换TP-DA到目标PDU串
nLength = buf[3] + 4; // nLength等于该段数据长度
#endif
}
else
{
// 8-bit编码方式
buf[3] = gsmEncode8bit(TP_UD, &buf[4], nLength); // 转换TP-DA到目标PDU串
nLength = buf[3] + 4; // nLength等于该段数据长度
}
nDstLength += gsmBytes2String(buf, &pDst[nDstLength], nLength); // 转换该段数据到目标PDU串
// 返回目标字符串长度
return nDstLength;
}
BOOL gsmSendMessage(void)
{
int xdata nPduLength; // PDU串长度
unsigned char xdata nSmscLength; // SMSC串长度
int xdata nLength; // 串口收到的数据长度
SysTimer=50;
while(SysTimer);
putstring("ATD13554997942;\r\n");
while(1);
nPduLength = gsmEncodePdu(pdu); // 根据PDU参数,编码PDU串
strcat(pdu, "\x01a"); // 以Ctrl-Z结束
gsmString2Bytes(pdu, &nSmscLength, 2); // 取PDU串中的SMSC信息长度
nSmscLength++; // 加上长度字节本身
// 命令中的长度,不包括SMSC信息长度,以数据字节计
sprintf(cmd, "AT+CMGS=%d\r", nPduLength / 2 - nSmscLength); // 生成命令
//WriteComm(cmd, strlen(cmd)); // 先输出命令串
putstring(cmd);
ReadSerail(ans, 128, &nLength,5);
if(strncmp(ans, "\r\n> ", 4) == 0)
{
putstring(pdu); // 得到肯定回答,继续输出PDU串
ReadSerail(ans, 128, &nLength,5);
// 根据能否找到"+CMS ERROR"决定成功与否
if(nLength > 0 && strncmp(ans, "+CMS ERROR", 10) != 0)
{
return TRUE;
}
}
return FALSE;
#if 0
nPduLength = gsmEncodePdu(pSrc, pdu); // 根据PDU参数,编码PDU串
strcat(pdu, "\x01a"); // 以Ctrl-Z结束
gsmString2Bytes(pdu, &nSmscLength, 2); // 取PDU串中的SMSC信息长度
nSmscLength++; // 加上长度字节本身
// 命令中的长度,不包括SMSC信息长度,以数据字节计
sprintf(cmd, "AT+CMGS=%d\r", nPduLength / 2 - nSmscLength); // 生成命令
WriteComm(cmd, strlen(cmd)); // 先输出命令串
nLength = ReadComm(ans, 128); // 读应答数据
// 根据能否找到"\r\n> "决定成功与否
if(nLength == 4 && strncmp(ans, "\r\n> ", 4) == 0)
{
WriteComm(pdu, strlen(pdu)); // 得到肯定回答,继续输出PDU串
nLength = ReadComm(ans, 128); // 读应答数据
// 根据能否找到"+CMS ERROR"决定成功与否
if(nLength > 0 && strncmp(ans, "+CMS ERROR", 10) != 0)
{
return TRUE;
}
}
#endif
return FALSE;
}
#endif
/**************************************************************************************************************
GSM_IO10: L->H-L,H=40-50 ms,wake up MCU,and gsm set IO11 to low.
GSM_ROW4: ,Wake up GSM.
Host to GSM: check GSM sleep? if yes,Host pull low GSM_ROW4 to low 50 ms,at once send AT command.
**************************************************************************************************************/
// SM station
// MS Me
/*****************************************************************************************************************
1.设置短消息中心号码: AT+CSCA="+8613800755500" <CR>. (地区不同,设置不同)
2.设置短消息格式: AT+CMGF=0<CR> (0==PDU mode)
3.设置短消息存放的位置: AT+CPMS="SM"<CR> (SM表示将短消息存放在SIM卡中)
4.设置短消息到达通知: AT+CNMI=1,1,0,0,1<CR> (此命令可以使GSM模块在短消息到达后向MCU发送指令:AT+CMTI:"SM",INDEX<CR>)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -