1. 程式人生 > >STM32F103 GU906B模組GPRS、簡訊收發、撥號等功能的實現

STM32F103 GU906B模組GPRS、簡訊收發、撥號等功能的實現

這個程式搞了我很久,尤其是對如何提高響應速度上,程式流程很簡單,大概就是:

傳送AT指令->等待模組響應->一旦響應了,立即返回,並處理掉。

這個程式不一定只能用在GU906上,程式框架在任何GPRS模組上都能用,只要修改相應的AT指令,按照對應模組的AT指令流程,做下流程上的修改,就沒啥問題,框架很簡單,不像某寶上店家的那些程式碼一樣,那些程式碼反正我是看的頭暈,程式介面我都留著,只要按照相應的流程呼叫介面就好。

下面是模組的程式碼gu906.c檔案

//                            _ooOoo_  
//                           o8888888o  
//                           88" . "88  
//                           (| -_- |)  
//                            O\ = /O  
//                        ____/`---'\____  
//                      .   ' \\| |// `.  
//                       / \\||| : |||// \  
//                     / _||||| -:- |||||- \  
//                       | | \\\ - /// | |  
//                     | \_| ''\---/'' | |  
//                      \ .-\__ `-` ___/-. /  
//                   ___`. .' /--.--\ `. . __  
//                ."" '< `.___\_<|>_/___.' >'"".  
//               | | : `- \`.;`\ _ /`;.`/ - ` : | |  
//                 \ \ `-. \_ __\ /__ _/ .-` / /  
//         ======`-.____`-.___\_____/___.-`____.-'======  
//                            `=---='  
//  
//         .............................................  
//                  佛祖保佑             永無BUG 
//          佛曰:  
//                 寫字樓裡寫字間,寫字間里程序員;  
//                 程式人員寫程式,又拿程式換酒錢。  
//                 酒醒只在網上坐,酒醉還來網下眠;  
//                 酒醉酒醒日復日,網上網下年復年。  
//                 但願老死電腦間,不願鞠躬老闆前;  
//                 賓士寶馬貴者趣,公交自行程式設計師。  
//                 別人笑我忒瘋癲,我笑自己命太賤;  
//                 不見滿街漂亮妹,哪個歸得程式設計師?  
//////////////////////////////////////////////////////////
#include <string.h>
#include <stdlib.h>
#include "stdio.h"
#include "delay.h"
#include "config.h"
#include "usart4.h"
#include "gu906.h"

#define DEBUG_EN  1

//接收快取
#define MAXRECVBUFF  USART4_BUFF

#define AT                  "AT\r\n"                                        //測試命令
#define ATE(x)              ((x)?("ATE1\r\n"):("ATE0\r\n"))                 //開回顯、關回顯 
#define ATESIM              "AT+ESIMS?\r\n"                                 //檢測卡是否存在
#define ATCNMI              "AT+CNMI=2,1\r\n"                               //設定這組引數來了新資訊儲存起來 
#define ATCMGD              "AT+CMGD=1,4\r\n"                               //刪除當前儲存器中全部簡訊 
#define ATCMGF              "AT+CMGF=1\r\n"                                 //0設定短訊息為PDU模式, 1設定短訊息為txet模式
#define ATCSMP              "AT+CSMP=17,167,2,25\r\n"                       //設定文字模式的引數
#define ATUCS2              "AT+CSCS=\"UCS2\"\r\n"                          //設定為 UCS2 編碼字符集
#define ATGB2312            "AT+CSCS=\"GB2312\"\r\n"                        //設定GB2312編碼
#define ATATD               "ATD%s;\r\n"                                    //對指定手機撥號
#define ATATH               "ATH\r\n"                                       //掛機
#define ATGSM               "AT+CSCS=\"GSM\"\r\n"                           //設定GSM字符集  
#define ATCPMS              "AT+CPMS=\"SM\",\"SM\",\"SM\"\r\n"              //設定簡訊儲存單元為SIM卡 
#define ATCSQ               "AT+CSQ\r\n"                                    //獲取訊號強度
#define ATCREG              "AT+CREG?\r\n"                                  //確保模組以及註冊到GSM網路
#define ATCIICR             "AT+CIICR\r\n"                                  //讓模組啟用 GPRS 網路,在需要反覆建立 TCP 連結的場合可提高速度       
#define ATCIPSTARTOK        "AT+CIPSTART?\r\n"                              //查詢當前是否有網路連線
#define ATCIPCLOSE          "AT+CIPCLOSE=0\r\n"                             //關閉網路連線
#define ATCIPSCONT(x)       ((x)?("AT+CIPSCONT=0,\"%s\",\"%s\",%d,2")\
                                :("AT+CIPSCONT\r\n"))                       //儲存設定     
#define ATCIPSTART          "AT+CIPSTART=\"%s\",\"%s\",%d\r\n"              //設定TCP連線的IP和埠
#define ATCIPMUX            "AT+CIPMUX=0\r\n"                               //單鏈接模式
#define ATCIPMODE(x)        ((x)?("AT+CIPMODE=1,0\r\n")\
                                :("AT+CIPMODE=0,0\r\n"))                    //資料透傳輸模式、非透傳
#define ATCIPCFG(x)         ((x)?("AT+CIPCFG=1,50,0\r\n")\
                                :("AT+CIPCFG=0,50,0\r\n"))                  //自動啟動連線命令                      
#define ATCIPPACK(x)        ((x)?("AT+CIPPACK=1,\"4C4F47494E3A31303031\"\r\n")\
                                :("AT+CIPPACK=0,\"0102A0\"\r\n"))           //設備註冊包、心跳包設定
#define ATCIPSEND(x)        ((x)?("AT+CIPSEND=%d\r\n")\
                                :("AT+CIPSEND\r\n"))                        //設定傳送的資料長度
