搜索
bottom↓
回复: 17
打印 上一主题 下一主题

小弟初次尝试写gprs状态机,烦请坛友们留步帮忙看看

[复制链接]

出0入0汤圆

跳转到指定楼层
1
发表于 2014-3-6 01:07:39 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
小弟一直在学习状态机,无奈状态机太高深到现在还没入门,马上就要毕业了现在开始整毕业设计,于是乎就尝试用状态机来做毕业设计,下位机使用gprs通信与上位机通信,因为下位机只需发送数据给上位机,所以现在只写了gprs发送部分。
10ms扫描一次状态机,代码如下:
    switch(gprs.status){
        /******************************************************
        **连接
        ******************************************************/
        case CONNECT:
        {
            SIM900_SendCommand("AT+CIPCLOSE\r\n");
            SIM900_SendCommand("AT+CIPSHUT\r\n");
            SIM900_SendCommand("AT+CIPSTART=\"TCP\",\"www.cmcu.vicp.net\",\"2741\"\r\n");  
            at.recvIsOk     = FALSE;
            gprs.status     = CHECK_CONNECT_STATUS;
            gprs.timeout    = 0;
            gprs.errorCount = 0;
            SIM900_ClearAtBuf();
        }break;
        /*****************************************************
        **检查连接状态
        *****************************************************/
        case CHECK_CONNECT_STATUS:
        {
            if(TRUE == at.recvIsOk){
                at.recvIsOk  = FALSE;
                gprs.timeout = 0;
                if(strstr(at.buf,"CONNECT OK")||            //连接成功?
                    strstr(at.buf,"ALREADY CONNECT")){      //已经连接了?
                    gprs.status = IDLE;
                }
                else if(strstr(at.buf,"CONNECT FAIL")){
                    gprs.status = CONNECT;
                }
                else{
                    at.recvIsOk = FALSE;
                }
                SIM900_ClearAtBuf();
            }
            else{
                if(++gprs.timeout >= 3000){     //超时?
                    gprs.timeout = 0;
                    gprs.status  = CONNECT;       //长时间无响应,重新发送连接指令
                }
            }
        }break;
        /*****************************************************
        **i空闲状态
        *****************************************************/
        case IDLE:
        {
            if(strstr(at.buf,"CLOSED")){                 //远程主机关闭?
                gprs.status  = CONNECT;                  //
                gprs.timeout = 0;
                break;
            }
            if(FALSE == gprs.txBufIsEmpty){     //发送缓冲区有新数据?
                gprs.status     = SEND_DATA;
                gprs.timeout    = 0;
                gprs.errorCount = 0;
                break;
            }
            if(++gprs.timeout >= 3000){                    //到了30秒?
                gprs.status     = SEND_HEARTBEAT;
                gprs.timeout    = 0;
                gprs.errorCount = 0;
            }
        }break;
        /*****************************************************
        **发送数据
        *****************************************************/
        case SEND_DATA:
        {
            strcat(cmdBuf,"AT+CIPSEND\r\n");
            strcat(cmdBuf,gprs.txBuf);
            strcat(cmdBuf,"\r\n");
            strcat(cmdBuf,&endAscii);
            SIM900_SendCommand(cmdBuf);
            SIM900_ClearAtBuf();
            at.recvIsOk  = FALSE;
            gprs.timeout = 0;
            gprs.status  = CHECK_SEND_DATA_STATUS;
            
        }break;
        /*****************************************************
        **检查发送数据状态
        *****************************************************/
        case CHECK_SEND_DATA_STATUS:
        {
            if(TRUE == at.recvIsOk){
                at.recvIsOk = FALSE;
                if(strstr(at.buf,"SEND OK")){                      //send ok为发送成功时返回的指令,所以只查找返回的指令中是否有send ok
                    gprs.status = IDLE;
                    gprs.txBufIsEmpty = TRUE;
                    memset(gprs.txBuf,0,sizeof(gprs.txBuf));
                    SIM900_ClearAtBuf();
                }   
            }
            else{
                if(++gprs.timeout > 1000){            //到了10秒?
                    gprs.timeout = 0;
                    gprs.status = SEND_DATA;         //10秒内没有返回到send ok,重新发送
                    if(++gprs.errorCount > 3){         
                        gprs.status = CONNECT;        //发送三次后仍然没有返回send ok,调到连接状态,重新连接 服务器
                    }
                }
            }
        }break;
        /*****************************************************
        **发送心跳包
        *****************************************************/
        case SEND_HEARTBEAT:
        {
            strcat(cmdBuf,"AT+CIPSEND\r\n");
            strcat(cmdBuf,"heart\r\n");
            strcat(cmdBuf,&endAscii);
            SIM900_SendCommand(cmdBuf);
            SIM900_ClearAtBuf();
            at.recvIsOk  = FALSE;
            gprs.status  = CHECK_SEND_HEARTBEAT_STATUS;
            gprs.timeout = 0;
        }break;
        /*****************************************************
        **检查发送心跳包状态
        *****************************************************/
        case CHECK_SEND_HEARTBEAT_STATUS:
        {
            if(TRUE == at.recvIsOk){
                at.recvIsOk = FALSE;
                if(strstr(at.buf,"SEND OK")){
                    gprs.status = IDLE;
                    SIM900_ClearAtBuf();  
                }
            }
            else{
                if(++gprs.timeout > 1000){
                    gprs.timeout = 0;
                    gprs.status = SEND_HEARTBEAT;
                    if(++gprs.errorCount > 3){
                        gprs.status = CONNECT;
                    }
                }
            }
        }break;
        default :
        {
            
        }break;
    }

