349264710 发表于 2015-9-19 23:43

我是土匪 发表于 2015-9-6 16:36
浅谈AT用法
一、         扔砖很多人都觉得AT很简单,一个字符串发过去,剩下就是喝茶等结果。土匪今天再 ...

无OS的框架,采用消息队列+软件定时器+状态机,主要是如何判断模块返回的是一个完整的帧,如何不漏掉URC,供外部调用的接口如何处理?坐等楼主的思路。

lib6303c 发表于 2015-9-20 14:50

学习了,真好要使用GPRS模块!:handshake

eternity1120 发表于 2015-9-21 10:45

mark

木棉海 发表于 2015-9-23 14:39

mark,正要用

我是土匪 发表于 2015-9-24 14:07

本帖最后由 我是土匪 于 2015-10-10 14:20 编辑

第三章 AT架构浅谈

一、指导思想前面已经讲过使用AT的原则:前一条AT返回结果后,在发送下一条。为了安全起见,增加超时机制是有必要的。二、   应用举例开门见山,步入正题,如何搭建一个发送AT的比较合理的架构?话题起大了,迟迟没想好如何解释,今天硬着头皮上了,目的是抛砖引玉,是交流贴。欢迎拍砖,砖块多了,房子才能盖起来。
选择常用的AT为例,假设想连续发送下列AT:l      ATl      ATE0l      AT+CMEE=0l      AT+IPC=0,0l      AT+CPIN?l      AT+CSQl      AT+CREG?l      AT+CGREG?l      AT+CGATT?

我是土匪 发表于 2015-9-24 14:16

n      架构1:查询模式适用于单任务系统,思路就是发送一条AT后,死等,直到返回值回来,根据返回值结果决定重发、发送下一条,或者其它AT.
思路简单,代码结构也简单,不容易出错。但处理URC(unsoliciteresult code)还是要增加串口接收中断的,且处理的实时性可能不够。还有个问题,有的AT即时回复,有的AT要等一会,甚至三分钟左右,这段时间死等意味着MCU就不能处理其它事情了,大部分情况下不能满足实际使用的。

我是土匪 发表于 2015-9-24 14:18

本帖最后由 我是土匪 于 2015-9-24 14:41 编辑

n      架构二:中断方式

个人喜欢用的方式。



我是土匪 发表于 2015-9-24 14:19

      架构三:多任务方式多任务处理起来会更简单,更清晰。

我是土匪 发表于 2015-9-24 14:19

代码在测试中,很快跟进。
感谢大家的支持

我是土匪 发表于 2015-9-24 14:20

349264710 发表于 2015-9-19 23:43
无OS的框架,采用消息队列+软件定时器+状态机,主要是如何判断模块返回的是一个完整的帧,如何不漏掉URC ...

欢迎拍砖。

我是土匪 发表于 2015-9-24 14:34

zuoxuqi 发表于 2015-9-9 09:51
楼主,期待下文啊

久等啦,工作忙,抱歉啦
欢迎拍砖。

我是土匪 发表于 2015-9-24 14:35

wang1979 发表于 2015-9-11 09:52
期待已久,继续期待!

已更新,欢迎拍砖,感谢支持!

我是土匪 发表于 2015-9-24 14:37

