打印
[MCU]

对于GPRS模块返回的AT指令数据,你们是怎么处理的?

[复制链接]
13614|25
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本帖最后由 insect2006 于 2015-6-2 15:12 编辑

MCU通过USART或者SPI连接GPRS模块(ME3000,SIM900之类的)
在接收中断中设置一缓冲区用于接收模块返回的字符串信息。

现在的问题是,MCU已经成功发送了AT指令给GPRS模块,但是如何判断接收数据的尾巴?

一般AT指令发下去模块会根据执行情况返回“OK”或者"ERROR",但是同时很多AT指令还附带其他信息字符串。

判断结尾的方式无非就以下两种:
通过接收时间来判断吧,比如持续数秒(3-5秒)没有接收到数据就认为当前数据接收结束,但是在一些AT指令中,比如建立TCP连接,发送完AT指令到模块会模块会迅速返回OK,但是附带的CONNECT OK 或者CONNECT FAILED字符串返回的时间根据实际建立连接的时间不同而不同,有可能3-5秒,也有可能10秒以上甚至更长。所以通过判断接收时间间隔在理论上就不可靠。

如果通过判断“\r\n\OK\r\n”来判断尾巴也不可靠,因为模块返回的字符串信息往往带有多个\r\n\OK\r\n,有时候是一个,有时候是2个甚至3个。而且有的指令比如关闭移动场景:AT+CIPSHUT,模块执行成功后只返回:\r\nSHUT OK\r\n,这样的话接收判断同样也觉得不可靠。

主要的原因个人觉得就是AT指令集的定义上没有明确的包头和包尾的定义,同时每一个AT指令其返回的格式和数据量及时间都没有严格的限制,不知道大家在处理这类接收数据后有没有比较好的办法?

相关帖子

沙发
insect2006|  楼主 | 2015-6-2 14:43 | 只看该作者
求高人指点,对字符串信息的接收和判断处理的通用流程方法!

使用特权

评论回复
板凳
gx_huang| | 2015-6-2 14:43 | 只看该作者
这个有什么好的办法呢,无非是接收每一帧数据,并缓冲,自己分析其中的含义,如果超时,认为失败。

使用特权

评论回复
地板
JY-DX-JY| | 2015-6-2 15:04 | 只看该作者
根据每条指令的不同,判断结尾,就是判断结尾的方式依各条指令而不同。如果超时,认为失败。

使用特权

评论回复
5
insect2006|  楼主 | 2015-6-2 15:18 | 只看该作者
JY-DX-JY 发表于 2015-6-2 15:04
根据每条指令的不同,判断结尾,就是判断结尾的方式依各条指令而不同。如果超时,认为失败。 ...

你也知道AT指令集有多庞大,这样弄下去要死人的,而且通用性也不好

使用特权

评论回复
6
JY-DX-JY| | 2015-6-2 15:19 | 只看该作者
你不会每条指令都用到吧?

使用特权

评论回复
7
insect2006|  楼主 | 2015-6-2 15:31 | 只看该作者
本帖最后由 insect2006 于 2015-6-2 15:32 编辑
gx_huang 发表于 2015-6-2 14:43
这个有什么好的办法呢,无非是接收每一帧数据,并缓冲,自己分析其中的含义,如果超时,认为失败。 ...

对于一次简单的TCP通讯,都需要数条AT指令来完成,如果对每条AT指令都设置等待超时,那么综合起来的时间开销,对于非多任务的裸机系统来说简直是灾难性的。若要放弃单纯的无意义等待时间而让CPU去执行其他任务,那么只能通过标志位来实现多任务间的协调,而标志位的置位又只能在中断程序里面判断执行,而在中断程序里面对字符串的判断处理在时间上同样开销巨大

使用特权

评论回复
8
insect2006|  楼主 | 2015-6-2 15:33 | 只看该作者
JY-DX-JY 发表于 2015-6-2 15:19
你不会每条指令都用到吧?

当然不会全部用到,但是数十上百条也不是轻易就可完成的

使用特权

评论回复
9
gx_huang| | 2015-6-2 15:44 | 只看该作者
insect2006 发表于 2015-6-2 15:31
对于一次简单的TCP通讯,都需要数条AT指令来完成,如果对每条AT指令都设置等待超时,那么综合起来的时间开 ...

我们10年前,还用西门子的模块做过手机的,一个MCU加一个模块,只要RAM足够,能缓冲串口数据,其它的就是要分析这些数据了,没有办法啊的呀。不过我做硬件,有几个人做软件,读取发送短信,设置,等等,就是要判断,超时处理的。甚至还得偷偷重启模块。

使用特权

评论回复
10
justtest111| | 2015-6-2 19:25 | 只看该作者
协议中加入该帧的数据长度?

使用特权

评论回复
11
MJM_WSY| | 2015-6-2 19:42 | 只看该作者
判断超时

使用特权

评论回复
12
hameyou| | 2015-6-3 08:43 | 只看该作者
使用状态机编程来处理老好了

使用特权

评论回复
13
张允| | 2015-6-3 08:49 | 只看该作者
除了GPRS注册指令、登录中心指令外,其他的可以直接判断OK
GPRS注册指令和登录中心指令可以采用延时等待方式和接收数据结合使用,如果信号不好,执行这2条指令时间还是比较长的。

使用特权

