天堂草原最受欢迎的角色,天堂动漫,天堂在线,色天堂下载,天堂中文在线资源,亚洲男人天堂

技術熱線: 4007-888-234
設計開發

專注差異化嵌入式產品解決方案 給智能產品定制注入靈魂給予生命

開發工具

提供開發工具、應用測試 完善的開發代碼案例庫分享

技術支持

從全面的產品導入到強大技術支援服務 全程貼心伴隨服務,創造無限潛能!

新品推廣

提供新的芯片及解決方案,提升客戶產品競爭力

新聞中心

提供最新的單片機資訊,行業消息以及公司新聞動態

單片機通過短信貓收發短信的方法

更新時間: 2019-03-26
閱讀量:2878

單片機通過短信貓收發短信的方法

       短信在現今的生活中起著非常重要的作用,我們每天都會使用它來進行信息的接收與發送,為我們的溝通提供新的手段。從本質上說,其實是一種數據傳輸的機制,通過GSM(全球移動通信系統)作為其傳輸的道路,從而實現了數據的遠距離傳輸。如果我們把它運用于單片機上,就可以實現單片機上的數據遠距離傳輸,這在實際的應用中是十分有用的。如數據的遠程采集與傳輸、環境的監測與報警等。
       然而要實現單片機發送短信,就要依賴于專用的硬件――短信貓(GSM Modem),,它用來負責與GSM網絡進行通信,而單片機則負責短信的編解碼。下面介紹短信的編碼,其實這些編碼我們每天都在使用,只是它藏匿于手機或終端設備中,不被我們熟知。

短信編碼

以一個發送實例來進行講解:
       筆者位于哈爾濱市,其短信中心號碼為13800451500,短信接收方號碼采用我本人的號碼15846003114,短信內容(最多為140個字節,如果是中文則最多為70個字)為“大家好!!!”。
先列出最終的編碼,然后再來慢慢分析:
0891683108401505F011000B815148063011F40008A70C59275BB6597DFF01FF01FF01
將以上編碼通過串口寫入短信貓,再輔以相應的AT指令與附加信息就可以成功發送短信。
1.08:短信中心地址長度(可以固定不變)
2.91:短信中心號碼類型(可以固定不變)
3.68:中國地區代碼(在中國范圍內固定不變)
4.3108401505F0:短信服務中心號碼 13800451500
 (根據地域的不同進行變動,實際情況下,可以固定不變,不論在中國任何地域都通過哈爾濱短信中心,但使用當地的服務中心收發會更快。)
       可以看到,短信服務中心號碼采用了一種比較特殊的表示方法。其實也很簡單就是在短信服務中心號碼后加一個F,號碼長度就變成了12位,然后對它每兩位中的字符進行對調。在后面的接收方號碼也是采用此種方法進行表示的,對這一點的理解的至關重要的,它將直接關系到短信發送的正確與否。
5.1100:發送短信的編碼方式(可以固定不變)
6.0B:目的地址長度(可以固定不變)
7.81:目的地址類型(可以固定不變)
8. 5148063011F4:目的地址,即接收方號碼 15846003114
如前面所說,接收方號碼亦采用此種方法。
9.0008:發送中文字符方式
10.A7:(可以固定不變)
11.0C:短信內容長度

12. 59275BB6597DFF01FF01FF01:發送中文字符的UNICODE碼
(根據發送信息內容進行變動)
中文的發送采用UNICODE編碼。由于手機上對編程的解碼也是采用UNICODE的,因此只有只用UNICODE編碼才能使短信內容成功顯示在手機上。其次,在向手機發送短信時,短信內容需要使用內存方式的顯示表示,如01FF為一個字符的UNICODE碼,在編碼中它為4個ASCII碼,而它表示是0x01ff,為兩個字節,這一點至關重要,不采用這種表示方法或表示有錯,則會導致在接收方手機上無顯示或顯示不正常。
      此編碼段是單片機進行數據傳輸的核心部分,它是真正的數據。在日常的中文短信編碼中均采用UNICODE,但其本身并不局限于UNICODE,如果接收終端是支持GB2312的,而不支持UNICODE,那么就可以在這里放相應的GB碼。脫離開字符編碼,其實可以放入任何數據,只是要在上一個編碼段中設置相應的數據長度即可。
      在筆者的短信收發系統中,采用西門子的TC35i作為短信貓,由于使用了一種支持GB2312硬件字庫的液晶顯示器,因此在數據編碼中直接使用GB碼,成功實現短信發送與接收,并在顯示器上對解碼后的內容進行顯示,達到了較好的效果。

