最近开始要做物联网的一个设备,由于是外用就考虑到了Arduino UNO小板跟4G模块,后面淘宝找到了一款已用的4G模块-墨子号BC26(注意:不是打广告哦),由于4G模块都是At命令操作的,跟Arduino UNO对接使用有些不方便使用,所以封装成了一个Arduino的c++类,很简单,但是也遇到一些奇葩问题,发到csdn,做个备注!
我的c++基础不是很好,有什么地方可以优化内存的,欢迎各位大佬指出!

Audrion 主类:

#include "BC26Socket.h"int socketId = 1;
int socketPort = 8888;
String socketHost = "47.92.146.210";
Socket socket;
SoftwareSerial socketSerial = SoftwareSerial(A0, A1); // arduino与bc26通讯的串口
boolean isCreateConnect = false; // 是否创建连接成功
boolean isConnect = false; // 是否连接到服务器
boolean isConnectNetWork = false; // 是否连接到网络
long connectTime = 0L; // 开始连接时间
long lastSendHeartbeatTime = 0L; // 最后发送心跳包时间
long lastHeartbeatTime = 0L; // 最后接收到心跳时间void socketConnect(); // socket连成功监听
void socketClose(); // socket断开监听
void socketMessage(String msg, int length); // socket消息监听
void sendHeartbeat(); // 发送心跳检测
void checkConnect(); // 检测连接
void checkHeartbeat(); // 检测心跳const char* Heartbeat = "hb"; // 心跳void setup() {Serial.begin(9600);socketSerial.begin(9600);socketSerial.setTimeout(100); // 设置每次读取间隔时间 , socket采用readString方法进行读取数据socket.initSocket(socketId, socketHost, socketPort, &socketSerial);socket.addSocketConnectListener(socketConnect);socket.addSocketCloseListener(socketClose);socket.addSocketMessageListener(socketMessage);socket.setLocalPort(6666);socket.seeIpAt();
}void loop() {if (!isConnectNetWork) {// 如果未连接到网络 继续监测网络状态isConnectNetWork = socket.checkNetWork();if (isConnectNetWork) {Serial.println("netWork OK");} else {Serial.println("netWork Error");delay(1000);}} else {if (!isCreateConnect) { // 如果没有成功创建socketSerial.println("start  connect");socket.close();socket.connect();connectTime = millis();isCreateConnect = true;if (isCreateConnect) {Serial.println("socket success");} else {Serial.println("socket error");delay(1000);}} else {socket.loopSocket();checkConnect();checkHeartbeat();sendHeartbeat();String command = Serial.readString();if (!command.equals("")) {Serial.println("client:");Serial.println(command);socket.send(command);}}}
}void sendHeartbeat() {if (isConnect && millis() - lastSendHeartbeatTime >= 1000L * 30) { // 如果连接成功 并且30秒内没有发送心跳包lastSendHeartbeatTime = millis();socket.send(Heartbeat);}
}void checkHeartbeat() {if (isConnect && millis() - lastHeartbeatTime > 1000L * 60) { // 如果一分钟未接收到心跳,断开重连Serial.println("heartbeat time out");socketClose();}
}// 检测连接
void checkConnect() {if (!isConnect && millis() - connectTime > 1000L * 10) { // 如果未连接成功 10秒等待检测Serial.println("time out");socketClose();}
}// socket连成功监听 该方法不知道为啥有些时候不会进入,可自行使用心跳机制完善
void socketConnect() {isConnect = true;lastHeartbeatTime = millis();Serial.println("connect success");
}// socket断开监听
void socketClose() {isConnect = false;isCreateConnect = false;isConnectNetWork = false;Serial.println("connect close");
}// socket消息监听
void socketMessage(String msg, int length) {Serial.print("server:");Serial.println(length);Serial.println(msg);if (msg.length() == length) {if (msg.equals(Heartbeat)) {lastHeartbeatTime = millis();}}
}

4G BC26封装.h文件

#include <SoftwareSerial.h>
#include <Arduino.h>class Socket {public :void initSocket(int socketId, String host, int port, SoftwareSerial *serial); // 初始化socketvoid addSocketConnectListener(void(*socketConnectListener)()); // 添加socket连接成功回调void addSocketCloseListener(void(*socketCloseListener)()); // 添加socket断开连接回调void addSocketMessageListener(void(*socketMessageListener)(String,int)); // 添加socket消息回调void setLocalPort(int localPort); // 设置socket本地接收端口void useUDP(); // 设置使用udpvoid useTCP(); // 设置使用tcpvoid useIPV4(); // 使用ipv4void useIPV6(); // 使用ipv6void testAT(); // 测试AT指令void seeIpAt(); // 查看ip AT指令void loopSocket(); // 轮询socket消息boolean connect(); // 开始建立连接socketboolean checkNetWork(); // 检测是否连接到网络boolean close(); // 关闭socketboolean send(String msg); // 发送消息private:boolean connectBC26(); // 开始连接bc26boolean analysisBC26(String *types, int typesLength); // 解析bc26消息void readBC26(); // 读取bc26void sendBC26(String command); // 发送命令到bc26private :int mSocketId; // socket通道idint mPort; // socket连接端口int mLocalPort = 0; // socket本地接收端口 0:bc26自动选择int mAccessMode = 1; // 0:buff模式需要手动去读取 1:push模式主动推送(现在主要使用该方式)int mProtocolType = 0; // 0:IPV4 1:IPV6int mReadLength = 0; // 读取到的数据的有效长度String mServiceType = String("TCP"); // 连接方式 "TCP","UDP"String mHost; // socket连接地址String mReadDoc[5]; //保存读取到的数据SoftwareSerial *mSerial = NULL;void(*connectListener)(); // 添加socket连接成功回调void(*closeListener)(); // 添加socket断开连接回调void(*messageListener)(String,int); // 添加socket消息回调
};

4G BC26封装.cpp实现文件

#include "BC26Socket.h"// 初始化 socket 连接信息
void Socket::initSocket(int socketId, String host, int port, SoftwareSerial *serial) {mSocketId = socketId;mHost = host;mPort = port;mSerial = serial;
}// 添加socket连接成功回调
void Socket::addSocketConnectListener(void(*socketConnectListener)()) {connectListener = socketConnectListener;
}// 添加socket断开连接回调
void Socket::addSocketCloseListener(void(*socketCloseListener)()) {closeListener = socketCloseListener;
}// 添加socket消息回调
void Socket::addSocketMessageListener(void(*socketMessageListener)(String, int)) {messageListener = socketMessageListener;
}void Socket::setLocalPort(int localPort) {mLocalPort = localPort;
}void Socket::useUDP() {mServiceType = String("TCP");
}void Socket::useTCP() {mServiceType = String("TCP");
}void Socket::useIPV4() {mProtocolType = 0;
}void Socket::useIPV6() {mProtocolType = 1;
}void Socket::testAT() {sendBC26("AT");delay(300);readBC26();analysisBC26(NULL, 0);
}void Socket::seeIpAt() {sendBC26("AT+CGPADDR");delay(300);readBC26();analysisBC26(NULL, 0);
}// 轮询socket消息
void Socket::loopSocket() {readBC26();analysisBC26(NULL, 0);
}// 检测网络状态
boolean Socket::checkNetWork() {sendBC26("AT+CGATT?");delay(300);readBC26();String types[] = {"+CGATT: 1"};return analysisBC26(types, 1);
}// 开始建立连接socket
boolean Socket::connect() {if (mHost == NULL || mHost.length() == 0) {Serial.println("error1");return false;}if (mSerial == NULL) {Serial.println("error2");return false;}return connectBC26();
}// 开始连接bc26
boolean Socket::connectBC26() {String command = "AT+QIOPEN=1,";command += mSocketId;command += ",\"";command += mServiceType;command += "\",\"";command += mHost;command += "\",";command += mPort;command += ",";command += mLocalPort;command += ",";command += mAccessMode;command += ",";command += mProtocolType;sendBC26(command);command = "";delay(300);readBC26();String types[1] = {"OK"};return analysisBC26(types, 1);
}// 关闭socket
boolean Socket::close() {String command = "AT+QICLOSE=";command += mSocketId;sendBC26(command);command = "";delay(300);readBC26();String types[1] = {"CLOSE OK"};return analysisBC26(types, 1);
}// 发送消息
boolean Socket::send(String msg) {String command = "AT+QISEND=";command += mSocketId;command += ",";command += msg.length();command += ",";command += msg;sendBC26(command);command = "";delay(300);readBC26();String types[1] = {"SEND OK"};return analysisBC26(types, 1);
}// 发送命令到bc26
void Socket::sendBC26(String command) {mSerial->println(command);//  Serial.println("+ send:");
//  Serial.println(command);
}// 读取bc26
void Socket::readBC26() {String command2 = mSerial->readString();mReadLength = 0;if (!command2.equals("")) {//    Serial.println("返回数据:");command2.replace("\r\n", "|");//    Serial.println(command2);do {int indexof = command2.indexOf("|");if (indexof == -1) {if (command2.length() > 0) {mReadDoc[mReadLength] = command2;mReadLength++;command2 = "";}} else {String str = command2.substring(0, indexof);if (str.length() > 0) {mReadDoc[mReadLength] = str;mReadLength++;str = "";}command2 = command2.substring(indexof + 1, command2.length());}} while (command2.length() > 0);//    command2 = "";//    if (mReadLength > 0) {//      Serial.print("- receive:");//      Serial.print(mReadLength);//      Serial.println("):");//      Serial.print("\t");//      for (int i = 0; i < mReadLength; i++) {//        Serial.print("|");//        Serial.print(mReadDoc[i]);//      }//    }//    Serial.println();}
}// 解析bc26消息
boolean Socket::analysisBC26(String *types, int typesLen) {int haveSize = 0;for (int i = 0; i < mReadLength; i++) {String type = mReadDoc[i];for (int s = 0; s < typesLen; s++) {String item = types[s];if (type.equals(item)) {haveSize++;}}if (type.startsWith("+")) {String types = type;types.trim();types.replace(" ", "");//      Serial.println("get+:" + types);if (type.startsWith("+QIOPEN:")) { // 如果开头是连接成功//        Serial.println("连接状态更改:" + types);String head = "+QIOPEN:";String command1 = head + mSocketId + ",0";String command2 = head + mSocketId + ",566";if (types.equals(command1)) { // 连接成功 可进行通讯connectListener();} else if (types.equals(command2)) { // 连接超时closeListener();}} else if (type.startsWith("+QIURC:")) { // 如果开头是socket关闭//        Serial.println("BC23上报:" + types);String command1 = "+QIURC:\"recv\"," ;command1 += mSocketId;command1 += ",";String command2 = "+QIURC:\"closed\"," ;command2 += mSocketId;if (types.startsWith(command1)) { // scket接收到消息String lengthStr = "0";if (type.lastIndexOf(",") != -1) {lengthStr = type.substring(type.lastIndexOf(",") + 1, type.length());}int length = lengthStr.toInt();String msg = "";if (i + 1 < mReadLength) {msg = mReadDoc[i + 1];}messageListener(msg, length);} else if (types.equals(command2)) { // socket 关闭closeListener();}}}}return haveSize >= mReadLength;
}

需要注意一下,可能我c++学艺不精问题吧,大家使用的使用尽量让Arduino可用动态内存大于50%,不然续写4g数据跟解析数据的时候会造成字符串丢失哦!

正式运行时,建议把调试的log代码都注释掉,这样好像可以留出大部分的动态内存!

Arduino与墨子号 BC26 4G模块的对接开发相关推荐

  1. 迅为嵌入式4412平台兼容3G/4G模块的安卓开发板

    安卓开发板特点说明: 1. 配备16G固态硬盘EMMC存储 2. 64位双通道2GB内存 三星S5M8767电源管理 板载高精度GPS模块 CAN,RS-485等工业接口 板载WIFI蓝牙模块,陀螺仪 ...

  2. Banana Pi R2 Pro使用EC25 4G模块实现路由功能,萤石云摄像头配置。

    器材:Banana Pi R2 Pro(Ubuntu 22.04 mate server),移远EC25 4G模块, CS-C6CN(4MP JD) EC25/EC20配置 将4G模块连接到开发板后, ...

  3. Arduino+2.4G模块做航模遥控器

    Arduino+2.4G模块做航模遥控器 萌新第一次发文,多多关照~ 玩航模估计有七八年了,玩arduino和各类单片机也有一两年啦,今年回家以后因为疫情被困在家里回不去,就寻思着用arduino做个 ...

  4. linux系统获取4G模块IMEI号

    如果4G设备正常运行 在终端输入下面命令会得到设备当前的信号 命令:cat /dev/ttyUSB2& //得到: [1] 1563 //得到结果 命令: echo -e "AT+C ...

  5. 4G模块SIM7600绑定AT指定串口号(二)

    0.问题描述 4G模块SIM7600插上USB线后会有5个串口号,在电脑没有其他串口插入情况下AT指令串口为/ttyUSB2,但是在机器人上使用时会有其他多个串口,一般我们会绑定串口建立符号链接,例如 ...

  6. arm oe linux gnueabi 系统,【技术分享】Quectel 4G模块Opencpu中实现高通wifi功能

    导语 越来越多的IOT应用场景中需要使用4G模块,而在有些特定的场合需要把4G上网能力转化wifi功能,比如说无人机中视频传输,以及打印机行业中都有类似的应用案例,以便更好的提供给更多的客户端去使用. ...

  7. 移远EC20 4G模块LTE开发板三网通模块 MQTT阿里云物联网

    摘自:移远EC20 4G模块LTE开发板三网通模块 MQTT阿里云物联网STM32代码-电脑看 地址:https://www.bilibili.com/video/BV1EJ411P7CR?from= ...

  8. 中移4G模块-ML302-OpenCpu开发-GPIO

    B站:https://space.bilibili.com/309103931 中移4G模块-ML302专栏:https://blog.csdn.net/qq_33259323/category_10 ...

  9. Mind+上传模式的第三方Arduino用户库实现 -DHT11温湿度模块

    Mind+上传模式的第三方Arduino用户库实现--DHT11模块读取温湿度 前言 Mind+是一款拥有自主知识产权的国产青少年编程软件,支持Arduino.micro:bit.掌控板等各种开源硬件 ...

  10. 4G模块使用记录移远EC20、BC20

    目录 0. 概述 硬件连接 -- UART 休眠管脚的使用 硬件连接 -- USB USB线序定义 驱动安装 抓取模组log 模组型号和SIM卡 模组区别 本地卡和漫游卡 SIM卡和APN 1. EC ...

最新文章

  1. 代码优化实战:我又优化了一百个if else!
  2. asp.net性能的技巧
  3. FFPEG 转码记录------解决了有流,但是没有码率和FPS?
  4. 关于四金计算和工资对照表
  5. 《leetcode》best-time-to-buy-and-sell-stock-i-ii-iii
  6. python12岁_12岁。Python操作Excel,12Python,excel
  7. Eclipse里的快捷键
  8. android mvp模式
  9. postgres预写式日志的内核实现详解-wal记录读取
  10. Redis脚本实现分布式锁
  11. 电子负载使用恒电流和恒电阻负载模式的方法
  12. VB6.0代码窗口不支持鼠标中键操作滚动条解决方法
  13. 网页携带参数,将参数通过网址传入到对应的页面输入框内
  14. 基于Helm和Operator的K8S应用管理
  15. 转载 javascript联动菜单
  16. catia中的螺旋伞齿轮画法_用catia画齿轮教程
  17. 龙芯2h芯片不能进入pmon_一种基于龙芯2H芯片应用的COMe_nano核心板的制作方法
  18. 洛谷 2887 USACO2007NOV 防晒霜Sunscreen 题解
  19. OpenStack 运维 - 部署Nova组件 [T版]
  20. 事和书的感悟_李孟_新浪博客

热门文章

  1. 5个不可多得的黑科技网站,让你在办公中如有神助,请低调收藏
  2. 基于MATLAB的数字水印技术实现
  3. 基于STM32单片机电阻电容电感检测仪设计
  4. 七巨头如何抵御抖音?
  5. WiFi基础知识解析
  6. Hive建表语句的中文注释乱码问题
  7. ubuntu下载安装jdk
  8. Ubuntu20.04下opencv的安装
  9. 简单通用的Makefile编写例子
  10. 2020-11-10 oracle 数据库sql 之decode函数