ddhex 发表于 2015-9-15 13:42
我一般是这么做的,所有的AT指令集,需要等待的时候,最好的策略其实是利用嵌入式操作系统的信号(信号量或 ...

每条AT都是等待执行结束,才发下一条
结合FIFO,定时器实现。

已更新,欢迎拍砖,欢迎交流。

我是土匪 发表于 2015-9-24 14:38

lib6303c 发表于 2015-9-20 14:50
学习了,真好要使用GPRS模块!

欢迎交流

cyw183846168 发表于 2015-9-24 16:27

mark,收藏下,最近一直在研究GPRS与EVDO的通信,学习下

heluo1985 发表于 2015-9-24 19:22

工作会用到,认真听课

我是土匪 发表于 2015-9-29 17:33

AT架构代码举例一、   代码举例(中断方式)下面几条AT是常用的,是很多复杂应用的基础,暂且举例如何发送下面的AT:l      ATl      ATE0l      AT+CMEE=0l      AT+IPC=0,0l      AT+CPIN?l      AT+CSQ请大家结合前面架构二:中断方式结构图思路一起看代码.1      GPRS模块开机2      GPRS模块同单片机同步,验证串口可以正常通信。 3      同步成功后,把要发送的AT放入队列:charGprsCommonAT_Init(void){               char At_Cmd_Buff = {0};            char At_Name_Buff = {0};
            //ATE0               strcpy(At_Name_Buff, "ATE");               strcpy(At_Cmd_Buff, "ATE0\r\n");               AT_InTo_Queue( At_Name_Buff,At_Cmd_Buff, NULL);
             //AT+CMEE=0               memset(At_Cmd_Buff, 0x0, sizeof(At_Cmd_Buff));               memset(At_Name_Buff, 0x0, sizeof(At_Name_Buff));               strcpy(At_Name_Buff,"AT+CMEE");               strcpy(At_Cmd_Buff, "AT+CMEE=0\r\n");                AT_InTo_Queue( At_Name_Buff, At_Cmd_Buff, NULL);
             //AT+IFC=0,0               memset(At_Cmd_Buff, 0x0, sizeof(At_Cmd_Buff));               memset(At_Name_Buff, 0x0, sizeof(At_Name_Buff));               strcpy(At_Name_Buff,"AT+IFC");               strcpy(At_Cmd_Buff, "AT+IFC=0,0\r\n");               AT_InTo_Queue( At_Name_Buff, At_Cmd_Buff, NULL);
               //AT+CPIN=0,0               memset(At_Cmd_Buff, 0x0, sizeof(At_Cmd_Buff));               memset(At_Name_Buff, 0x0, sizeof(At_Name_Buff));               strcpy(At_Name_Buff,"AT+CPIN");               strcpy(At_Cmd_Buff, "AT+CPIN?\r\n");                AT_InTo_Queue( At_Name_Buff, At_Cmd_Buff, NULL);
               //AT+CSQ               memset(At_Cmd_Buff, 0x0, sizeof(At_Cmd_Buff));               memset(At_Name_Buff, 0x0, sizeof(At_Name_Buff));               strcpy(At_Name_Buff,"AT+CSQ");               strcpy(At_Cmd_Buff, "AT+CSQ\r\n");                  AT_InTo_Queue( At_Name_Buff, At_Cmd_Buff, NULL);}

我是土匪 发表于 2015-9-29 17:38

4 启动定时器,检查队列有待发送的AT,且前一条AT执行结束再发送下一条AT:AtCmdEntity*pCurrentCmd = NULL;
voidAtcTimerHandle(void){    /* No ATC is running */    if ((NULL == pCurrentCmd) )    {      if ((!AtQueueIsEmtpy( )) &&(At_Status == ATC_RSP_FINISH))      {            if (AtQueueOut(&pCurrentCmd))            {                     At_Status = ATC_RSP_WAIT;                     Up_TxBuf((char*)pCurrentCmd->atData, strlen(pCurrentCmd->atData));                     Sent_String(Tx_Buf,strlen(Tx_Buf));            }      }    }}

我是土匪 发表于 2015-9-29 17:40

5AT返回值的解析和URC的处理:typedefAtcRspType (*AT_cmdHandle)(bool *urc);typedef struct{    char *name;    AT_cmdHandle atHandle;}AtcHandleType;//AT 列表AtcHandleTypeatCmdTable[ ] = {      {"ATE",AtHandle},      {"AT+CMEE",AtHandle},      {"AT+IFC",AtHandle},      {"AT+CPIN",   CpinHandle},      {"AT+CSQ",CsqHandle}};voidDeal_ATCmd(void){    bool urc= TRUE;    u16 i = 0;

    if (GPRS_SYNC == Gprs_Status)       {      if (NULL != pCurrentCmd)      {            for (i = 0; i <sizeof(atCmdTable)/sizeof(atCmdTable); i++)            {                if(!strcmp(pCurrentCmd->atName, atCmdTable.name))                {                  At_Status =atCmdTable.atHandle(&urc);                                  if (ATC_RSP_FINISH ==At_Status)                  {                        pCurrentCmd = NULL;                  }                }            }      }       if (urc)      {            Deal_URCHandle();      }    }   }

我是土匪 发表于 2015-9-29 17:42

6 通用型AT返回值的处理AtcRspType AtHandle( bool *urc){   char *Rsp_Str[ ] = {"OK","ERROR"};   s16res = -1;   char *p;       u8i = 0;    p= (char *)Rx_Data.buf;
   while ( '\r' == *p || '\n' == *p)    {       p++;    }       for (i = 0; i < sizeof(Rsp_Str) / sizeof(Rsp_Str); i++)    {   if (strstr( p,Rsp_Str))       {         res = i;         break;       }    }    *urc = FALSE;   switch (res)    {       case 0:/* OK */       {         At_Status= ATC_RSP_FINISH;       }       break;      case 1: /* ERROR */       {         At_Status = ATC_RSP_FINISH;       }       break;       default:          *urc = TRUE;       break;    }    return At_Status;}
页: 1 2 3 [4] 5 6 7 8 9
查看完整版本: 【原创连载】+和土匪一起玩GPRS模块