14.:發送結束標志(十六進制為0x1A),表示短信碼結束。
結束標志在實際的操作中很容易遺忘,請讀者加以注意。

 UNICODE與GB2312碼

 與短信收發相關的AT指令

短信編碼還要輔以相應的AT指令,才能實現短信的發送。AT指令如下:
AT:用以與Modem的握手,返回OK則說明握手成功。
AT+CMGR=X:用以讀取第X條短信。

AT+CMGD=X:用以刪除第X條短信。
AT+CMGS=X:設置發送短信的字節數為X。
實際的AT指令集功能非常豐富,在應用中也是非常重要,尤其在手機開發中更如此。在這里只是實現簡單的短信收發,只涉及到以上幾條AT指令。讀者如果想進行深入的了解,可以翻閱相應的手冊。

短信的發送過程(以下過程中>代表發送,<代表接收)

通訊握手

>AT(回車 十六進制的0x0d 0x0a)
         <ok< />
           收到OK,說明握手成功。
       2.  設置短信字節數
          >AT+CMGS=26(回車)
           設置短信字節數,由筆者的使用經驗,后面的數值為短信內容的字節數+14。
           如上面的編碼中內容為12個字節,則后面的數值為12+14=26
       3.  發送短信編碼
          <>
           收到>符號,說明貓正在等待接收短信編碼
>0891683108401505F011000B815148063011F40008A70C59275BB6597DFF01FF01FF01

          發送短信編碼,送送完畢后,如果短信貓已經接收,則啟動短信發送。
       4.短信發送結果檢測
          <+CMGS:45
         <ok< />
          在短信發送成功后,會返回&ldquo;+CMGS&rdquo;,后面的45,是表示第45條短信。如果沒有返回此字符串則說明發送失敗。

          以上過程可以通過串口調試工具手工進行,而這里需要實現的是單片機的自動發送。握手、設置短信字節數、發送短信編碼、發送結果檢測等都需要單片機來實現。
   (5)單片機實現短信自動發送
            進行短信發送的前提是短信內容的正確編碼。經過以上對短信發送過程的分析,可以通過單片機對其進行實現。下面是實現程序例程:
/*-------------------------------------------------------------------------
 函數名:PDU_SMS()
 功能  :發送短信
 參數說明:SMS_Center為短信中心號碼 11位

           SMS_Telenum為短信接收方的號碼 11位

           SMS_Context為短信的內容

--------------------------------------------------------------------------------*/

int PDU_SMS(char *SMS_Center, char *SMS_Telenum,

char *SMS_Context,char is_GB)

