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;}