【C语言】自用AT框架效果和使用说明

代码

https://download.csdn.net/download/ylc0919/13606978

效果

这是一个项目中用到AT指令的部分:

/* 配置lora模块  */
void HandleLoraConfig(void)
{
 if(SYS_MAIN_FLAG&1<<5)
 {
  char cmd_buf1[64]={0};
  char cmd_buf2[64]={0};
  char cmd_buf3[64]={0};
  char cmd_buf4[64]={0};
  char cmd_buf5[64]={0};
  switch(lora_config_steps)
  {
   case 0:       //复位并打开AT脚(1ms阻塞)
    LORA_RESET=0;    //开始复位,延时20us以上
    clear_at_queue();   //清空AT队列
    lora_tick_num=0;   //复位计数
    timer_enable_flag|=1<<4; //使能lora计时器
    if(lora_tick_num)
    {
     LORA_RESET=1;   //复位完成
     LORA_AT=1;    //进入AT模式
     lora_config_steps=1; //进入下一步
    }
    break;
   case 1:       //将配置参数送入队列
    at_cmd_test();
    snprintf(cmd_buf1, 64, "AT+NET=%02x\r\n", lora_config.net);
    snprintf(cmd_buf2, 64, "AT+TFREQ=%08x\r\n", lora_config.tfreq);
    snprintf(cmd_buf3, 64, "AT+RFREQ=%08x\r\n", lora_config.rfreq);
    snprintf(cmd_buf4, 64, "AT+RXW=%02x\r\n", lora_config.rxw);
    snprintf(cmd_buf5, 64, "AT+AK=%s\r\n", lora_config.AES);
    //             atstr          len  type  retrynum   otime  noAck
    write_cmd_to_queue((u8*)cmd_buf1,strlen(cmd_buf1), 3,  5,  100, 0);  //设置通信模式
    write_cmd_to_queue((u8*)cmd_buf2,strlen(cmd_buf2), 4,  5,  100, 0);  //设置发送频点
    write_cmd_to_queue((u8*)cmd_buf3,strlen(cmd_buf3), 5,  5,  100, 0);  //设置接收频点
    write_cmd_to_queue((u8*)"AT+RIQ=00\r\n", 11,  6,  5,  100, 0);  //关闭接收反转,暂不支持修改
    write_cmd_to_queue((u8*)"AT+TIQ=00\r\n", 11,  7,  5,  100, 0);  //关闭发送反转,暂不支持修改
    write_cmd_to_queue((u8*)"AT+LCP=FFFF\r\n", 13,  8,  5,  100, 0);  //长期休眠,暂不支持修改
    write_cmd_to_queue((u8*)cmd_buf4,strlen(cmd_buf4), 9,  5,  100, 0);  //接收窗口时间
    write_cmd_to_queue((u8*)cmd_buf5,strlen(cmd_buf5), 10,  5,  100, 0);  //AES加密
    write_cmd_to_queue((u8*)"AT+ID?\r\n",  8,  11,  5,  100, 0);  //获取设备ID
    lora_config_steps=2;  //进入下一步
    break;
   case 2:       //执行读队列发送(一直执行,直到接收处理函数中跳入下一步)
    if(lora_tick_num>=10)  //每10ms执行一次
    {
     lora_tick_num=0;
     read_cmd_queue_and_send();
    }
    break;
   default:      //执行完毕,关闭AT,进入透传模式,清除标记
    LORA_AT=0;
    lora_config_steps=0;
    timer_enable_flag&=~(1<<4);
    SYS_MAIN_FLAG&=~(1<<5);
    break;
  }
 }
}

可以看到在步骤1中将需要用到的命令,通过写队列函数写进去,然后在循环中不断执行读队列发送命令函数就行,简单实用。

使用说明

写队列函数

函数原型:

void write_cmd_to_queue(u8 *atstr,	//命令缓存地址
			u16 len,	//命令长度
			u8 type,	//命令标识
			u8 retryNum,	//重发次数
			u16 otime,	//AT指令一次发送超时时间计数
			u16 noAckOtime);//一条AT指令总超时时间计数

接像上面示例那样将AT指令填进去就可以,需要注意的是:

1.如果otime为0,则retryNum无意义。

2.如果otime和noAckOtime都为0,则没有超时处理。

3.type需要大于2,且每个指令对应一个type,用于AT指令的回复与超时处理。至于为什么要大于2,下面再说。

读队列与发送函数

函数原型:void read_cmd_queue_and_send(void);函数比较长,就不贴出来了。