{

  int i,j;

  unsigned char len,time;

  char lens[3];

  time=0;

  for(i=0;i<300;i++) PDU_Code[i]=PDU_t[i];

  /*----------設置短信中心號碼--------------*/

  for (i = 0, j = 0; i < strlen(SMS_Center) / 2; i++)

  {

    PDU_Code[6+(j++)] = SMS_Center[2 *i + 1];

    PDU_Code[6+(j++)] = SMS_Center[2 *i];

  }

  PDU_Code[6+j++] = 'F';    //在最后補上的F

  PDU_Code[6+j] = SMS_Center[strlen(SMS_Center) - 1];

  /*---------------------------------------------*/

  /*----------設置接收號碼--------------*/

  for (i = 0, j = 0; i < strlen(SMS_Telenum) / 2; i++)

  {

    PDU_Code[26+(j++)] = SMS_Telenum[2 *i + 1];

    PDU_Code[26+(j++)] = SMS_Telenum[2 *i];

  }

  PDU_Code[26+j++] = 'F';

  PDU_Code[26+j] = SMS_Telenum[strlen(SMS_Telenum) - 1];

  /*---------------------------------------------*/

  /*----------設置短信內容長度--------------*/

  if(is_GB==0)

  len = strlen(SMS_Context) *2;

  else

  len = strlen(SMS_Context);



  PDU_Code[44] = (len >> 4) > 9 ? (len >> 4) + 55: (len >> 4) + 48;

  PDU_Code[45] = (len &0x0f) > 9 ? (len &0x0f) + 55: (len &0x0f) + 48;

  /*---------------------------------------------*/



  /*----------編碼短信內容--------------*/

  if(is_GB==0)//如果不是GB碼,短信內容為ascii碼字符串

  {

  for (i = 0,j=0; i<strlen(SMS_Context);i++)

  {

     szzh16(SMS_Context[j++],lens);

     PDU_Code[46+i*4] = '0';

     PDU_Code[46+i*4+1] = '0';

     PDU_Code[46+i*4+2] = lens[0];

     PDU_Code[46+i*4+3] = lens[1];

  }

  PDU_Code[46+i*4] = 0x1a;

  PDU_Code[46+i*4+1] = 0xff;

  }

  else              

//短信內容為GB碼,如果要使手機能夠顯示,改到UNICODE編碼

  {

  for (i = 0,j=0; i<strlen(SMS_Context);i++)

  {

     szzh16((int)SMS_Context[j++],lens);

     PDU_Code[46+i*2] = lens[0];

     PDU_Code[46+i*2+1] = lens[1];

  }

  PDU_Code[46+i*2] = 0x1a;

  PDU_Code[46+i*2+1] = 0xff;

  }

  /*---------------------------------------------*/

  if(PDU_HandShake())

  {

  do

  {

  //LCD_PutChn(5,96,"SS...");

  //if(is_GB)

  PDU_EnablePDU();

  if(is_GB==0)

  PDU_SetLength(Strlen(SMS_Context)*2);

  else

  PDU_SetLength(Strlen(SMS_Context));

  PDU_Send(PDU_Code);

  //LCD_PutEng(5,96,"SS");

  for(i=0;i<25;i++)

  delay(20000);  

  sbuf[counter]=0;

  //LCD_PutNum16(5,96,time);

  counter=0;

  time++;

  }

 //判斷是否發送成功,如果不成功繼續發送,最多4次,如仍不成功,返回0

  while(strpos(sbuf+strlen(sbuf)-20,'G')==-1&&time<4);



  if(strpos(sbuf+strlen(sbuf)-20,'G')==-1)

  return 0;

  else

  return 1;  //成功的話返回0

  }

  else

  {

  //LCD_PutEng(5,96,"LL");

  sbuf[counter]=0;

  //LCD_PutEng(0,0,sbuf);

  counter=0;

  return 0;

  }

}

       以上程序成功實現短信的發送,其中的一些函數限于篇幅可自行實現。
   (6)單片機對短信的讀取與解碼
            單片機可以通過AT指令對短信貓中的短信進行讀取,并對讀入的短信數據進行分析與解碼。
            讀出的短信格式與發送時的短信編碼大致是相同的。下面給出相應的程序例程,讀者可以在自行實驗中對照驗證。

讀取某一條短信,并將其進行顯示

/*-------------------------------------------------------

函數名:LAD_SMS()(short for "Load And Display the Short MessageS")

功能:用戶函數,讀取第n條短信,并在LCD的(x,y)位置顯示出來

作者:于振南

----------------------------------------------------------*/

unsigned char LAD_SMS(unsigned char n,unsigned char x,unsigned char y)