#define ATCGMR              "AT+CGMR\r\n"                                   //獲取基站資訊          
#define ATCMGS              "AT+CMGS=\"%s\"\r\n"                            //設定需要傳送簡訊的手機號
#define ATCMGR              "AT+CMGR=%s\r\n"                                //設定要讀取的簡訊的位置
#define ATCSTT              "AT+CSTT=\"CMNET\"\r\n"                         //賬號配置
#define ATCIPSCONT_C        "AT+CIPSCONT?\r\n"                              //查詢透傳連線情況            
#define GPRSSEND            0x1A                                 
#define CLOSEDTU            "+++"                                            //關閉透傳
#define OPENDTU             "ATO0\r\n"                                      //重新進入透傳

enum order{
    //與命令對應的
    _AT = 1,_ATE,_ATESIM,_ATCNMI,_ATCMGD,_ATCMGF,_ATCSMP,_ATUCS2,
    _ATGB2312,_ATATD,_ATATH,_ATGSM,_ATCPMS,_ATCSQ,_ATCREG,
    _ATCIICR,_ATCIPSTARTOK,_ATCIPCLOSE,_ATCIPSCONT,_ATCIPSTART,
    _ATCIPMUX,_ATCIPMODE,_ATCIPCFG,_ATCIPPACK,_ATCIPSEND,_ATCGMR,
    _ATCMGS,_ATCMGR,_GPRSSEND,_ATCSTT,_ATCIPSCONT_C,_CLOSEDTU,_OPENDTU,
    
    //額外的資料型別
    _GSMSEND,_GSMSENDEND
};

struct GprsData{
    char *order;   
    int olen;         
    enum order type;    
};

//GPRS資料儲存位置
static char GPRS_Data[MAXRECVBUFF]={0};
static int  GPRS_Dlen = 0;
static u8   GPRS_Dtu_ConLock = 0;

u8 RestartGprs = 0; //重啟GPRS標誌

#if GU906GSM_EN
//簡訊資訊在SIM卡中的位置
static char SIMDataID[5]=""; 
struct user_simdata sim;
#endif

/*********************************************************
  * @function  GPRS_ascii_to_hex
  * @role      
  * @input     
  * @output    None
  * @return    
  ********************************************************/
static int GPRS_ascii_to_hex(u8 *asc_data, u8 *hex_data, int len)
{
    int i;
    u8 tmp_dat;
    for(i = 0; i < len; i++)
    {
        if ((asc_data[i] >= '0') && (asc_data[i] <= '9')){
            tmp_dat = asc_data[i] - '0';
        }else if ((asc_data[i] >= 'A') && (asc_data[i] <= 'F')){ // A....F
            tmp_dat = asc_data[i] - 0x37;
        }
        else if((asc_data[i] >= 'a') && (asc_data[i] <= 'f')){ // a....f
            tmp_dat = asc_data[i] - 0x57;
        }else return -1;
        hex_data[i] = tmp_dat;  
    }
    return 0;
}

/*********************************************************
  * @function  mypow
  * @role      pow庫函式的實現,計算num的n次冪,其中n為整數 
  * @input     num
  * @output    n
  * @return    計算結果
  *******************************************************
static int mypow(int num,int n)
{
    int powint=1;
    int i;
    for(i=1;i<=n;i++) powint*=num;
    return powint;
}
*/
/*********************************************************
  * @function  FreeStr
  * @role      刪除字串中的字串,支援16進位制資料,無視結束符
  * @input     字串、字串總長度、開始刪除的起始位置、要刪除的長度
  * @output    None
  * @return    None
  ********************************************************/
static void FreeStr(char *str, int strsiz, int head, int len)
{
    int i = 0;
    while(len--)
    {
        for(i = head; i < strsiz;i++)
        {
            str[i] = str[i+1];
        }
    }
}

#if GU906GSM_EN
/*********************************************************
  * @function  GU906_ParsingSIM
  * @role      解析SIM卡中的簡訊資料
  * @input     卡中的資料
  * @output    None
  * @return    成功返回:0,失敗返回:-1
    @data      
    +CMGR: "REC READ","18750******",,"2015/03/14 20:02:15+32"
     124abcABC

    OK
  ********************************************************/
static int GU906_ParsingSIM(char *pinput)
{
    char *p = pinput;
    int i;
    #if DEBUG_EN
    printf("\n分離手機號\n");
    #endif
    if((p = strstr(p,"\",\"")) == 0)
        return -1;
    p += 3;
    memset(sim.phone,0,sizeof(sim.phone));
    for (i = 0; (*p != '\"') && (*p != '\0'); ++i,p++){
        sim.phone[i] = *p;
    }
    sim.phone[i] = '\0';
    #if DEBUG_EN
    printf("sms.phone[%s]\r\n",sim.phone);
    printf("\n分離裝置型別\n");
    #endif
    
    p +=2;
    memset(sim.dev,0,sizeof(sim.dev));
    for (i = 0; (*p != ',') && (*p != '\0'); ++i,p++){
        sim.dev[i] = *p;
    }
    #if DEBUG_EN
    printf("sms.dev[%s]\r\n",sim.dev);
    printf("\n分離時間\n");
    #endif
    
    p += 2;
    memset(sim.date,0,sizeof(sim.date));
    for (i = 0; (*p != '\"') && (*p != '\0'); ++i,p++){
        sim.date[i] = *p;
    }
    #if DEBUG_EN
    printf("sms.date[%s]\r\n",sim.date);
    printf("\n分離資料\n");
    #endif
    
    p++;
    memset(sim.data,0,sizeof(sim.data));
    while((*p != '\0') && ((*p == '\n') || (*p == '\r')) ) p++;
    for (i = 0; (*p != '\0') && (*p != '\n') && (*p != '\r'); ++i,p++){
        sim.data[i] = *p;
    }
    sim.data[i] = '\0';
    #if DEBUG_EN
    printf("sms.data:[%s]\r\n",sim.data );
    #endif
    return 0;
}
#endif

/*********************************************************
  * @function  GetRecvData
  * @role      提取字串中跟命令無關的資料,有時在進行命令操作時,
               會突然收到簡訊,什麼的,這裡要做的就是處理並過濾掉這些資料。
               還有模組突然復位了,這裡也做判斷,並復位CPU。
  * @input     資料和資料長度
  * @output    None
  * @return    None
  ********************************************************/
