小弟初次尝试写gprs状态机,烦请坛友们留步帮忙看看
小弟一直在学习状态机,无奈状态机太高深到现在还没入门,马上就要毕业了现在开始整毕业设计,于是乎就尝试用状态机来做毕业设计,下位机使用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;
} 你读取短信也用状态机吗 gprs状态机.标记! 启发甚大,昨晚还在准备吧GPRS部分的代码改成状态机的,也是一时半会儿没太好的思路。 好方法! gprs状态机.标记! 顶起,对于AT指令回复消息很好的处理方式,AT指令回复太乱不利于程序处理 用状态机还是不错的选择 MARK一下!!感觉你这个非常靠谱,我也打算写个类似的机制,写完以后更新上来 不错,可以参考下 学习了,看了一下代码,有下面一个问题。
楼主的思路是应用层将数据压入gprs.txBuf中,然后状态机负责发送。比如说,应用层第一次发送数据,此时网络状态不好,状态机停留在CHECK_SEND_DATA_STATUS,然后这时,应用层第二次发送数据,也压入gprs.txBuf中。然后当收到send ok时,状态机会把gprs.txBuf清空,这时gprs.txBuf里还有尚未发送的数据吧? int 发表于 2016-10-21 14:34
学习了,看了一下代码,有下面一个问题。
楼主的思路是应用层将数据压入gprs.txBuf中,然后状态机负责发送 ...
是的,异常处理做的不好,那是我刚学状态机的时候写的,现在再回来看,还是很多地方写的不好,比如你说的这个问题,就是一个很大的bug cyj_0220 发表于 2016-10-23 21:35
是的,异常处理做的不好,那是我刚学状态机的时候写的,现在再回来看,还是很多地方写的不好,比如你说的 ...
最近一直也在研究裸机下的GPRS驱动,大概思路和楼主类似,就是把GPRS驱动状态机放在超级循环里,状态机建立缓冲,自行处理多条发送的问题,然后应用层调用接口。
这样的好处就是不阻塞,但是有一个问题就是应用层调用接口发送数据后,没法知道这条数据是否发送成功。
不知道楼主这个驱动状态机有没有继续完善,或者有更好的办法,可以一起讨论一下。 mark 学习 收藏,,,os配合状态机视乎更好用 int 发表于 2016-10-23 21:51
最近一直也在研究裸机下的GPRS驱动,大概思路和楼主类似,就是把GPRS驱动状态机放在超级循环里,状态机建 ...
os下:
状态机运行在一个单独的线程中,应用层调用接口发送数据后,阻塞等待信号;
状态机发送成功或失败后,发送信号给应用层;这样应用层就知道这条数据是否发送成功了。
裸机下,把状态机运行在定时器中断中,状态机发送成功后置标志位;
应用层调用接口发送数据后,查询该标志位; 标记一下 谢谢分享 wq_601840968 发表于 2019-4-17 16:45
os下:
状态机运行在一个单独的线程中,应用层调用接口发送数据后,阻塞等待信号;
状态机发送成功或失败 ...
有OS处理会方便很多。裸机的话,应用层调用接口发送数据后,没法知道这条数据是否发送成功,只能之后再查标志位或者阻塞查标志位了。
页:
[1]