一,簡介
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