static void GetRecvData(char *pBuff, int *pLen)
{
    int rlen = 0;
	char buff[5]="";
    int i = 0;
    char *p1 = NULL;
    char *p2 = NULL;    

    if((pBuff == NULL) || (*pLen == 0))
        return;
    if (((p1 = strstr(pBuff, "+IPD,")) != 0) && ((p2 = strchr(pBuff, ':')) != 0))
    {
        p1+=5;
		for (i = 0; ((p1-pBuff) < *pLen) && (i < 5) && (*p1 != ':'); ++i,++p1) {
			buff[i] = *p1;
		}
		buff[i] = '\0';
		rlen = atoi(buff);
        p2++;
		GPRS_Dlen = ((rlen >= (*pLen - (p2 - pBuff)))?(*pLen - (p2 - pBuff)):rlen);
		memcpy(GPRS_Data, p2,GPRS_Dlen);
		rlen = GPRS_Dlen;
		
        p1 = strstr(pBuff, "+IPD,");
        p2 = strchr(pBuff, ':');
	    rlen += ((p2+1)-p1);
		FreeStr(pBuff, *pLen,p1-pBuff, rlen);
		if((*pLen -rlen) <=3)
			*pLen = 0;
		else
			*pLen -=rlen;
        #if DEBUG_EN
        printf("B[%d][%s]\r\n",*pLen, pBuff);
        #endif
    }
    #if GU906GSM_EN
    else if (strstr(pBuff, "+CMTI:") && ((p1 = strchr(pBuff, ',')) != 0)){   //+CMTI: "SM",2 有簡訊訊息到來  
        rlen = 0;
        p1++;
        for(i = 0; *p1 != '\r' && *p1 != '\n' && *p1 != '\0' && rlen < sizeof(SIMDataID);i++, p1++){
            if(*p1 >= '0' && *p1 <= '9')
                SIMDataID[rlen++] = *p1;
        }
        SIMDataID[rlen] = '\0'; 
    }
    else if ((p1 = strstr(pBuff, "+CMGR:")) != 0){ //讀取到短訊息
        GU906_ParsingSIM(p1);
    }
    #endif
    else if(strstr(pBuff,"[0000]") || strstr(pBuff,"Build Time")) 
    {
        #if (DEBUG_EN == 1)
        printf("restart...\r\n\r\n");
        #endif
        RestartGprs = 1;
    }
}

/*********************************************************
  * @function  GetFreeBuff
  * @role      處理掉快取中多餘的資料,同時也起到延時200ms的作用,
               讀取資料函式自帶延時10ms,所以這裡num=20,
               GU906傳送命令不能太快,不然GU906會因為處理不過來,而導致出錯。
  * @input     None
  * @output    None
  * @return    None
  ********************************************************/
static void GetFreeBuff(int num)
{
    char buff[MAXRECVBUFF] = {0};
    int siz = 0;
    while(num--)
    {
        siz = usart4_Receive(buff,MAXRECVBUFF);
        if(siz)
        {
            GetRecvData(buff, &siz);    
        }
    }
}

    
/*********************************************************
  * @function  SendAT
  * @role      傳送AT指令並接收
  * @input     gprs:要傳送的引數
  * @output    out:返回的引數
  * @return    成功返回:_ATOK,失敗返回:_ATERROR
  ********************************************************/
