物联网实战--驱动篇之(六)4G通讯(Air780E)

[复制链接]
发表于 2026-2-1 18:24:11 | 显示全部楼层 |阅读模式
目次
一、4G模块简介
二、AIR780E驱动步调
三、AIR780使用注意事项
四、团结MQTT传输测试

 本项目标互换QQ群:701889554
物联网物联网实战--入门篇https://blog.csdn.net/ypp240124016/category_12609773.html
物联网物联网实战--驱动篇https://blog.csdn.net/ypp240124016/category_12631333.html
物联网物联网实战--平台篇https://blog.csdn.net/ypp240124016/category_12653350.html
端点物联开辟教程 https://blog.csdn.net/ypp240124016/category_12696766.html
一、4G模块简介

        4G应该是我们一样寻常生存最常见的一种互联网通讯方式了,每个智能手机都设置了,不外手机的4G跟我们物联网范畴要用的4G有点区别。起首是物联网接纳模块化4G,手机是CPU内部直接集成了4G基带,技能水平肯定高很多了;其次是网速,手机为了满意一样寻常看视频的需求,速率比力快,理论下载速率是150M,接纳CAT4标准;而我们要用的物联网4G模块接纳CAT1标准,下载速率10M左右,从资本和需求上来讲比力恰当。
        基于CAT1标准的4G模组没出来之前,4G模块一样寻常是作为网关与服务器的通讯链路,由于资本比力高,一个都要150左右;厥后基于CAT1的4G模块出来子女价来到了60元左右,随着用量的增长以及技能的更新,资本在不绝地低落,前两年AIR720差不多40元左右,现在我们的测试型号AIR780E单纯模组TB代价也就差不多20块左右。就这4G资本,用在装备端作为通讯链路应该没什么标题了,比如充电宝、共享单车、按摩椅等等,而且AIR780E尚有肯定的低功耗水平,根据手册(现在还没测试过),极致低功耗可以到达2uA,已经差不多SX1278的水平了。
        总体来讲,基于CAT1的4G模组可以满意绝大多数的应用需求,以是须要好好学习,我们这里以合宙的AIR780E为例,写个驱动步调。


二、AIR780E驱动步调

        AIR780的驱动跟之前的esp8266 WiFi驱动很雷同,可以参考。物联网实战--入门篇之(六)嵌入式-WIFI驱动(ESP8266)-CSDN博客     