评论回复
14
ocon| | 2015-6-3 09:40 | 只看该作者
我也是用状态机层层分解独立调试,为不同的指令设置不同的超时时间长度和重试次数,决不死等,为用到的每条AT指令设计单独的字符检索和出错处理程序,中断只用来维护时间标志和缓冲串口数据。这个是主要流程:




使用特权

评论回复
评分
参与人数 1威望 +1 收起 理由
wrr360661326 + 1 赞一个!
15
wyscjm| | 2015-6-3 09:51 | 只看该作者
AT命令搞死

使用特权

评论回复
16
ta1ent| | 2015-6-3 11:06 | 只看该作者
状态机分析指令+1

使用特权

评论回复
17
dong_abc| | 2015-6-3 12:24 | 只看该作者
本帖最后由 dong_abc 于 2015-6-3 12:30 编辑
ocon 发表于 2015-6-3 09:40
我也是用状态机层层分解独立调试,为不同的指令设置不同的超时时间长度和重试次数,决不死等,为用到的每条 ...

:handshake  :handshake


void gprs_init(void)
{   
    if((strstr(aUart5RxBuffer, "command ready") == NULL)
        /*||(strstr(aUart5RxBuffer, "+SIM READY") == NULL)*/)
    {
         gprs_init_ok = 0;                        
    }
    else
    {
         gprs_init_ok = 1;   
    }  
}


void ppp_config(void)
{         
    switch (ppp_config_step)
    {
        case 0:
            free_rom_buf(aUart5RxBuffer,sizeof(aUart5RxBuffer));
            gprs_puts("AT+GTSET=\"LPMMODE\",0\r\n");
            gprs_tick = msTicks;            
            ppp_config_step = 1;
            break;
        case 1:
            if((msTicks - gprs_tick) > 500)
            {        
                if(strstr(aUart5RxBuffer, "OK") == NULL)                  
                {
                    ppp_config_step = 0;                    
                }
                else
                {
                    ppp_config_step = 2;                                   
                }
                free_rom_buf(aUart5RxBuffer,sizeof(aUart5RxBuffer));                        
            }               
            break;
               
//===================================================            
        case 2:
            gprs_puts("AT+CPIN?\r\n");
            ppp_config_step = 3;
            gprs_tick = msTicks;
            break;        
        case 3:
            if((msTicks - gprs_tick) > 500)
            {
                if((strstr(aUart5RxBuffer, "OK") == NULL) || (strstr(aUart5RxBuffer, "+CPIN: READY") == NULL))
                {
                     ppp_config_step = 2;
                }
                else
               {
                    ppp_config_step = 4;                                                                     
               }
               free_rom_buf(aUart5RxBuffer,strlen(aUart5RxBuffer));
            }            
            break;         
//======================================================           
        case 4:
            gprs_puts("AT+CSQ\r\n");
            ppp_config_step = 5;
            gprs_tick = msTicks;
            break;
        case 5:
            if((msTicks - gprs_tick) > 500)
            {
                if(strstr(aUart5RxBuffer, "OK") == NULL)
                {
                    ppp_config_step = 4;
                }
                else
                {
                    ppp_config_step = 6;                           
                }
                free_rom_buf(aUart5RxBuffer,strlen(aUart5RxBuffer));
            }            
            break;
            
//=====================================================            
        case 6:
            gprs_puts("AT+CREG?\r\n");
            ppp_config_step = 7;
            gprs_tick = msTicks;
            break;
        case 7:
            if((msTicks - gprs_tick) > 500)
            {
                if(strstr(aUart5RxBuffer, "+CREG: 0,0") == NULL)
                {
                    ppp_config_step = 8;
                }
                else
                {
                    ppp_config_step = 6;                  
                }
                free_rom_buf(aUart5RxBuffer,strlen(aUart5RxBuffer));
            }            
            break;
            
//=========================================================
        case 8:
            //gprs_puts("AT+MIPCALL=1,\"3GNET\"\r\n");
            gprs_puts("AT+MIPCALL=1,\"xagfzqx.ydoa.snapn\"\r\n");
            ppp_config_step = 9;
            gprs_tick = msTicks;
            break;
        case 9:
            if((msTicks - gprs_tick) > 3000)
            {
                if(strstr(aUart5RxBuffer, "+MIPCALL: 0") == NULL)
                {
                        ppp_config_step = 0;
                        ppp_config_ok = 1;                    
                }
                else
                {
                      ppp_config_step = 8;                                    
                }
                free_rom_buf(aUart5RxBuffer,strlen(aUart5RxBuffer));
            }            
            break;            
                  
        default:
            break;
    }   
      
}

void gprs_monit_routine(void)
{   
   if(!gprs_init_ok)                                          { gprs_init(); }
   
   if((gprs_init_ok)&&(!ppp_config_ok))                       { ppp_config(); }
     
   if((ppp_config_ok)&&(data_is_ok)&&(!http_send_cmplt))      { http_send_test(); }         
}  

使用特权

评论回复
18
lvyunhua| | 2015-11-2 16:02 | 只看该作者
我也是用状态机来读取收到的数据。

使用特权

评论回复
19
yuanquan12345| | 2015-11-2 16:24 | 只看该作者
学习。

使用特权

评论回复
20
wrr360661326| | 2016-1-12 09:57 | 只看该作者

这个代码是怎么判断超时的?如果小于500接收到回复的报文,是不是也就白等了?还有大于3000的地方,每次都要等这么久之后才能去判断啊?

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

25

主题

146

帖子

1

粉丝