static s8 SendAT(struct GprsData *gprs, char *out, u32 Delay)
{
    int siz = 0;
    int i = 0;
    char *p = gprs->order;  
    u8 dat[2];
    u8 csq = 0;
    s8 ret = _ATERROR;
    char buff[MAXRECVBUFF] = {0};
    RestartGprs = 0;

#if (DEBUG_EN == 1)
    printf("\r\n------------------------------\r\n");
    printf("len[%d]\r\n", gprs->olen);
    for(i = 0; i< gprs->olen; i++,++p)
        printf("%c", *p);
    printf("\r\n");
#endif
    i = 0;
    p = NULL;
    GetFreeBuff(10);
    usart4_Send(gprs->order,gprs->olen);
    if((gprs->type == _GSMSEND) || (gprs->type == _ATATD)) 
    {
        ret = _ATOK;
        goto GU906_SENDATRET;
    }

    while(1)
    {
        for(i = 0;i<sizeof(buff);i++) 
			buff[i]=0;
        siz = 0; i = 0;
        while(siz == 0)
        {
            siz = usart4_Receive(buff,MAXRECVBUFF);
            if(siz){
				#if (DEBUG_EN == 1)
				printf("\r\nrecv:\r\n");
				printf("[%s]\r\n",buff);
				#endif
                GetRecvData(buff, &siz);
            }
            if(i++ > Delay) 
            {
                ret = _ATOTIME;
                goto GU906_SENDATRET;
            }
        }
        
        if(RestartGprs){
            ret = _ATERROR;
            goto GU906_SENDATRET;
        }
        
        switch(gprs->type)
        {
            case _AT:
            case _ATE:   
            case _ATCNMI:
            case _ATCMGD:
            case _ATCMGF:
            case _ATCSMP:
            case _ATUCS2:
            case _ATATH :
            case _ATGSM :
			case _ATCSTT:
            case _ATCIICR:
            case _ATCIPCFG:
            case _ATCIPPACK:
            case _ATCIPSCONT:
			case _OPENDTU:
            case _CLOSEDTU:
            case _ATGB2312:
                if(strstr(buff, "OK")){
                    ret = _ATOK;
                    goto GU906_SENDATRET;
                }else if(strstr(buff, "ERROR") || strstr(buff,"NO CARRIER")) {
                    GetFreeBuff(100);
                    ret = _ATERROR;
                    goto GU906_SENDATRET;
                }
            break;
                
            case _ATCPMS:
				if(strstr(buff, "OK") && strstr(buff, "+CPMS:")){
					 ret = _ATOK;
                     goto GU906_SENDATRET;
				}else if(strstr(buff, "ERROR")){
					ret = _ATERROR;
                    goto GU906_SENDATRET;
				}
				break;
				
            case _ATESIM:
				ret = _ATERROR;
				if(strstr(buff, "OK"))
				{
					if((p = strstr(buff, "+ESIMS: ")) != 0)
					{
						p += 8;
						if(1 == (*p -'0'))
							ret = _ATOK;	
					}
					goto GU906_SENDATRET;
				}
				break;
            
            case _ATCMGS:
                if(strstr(buff, ">")){
                    GetFreeBuff(1);
                    ret = _ATOK;
                    goto GU906_SENDATRET;
                }
				break;

            case _ATCSQ:
				if(strstr(buff, "OK"))
				{
					if((p = strstr(buff, "+CSQ:")) != 0)
					{
						GPRS_ascii_to_hex((u8 *)(p+6), dat, 2);
						csq = dat[0]*10 + dat[1];
						#if DEBUG_EN
						printf("訊號:[%d]\r\n", csq);
						#endif	
						if (csq < 99 && csq >= GPRSCSQ){ //網路訊號要大於GPRSCSQ(18)
							ret = _ATOK;
							goto GU906_SENDATRET;
						} else {
							ret = _ATERROR;
							goto GU906_SENDATRET;
						}	
					}
				}
				else{
					ret = _ATERROR;
					goto GU906_SENDATRET;
				}
				break;

            case _ATCIPSTARTOK:
				if(strstr(buff, "OK"))
				{
					if (strstr(buff, "+CIPSTART:")) {
						ret = _ATOK;
						goto GU906_SENDATRET;
					}	
					ret = _ATERROR;
					goto GU906_SENDATRET;					
				}else if(strstr(buff, "ERROR")) {
					ret = _ATERROR;
                    goto GU906_SENDATRET;
				}
				break;				
			
            case _ATCREG:
				if(strstr(buff, "OK"))
				{
					if ((p = strstr(buff, "+CREG: ")) != 0)
					{
						p += 7;
						if(('0' == *p) || ('5' == *p)) 
						{
							ret = _ATOK;
							goto GU906_SENDATRET;
						}
					}	
					ret = _ATERROR;
					goto GU906_SENDATRET;					
				}else if(strstr(buff, "ERROR")) {
					ret = _ATERROR;
                    goto GU906_SENDATRET;
				}
				break;

            case _ATCIPSEND:
                if (strstr(buff, ">")) {
                    ret = _ATOK;
                    goto GU906_SENDATRET;
                }
                else if (strstr(buff, "ERROR")){
                    ret = _ATERROR;
                    goto GU906_SENDATRET;
                }
            break;

            case _ATCIPMUX:
                if(strstr(buff, "+CIPMUX: 0") && strstr(buff, "OK")) {
                    ret = _ATOK;
                    goto GU906_SENDATRET;
                }else if (strstr(buff, "ERROR")){
                    ret = _ATERROR;
                    goto GU906_SENDATRET;
                }
				break;

            case _ATCIPMODE:
                if(strstr(buff, "+CIPMODE: ") && strstr(buff, "OK")) {
                    ret = _ATOK;
                    goto GU906_SENDATRET;
                }else if (strstr(buff, "ERROR")){
                    ret = _ATERROR;
                    goto GU906_SENDATRET;
                }
				break;

            case _GPRSSEND:
                if(strstr(buff, "SEND OK")) {
                   ret = _ATOK;
                   goto GU906_SENDATRET;
                }
            break;

            case _ATCMGR:
                GetRecvData(buff, &siz);
                ret = _ATOK;
                goto GU906_SENDATRET;
            //break; 

            case _ATCIPCLOSE:
                if (strstr(buff, "CLOSE OK") || strstr(buff, "+CME ERROR:")) {
                    ret = _ATOK;
                    goto GU906_SENDATRET;
                }
                else if(strstr(buff, "ERROR")){
                    ret = _ATERROR;
                    goto GU906_SENDATRET;   
                }
            break;

            case _ATCIPSTART:
                if(!GPRS_Dtu_ConLock)
                {
                    if(strstr(buff, "CONNECT OK")){
                        ret = _ATOK;
                        goto GU906_SENDATRET;
                    }
                    else if(strstr(buff, "RECONNECTING") || strstr(buff, "ERROR") || strstr(buff, "CONNECT FAIL")){
                        GetFreeBuff(100);
                        ret = _ATERROR;
                        goto GU906_SENDATRET;
                    }                    
                }
                else if(strstr(buff, "OK")){
                    ret = _ATOK;
                    goto GU906_SENDATRET;
                }
				else if(strstr(buff, "ERROR")){
                    ret = _ATERROR;
                    goto GU906_SENDATRET;   
                }
				break;
            
            case _GSMSENDEND: 
                GetFreeBuff(100);
                ret = _ATOK;
                goto GU906_SENDATRET; //忽略返回資訊
                /*
                if(strstr(buff, "+CMGS:")) {
                    if(strstr(buff, "OK"))
                        return _ATOK;
                    lock = 1;
                }
                else if(lock && strstr(buff, "OK")) {
                    return _ATOK;
                }else return _ATOK; //忽略返回資訊
                break;
                */
			case _ATCIPSCONT_C:
				if(strstr(buff,"OK"))
				{
					printf("Line:%d\r\n",__LINE__);
					if(0 != (p = strstr(buff,"+CIPMODE: ")))
					{
						p += 10;
						printf("Line:%d\r\n",__LINE__);
						if(1 == (*p -'0'))
						{
							printf("Line:%d\r\n",__LINE__);
							if(0 != (p = strstr(buff,"+CIPSTART: ")))
							{
								printf("Line:%d\r\n",__LINE__);
								if(strstr(buff,"218.66.59.201") && strstr(buff,"8888"))
								{
									printf("DTU OK\r\n");
									GPRS_Dtu_ConLock = 1;
									ret = _ATOK;
									goto GU906_SENDATRET;
								}
							}						
						}
					}
					GPRS_Dtu_ConLock = 0;
					ret = _ATOK;
					goto GU906_SENDATRET;
				}else if(strstr(buff, "ERROR")){
                    ret = _ATERROR;
                    goto GU906_SENDATRET;   
                }
				break;
				
            default: break; 
        }   
    }
    GU906_SENDATRET:
    return ret;
}

