Arduino开发中Adafruit_ATParser构造函数使用及通信问题咨询
项目背景
- 为所属研究团队开发玉米茎秆抗性测试实验设备:设备通过连接Arduino的电机与荷载传感器对玉米茎秆施加旋转作用力,同步记录茎秆抗性数据
- 当前正在为设备集成蓝牙通信功能,选用模块为Adafruit Bluefruit LE UART Friend
- 已搭建包含3个特征值的BLE GATT服务:2个特征值用于存储采集到的抗性数据,1个整数类型特征值用于存储控制指令,供设备读取后执行对应操作,目前在读取指令特征值环节遇到代码报错
问题复现
存在报错的读取函数代码
void get_input(){ uint16_t bufSize = 15; char inputBuffer[bufSize]; bleParse = Adafruit_ATParser(); // 抛出编译错误:bleParse was not declared in this scope bleParse.atcommandStrReply("AT+GATTCHAR=3",&inputBuffer,bufSize,1000); Serial.print("input:"); Serial.println(inputBuffer); }
目标调用方法所属库源码(来自Adafruit_BluefruitLE_nRF51库的Adafruit_ATParser.cpp)
/******************************************************************************/ /*! @brief 构造函数 */ /******************************************************************************/ Adafruit_ATParser::Adafruit_ATParser(void) { _mode = BLUEFRUIT_MODE_COMMAND; _verbose = false; } /******************************************************************************/ /*! @brief 发送AT指令,将多行字符串响应写入用户提供的缓冲区 @param[in] cmd AT指令内容 @param[in] buf 用户提供的存储缓冲区 @param[in] bufsize 缓冲区大小 @param[in] timeout 超时时间,单位毫秒 */ /******************************************************************************/ uint16_t Adafruit_ATParser::atcommandStrReply(const char cmd[], char* buf, uint16_t bufsize, uint16_t timeout) { uint16_t result_bytes; uint8_t current_mode = _mode; // 必要时切换模式执行指令 if ( current_mode == BLUEFRUIT_MODE_DATA ) setMode(BLUEFRUIT_MODE_COMMAND); // 执行带参数的指令并获取响应 println(cmd); result_bytes = this->readline(buf, bufsize, timeout, true); // 必要时切回原数据模式 if ( current_mode == BLUEFRUIT_MODE_DATA ) setMode(BLUEFRUIT_MODE_DATA); return result_bytes; }
已尝试的无效实例化写法
查阅库自带所有示例均未找到Adafruit_ATParser类的直接使用案例,所有示例均自行实现场景化的数据解析逻辑,例如neopixel_picker示例中的packetParser.cpp仅实现该场景下的蓝牙数据读取,从未引用或直接实例化Adafruit_ATParser类。尝试过的所有实例化写法均失败,包括:
bleParse = Adafruit_ATParser();Adafruit_ATParser bleParse();Adafruit_ATParser();ble.Adafruit_ATParser bleParse();
已有蓝牙连接对象代码
项目中ble为已定义的Arduino与蓝牙模块的串口连接对象,实例化代码如下:
SoftwareSerial bluefruitSS = SoftwareSerial(BLUEFRUIT_SWUART_TXD_PIN, BLUEFRUIT_SWUART_RXD_PIN); Adafruit_BluefruitLE_UART ble(bluefruitSS, BLUEFRUIT_UART_MODE_PIN,BLUEFRUIT_UART_CTS_PIN, BLUEFRUIT_UART_RTS_PIN);
1. Adafruit_ATParser()构造函数的正确使用方式
普通用户根本不需要手动实例化Adafruit_ATParser类,自然也不存在所谓“用户侧的正确构造写法”。
这个类是整个Bluefruit LE库的公共基类,你已经完成实例化的ble对象本身就继承了Adafruit_ATParser的所有公有方法,包括你要调用的atcommandStrReply。
你之前尝试的写法全部无效的原因:
Adafruit_ATParser bleParse();触发C++经典的“最令人烦恼的解析”问题,这行代码会被编译器判定为“声明一个名为bleParse、返回值类型为Adafruit_ATParser、无入参的函数”,根本不是对象实例化语句。- 其余写法要么未声明变量类型,要么错误将ATParser识别为ble对象的内部类/成员,完全不符合库的设计逻辑。
- 即便你绕开编译错误手动实例化了一个独立的ATParser对象,这个对象也没有绑定任何串口硬件,根本无法和蓝牙模块通信。
修正后的读取函数代码如下,不需要新建任何ATParser对象:
void get_input(){ uint16_t bufSize = 15; char inputBuffer[bufSize]; // 直接通过已初始化完成的ble对象调用继承来的AT指令方法 ble.atcommandStrReply("AT+GATTCHAR=3", inputBuffer, bufSize, 1000); Serial.print("input:"); Serial.println(inputBuffer); }
注意:原代码传参时写的&inputBuffer是错误写法,数组名本身就是指向内存首地址的指针,额外加取地址符会传递错误的指针类型,引发内存访问异常。
2. 为什么ATParser不需要手动关联ble对象就能发送AT指令
这是C++类继承机制的正常表现:Adafruit_BluefruitLE_UART类的继承链为 Adafruit_BluefruitLE_UART → 继承自Adafruit_BluefruitLE公共基类 → 继承自Adafruit_ATParser公共基类。
ATParser类中定义的println、readline、setMode等和硬件交互的方法均为虚函数,最终由Adafruit_BluefruitLE_UART类实现,自动绑定到你初始化时传入的SoftwareSerial串口对象上。当你通过ble对象调用继承来的AT指令方法时,指令会直接通过你配置的串口发送给蓝牙模块,不需要额外给ATParser绑定连接对象。
官方示例中不直接出现Adafruit_ATParser类名的原因也很简单:所有示例都是直接通过ble对象调用继承来的方法,不需要单独提及基类名称。
内容的提问来源于stack exchange,提问作者KopiousKarp