以及AT指令手册Luat社区  
        起首来相识下4G模块的入网流程,模块上电后起首会举行网络注册,就是看下有没有信号了,这时间属于基站跟4G模组底层之间的事变,有没有4G卡临时不影响;第二步就是PDP上下文移动场景创建,简朴明白就是创建一个可以用于互联网通讯的身份,这时间须要你的4G模组里有可用的4G卡;第三步是网络附着,4G模组和基站相互互换认证信息,只有附着了网络,后续才气分配IP地点,举行网络通讯。到这一步为止,只要你的卡能用,每个步调都是自动完成的,驱动步调只要隔断几秒查询下各个步调的实行环境就行了。
        接下来就是设置一些网络参数了,比如多路毗连、快发模式和APN,这里的APN相称于VIP品级了,跟开的卡有关系,有的卡保密品级比力高,会有专门的APN账户暗码,寻常卡就默认就行了。
        剩下就是末了一步,激活移动场景,获取IP地点就行了,别的网络毗连部分跟esp8266是一样的,对于4G模组一样寻常不作为服务端的,以是不必关系服务端的标题,都是作为客户端毗连。接下来先重新文件开始:
       
         根本上都有解释了,AIR780E支持6个客户端毗连,根本够用了。状态值就是刚才分析的那些了,入网乐成后就可以举行毗连使用了。客户端的界说跟esp8266的一样,团体工作的布局体有些区别,起首这里少了服务器干系的内容,其次是多了信号强度、模块序列号IMEI、卡号ICCID和定位信息,此中定位信息其他型号的4G模组不肯定有,这个型号有的,我们紧张接纳了经纬度和海拔,其他临时忽略。
        下面紧张看下注册流程和罗致处理处罚,代码如下:
  1. /*               
  2. ================================================================================
  3. 描述 : 网络注册函数
  4. 输入 :
  5. 输出 :
  6. ================================================================================
  7. */
  8. void drv_air780_reg_process(void)
  9. {
  10.         static u32 last_sec_time=0, wait_time=2;
  11. //  static char cmd_buff[100]={0};
  12.         u32 now_sec_time=drv_get_sec_counter();
  13.         if(now_sec_time-last_sec_time>wait_time)
  14.         {
  15.                 switch(g_sAir780Work.state)
  16.                 {
  17.                         case AIR780_STATE_START:
  18.                         {
  19.                                 drv_air780_uart_send("ATE0\r\n");
  20.                                 delay_os(200);         
  21.         
  22.         drv_air780_send_at("RESET");//复位模块        
  23.                                 g_sAir780Work.state=AIR780_STAT_INIT;               
  24.         wait_time=5;                       
  25.                                 break;
  26.                         }
  27.                         case AIR780_STAT_INIT:
  28.                         {
  29.                                 drv_air780_uart_send("ATE0\r\n");
  30.                                 delay_os(200);     
  31.         drv_air780_send_at("CSQ");//查询信号强度
  32.                                 delay_os(200);     
  33.         drv_air780_send_at("CGNSPWR=1");//打开GPS      
  34.                                 delay_os(200);     
  35.         drv_air780_send_at("CGNSAID=31,1,1,1");//使能位置辅助定位           
  36.         g_sAir780Work.state=AIR780_STAT_CGREG;
  37.                                 break;
  38.                         }         
  39.                         case AIR780_STAT_CGREG://查询网络注册状态
  40.                         {
  41.         drv_air780_send_at("CGREG?");//查询网络连接信息
  42.                                 wait_time=3;
  43.         break;
  44.                         }
  45.                         case AIR780_STAT_CGACT://查询PDP状态
  46.                         {
  47.         drv_air780_send_at("CGACT?");//查询网络连接信息
  48.                                 wait_time=3;
  49.         break;
  50.                         }      
  51.                         case AIR780_STAT_CGATT0://查询附着状态
  52.                         {
  53.         drv_air780_send_at("CGATT?");//查询网络连接信息
  54.                                 wait_time=3;
  55.         break;
  56.                         }   
  57.                         case AIR780_STAT_CGATT1://已附着
  58.                         {
  59.         drv_air780_send_at("CIPMUX=1");//多路连接
  60.         delay_os(200);
  61.         drv_air780_send_at("CIPQSEND=0");//快发模式
  62.         delay_os(200);
  63.         drv_air780_send_at("CSTT");//设置APN      ="cmnet","",""     
  64.                                 wait_time=2;
  65.         g_sAir780Work.state=AIR780_STAT_CIICR;
  66.         break;
  67.                         }   
  68.                         case AIR780_STAT_CIICR:
  69.                         {
  70.         drv_air780_send_at("CIICR");////激活移动场景,获取IP地址
  71.         delay_os(1000);
  72.         drv_air780_send_at("CIFSR");//查询IP地址           
  73.         g_sAir780Work.state=AIR780_STAT_OK;
  74.                                 wait_time=3;
  75.         break;
  76.                         }   
  77.                         case AIR780_STAT_OK://入网成功
  78.                         {
  79.         static u8 counts=0;
  80.         if(counts++%2==0)
  81.         {
  82.           if(g_sAir780Work.imei_buff[0]==0)
  83.           {
  84.             drv_air780_send_at("CGSN");
  85.           }
  86.           else if(g_sAir780Work.iccid_buff[0]==0)
  87.           {
  88.             drv_air780_send_at("ICCID");
  89.           }
  90.           else
  91.           {
  92.             static u8 flag=0;
  93.             if(flag++%2==0)
  94.             {
  95.               drv_air780_send_at("CSQ");//查询信号强度
  96.             }
  97.             else
  98.             {
  99.               drv_air780_send_at("CGNSINF");//查询GPS信息
  100.             }
  101.           }
  102.          
  103.         }
  104.         else
  105.         {
  106.           drv_air780_connect_process();
  107.         }
  108.                                 wait_time=3;
  109.         break;
  110.                         }         
  111.                 }
  112.                 last_sec_time=drv_get_sec_counter();
  113.         }
  114. }