/*********************************************************
  * @function  GU906_ExecuteOrder
  * @role      執行命令
  * @input     None
  * @output    None
  * @return    成功返回:_ATOK,失敗返回:_ATERROR,超時返回:_ATOTIME
  ********************************************************/
static s8 GU906_ExecuteOrder(char *Order, u32 len, enum order type, u32 num)
{
	u32 i = 0;
	u32 delay_time = 1000;
	s8 ret = _ATOTIME;
    struct GprsData gprs;
	
    if(type == _ATCIPSTART)
        delay_time = 4000;
    if(type == _GPRSSEND)
        delay_time = 10;
	
    gprs.order = Order;
    gprs.olen = len;
    gprs.type = type;
	while((ret = SendAT(&gprs, NULL, delay_time)) != _ATOK)
	{
		if(ret == _ATERROR) {
			if(++i >= num) return _ATERROR;
			delay_s(1);
		}else return _ATOTIME;
	}
	return _ATOK;
}

/*********************************************************
  * @function  GU906_init
  * @role      GSM初始化
  * @input     None
  * @output    None
  * @return    成功返回:_ATOK,失敗返回:_ATERROR,超時返回:_ATOTIME
  ********************************************************/
s8 GU906_init(void)
{
	s8 ret = _ATOTIME;

    // 開回顯:ATE1 關回顯:ATE0
	if(_ATOK != (ret = GU906_ExecuteOrder(ATE(0), strlen(ATE(0)), _ATE, 2)))
		return ret;
	
	// 查詢卡是否存在
	if(_ATOK != (ret = GU906_ExecuteOrder(ATESIM, strlen(ATESIM), _ATESIM, 10))) 
		return ret;

#if GU906GSM_EN
    // 設定簡訊模式為text模式
	if(_ATOK != (ret = GU906_ExecuteOrder(ATCMGF, strlen(ATCMGF), _ATCMGF, 2))) 
		return ret;

    // 設定簡訊儲存單元為SIM卡
	if(_ATOK != (ret = GU906_ExecuteOrder(ATCPMS, strlen(ATCPMS), _ATCPMS, 2))) 
		return ret;

    // 設定這組引數來了新資訊儲存起來
	if(_ATOK != (ret = GU906_ExecuteOrder(ATCNMI, strlen(ATCNMI), _ATCNMI, 2))) 
		return ret;
#endif
    
    //刪除SIM卡中的所有簡訊
	if(_ATOK != (ret = GU906_ExecuteOrder(ATCMGD, strlen(ATCMGD), _ATCMGD, 2))) 
		return ret;

    //查詢訊號強度 訊號強度大於等於18才行
	while(_ATOK != (ret = GU906_ExecuteOrder(ATCSQ, strlen(ATCSQ), _ATCSQ, 60)))
	{
		if(ret == _ATOTIME) return ret;
	}
    return _ATOK;  
}

/*********************************************************
  * @function  GU906_Module_State
  * @role      判斷GU906的狀態
  * @input     None
  * @output    None
  * @return    成功返回:_ATOK,失敗返回:_ATERROR,超時返回:_ATOTIME
  ********************************************************/
s8 GU906_Module_State(void)
{
	return GU906_ExecuteOrder(AT, strlen(AT), _AT, 0);
}

/*********************************************************
  * @function  GU906_TCP_Socket
  * @role      進行TCP連線
  * @input     IP地址與埠
  * @output    None
  * @return    成功返回:_ATOK,失敗返回:_ATERROR,超時返回:_ATOTIME
  ********************************************************/
s8 GU906_TCP_Socket(struct Gprs_Config *GprsCon)
{
    char cipstart[100] = {0};
    s8 ret = _ATOTIME;
	
    if(GprsCon->server_ip == NULL || !GprsCon->server_port) return ret;
    if(!strlen((char *)GprsCon->server_ip)) return ret;
	
    //確保模組以及註冊到GSM網路
	if(_ATOK != (ret = GU906_ExecuteOrder(ATCREG, strlen(ATCREG), _ATCREG, 2))) 
		return ret;

    //讓模組啟用 GPRS 網路,在需要反覆建立 TCP 連結的場合可提高速度
	if(_ATOK != (ret = GU906_ExecuteOrder(ATCIICR, strlen(ATCIICR), _ATCIICR, 2))) 
		return ret;
	
    //查詢當前是否有網路連線
	while(_ATOK == GU906_ExecuteOrder(ATCIPSTARTOK, strlen(ATCIPSTARTOK), _ATCIPSTARTOK, 0)) 
	{
		//關閉網路連線
		if(_ATOK != (ret = GU906_ExecuteOrder(ATCIPCLOSE, strlen(ATCIPCLOSE), _ATCIPCLOSE, 2))) 
			return ret;
		
		//儲存設定
		if(_ATOK != (ret = GU906_ExecuteOrder(ATCIPSCONT(0), strlen(ATCIPSCONT(0)), _ATCIPSCONT, 2))) 
			return ret;
	}
 
    //單鏈接模式
	if(_ATOK != (ret = GU906_ExecuteOrder(ATCIPMUX, strlen(ATCIPMUX), _ATCIPMUX, 2))) 
		return ret;

    //非資料透傳輸模式
	if(_ATOK != (ret = GU906_ExecuteOrder(ATCIPMODE(0), strlen(ATCIPMODE(0)), _ATCIPMODE, 2))) 
		return ret;

    //自動啟動連線命令
	if(_ATOK != (ret = GU906_ExecuteOrder(ATCIPCFG(0), strlen(ATCIPCFG(0)), _ATCIPCFG, 2))) 
		return ret;

    //心跳包設定
	if(_ATOK != (ret = GU906_ExecuteOrder(ATCIPPACK(0), strlen(ATCIPPACK(0)), _ATCIPPACK, 2))) 
		return ret;
	
    //連線到伺服器
    //cipstart=(char *)mymalloc(100); 
    //if(cipstart==NULL) return -1; 
    sprintf(cipstart, ATCIPSTART,"TCP", GprsCon->server_ip, GprsCon->server_port);
	ret = GU906_ExecuteOrder(cipstart, strlen(cipstart), _ATCIPSTART, 3);
	
    //myfree(cipstart);
    return ret;
}