该函数读队列并发送AT命令,包括了超时处理。建议每10ms调用一次,调用时间间隔为超时计数时间间隔,超时时间=调用间隔*超时计数。

其中需要修改的地方有两个发送函数及三个超时处理:

1.两个发送函数,代码中我用了HAL库的串口发送函数

HAL_UART_Transmit(&huart3, 
		(uint8_t *)at_queue.txbuf,//读到的命令
		at_queue.cmd.len, 	//读到的命令长度
		0xffff);//串口,以阻塞模式发送

移植时只需要找到这两个函数,把他们换成自己的发送函数就行。

2.三个超时处理,分别是有重发次数的超时处理,无重发次数的超时处理,总超时处理,不一定全部用到,需要用哪个就改哪个,不需要用的保持原样即可,具体位置代码中都有注释。

测试与模块判断函数

函数如下:

/*测试模块是否正常*/
void at_cmd_test(void)
{ //             atstr       len  type  retrynum   otime  noAck
 write_cmd_to_queue("AT\r\n",  4,  1,  30,  100, 0);
 write_cmd_to_queue("ATI\r\n",  5,  2,  5,  100, 0);
}

如上面示例一样,在开始先将AT和ATI送入队列,如果连AT都没有回复,那么也没必要继续往下执行了,ATI用于判断是什么模块。

AT接收处理函数

void at_recv_proc(u8 *buf,u16 len)
{
 char *p;
 p=(char*)buf;
 if(at_queue.cmd.type==1)        //AT  
 {
  if((strstr(p,"AT\r\n"))||(strstr(p,"\r\nOK\r\n")))
  {
   at_flag&=~(1<<0);
  }
 }
 else if(at_queue.cmd.type==2)       //ATI
 {
  if(strstr(p,"EC600S"))        //可以根据版本信息不同,在此处执行对应初始化函数
  {  
   at_flag&=~(1<<0);
   at_queue.modType=MOD_EC600S;
  }
  else if(strstr(p,"+ATI:"))
  {
   at_flag&=~(1<<0);
   at_queue.modType=MOD_LORA;
  }
 }
 else{             //得到版本信息后,在此处执行对应的处理程序
  switch(at_queue.modType)
  {
   case MOD_EC600S:
//    ec600RxProc(buf,len);
    break;
   case MOD_LORA:
    lora_recv_proc(buf,len);
    break;
   default:break;
  }
 }
}

该函数处理了at_cmd_test()函数的两个命令,并根据ATI命令收到的回复判断模块类型,调用相应模块的AT接收处理。该函数在串口接收处理中调用。

当然,如果只针对一个模块,完全可以忽略此函数,直接在串口接收处理中调用对应模块的AT处理函数,以下是上面示例对应的接收处理:

/*lora模块接收处理*/
void lora_recv_proc(u8 *buf,u16 len) 
{
 char *p,*q=NULL;
 u8 i=0;
 p=(char*)buf;
 /*一般情况*/
 switch(at_queue.cmd.type)      
 {
  case 3:if(strstr(p,"OK"))     //设置通信模式
   at_flag&=~(1<<0);
   break;
  case 4:if(strstr(p,"OK"))     //设置发送频点
   at_flag&=~(1<<0);
   break;
  case 5:if(strstr(p,"OK"))     //设置接收频点
   at_flag&=~(1<<0);
   break;
  case 6:if(strstr(p,"OK"))     //关闭接收反转
   at_flag&=~(1<<0);
   break;
  case 7:if(strstr(p,"OK"))     //关闭发送反转
   at_flag&=~(1<<0);
   break;
  case 8:if(strstr(p,"OK"))     //长期休眠
   at_flag&=~(1<<0);
   break;
  case 9:if(strstr(p,"OK"))     //接收窗口时间
   at_flag&=~(1<<0);
   break;
  case 10:if(strstr(p,"OK"))     //AES加密
   at_flag&=~(1<<0);
   break;
  case 11:q=strstr(p,"+ID:");     //ID 16个16进制数字
   if(q)
   {
    at_flag&=~(1<<0);
    q=q+4;
    for(i=0;i<16;i++)
    {
     mSystem.loraID[i]=*q;
     q++;
    }
    lora_config_steps=3;    //最后一条指令处理完进入下一步
   }
   break;  
  default:break;
 }
  /*特殊情况:无*/
}
  • 4
    点赞
  • 9
    收藏
  • 打赏
    打赏
  • 17
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:游动-白 设计师:我叫白小胖 返回首页
评论 17

打赏作者

游楽场

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值