阿莫论坛20周年了!感谢大家的支持与爱护!!

一只鸟敢站在脆弱的枝条上歇脚,它依仗的不是枝条不会断,而是自己有翅膀,会飞。

出0入0汤圆

2
发表于 2015-6-8 10:59:13 | 只看该作者
你读取短信也用状态机吗

出0入0汤圆

3
发表于 2015-6-8 11:05:03 | 只看该作者
gprs状态机.标记!

出0入0汤圆

4
发表于 2015-6-10 17:42:52 | 只看该作者
启发甚大,昨晚还在准备吧GPRS部分的代码改成状态机的,也是一时半会儿没太好的思路。

出0入4汤圆

5
发表于 2015-6-10 21:45:31 | 只看该作者
好方法!

出0入0汤圆

6
发表于 2015-6-10 22:10:03 | 只看该作者
gprs状态机.标记!

出0入0汤圆

7
发表于 2015-11-12 16:14:06 | 只看该作者
顶起,对于AT指令回复消息很好的处理方式,AT指令回复太乱不利于程序处理  

出0入4汤圆

8
发表于 2015-11-12 16:37:37 | 只看该作者
用状态机还是不错的选择

出0入0汤圆

9
发表于 2016-8-8 18:56:52 | 只看该作者
MARK一下!!感觉你这个非常靠谱,我也打算写个类似的机制,写完以后更新上来

出5入4汤圆

10
发表于 2016-8-9 08:43:17 | 只看该作者
不错,可以参考下

出0入0汤圆

11
发表于 2016-10-21 14:34:58 | 只看该作者
学习了,看了一下代码,有下面一个问题。
楼主的思路是应用层将数据压入gprs.txBuf中,然后状态机负责发送。比如说,应用层第一次发送数据,此时网络状态不好,状态机停留在CHECK_SEND_DATA_STATUS,然后这时,应用层第二次发送数据,也压入gprs.txBuf中。然后当收到send ok时,状态机会把gprs.txBuf清空,这时gprs.txBuf里还有尚未发送的数据吧?

出0入0汤圆

12
 楼主| 发表于 2016-10-23 21:35:28 | 只看该作者
int 发表于 2016-10-21 14:34
学习了,看了一下代码,有下面一个问题。
楼主的思路是应用层将数据压入gprs.txBuf中,然后状态机负责发送 ...

是的,异常处理做的不好,那是我刚学状态机的时候写的,现在再回来看,还是很多地方写的不好,比如你说的这个问题,就是一个很大的bug

出0入0汤圆

13
发表于 2016-10-23 21:51:15 | 只看该作者
cyj_0220 发表于 2016-10-23 21:35
是的,异常处理做的不好,那是我刚学状态机的时候写的,现在再回来看,还是很多地方写的不好,比如你说的 ...

最近一直也在研究裸机下的GPRS驱动,大概思路和楼主类似,就是把GPRS驱动状态机放在超级循环里,状态机建立缓冲,自行处理多条发送的问题,然后应用层调用接口。

这样的好处就是不阻塞,但是有一个问题就是应用层调用接口发送数据后,没法知道这条数据是否发送成功。

不知道楼主这个驱动状态机有没有继续完善,或者有更好的办法,可以一起讨论一下。

出0入4汤圆

14
发表于 2017-2-7 11:20:14 来自手机 | 只看该作者
mark 学习

出0入0汤圆

15
发表于 2018-1-19 22:29:41 | 只看该作者
收藏,,,os配合状态机视乎更好用

出0入0汤圆

16
发表于 2019-4-17 16:45:21 | 只看该作者
int 发表于 2016-10-23 21:51
最近一直也在研究裸机下的GPRS驱动,大概思路和楼主类似,就是把GPRS驱动状态机放在超级循环里,状态机建 ...

os下:
状态机运行在一个单独的线程中,应用层调用接口发送数据后,阻塞等待信号;
状态机发送成功或失败后,发送信号给应用层;这样应用层就知道这条数据是否发送成功了。

裸机下,把状态机运行在定时器中断中,状态机发送成功后置标志位;
应用层调用接口发送数据后,查询该标志位;

出0入0汤圆

17
发表于 2019-4-17 17:01:59 | 只看该作者
标记一下 谢谢分享

出0入0汤圆

18
发表于 2019-4-24 13:17:40 | 只看该作者
wq_601840968 发表于 2019-4-17 16:45
os下:
状态机运行在一个单独的线程中,应用层调用接口发送数据后,阻塞等待信号;
状态机发送成功或失败 ...

有OS处理会方便很多。裸机的话,应用层调用接口发送数据后,没法知道这条数据是否发送成功,只能之后再查标志位或者阻塞查标志位了。
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-3-29 04:10

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表