/*********************************************************
  * @function  GU906_DTU_Socket
  * @role      設定透傳模式
  * @input     IP地址與埠
  * @output    None
  * @return    成功返回:_ATOK,失敗返回:_ATERROR,超時返回:_ATOTIME
  ********************************************************/
s8 GU906_DTU_Socket(struct Gprs_Config *GprsCon)
{
    char atorder[100] = "";
    s8 ret = _ATOTIME;
    
    if(GprsCon->server_ip == NULL || !GprsCon->server_port) return ret;
    if(!strlen((char *)GprsCon->server_ip)) return ret;
    
    //atorder=(char *)mymalloc(100); 
    //if(atorder==NULL) return -1; 
    
    //查詢資料透設定情況
	if(_ATOK != (ret = GU906_ExecuteOrder(ATCIPSCONT_C, strlen(ATCIPSCONT_C), _ATCIPSCONT_C, 2))) 
		goto GU906_DTU_SOCKETEND;
 
    if(!GPRS_Dtu_ConLock)
	{
		//設定賬號
		if(_ATOK != (ret = GU906_ExecuteOrder(ATCSTT, strlen(ATCSTT), _ATCSTT, 2))) 
			goto GU906_DTU_SOCKETEND;
		
		//透傳引數設定
		if(_ATOK != (ret = GU906_ExecuteOrder(ATCIPCFG(1), strlen(ATCIPCFG(1)), _ATCIPCFG, 2))) 
			goto GU906_DTU_SOCKETEND;
		
		//設定心跳
		if(_ATOK != (ret = GU906_ExecuteOrder(ATCIPPACK(0), strlen(ATCIPPACK(0)), _ATCIPPACK, 2))) 
			goto GU906_DTU_SOCKETEND;
		
		//設定設備註冊包
		if(_ATOK != (ret = GU906_ExecuteOrder(ATCIPPACK(1), strlen(ATCIPPACK(1)), _ATCIPPACK, 2))) 
			goto GU906_DTU_SOCKETEND;
		
		//單鏈接模式
		if(_ATOK != (ret = GU906_ExecuteOrder(ATCIPMUX, strlen(ATCIPMUX), _ATCIPMUX, 2))) 
			goto GU906_DTU_SOCKETEND;

		//資料透傳輸模式
		if(_ATOK != (ret = GU906_ExecuteOrder(ATCIPMODE(1), strlen(ATCIPMODE(1)), _ATCIPMODE, 2))) 
			goto GU906_DTU_SOCKETEND;

		//儲存設定
		sprintf(atorder, ATCIPSCONT(1),"TCP", GprsCon->server_ip, GprsCon->server_port);
		if(_ATOK != (ret = GU906_ExecuteOrder(atorder, strlen(atorder), _ATCIPSCONT, 2))) 
			goto GU906_DTU_SOCKETEND;
		
		GPRS_Dtu_ConLock = 1;
	}

    //建立資料透連線
    sprintf(atorder, ATCIPSTART, "TCP", GprsCon->server_ip, GprsCon->server_port);
	if(_ATOK != (ret = GU906_ExecuteOrder(atorder, strlen(atorder), _ATCIPSTART, 2))) 
		goto GU906_DTU_SOCKETEND;

    GU906_DTU_SOCKETEND:
    //myfree(atorder);
    return ret;
}

/*********************************************************
  * @function  GU906_DtuOrAT
  * @role      透傳模式與AT模式轉換
  * @input     None
  * @output    None
  * @return    成功返回:_ATOK,失敗返回:_ATERROR,超時返回:_ATOTIME
  ********************************************************/
s8 GU906_DtuOrAT(u8 type)
{
    s8 ret = _ATERROR;
	if(type)
	{
		while(!GPRS_Dtu_ConLock)
		{
			//開啟透傳
			delay_s(2);
			if(_ATOK != (ret = GU906_ExecuteOrder(OPENDTU, strlen(OPENDTU), _OPENDTU, 0))) 
				goto GU906_DTUOFFONEND;
			GPRS_Dtu_ConLock = 1;
		}
	}
	else
	{
		while(GPRS_Dtu_ConLock)
		{
			//關閉透傳
			delay_s(2);
			if(_ATOK != (ret = GU906_ExecuteOrder(CLOSEDTU, strlen(CLOSEDTU), _CLOSEDTU, 0)))
			{
				delay_s(1);
				if(_ATOK != (GU906_Module_State()))
					goto GU906_DTUOFFONEND;	
			}
			GPRS_Dtu_ConLock = 0;
		}	
	}
	
	GU906_DTUOFFONEND:
	return ret;
}
/*********************************************************
  * @function  GU906_GPRS_write
  * @role      gprs傳送資料
  * @input     要傳送的資料與資料長度
  * @output    None
  * @return    成功返回:_ATOK,失敗返回:_ATERROR,超時返回:_ATOTIME
  ********************************************************/
s8 GU906_GPRS_write(char* pdat, int len)
{
    char atorder[20] = "";
    s8 ret = -1;
    if(strlen(pdat) == 0) return 0;
	
    //atorder = (char *)mymalloc(20); 
    //if(atorder == NULL) return -1; 
	
	if(!GPRS_Dtu_ConLock)//非資料透模式
	{
		//設定資料長度
		sprintf(atorder, ATCIPSEND(1), len);
		if(_ATOK != (ret = GU906_ExecuteOrder(atorder, strlen(atorder), _ATCIPSEND, 0))) 
			goto GU906_GPRS_WRITERET;
		
		//傳送資料
		if(_ATOK != (ret = GU906_ExecuteOrder(pdat, len, _GPRSSEND, 0))) 
			goto GU906_GPRS_WRITERET;
	}
	else
	{
		//傳送資料
		usart4_Send(pdat, len);
		ret = _ATOK;
	}
    GU906_GPRS_WRITERET:
    //myfree(atorder);
    return ret;
}

