1. 程式人生 > >STM32 GSM模組傳送中文簡訊

STM32 GSM模組傳送中文簡訊

/*
函式名: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;
}