sim808模块收发送短信
一,简介
SIM 808发送短信分text模式和PDU模式。text模式已ascii码发送短信,这种模式比较简单,发送命令AT+CMGF=1就可以发送短信,而PDU模式比较复杂,首先发送命令AT+CMGF=0,才能进行发送PDU短信。这里主要讲解PDU的发送方式。
二,文本方式发送短信
确保SIM模块初始化完成:
1,设置发送模式
AT+CMGF=1
2,接收方电话号码
AT+CMGS=138XXXXxxxx
3,输入内容
>hello world !
4,完成发送
输入完短信内容后按组合键“ctrl+z”作为结束符,“ctrl+z”在ascii码中的数值是“0x1a”,所以在编程时可以直接在信息内容后进行字符串拼接。
三,PDU方式收发短信
1,发送短信
我们先来看PDU发送短信的流程:
1),设置发送模式
AT+CMGF=0
2),发送将发送的短信长度
AT+CMGS=信息长度
3),发送短信
0891683108705505F011000D91688112790924F70008000A68077b7e632f52a8002e
我们把短信内容给分段,
0891683108705505F0 11000D91688112790924F7000800 0A68077b7e632f52a8002e
绿色部分是号码中心段,蓝色部分是发送号码段,红色部分是发送信息段。
4),先来看中心号码段。
我们其实还可以将其再细分:
08 91 683108705505F0
其中91是国际化的意思,这个作为前缀必须加上。
683108705505F0是什么意思呢?我们将它奇数位和偶数位反转看看:
“683108705505F0”
“8613800755500F”
13800755500是深圳地区的中心号码,86是中国地区的前缀。F是因为在进行PDU编码的时候规定了如果号码位数是奇数位那么就要在末尾加F进行补齐,由于我们国家的手机号码位数都是11位,因此要在末尾补F。于是我们的中心号码加86补齐F再奇偶位反转最后加91国际化前缀就由原来的:
“13800755500”
变成了:
“91683108705505F0”
接着我们数一下它有多少位,16位,16/2=8,所以我们把整个中心号码组合编码后的长度除以2,最后以十六进制的表示方式加在它的前端就大功告成了。
“0891683108705505F0”
5),收信方号码段。
“11000D91688112790924F7000800”
将其细分:
1100 0D91688112790924F7 00 08 00
其中“1100”和“000800”分别是收信方号码段固定的前缀和后缀,所以一定要记得加上。其中08两位表明了发送短信的编码方式。如果为00是按7bit的编码发送短信英文字符数字常以这种方式发送;如果是04是按8bit的编码发送短信图片等一般以这种方式发送;如果是08则是以ucs2的编码方式发送中文都是以这种方式发送。
“688112790924F7”和中心号码段一样的编码方式,原型是:
“8618219790427”。
“0D91”需要注意一下,其中这里的“91”和中心号码段的“91”意义不一样了,这里是表示接收方的设备是手机的意思,“81”则是小灵通。“0D”是一个十六进制数,还原为十进制后是13,什么意思呢?接受方的号码是“8618219790427”共13位。
因此接收方电话经偶数位<补齐F>
然后<奇数偶数位反转>
再<加上号码长度>
最后<加上前后缀>最终由:
“8618219790427”
转型为:
“11000D91688112790924F7000800”。
6),信息段
“0A68077b7e632f52a8002e”
前面我们说过发送中文是以ucs2方式发送的,即unicode码发送,把68077b7e632f52a8002e编码还原成GB码是“标签振动.”
其编码(十六进制)长度是20位,20/2=10,10的十六进制表示方式是0X0A。因此信息段的最终编码为:
“0A68077b7e632f52a8002e”
7),组合
我们把上面的编码组合,于是发送的内容为
“0891683108705505F011000D91688112790924F70008000A68077b7e632f52a8002e”
我们把短信中心号码去除变为
“11000D91688112790924F70008000A68077b7e632f52a8002e”
计算一下字符串长度,50位。OK,50/2=25。于是在PDU模式下,我们所谓的“信息长度”:AT+CMGS=25。
至此整个PDU发送短信完成
2,接收短信
接收到的短信的解码和发送短信基本相同。我们先看一下两条接收到的短信编码
0891683108705505F0240D91683186869254F70000616032514222230163
0891683108705505F0240D91683186869254F7000861603251547523026211
将编码分段:
0891683108705505F0 24 0D 91 683186869254F7 00 00 61 60 32 51 42 22 23 01 63
0891683108705505F0 24 0D 91 683186869254F7 00 08 61 60 32 51 54 75 23 02 6211
红色部分为短信编码00:7bit 04:8bit 08:ucs2,
绿色部分为短信中心时间戳,
蓝色部分为接发送的消息体长度.
橙色部分为消息体
四,一些转换函数
// 十六进制数据映射表
const char HexTbl[] = { "0123456789ABCDEF" };
// 十六进制字符转为数字
unsigned char HexChar2Number(char hex)
{
unsigned char value = 0;
if (hex >= '0' && hex <= '9')
{
value = hex - '0';
}
else if (hex >= 'A' && hex <= 'Z')
{
value = hex - 'A' + 10;
}
else if (hex >= 'a' && hex <= 'z')
{
value = hex - 'a' + 10;
}
return value;
}
// 两个十六进制字符转为十进制数据
unsigned char strHex2Byte(char *pHex)
{
unsigned char value;
value = HexChar2Number(pHex[0]) << 4;
value |= HexChar2Number(pHex[1]);
return value;
}
/**********************************************************
GSM PDU 7bit编码,由ASCII字符串转为编码后的7bit PDU字符串
"hellohello"----->"E8329BFD4697D9EC37"
pDst:编码后的目标指针
pSrc:编码前的ASCII字符串指针
返回:编码后的字符数据长度
***********************************************************/
int PDU_7BIT_Encoding(unsigned char *pDst, char *pSrc)
{
int i;
unsigned char hexVlaue; // 保存编码过程中的十六进制数据
unsigned char nLeft; // 左边应填充的位个数
unsigned char fillValue; // 用于填充的数据
int Cnt = 0; // 编码后数据长度
int nSrcLength = strlen(pSrc); // 源字符串长度
nLeft = 1; // 初始值左边应填充1位
for (i = 0; i < nSrcLength; i++)
{
hexVlaue = *pSrc >> (nLeft - 1); // 先将当前字符右移相应位;
fillValue = *(pSrc + 1) << (8 - nLeft); // 取出下一个字符的低位,并从低位移到高位存放到fillValue
hexVlaue = hexVlaue | fillValue; // 将下一个字符的低位补到该字符的高位得到该位的编码
*pDst++ = HexTbl[hexVlaue >> 4]; // 将编码后的十六进制转为相应的字符串放到pDst中
*pDst++ = HexTbl[hexVlaue & 0x0F];
Cnt += 2; // 字符串长度加2
nLeft++; // 左边应填充的位个数加1
if (nLeft == 8) // 移动8次后将产生一个空字符0x00,实为8个字节数据转为7字节数据
{
pSrc++; // 跳过该字符
i++;
nLeft = 1; // 下次循环将重复前面过程
}
pSrc++; // 源字符串指针移向下一字符
}
*pDst = '\0'; // 字符串末尾设置为0
return Cnt;
}
/**********************************************************
GSM PDU 7bit字符串解码,由7bit PDU字符串转为ASCII字符串
"E8329BFD4697D9EC37"----->"hellohello"
pDst:解码后的ASCII字符串目标指针
pSrc:解码前的PDU 7bit字符串指针
返回:解码后的ASCII字符串长度
***********************************************************/
int PDU_7BIT_Decoding(char *pDst, char *pSrc)
{
int i;
int Cnt = 0; // 解码后字符串长度
unsigned char nLeft = 1; // 左边填充位个数
unsigned char fillValue = 0; // 填充的数据
unsigned char oldFillValue = 0; // 上一次填充的数据
int srcLength = strlen(pSrc); // 获得PDU编码长度
for (i = 0; i < srcLength; i += 2)
{
*pDst = strHex2Byte(pSrc); // 获取当前字符
fillValue = (unsigned char)*pDst;
fillValue >>= (8 - nLeft); // 取出编码时填充到该字节的数据
*pDst <<= (nLeft - 1); // 左移至原始位置
*pDst &= 0x7F; // 去掉最高位
*pDst |= oldFillValue; // 将上一次取出的补位加到末尾
oldFillValue = fillValue;
pDst++; // 目标地址加1
Cnt++; // 解码长度加1
nLeft++; // 左边填充位个数加1
if (nLeft == 8) // 第8个字节将产生一个完全的填充数据
{
*pDst = oldFillValue; // 直接将该填充数据放到下一个目标地址中
pDst++;
Cnt++;
nLeft = 1; // 复位nLeft,重复以上步骤
oldFillValue = 0;
}
pSrc += 2; // 源指针向后移两字节
}
*pDst = '\0'; // 目标字符串末尾设为0
return Cnt;
}
五,参考资料
http://blog.sina.com.cn/s/blog_524846000101cwtr.html
转载请注明出处:http://www.cnblogs.com/fyluyg/articles/5703306.html