/*********************************************************
  * @function  GU906_GPRS_read
  * @role      查詢是否接收到資料
  * @input     輸出快取大小
  * @output    接收到的資料
  * @return    接收到的資料長度
  ********************************************************/
u32 GU906_GPRS_read(char *pout, int len)
{
    int i = 0;
	
	if(!GPRS_Dtu_ConLock)
	{
		GPRSREAD:
		if(GPRS_Dlen){
			for(i = 0;(i < GPRS_Dlen) && (i < (len -1)); i++){
				pout[i] = GPRS_Data[i];
			}
			memset(GPRS_Data, 0, sizeof(GPRS_Data));
			GPRS_Dlen = 0;
			return i;
		}else{
			GetFreeBuff(1);
			if(GPRS_Dlen)
				goto GPRSREAD;
		}	
	}
	else
	{
		return usart4_Receive(pout,len);
	}
    return 0;
}

/*********************************************************
  * @function  GU906_make_phone
  * @role      向指定的手機撥號
  * @input     手機號
  * @output    None
  * @return    成功返回:_ATOK,失敗返回:_ATERROR,超時返回:_ATOTIME
  ********************************************************/
s8 GU906_make_phone(char *phone)
{
    char mphone[20]="";
    sprintf(mphone, ATATD, phone);  
    return GU906_ExecuteOrder(mphone, strlen(mphone), _ATATD, 0);
}

/*********************************************************
  * @function  GU906_Answer_Phone
  * @role      等待電話被接聽
  * @input     手機號
  * @output    None
  * @return    成功返回:_ATOK,失敗返回:_ATERROR,超時返回:_ATOTIME
  ********************************************************/
s8 GU906_Answer_Phone(u32 Delay)
{
	int siz = 0;
	u32 i = 0;
	char buff[MAXRECVBUFF] = "";
	
	i = 0;
	while(1)
	{
		siz = 0;
		siz = usart4_Receive(buff,MAXRECVBUFF);
		if(siz){
			GetRecvData(buff, &siz);
			if(strstr(buff, "+COLP:") && strstr(buff, "OK")){
				return _ATOK;
			}else if(strstr(buff, "NO CARRIER") || strstr(buff, "+CREG: 1") || strstr(buff, "ERROR")){
				return _ATERROR;
			}
		}
		if(i++ > Delay) 
		{
			return _ATOTIME;
		}
	}
}		
/*********************************************************
  * @function  GU906_end_phone
  * @role      掛機
  * @input     None
  * @output    None
  * @return    成功返回:_ATOK,失敗返回:_ATERROR,超時返回:_ATOTIME
  ********************************************************/
s8 GU906_end_phone(void)
{
    return GU906_ExecuteOrder(ATATH, strlen(ATATH), _ATATH, 0);
}

#if GU906GSM_EN
/*********************************************************
  * @function  GU906_Chinese_text
  * @role      向指定的手機發送中文簡訊
  * @input     phone 手機號指標,pmsg 短訊息指標
  * @output    None
  * @return    成功返回:_ATOK,失敗返回:_ATERROR,超時返回:_ATOTIME
  ********************************************************/
s8 GU906_Chinese_text(char *phone,char* pmsg)
{
	s8 ret = _ATOTIME;
    char atphone[50] = "";
    char end[]={0x1A,0x00};
	
    if(strlen(phone) != 11)  return _ATERROR;
    //atphone = (char *)mymalloc(50); 
    //if(atphone == NULL) return -1; 
	
    //設定短訊息為txet模式
	if(_ATOK != (ret = GU906_ExecuteOrder(ATCMGF, strlen(ATCMGF), _ATCMGF, 2))) 
		goto GU906_CHINESE_TEXTEND;
    
    //設定GB2312編碼
	if(_ATOK != (ret = GU906_ExecuteOrder(ATGB2312, strlen(ATGB2312), _ATGB2312, 2))) 
		goto GU906_CHINESE_TEXTEND;
	
    //設定這組引數來了新資訊儲存起來 
	if(_ATOK != (ret = GU906_ExecuteOrder(ATCNMI, strlen(ATCNMI), _ATCNMI, 2))) 
		goto GU906_CHINESE_TEXTEND;
	
    //設定使用者手機號
	sprintf(atphone,ATCMGS,phone);
	if(_ATOK != (ret = GU906_ExecuteOrder(atphone, strlen(atphone), _ATCMGS, 2))) 
		goto GU906_CHINESE_TEXTEND;
	
    //傳送資料
	if(_ATOK == (ret = GU906_ExecuteOrder(pmsg, strlen(pmsg), _GSMSEND, 0))) 
	{
		ret = GU906_ExecuteOrder(end, 1, _GSMSENDEND, 0);
	}
	GU906_CHINESE_TEXTEND:
	//myfree(atphone);
    return ret;
}

/*********************************************************
  * @function  GU906_Read_SIM
  * @role      讀取簡訊資訊
  * @input     簡訊在SIM卡中的位置
  * @output    None
  * @return    成功返回:_ATOK,失敗返回:_ATERROR,超時返回:_ATOTIME 
  ********************************************************/
static s8 GU906_Read_SIM(char *pnum)
{
	s8 ret = _ATOTIME;
    char cmgr[20]="";
    //讀取簡訊的編碼格式為GB2312
	if(_ATOK != (ret = GU906_ExecuteOrder(ATGB2312, strlen(ATGB2312), _ATGB2312, 2))) 
		return ret;
	
    //讀取短訊息
    sprintf(cmgr,ATCMGR,pnum);
    return GU906_ExecuteOrder(cmgr, strlen(cmgr), _ATCMGR, 2);
}

/*********************************************************
  * @function  GU906_DeleteSms
  * @role      刪除SIM卡中的所有簡訊
  * @input     None
  * @output    None
  * @return    成功返回:_ATOK,失敗返回:_ATERROR,超時返回:_ATOTIME 
  ********************************************************/
static int GU906_DeleteSms(void)
{
    return GU906_ExecuteOrder(ATCMGD, strlen(ATCMGD), _ATCMGD, 2);
}

