STM32 GSM模組傳送中文簡訊
阿新 • • 發佈:2019-02-01
/* 函式名:void GSM_Send_CN_MSG(unsigned char *ucTargetPhone,unsigned char *ucSmsCentergetPhone, unsigned char *ucContent) 函式功能:傳送一條中文簡訊 引數: *ucTargetPhone 目標手機號碼 *ucSmsCentergetPhone 簡訊中心號碼 *ucContent 簡訊內容; 呼叫示例:GSM_Send_CN_MSG("8615990472896","8613800951500","你好!Hellow World!"); */ void GSM_Send_CN_MSG(unsigned char *ucTargetPhone,unsigned char *ucSmsCentergetPhone,unsigned char *ucContent) { INT8U ucSMSCenter[20]; //存放顛倒後的簡訊中心號碼 INT8U ucTgPhone[20]; //存放顛倒後的接收方電話號碼 INT8U ucHead[100]; //協議頭 INT8U ucMSG[200]; //協議資料 INT8U ucLEN[5]; //臨時長度 INT8U ucPEnd[2]={0x1A,'\0'}; //結束符0x1A,也就是所謂的<Ctrl+Z> GSM_TxString("AT+CMGF=0\r\n"); //設定以PDU格式傳送接收簡訊 OSTimeDlyHMSM(0, 0, 1,0); //顛倒簡訊中心號碼 memset(ucSMSCenter,0,sizeof(ucSMSCenter)); GSM_InvertNumbers(ucSMSCenter,ucSmsCentergetPhone); //顛倒接收方電話號碼 memset(ucTgPhone,0,sizeof(ucTgPhone)); GSM_InvertNumbers(ucTgPhone,ucTargetPhone); //組成協議資料 memset(ucMSG,0,sizeof(ucMSG)); GB2UnicodeStr(ucMSG,ucContent); //簡訊內容轉成Unicode字串,放到strMSG[] strcat(ucMSG,ucPEnd); //在末尾加個傳送結束符0x1A,也就是所謂的<Ctrl+Z> //拼接協議頭 memset(ucHead,0,sizeof(ucHead)); strcat(ucHead,"08"); //08長度 strcat(ucHead,"91"); //91 國家程式碼 strcat(ucHead,ucSMSCenter); //顛倒後的簡訊中心號碼 strcat(ucHead,"11"); //11 簡訊訊息型別 不需要狀態報告 (31)需要報告 strcat(ucHead,"00"); //資訊參考 I2HEXa8(ucLEN,strlen((char *)ucTargetPhone));//目標電話長度 轉成十六進位制形式的字串 strcat(ucHead,ucLEN); //目標電話長度 strcat(ucHead,"91"); //91 國家程式碼 strcat(ucHead,ucTgPhone); //顛倒後的目的碼 strcat(ucHead,"00"); //協議標示 對於標準情況下的下 MS-to-SC 短訊息傳送,只需設定 PID 為 00 strcat(ucHead,"08"); //資料編碼方案 08 或者04 均可傳送出去 strcat(ucHead,"00"); //資訊有效期 具體參考GSM 03.40 或者PDU中文的文件的計算方法 //將協議資料部分長度拼到協議頭 I2HEXa8(ucLEN,strlen((char *)ucMSG)/2 ); //轉成十六進位制形式的字串 strcat(ucHead,ucLEN); //獲取協議總體長度 I2DECa8(ucLEN ,(strlen((char *)ucMSG)/2)+15 );//轉成十進位制形式的字串 //向串列埠傳送AT指令 GSM_TxString("AT+CMGS="); //傳送簡訊 GSM_TxString(ucLEN); //協議總長度 GSM_TxString("\r\n"); OSTimeDlyHMSM(0, 0, 0,800); GSM_TxString(ucHead); //寫入協議頭 GSM_TxString(ucMSG); //寫入協議資料 GSM_TxString("AT+CMGF=1\r\n"); //傳送結束後,改回TXT模式,要不接收到的簡訊都是PDU格式的,以至於無法接收簡訊命令! OSTimeDlyHMSM(0, 0, 0,500); } /* ------------------------------------------------------------------------- */ // 把一個16位整數轉換為16進位制的ASCII碼字串,例:0x1234 => "1234" void I2HEXa16(char *str,INT16U num) { unsigned char BL; BL= num&0x000F; str[3]= (BL>9u) ? BL+'A'-10:BL+'0'; num>>=4; //右移4位 BL= num&0x000F; str[2]= (BL>9u) ? BL+'A'-10:BL+'0'; num>>=4; BL= num&0x000F; str[1]= (BL>9u) ? BL+'A'-10:BL+'0'; num>>=4; BL= num&0x000F; str[0]= (BL>9u) ? BL+'A'-10:BL+'0'; str[4]='\0'; } /* ------------------------------------------------------------------------- */ // 把一個8位整數轉換為16進位制的ASCII碼字串,例:0x12 => "12" void I2HEXa8(INT8U *str,INT8U num) { unsigned char BL; BL= num>>4; str[0]= (BL>9u) ? BL+'A'-10:BL+'0'; BL= num&0x0F; str[1]= (BL>9u) ? BL+'A'-10:BL+'0'; str[2]='\0'; } /* ------------------------------------------------------------------------- */ // 把一個8位整數轉換為10進位制的ASCII碼字串,例:123 => "123" void I2DECa8(INT8U *str,INT8U num) { str[0]= num/100+'0'; str[1]= (num/10)%10+'0'; str[2]= num%10+'0'; str[3]='\0'; } /* ------------------------------------------------------------------------- */ // 查表將一個GB碼轉換為UNICODE碼並返回,若找不到則返回 0 INT16U SearchGB(INT16U GB) { int i;<p> for(i = 0; i <7445; i++) { if(GB2312_Unicode[i][0] == GB) return GB2312_Unicode[i][1]; //找到後返回相應的Unicode值 } return 0; //查到最後都沒有的話,返回0 }</p><p> </p><p>/* ------------------------------------------------------------------------- */ // 將GB碼字串轉換為 UNICODE 碼字串,返回Unicode字串的長度 INT16U GB2UnicodeStr(unsigned char *strto,unsigned char *strfrom) { INT16U GB=0; INT16U Unicode=0; INT16U temp=0; INT16U i=0; char str[5]; strto[0]='\0';//相當於清空這個字串 i=0; while(strfrom[i]!='\0') { if(strfrom[i]>0x7F)//大於ASCII碼的值,判定為漢字字元 { GB=strfrom[i++]; GB<<=8; GB+=strfrom[i++]; Unicode=SearchGB(GB); if(Unicode==0) return 0; else { I2HEXa16(str,Unicode); strcat((char *)strto,str); } } else//否則為ASCII碼 { //只要把8位ASCII碼擴充套件為16位就是相應的Unicode碼了 temp=strfrom[i++]; I2HEXa16(str,temp); strcat((char *)strto,str); } } return strlen((char *)strto); } const INT16U GB2312_Unicode[7445][2] = { /*GB2312 |Unicode*/ 0xA1A1, 0x3000, /* ' ' -> 12288 */ 0xA1A2, 0x3001, /* '、' -> 12289 */ 0xA1A3, 0x3002, /* '。' -> 12290 */ 0xA1A4, 0x30FB, /* '·' -> 12539 */ 0xF7FC, 0x9F3D, /* '鼽' -> 40765 */ 0xF7FD, 0x9F3E, /* '鼾' -> 40766 */ 0xF7FE, 0x9F44 /* '齇' -> 40772 */ }; /******************************************************************* 函式功能:正常順序的字串轉換為兩兩顛倒的字串,若長度為奇數,補'F'湊成偶數 如:"8613851872468" --> "683158812764F8" 輸入引數:pSrc: 源字串指標 pDst: 目標字串指標 返回值: 目標字串長度 *********************************************************************/ void GSM_InvertNumbers(unsigned char* pDst,unsigned char* pSrc) { INT16U nSrcLength=0; // 字串長度 INT16U i=0; unsigned char strFrom[30]; strcpy(strFrom,pSrc); nSrcLength = strlen((char *)strFrom);//得到原始字串的長度 if(nSrcLength & 1)//源串長度是奇數嗎? {//如果是奇數,那就在源串末尾加個‘F’,讓它的長度變為偶數。 strcat(strFrom,"F"); i=0; while(strFrom[i]!='\0') { pDst[i] = strFrom[i+1]; pDst[i+1] = strFrom[i]; i+=2; } pDst[i] = '\0'; } else //如果不是奇數,就直接轉換 { i=0; while(strFrom[i]!='\0') { pDst[i] = strFrom[i+1]; pDst[i+1] = strFrom[i]; i+=2; } pDst[i] = '\0'; } }</p>
----------------------------------------------------------------------------------------LIUNX 分割線 ---------------------------------------------------------------------------------------------------------------------
int Ucs22(const char* src, unsigned char* dst, int srclen) { unsigned short unicode,unicode2; int cnt=0; unsigned num=0; for(cnt=2;cnt<srclen;cnt + 2) { unicode = src[cnt++]; unicode2 = src[cnt++]; *dst++=unicode2; *dst++=unicode; num = num +2; } return num; }
//UNICODE碼轉為GB2312碼 int u2g(char *inbuf,int inlen,char *outbuf,int outlen) { <span style="white-space:pre"> </span>return code_convert("unicode","gb2312",inbuf,inlen,outbuf,outlen); } //GB2312碼轉為UNICODE碼 int g2u(char *inbuf,size_t inlen,char *outbuf,size_t outlen) { <span style="white-space:pre"> </span>return code_convert("gb2312","unicode",inbuf,inlen,outbuf,outlen); }
<pre name="code" class="csharp">int GSM_Send_CN_MSG(int iDev,UINT8 *ucTargetPhone,UINT8 *ucSmsCentergetPhone,UINT8 *ucContent)
{
UINT8 ucSMSCenter[20]; //存放顛倒後的簡訊中心號碼
UINT8 ucTgPhone[20]; //存放顛倒後的接收方電話號碼
INT8 cHead[100]; //協議頭
INT8 cMSG[300]; //協議資料
INT8 cMSGtmp[300]; //協議臨時資料
int iMsgLen=0;
INT8 cLEN[5]; //臨時長度
INT8 cPEnd[2]={0x1A,'\0'}; //結束符0x1A,也就是所謂的<Ctrl+Z>
//GSM_TxString("AT+CMGF=0\r\n"); //設定以PDU格式傳送接收簡訊
//Delayms(1000);
//顛倒簡訊中心號碼
memset(ucSMSCenter,0,sizeof(ucSMSCenter));
GSM_InvertNumbers(ucSMSCenter,ucSmsCentergetPhone);
//顛倒接收方電話號碼
memset(ucTgPhone,0,sizeof(ucTgPhone));
GSM_InvertNumbers(ucTgPhone,ucTargetPhone);
//組成協議資料
memset(cMSGtmp,0,sizeof(cMSGtmp));
//GB2UnicodeStr(ucMSG,ucContent); //簡訊內容轉成Unicode字串,放到strMSG[]
char cMsg[300];
int ii = 0;
//方法1 對照表
/*
iMsgLen = gsmEncodeUcs22((INT8 *)ucContent,(UINT8 *)cMSGtmp,strlen((INT8 *)ucContent));
printf("--iMsgLen-->%d<--->%s<--->%d<-->%s<--\n",iMsgLen,cMSGtmp,strlen((INT8 *)ucContent),ucContent);
for(ii = 0 ; ii < iMsgLen; ii++)
{
printf("-%02x",cMSGtmp[ii]);
}
printf("\n");*/
//方法2 LINUX字符集
memset(cMsg,0,sizeof(cMsg));
iMsgLen = 0 ;
int iRett = g2u(ucContent,strlen((INT8 *)ucContent),cMsg,OUTLEN);
/*printf("--iRett-->%d<-OUTLEN-->%d<--->%s<--->%d<-->%s<--\n",iRett,OUTLEN,cMsg,strlen((INT8 *)ucContent),ucContent);
for(ii = 0 ; ii < iRett; ii++)
{
printf("-%02x",cMsg[ii]);
}
printf("\n");*/
memset(cMSGtmp,0,sizeof(cMSGtmp));
iMsgLen = Ucs22(cMsg,cMSGtmp,iRett);
/*printf("--->%d<--->%s<----\n",iMsgLen,cMsg);
for(ii = 0 ; ii < iMsgLen; ii++)
{
printf("-%02x",cMSGtmp[ii]);
}
printf("\n");*/
memset(cMSG,0,sizeof(cMSG));
gsmBytes2String((UINT8 *)cMSGtmp,cMSG,iMsgLen);
strcat(cMSG,cPEnd); //在末尾加個傳送結束符0x1A,也就是所謂的<Ctrl+Z>
//拼接協議頭
memset(cHead,0,sizeof(cHead));
strcat(cHead,"08"); //08長度
strcat(cHead,"91"); //91 國家程式碼
strcat(cHead,(INT8 *)ucSMSCenter); //顛倒後的簡訊中心號碼
strcat(cHead,"11"); //11 簡訊訊息型別 不需要狀態報告 (31)需要報告
strcat(cHead,"00"); //資訊參考
I2HEXa8((UINT8 *)cLEN,strlen((INT8 *)ucTargetPhone));//目標電話長度 轉成十六進位制形式的字串
strcat(cHead,cLEN); //目標電話長度
strcat(cHead,"91"); //91 國家程式碼
strcat(cHead,(INT8 *)ucTgPhone); //顛倒後的目的碼
strcat(cHead,"00"); //協議標示 對於標準情況下的下 MS-to-SC 短訊息傳送,只需設定 PID 為 00
strcat(cHead,"08"); //資料編碼方案 08 或者04 均可傳送出去
strcat(cHead,"00"); //資訊有效期 具體參考GSM 03.40 或者PDU中文的文件的計算方法
//將協議資料部分長度拼到協議頭
I2HEXa8((UINT8 *)cLEN,strlen(cMSG)/2 ); //轉成十六進位制形式的字串
strcat(cHead,cLEN);
//獲取協議總體長度
I2DECa8((UINT8 *)cLEN ,(strlen(cMSG)/2)+15 );//轉成十進位制形式的字串
//向串列埠傳送AT指令
WritePort(iDev, "AT+CMGS=", strlen("AT+CMGS="));
WritePort(iDev, (UINT8 *)cLEN, strlen((UINT8 *)cLEN));
WritePort(iDev, "\r\n", strlen("\r\n"));
int iLen = 0;
char cData[512];
memset(cData, 0, sizeof(cData));
iLen = 0;
iLen =ReadPort(iDev, cData, sizeof(cData));
if(iLen < 1)
{
printf("ReadPort error!\n");
ClosePort(iDev);
return 0;
}
WritePort(iDev, (UINT8 *)cHead, strlen((UINT8 *)cHead));
WritePort(iDev, (UINT8 *)cMSG, strlen((UINT8 *)cMSG));
int i = 100;
while(i > 1)
{
memset(cData, 0, sizeof(cData));
iLen = 0;
iLen =ReadPort(iDev, cData, sizeof(cData));
if(iLen > 1)
{
if(strstr(cData,"+CMGS:")>0 && strstr(cData,"OK")>0)
{
return 1;
}
if(strstr(cData,"ERROR")>0 )
{
return 0;
}
return 0;
}
i = i-1;
usleep(200);
}
return 0;
}