复制代码
           在起始状态下我们直接复位了模块,如许可以克制与之前的状态辩说,这个模块的启动速率很快,2~3秒就完成了;在初始化阶段,把回显关掉,克制影响罗致剖析,同时打开定位的干系功能,定位功能要几十秒以致几分钟才气有效果,而且最好天线要靠窗户边大概户外才行;接下去几步都是查询状态,罗致处理处罚等等,这里先跳到入网乐成后的状态。分别分时举行了网络毗连、哀求IMEI、哀求ICCID、查询信号强度和查询定位信息等任务,此中IMEI和ICCID只要哀求到后就不再重复实行了,剩下就是信号强度和定位信息不绝更新。
        接下来是罗致处理处罚的代码:
  1. /*               
  2. ================================================================================
  3. 描述 : 接收处理
  4. 输入 :
  5. 输出 :
  6. ================================================================================
  7. */
  8. void drv_air780_recv_process(void)
  9. {
  10.         u16 recv_len;
  11.         char *pData=NULL;
  12.        
  13.         if(g_sAir780Work.pUART->iRecv>0)
  14.         {
  15.                 recv_len=0;
  16.                 while(recv_len<g_sAir780Work.pUART->iRecv)
  17.                 {
  18.                         recv_len=g_sAir780Work.pUART->iRecv;
  19.                         delay_ms(5);
  20.                 }
  21.                 char *pBuff=(char*)g_sAir780Work.pUART->pBuff;
  22.                 printf("air780 recv=%s\n", g_sAir780Work.pUART->pBuff);
  23.                 if( (pData=strstr(pBuff, "+RECEIVE,"))!=NULL )//接收到数据
  24.                 {
  25.       pData=pBuff;
  26.       while((pData=strstr(pData, "+RECEIVE,"))!=NULL)
  27.       {
  28.         pData+=strlen("+RECEIVE,");
  29.         u8 sock_id=atoi(pData);
  30. //        printf("sock_id=%d\n", sock_id);
  31.         if(sock_id<AIR780_MAX_LINK_NUM && (pData=strstr(pData, ","))!=NULL )
  32.         {
  33.           pData+=1;
  34.           u16 data_len=atoi(pData);
  35.           if( (pData=strstr(pData, ":"))!=NULL )
  36.           {
  37.             pData+=3;//: 0D 0A
  38.             g_sAir780Work.client_list[sock_id].keep_time=drv_get_sec_counter();
  39.             printf_hex("air780 data buff= ", (u8*)pData, data_len);
  40.             if(g_sAir780Work.fun_recv_parse!=NULL)
  41.             {
  42.               g_sAir780Work.fun_recv_parse(sock_id, (u8*)pData, data_len);//接收处理
  43.             }
  44.             pData+=data_len;
  45.           }
  46.         }                        
  47.       }
  48.        
  49.                 }               
  50.     else if( (pData=strstr(pBuff, "+CSQ: "))!=NULL )//信号强度
  51.     {
  52.       pData+=strlen("+CSQ: ");
  53.       g_sAir780Work.rssi=atoi(pData);
  54.       printf("***rssi=%d\n", g_sAir780Work.rssi);
  55.     }
  56.     else if( (pData=strstr(pBuff, "+CGNSINF:"))!=NULL )//定位信息
  57.     {
  58.       pData+=strlen("+CGNSINF:");
  59. //      printf("GPS=%s", pBuff);
  60.       for(u8 i=0; i<5; i++)
  61.       {
  62.         if( (pData=strstr(pData, ","))!=NULL )
  63.         {
  64.           pData+=1;
  65.           switch(i)
  66.           {
  67.             case 2:
  68.             {
  69.               g_sAir780Work.deg_sn=atof(pData);//纬度
  70.               break;
  71.             }
  72.             case 3:
  73.             {
  74.               g_sAir780Work.deg_we=atof(pData);//经度
  75.               break;
  76.             }   
  77.             case 4:
  78.             {
  79.               g_sAir780Work.hight=atof(pData);//海拔
  80.               break;
  81.             }            
  82.           }
  83.         }
  84.         else
  85.         {
  86.           break;
  87.         }
  88.       }
  89.       printf("GPS: WE=%.3f deg, SN=%.3f deg, H=%.3f m\n", g_sAir780Work.deg_we, g_sAir780Work.deg_sn, g_sAir780Work.hight);
  90.     }   
  91.                 else if((pData=strstr((char*)pBuff, "+CGEV: "))!=NULL)//PDP变化
  92.                 {
  93.                         pData+=strlen("+CGEV: ");
  94.                         if(strstr(pData, "DEACT")!=NULL)//移动场景去活
  95.                         {
  96.                                                
  97.         drv_air780_send_at("CIPSHUT");//去激活
  98.                                 delay_os(100);
  99.                                 g_sAir780Work.state=AIR780_STATE_START;
  100.                                 printf("===RDY net_state=AIR780_STATE_START\n");                       
  101.                         }
  102.                         else if(strstr(pData, "ACT")!=NULL)//移动场景激活
  103.                         {
  104.                                 if(g_sAir780Work.state==AIR780_STAT_CIICR)
  105.                                 {
  106.                                         g_sAir780Work.state=AIR780_STAT_OK;
  107.                                 }
  108.                         }                                               
  109.                 }            
  110.                 else if((pData=strstr((char*)pBuff, "+CGREG:"))!=NULL)//注册查询
  111.                 {
  112.                         pData+=strlen("+CGREG:");
  113.                         if((pData=strstr((char*)pBuff, ",1"))!=NULL || (pData=strstr((char*)pBuff, ",5"))!=NULL)//注册成功
  114.                         {
  115.                                 g_sAir780Work.state=AIR780_STAT_CGACT;
  116.                                 printf("=== +CGREG:1\n");
  117.                         }
  118.                 }                       
  119.                 else if((pData=strstr((char*)pBuff, "+CGACT: "))!=NULL && (pData=strstr((char*)pBuff, ",1"))!=NULL)//PDP查询
  120.                 {
  121.                         g_sAir780Work.state=AIR780_STAT_CGATT0;
  122.                         printf("=== AIR780_STAT_CGATT0\n");
  123.                 }
  124.                 else if((pData=strstr((char*)pBuff, "+CGATT: 1"))!=NULL)//附着查询
  125.                 {
  126.                         g_sAir780Work.state=AIR780_STAT_CGATT1;
  127.                         printf("=== +CGATT: 1\n");
  128.                 }            
  129.                 else if((pData=strstr((char*)pBuff, ", CONNECT OK"))!=NULL)//连接检测  || (pData=strstr((char*)pBuff, ", ALREADY CONNECT"))!=NULL
  130.                 {
  131.                         u8 sock_id=0;
  132.                         pData--;
  133.                         printf("### pData=%s\n", pData);
  134.                         if(pData[0]>='0' && pData[0]<='9')
  135.                         {
  136.                                 sock_id=pData[0]-'0';
  137.                                 printf("=== air780 sock_id=%d connect ok!\n", sock_id);
  138.                                 if(sock_id<AIR780_MAX_LINK_NUM)
  139.                                 {
  140.                                         g_sAir780Work.client_list[sock_id].conn_state=true;
  141.                                         g_sAir780Work.client_list[sock_id].keep_time=drv_get_sec_counter();
  142.                                 }
  143.                         }
  144.                        
  145.                 }               
  146.                 else if((pData=strstr((char*)pBuff, ",CLOSE OK"))!=NULL)//关闭
  147.                 {
  148.                         u8 sock_id=0;
  149.                         pData--;
  150.                         if(pData[0]>='0' && pData[0]<='9')
  151.                         {
  152.                                 sock_id=pData[0]-'0';
  153.                                 printf("=== sock_id=%d close ok!\n", sock_id);
  154.                                 if(sock_id<AIR780_MAX_LINK_NUM)
  155.                                 {
  156.                                         g_sAir780Work.client_list[sock_id].conn_state=false;
  157.                                 }
  158.                         }
  159.                 }               
  160.                 else if((pData=strstr((char*)pBuff, "+PDP: DEACT"))!=NULL)//PDP失效
  161.                 {               
  162.       drv_air780_send_at("CIPSHUT");//去激活
  163.                         delay_os(100);
  164.                         g_sAir780Work.state=AIR780_STATE_START;
  165.                         printf("===RDY net_state=AIR780_STATE_START\n");                       
  166.                 }         
  167.                 else if(pBuff[2]>='0' && pBuff[2]<='9' && g_sAir780Work.imei_buff[0]==0)//IMEI检测
  168.                 {
  169.                         bool is_number=true;
  170.                         pBuff+=2;
  171.                         for(u8 i=0; i<15; i++)
  172.                         {
  173.                                 if(pBuff[i]<'0' || pBuff[i]>'9')
  174.                                 {
  175.                                         is_number=false;
  176.                                         break;
  177.                                 }
  178.                         }
  179.                         if(is_number==true)
  180.                         {
  181.                                 memset(g_sAir780Work.imei_buff, 0, sizeof(g_sAir780Work.imei_buff));
  182.                                 memcpy(g_sAir780Work.imei_buff, pBuff, 15);
  183.                                 printf("imei=%s\n", g_sAir780Work.imei_buff);
  184.                         }
  185.                 }
  186.                 else if((pData=strstr((char*)pBuff, "+ICCID: "))!=NULL)//ICCID检测
  187.                 {
  188.                         pData+=strlen("+ICCID: ");
  189.                         memset(g_sAir780Work.iccid_buff, 0, sizeof(g_sAir780Work.iccid_buff));
  190.                         memcpy(g_sAir780Work.iccid_buff, pData, 20);
  191.                         printf("iccid=%s\n", g_sAir780Work.iccid_buff);
  192.                 }   
  193.                 UART_Clear(g_sAir780Work.pUART);
  194.         }
  195. }