{

 unsigned char i,len,t;

 char temp[5];

 char temp1[3];

 //IN_Draw_BlankorBlackRect(0,20,30,72,0);

 szzh10(n,temp1);  

//將n轉為相應的字符串,如n=21,則字符串為"21",用以與AT指令拼接。

 t=85;

 clear_sbuf();

 counter=0;

 send_s("AT+CMGR=");//AT+CMGR為讀取短信的AT指令

 send_s(temp1);//上面所得的字符串

 send(0x0d);

 send(0x0a);

 for(i=0;i<10;i++) delay(10000);  //等待讀取完畢

 sbuf[counter]=0;   //在收到的數據末尾附加'\0'

 temp[0]=sbuf[23];

<, SPAN style="mso-spacerun: yes"> temp[1]=sbuf[24];

 temp[2]=sbuf[25];

 temp[3]=0;

 if(sbuf[25]!=0x0d) t++;

 for(i=0;i<strlen(temp);i++) if(temp[i]==0x0d) temp[i]=0;

 len=atoi(temp);  //獲取收到的短信內容長度

   //LCD_PutEng(23,76,"(SM:");

   //LCD_PutNum16(27,76,n);

   //LCD_PutEng(29,76,")");

 if(len==0)

 {

  //LCD_PutEng(5,96,"EMP");

  //LCD_PutChn(x,y,">短信空");

  delay(50000);

  return 0;

 }

 len-=20;

 if(len>90)

 {

  //LCD_PutEng(5,96,"MTL");

  //LCD_PutChn(x,y,">短信太長");

  delay(50000);

  return 0;

 }



 for(i=0;i<len;i++)

 {

  temp[0]=sbuf[t+2*i];

  temp[1]=sbuf[t+2*i+1];

  temp[2]=0;

  sbuf[i]=_hex_(temp);   

  //收到的短信內容是內存方式的顯示表示,轉為十六進制數

 }

 sbuf[i]=0;

 Analysis_Pro();//解碼后的內容在sbuf中,此函數對其進行顯示輸出

 //LCD_PutEng(x,y,inf_bw.Date);

 //LCD_PutEng(x,y,sbuf+29);

 delay(50000);

 clear_sbuf();

 counter=0;

 return 1;

}


檢測新短信

/*-------------------------------------------------------

函數名:Check_New()

功能:用戶函數,檢測有無新的短信,如果有返回1,否則返回0

作者:于振南

----------------------------------------------------------*/

unsigned char Check_New()

{int i;

 send_s("AT+CMGL=0"); //AT+CMGL=0為讀取新短信的AT指令

 send(0x0d);

 send(0x0a);  //發送回車

 delay(10000);   //等待接收完畢

 if(sbuf[12]=='O') return 0xff;

 if(sbuf[12]=='+')

 {

  for(i=18;i<23;i++)

  if(sbuf[i]==',') sbuf[i]=0;

  return atoi(sbuf+19);    //返回新短信的位置

 }

}


刪除某條短信

/*-------------------------------------------------------

函數名:Delete()

功能:用戶函數,刪除第n條短信

作者:于振南

----------------------------------------------------------*/

unsigned char Delete(unsigned char n)

{

 char t[10];

 char t1[5];

 strcpy(t,"AT+CMGD=");  //AT+CMGD為刪除短信的AT指令

 szzh10(n,t1);

 strcpy(t+8,t1);

 while(Send_AT_CMD(t)!=1);

 //LCD_PutEng(5,96,"SM");

 //LCD_PutNum16(7,96,n);

 //LCD_PutEng(10,96,"De");

 delay(60000);

 return 1;

}



联系我们: 城步| 丰原市| 锡林郭勒盟| 云南省| 郴州市| 景谷| 沁源县| 晋州市| 隆子县| 兴国县| 邯郸市| 安新县| 鄂托克旗| 天长市| 广宗县| 东源县| 惠来县| 张北县| 五家渠市| 富民县| 临湘市| 庆安县| 老河口市| 敖汉旗| 吉林省| 城市| 涿鹿县| 福州市| 天镇县| 淮阳县| 鹤峰县| 泸溪县| 定襄县| 临武县| 定西市| 怀化市| 潞西市| 富阳市| 衢州市| 夏津县| 清水河县|