/*********************************************************
  * @function  GU906_Read_UserSMS
  * @role      查詢並讀取簡訊資料
  * @input     None
  * @output    None
  * @return    0,接收到新資料,-1,未接收到新資料
  ********************************************************/
s8 GU906_Read_UserSMS(void)
{
    SMSREAD:
    if(strlen(SIMDataID)){
        #if DEBUG_EN
        printf("SIMDataID[%s]\r\n",SIMDataID);
        #endif
        GU906_Read_SIM(SIMDataID);
        GU906_DeleteSms();
        memset(SIMDataID,0,sizeof(SIMDataID));
        return 0;
    }else{
        GetFreeBuff(1);
        if(strlen(SIMDataID))
            goto SMSREAD;
    }
    return -1;
}
#endif

gu906.檔案如下

#ifndef _GU906_H_
#define _GU906_H_
#include "sys.h"

#define GU906GSM_EN   1    //是否開啟簡訊功能 
#define GPRSCSQ       18   //訊號強度,在使用GPRS功能時,最低要求訊號強度不得低於18

#define _ATOK          0  //執行成功
#define _ATERROR      -1  //執行錯誤
#define _ATOTIME      -2  //執行超時
#define _LINKNOT      -3  //掉線了

struct Gprs_Config{
	u8 *server_ip;     //伺服器IP
	u32 server_port;   //伺服器埠
};

#if GU906GSM_EN
//根據實際記憶體情況而定
struct user_simdata{
	char phone[15];  //使用者手機號
	char dev[50];    //使用者使用的裝置
	char date[50];   //接收時間
	char data[200];  //接收的資料
};
extern struct user_simdata sim;
s8 GU906_Read_UserSMS(void);
s8 GU906_Chinese_text(char *phone,char* pmsg);
#endif

s8  GU906_init(void);
s8  GU906_Module_State(void);
s8  GU906_TCP_Socket(struct Gprs_Config *GprsCon);
s8  GU906_DTU_Socket(struct Gprs_Config *GprsCon);
s8  GU906_GPRS_write(char* pdat, int len);
u32 GU906_GPRS_read(char *pout, int len);

s8  GU906_make_phone(char *phone);
s8  GU906_Answer_Phone(u32 Delay);
s8  GU906_end_phone(void);
s8  GU906_DtuOrAT(u8 type);


#endif

main.c

#include <string.h>
#include <stdlib.h>
#include "stdio.h"
#include "delay.h"
#include "GU906.h"
#include "config.h"
#include "usart1.h"
#include "usart4.h"

int main(void)
{    
	u32 ret = 0;
	char buff[200]="";
	struct Gprs_Config GprsCon;
	delay_init();
	usart4_Configuration(115200);    //GU900預設通訊波特率是115200
	usart1_Configuration(115200);    //除錯輸出埠波特率設定
	delay_s(5);                      //剛上電 要等待10秒,等待GU906模組初始化完成
	
	printf("\r\nBegin...\r\n");
	GprsCon.server_ip = (u8 *)"210.66.59.211"; //GPRS通訊時的伺服器IP
	GprsCon.server_port = atoi("8888");        //GPRS通訊時的伺服器埠
	
	//GSM初始化
	while(1)
	{
		if(_ATOK == GU906_init()){
			printf("GU906 init ok.\r\n\r\n");
			break;
		}
		printf("init error.\r\n");
		delay_s(1);
	}
	
	/*****************************************************************************/
	//GU906 GPRS TCP 非透傳模式通訊測試
	while(1)
	{
		if(_ATOK == GU906_TCP_Socket(&GprsCon))
		{
			printf("socket ok\r\n\r\n");
			delay_s(3);	
			while(1)
			{
				ret = GU906_GPRS_read(buff, 200);
				if(ret)
				{
					printf("GPRS:[%d][%s]\r\n", ret,buff);
					if(_ATOK != GU906_GPRS_write((char *)"OK", 2))
					{
						printf("Send Error.\r\n");
					}					
				}
			}
		}
		printf("GU906_TCP_Socket ERROR.\r\n");
		while(1);
	}
	/*******************************************************************************/
	
	/*****************************************************************************/
	//GU906 GPRS TCP 透傳模式通訊測試
	while(1)
	{
		if(_ATOK == GU906_DTU_Socket(&GprsCon))
		{
			printf("socket ok\r\n\r\n");
			delay_s(3);	
			while(1)
			{
				ret = GU906_GPRS_read(buff, 200);
				if(ret)
				{
					printf("GPRS:[%d][%s]\r\n", ret,buff);
					if(_ATOK != GU906_GPRS_write((char *)buff, ret))
					{
						printf("Send Error.\r\n");
					}					
					
					if(strstr(buff,"CLOSE"))
					{
						GU906_DtuOrAT(0);
					}
					if(strstr(buff,"OPEN"))
					{
						GU906_DtuOrAT(1);
					}
				}
			}
		}
		printf("GU906_TCP_Socket ERROR.\r\n");
		while(1);
	}
	/*******************************************************************************/
	
	/*****************************************************************************/
	//傳送簡訊測試
    while(_ATOK != GU906_Chinese_text("18750******", "123abd 測試"))
    {
        delay_s(5);
    }

	//接收簡訊測試
    while(1)
    {
        if(0 == GU906_Read_UserSMS())
        {
            printf("------------------------------\r\n");
            printf("號碼:%s\r\n",sim.phone);
            printf("裝置:%s\r\n",sim.dev);
            printf("時間:%s\r\n",sim.date);
            printf("資訊:%s\r\n",sim.data);
        }
        delay_ms(50);
    }
	/******************************************************************************/
	
	/*****************************************************************************/
	//打電話測試
	if (_ATOK == GU906_make_phone("18750******"))
	{
		//等待接聽
		while(_ATOTIME == GU906_Answer_Phone(1000))
		{
			printf("make ok\r\n");
			GU906_end_phone();			
		}
		printf("make ok\r\n");
	}
	else 
	{
		printf("make error\r\n");
		//SoftReset();
	}
	/******************************************************************************/
	while(1);
}



工程下載:

連結:http://pan.baidu.com/s/1dEQwME9 密碼:9fwz