复制代码
        罗致处理处罚的根本思绪是根据AT指令返回的关键字举行匹配,得到对应动作的状态值并剖析。这里要注意的点是,数据罗致"+RECEIVE,"要放在第一个,如许才不会被数据区的内容干扰;定位信息要根据AT指令手册去对应剖析,我们只获取了经度、纬度和海拔3个信息,有须要详细的自行添加;尚有一个比力紧张的场景去激活,简朴讲就是信号比力差,4G模组跟基站临时断开了,这时间是须要重新走一遍流程注册的,以是这个状态要检测,否则数据发送和网络毗连都会发生错误的,在产物应用的时间如果忽略这个标题那么很大概导致的效果是大面积失联,客户投诉,市场丢失等标题,这个变乱在一些共享充电宝厂商身上发生过的。
        别的也没有什么大标题了,模块的功能很丰富,我们这里只是根本应用,有须要可以根据AT指令手册自己扩展,剩下的就是回调函数注册、初始化等通例使用了。
  
三、AIR780使用注意事项

        最根本的是天线要插,而且要4G的,不要433M的天线插一根,没啥用的,很多胶棒天线长得都一样,自己要记得标识;然后就是4G卡的标题,很多物联网卡是专用的,不能放在手机使用,不能换装备使用,跟第一个4G模块是绑定的,换装备是不能用的,须要接洽开卡的客户司理清除绑定,这么做紧张是怕卡被拿去非法使用。
        电源标题也是容易被忽略的,模块在网络注册的时间峰值电流比力大,如果电源芯片功率不敷的话会导致模块不绝重启,在电路操持的时间要严格对照手册举行。
        我这里使用的是串口2举行驱动,自己接线要注意,PA2接模块的RX,PA3接模块的TX,我购买的模块供电是5V的,接线就是5V-TX-RX-GND 4根线就行了,很简朴,详细购买链接如下,可作参考。https://item.taobao.com/item.htm?_u=apfmfmg56fd&id=720428359893&spm=a1z09.2.0.0.20d42e8dQqVw5W&skuId=5332410429413

        


四、团结MQTT传输测试

        之前的净化器项目是用WiFi作为网络链路的,我们现在改成4G,使用很简朴,这也是为什么我们要模块化封装驱动步调的缘故起因,分级分层,现实做项目标时间根据用户需求随时可以切换方案,维护起来不容易堕落,下面看下代码,只要改几行就富足了。      ​​​

        就是把app_mqtt.c文件中的WIFI参数设置改成4G的设置就行了,4G的设置更为简朴,不要账户暗码什么的。这里由于4G模块必须毗连互联网,以是MQTT的服务器用EMQ官方的测试服务器,域名是broker.emqx.io,端口1883,MQTT账户暗码任意设置一个就行了,服务器不做查抄。用户端我们就不消手机了,直接用客户端工具看下有没有数据发过来就行了。


        很显着这些数据就是从装备端发送出来的。

        4G模组AIR780E的驱动步调临时就这些了,驱动代码在这里下载:https://download.csdn.net/download/ypp240124016/89110607

        本人的别的文章导航地点:端点物联网学习资源合集-CSDN博客 
        学习互换QQ群:  701889554





本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表