diff --git a/Arduino_ESP32_oscilloscope/Arduino_ESP32_oscilloscope.ino b/Arduino_ESP32_oscilloscope/Arduino_ESP32_oscilloscope.ino index 0cc68d8fb7ba31be62e039b374836a0ffa221c74..a9e7f7d935cdf45416ae53764eeab46dfc76e068 100644 --- a/Arduino_ESP32_oscilloscope/Arduino_ESP32_oscilloscope.ino +++ b/Arduino_ESP32_oscilloscope/Arduino_ESP32_oscilloscope.ino @@ -1,60 +1,43 @@ /* -select engineering environment: ESP32_WROVER_Kit(all_versions) -想使用“学会助手”功能,查看 myBlueTooth.h 头文件里面有相关说明 -学会助手的串口和示波器功能,可以使用了 ^_^ +选择工程环境:ESP32_WROVER_Kit +如需使用“学会助手”功能,请参阅myBlueTooth.h头文件中的相关说明 +“学会助手”的串口功能、示波器功能和遥控器功能现已可用 ^_^ */ #include #include "myBlueTooth.h" +#include -BluetoothSerial SerialBlueTooth; +BluetoothSerial SerialBlueTooth; // 定义蓝牙串口对象 + +// 串口回调函数和遥控器回调函数不能同时使用 +// 回调函数和示波器和遥控器功能不能同时使用 void setup() { - Serial.begin(115200); // 开启串口通信:115200 + // 初始化串口通信,设置波特率为115200 + Serial.begin(115200); + + // // 启用串口通信的回调功能 + // test_serial_port_callback_enable(true); - // 此函数执行一次,可以了 - // 开启串口中断模式 - test_serial_port_callback_function(true); + // // 启用遥控器功能的回调 + // test_remote_control_callback_enable(true); - BTinitialize("mini_car"); // 蓝牙初始化 // 默认蓝牙名称:mini_bot + // 初始化蓝牙模块,设置蓝牙名称为"mini_car" + BTinitialize("mini_car"); } void loop() { - // ... - - delay(100); -} - - - - - - -/************************* test code area begin *************************/ - -// char *data = Uart_ReceiveData(); -// SerialBlueTooth.write((uint8_t *)data, strlen(data)); // 输出到连接的设备 -// SerialBlueTooth.println(); -// SerialBlueTooth.printf(data, strlen(data)); // 输出到连接的设备 -// SerialBlueTooth.println(); - -// delay(1000); - -// Serial.write(data, strlen(data)); // 输出到串行监视器 -// Serial.println(); -// Serial.printf(data, strlen(data)); // 输出到串行监视器 -// Serial.println(); - -// char ch[] = "hello"; - -// Uart_SendByte((uint8_t *)ch); - -// Uart_SendArray((uint8_t *)ch, sizeof(ch)); + // 测试发送波形数据到其他设备 + test_oscilloscope_send_wave(); -// SendWave(); + // // 执行示波器功能的数据发送和接收 + // test_oscilloscope_send_and_Receive(); -// test_oscilloscope_input_and_output(); + // // 遥控器的定时功能演示 + // test_remote_control_Timer_function(); -/************************* test code area end *************************/ \ No newline at end of file + delay(10); +} \ No newline at end of file diff --git a/Arduino_ESP32_oscilloscope/myBlueTooth.cpp b/Arduino_ESP32_oscilloscope/myBlueTooth.cpp index 9c1e51615921966bf2df27697d4bc793251f5e49..dd48703d4a5e20f81f702629aa0480f5d8935126 100644 --- a/Arduino_ESP32_oscilloscope/myBlueTooth.cpp +++ b/Arduino_ESP32_oscilloscope/myBlueTooth.cpp @@ -2,14 +2,15 @@ /************************* blueTooth part *************************/ BluetoothSerial SerialBT; // 蓝牙类实例化 -String BlueToothName = ""; // 蓝牙名称 static char blueToothBuffer[100]; // 接收缓冲区 /************************* XHZS part *************************/ -bool SERIAL_PORT_CALLBACK_FUNCTION_ENABLE = false; // 默认串口关闭 -char RemoteControlDataLength = 0; // 数据长度 -uint8_t DataFormat[8] = {0}; // 遥控器数据格式 +bool SERIAL_PORT_CALLBACK_ENABLE = false; // 默认串口关闭 +bool REMOTE_CONTROL_CALLBACK_ENABLE = false; // 默认遥控器关闭 +// 定义常量替代硬编码 +constexpr char DIGIT_ZERO = 0x30; +constexpr char DIGIT_ONE = 0x31; /************************* blueTooth begin *************************/ @@ -26,13 +27,16 @@ void BTinitialize(const String &deviceName) SerialBT.register_callback(Bluetooth_Event); // 设置事件回调函数 连接 断开 发送 接收 - if (SERIAL_PORT_CALLBACK_FUNCTION_ENABLE == true) + if (SERIAL_PORT_CALLBACK_ENABLE == true) { - SerialBT.onData(Uart_onDataReceive); // 测试手柄功能未完成_2024-07-27 - // SerialBT.onData(BTcallbackFunction); + SerialBT.onData(Uart_onDataReceive); + } + else if (REMOTE_CONTROL_CALLBACK_ENABLE == true) + { + SerialBT.onData(RemoteControlOnDataReceive); } SerialBT.begin(deviceName); // Bluetooth device name - BlueToothName = deviceName; + // BlueToothName = deviceName; } /*蓝牙发送浮点数据,转为字符串发送*/ @@ -119,12 +123,17 @@ void BTAuthCompleteCallback(boolean success) } /************************* blueTooth end *************************/ -// +// 函数前置声明 /************************* XHZS begin *************************/ -// 当通过UART接收到数据时,此函数将被调用 +/* + * 串口接收到数据开启调用,和stm32的中断函数一样 + * 需要在串口发送和接收实现自己逻辑代码,直接写代码逻辑 + * 回调函数不能有耗时操作,延时操作禁止使用的,会触发看门狗,不断重启 + */ void Uart_onDataReceive(const uint8_t *dataBuffer, size_t dataSize) { + // 判断接收到的数量 if (dataSize > 0) { SerialBT.write(dataBuffer, dataSize); // 输出到连接的设备 @@ -132,7 +141,7 @@ void Uart_onDataReceive(const uint8_t *dataBuffer, size_t dataSize) } } -// 获取接收到的数据 +// 获取串口接收到的数据 char *Uart_getReceiveData() { return blueToothBuffer; @@ -166,7 +175,7 @@ void Uart_SendArray(const uint8_t *array, size_t arraySize) *注意事项:示波器支持 uin16_t,建立一个 uint16_t fun[4] 数组, 元素是通道数量 **************************************************************/ -void XHZS_SendWave(const void *waveAddr, uint16_t waveSize) +void XHZS_SendWave(const uint8_t *waveAddr, uint16_t waveSize) { // 参数检查 if (waveAddr == nullptr || waveSize == 0) @@ -177,7 +186,7 @@ void XHZS_SendWave(const void *waveAddr, uint16_t waveSize) uint8_t cmd_tail[2] = {0xFC, 0x03}; // 帧尾 Uart_SendArray(cmd_head, sizeof(cmd_head)); // 发送帧头 - Uart_SendArray((uint8_t *)waveAddr, waveSize); // 发送数据 + Uart_SendArray(waveAddr, waveSize); // 发送数据 Uart_SendArray(cmd_tail, sizeof(cmd_tail)); // 发送帧尾 } @@ -191,7 +200,7 @@ void XHZS_SendWave(const void *waveAddr, uint16_t waveSize) void SendWave() { // // 输出平行线测试 start ----------------------- - // int32_t line[4] = {0}; // 注意数据类型;数组大小即为通道数量,最多四条通道 + // char line[4] = {0}; // 注意数据类型;数组大小即为通道数量,最多四条通道 // for (size_t i = 0; i < 500; i += 0.1) // { // line[0] = (line[0] > 10 ? -10 : (line[0] += 1)); @@ -199,8 +208,9 @@ void SendWave() // line[2] = 5.0; // line[3] = 0.0; - // XHZS_SendWave(line, sizeof(line)); - // vTaskDelay(50 / portTICK_PERIOD_MS); // 延时 100ms + // XHZS_SendWave((uint8_t *)line, sizeof(line)); + // vTaskDelay(50 / portTICK_PERIOD_MS); // 延时函数可以注释掉 + // // } // // 输出平行线测试 end ----------------------- @@ -213,9 +223,9 @@ void SendWave() Wave[1] = cos(i); Wave[2] = -sin(i); Wave[3] = -cos(i); - XHZS_SendWave(Wave, sizeof(Wave)); + XHZS_SendWave((uint8_t *)Wave, sizeof(Wave)); - vTaskDelay(50 / portTICK_PERIOD_MS); + vTaskDelay(50 / portTICK_PERIOD_MS); // 延时函数可以注释掉 } // 正弦波测试 end ----------------------- } @@ -300,8 +310,6 @@ char OscGetValue(const char *p, const char *name, float *value) return 2; } -/************************* XHZS end *************************/ - // 获取摇杆数据转换为 x and y void getInterruptJoystickvalue_XY(char *receiveBuffer, short *joystick_X, short *joystick_Y) { @@ -318,63 +326,31 @@ void getInterruptJoystickvalue_XY(char *receiveBuffer, short *joystick_X, short // cmd4 = receiveBuffer[3] & 0xF0; data[3] = receiveBuffer[3] & 0x0F; - // 对摇杆数值默认值做了修改,中心数值是0,偏离中心越远数值越大 0~100 + // 对摇杆数值默认值做了修改,中心数值是0,偏离中心越远数值越大 100~0~100 x = (data[0] * 16 + data[1]) - 100; *joystick_X = (x > 0) ? x : -x; y = (data[2] * 16 + data[3]) - 100; *joystick_Y = (y > 0) ? y : -y; } -// /************************************************************** -// *函数名称:test_remote_control -// *简 介:蓝牙数据接收,回调函数 -// *输 入:无 -// *输 出:默认输出按键状态 -// *注意事项:1)蓝牙接收到数据后,会调用此函数,不要在循环中使用,有卡死程序风险 -// 2)回调函数不能有耗时操作,延时操作禁止使用的,会触发看门狗,不断重启 -// 3)打印函数测试使用,注释掉写你的逻辑代码 -// **************************************************************/ - -void test_remote_control(const uint8_t *buffer, size_t size) +/* + * 遥控器的非定时模式 + * RemoteControlOnDataReceive() 前面的函数解析好了,遥控器的每个按键对应着一个 case, + * 在 case INTERRUPT_RIGHT_UP 表示,右边的方向按钮的向上按钮,根据按键的状态,写自己的逻辑代码 + * cmd[0] 遥控器的指令,data[0] 表示遥控器的状态,0 表示松开,1 表示按下,摇杆显示 x and y 数值 + */ +void RemoteControlInterruptMode33(uint8_t *cmd, uint8_t *data, short left_X, short left_Y, short right_X, short right_Y) { - uint8_t cmd[4] = {0}; - uint8_t data[4] = {0}; - - // 摇杆相关变量 - short left_X = 0, left_Y = 0, right_X = 0, right_Y = 0; - char receiveBuffer[4] = {0}; // 中断接收数据 - char temp = 0; - memcpy(receiveBuffer, buffer, size); - - // 按键接收大小为1,摇杆接收大小为4 - if (size == 4) - { - temp = (receiveBuffer[0] & 0xF0); - // cmd[0] = (temp == 0x10) ? 0x9A : ((temp == 0x50) ? 0X9B : 0x00); - // data[0] = receiveBuffer[0] & 0x0F; - if (temp == 0x10) - { - cmd[0] = 0x9A; - getInterruptJoystickvalue_XY(receiveBuffer, &left_X, &left_Y); - } - else if (temp == 0x50) - { - cmd[0] = 0x9C; - getInterruptJoystickvalue_XY(receiveBuffer, &right_X, &right_Y); - } - } - else if (size == 1) - { - cmd[0] = (receiveBuffer[0] & 0xF0); - data[0] = (receiveBuffer[0] & 0x0F); - } - - // 遥控器中断指令枚举定义 enum INTERRUPT_MODE_ORDER + // 在指定的按钮 case 中实现逻辑代码,中断不用有延时操作 switch (cmd[0]) { case INTERRUPT_LEFT_UP: // 指令 cmd[0] 数据 data[0] + // 逻辑代码区 begin + SerialBT.printf("%X-%X\r\n", cmd[0], data[0]); + + // 逻辑代码区 end break; case INTERRUPT_LEFT_DOWN: @@ -405,17 +381,17 @@ void test_remote_control(const uint8_t *buffer, size_t size) SerialBT.printf("%X-%X\r\n", cmd[0], data[0]); break; - case INTERRUPT_LEFT_X_Y: + case INTERRUPT_LEFT_X: // 摇杆数值在 left_X and left_Y - // 逻辑代码区 start + // 逻辑代码区 begin SerialBT.printf("x: %d y: %d\n", left_X, left_Y); // 逻辑代码区 end break; - case INTERRUPT_RIGHT_X_Y: - // 逻辑代码区 start + case INTERRUPT_RIGHT_X: + // 逻辑代码区 begin SerialBT.printf("x: %d y: %d\n", right_X, right_Y); @@ -447,58 +423,92 @@ void test_remote_control(const uint8_t *buffer, size_t size) break; } } + /* - * 遥控器的界面选择,使用 enum INTERFACE_SIZE + * RemoteControlOnDataReceive() 前面的函数解析好了,在这里使用结构体成员的方法,获取数值 + * 遥控器的非定时模式,1 表示按下,0 表示松开,摇杆显示 x and y 数值 */ -void XHZS_RemoteControlIntialization(INTERFACE_SIZE isDirectionalPad1, - INTERFACE_SIZE isDirectionalPad2, - INTERFACE_SIZE isButtonA, - INTERFACE_SIZE isButtonB, - INTERFACE_SIZE isButtonC, - INTERFACE_SIZE isButtonD, - INTERFACE_SIZE isSwitchE, - INTERFACE_SIZE isSwitchF) -{ - RemoteControlDataLength = isDirectionalPad1 + - isDirectionalPad2 + - isButtonA + - isButtonB + - isButtonC + - isButtonD + - isSwitchE + - isSwitchF; - DataFormat[0] = isDirectionalPad1; - DataFormat[1] = isDirectionalPad2; - DataFormat[2] = isButtonA; - DataFormat[3] = isButtonB; - DataFormat[4] = isButtonC; - DataFormat[5] = isButtonD; - DataFormat[6] = isSwitchE; - DataFormat[7] = isSwitchF; +void RemoteControlInterruptMode22(structRemoteControlFormat *structBuffer) +{ + // 遍历结构体成员代码,了解 struct structRemoteControlFormat 格式内容 + // structBuffer->A 和 ptr[10] 这两个表达都是同一个地址,他们位置都是:10 + short *ptr = &structBuffer->begin; // 获取结构体首地址 + for (size_t i = 0; i < structBuffer->end, i < 20; i++) + { + Serial.printf("%d-%d ", i, ptr[i]); + } + Serial.println(); +} + +/* + * 串口接收到数据开启调用,和stm32的中断函数一样,在 RemoteControlOnDataReceive() 函数实现数据解析工作, + * 你的逻辑代码建议在 RemoteControlInterruptMode22() 或者在 RemoteControlInterruptMode33() 实现 + * 回调函数不能有耗时操作,延时操作禁止使用的,会触发看门狗,不断重启 + * 函数功能:把不同的按钮指令,存放在指定的结构体中 + */ +void RemoteControlOnDataReceive(const uint8_t *buffer, size_t size) +{ + structRemoteControlFormat outputBuffer = {}; // 输出的缓冲区 + outputBuffer.end = 20; + uint8_t cmd[4] = {0}; // 指令 + uint8_t data[4] = {0}; // 数据 + + char receiveBuffer[4] = {0}; + memcpy(receiveBuffer, buffer, size); + short *ptr = &outputBuffer.begin; + + // 判断是否摇杆数据,在进行解释 + if (size == 4) + { + if ((receiveBuffer[0] & 0xF0) == 0x10) + { + cmd[0] = 0x9A; + getInterruptJoystickvalue_XY(receiveBuffer, &outputBuffer.LEFT_x, &outputBuffer.LEFT_y); + } + else if ((receiveBuffer[0] & 0xF0) == 0x50) + { + cmd[0] = 0x9C; + getInterruptJoystickvalue_XY(receiveBuffer, &outputBuffer.RIGHT_x, &outputBuffer.RIGHT_y); + } + } + else if (size == 1) + { + cmd[0] = (receiveBuffer[0] & 0xF0) / 16; + data[0] = (receiveBuffer[0] & 0x0F); + // 在这里把结构体当成一个数组来使用 + ptr[cmd[0]] = data[0]; + // switch case 模式 * 16 + cmd[0] = cmd[0] * 16; + } + // 选择一个函数使用 + // 使用结构体的成员方法 + RemoteControlInterruptMode22(&outputBuffer); + // 使用 switch case 模式 + // RemoteControlInterruptMode33(cmd, data, outputBuffer.LEFT_x, outputBuffer.LEFT_y, outputBuffer.RIGHT_x, outputBuffer.RIGHT_y); } // 获取摇杆数值 // (inputButton[inputPosition + 0] - 0x30) 把字符转化为数字 -void getJoystickValue(short *outputButton, char outputPosition, char *inputButton, char inputPosition) +void getJoystickValue(short *outputButton, char outputPosition, const char *inputButton, char inputPosition) { - outputButton[outputPosition + 0] = (inputButton[inputPosition + 0] - 0x30) * 100 + - (inputButton[inputPosition + 1] - 0x30) * 10 + - (inputButton[inputPosition + 2] - 0x30) - 100; - outputButton[outputPosition + 0] = ((outputButton[outputPosition + 0]) > 0 ? (outputButton[outputPosition + 0]) : -(outputButton[outputPosition + 0])); - - outputButton[outputPosition + 1] = (inputButton[inputPosition + 3] - 0x30) * 100 + - (inputButton[inputPosition + 4] - 0x30) * 10 + - (inputButton[inputPosition + 5] - 0x30) - 100; - outputButton[outputPosition + 1] = ((outputButton[outputPosition + 1]) > 0 ? (outputButton[outputPosition + 1]) : -(outputButton[outputPosition + 1])); + outputButton[outputPosition] = (inputButton[inputPosition] - DIGIT_ZERO) * 100 + + (inputButton[inputPosition + 1] - DIGIT_ZERO) * 10 + + (inputButton[inputPosition + 2] - DIGIT_ZERO) - 100; + outputButton[outputPosition] = outputButton[outputPosition] > 0 ? outputButton[outputPosition] : -outputButton[outputPosition]; + + outputButton[outputPosition + 1] = (inputButton[inputPosition + 3] - DIGIT_ZERO) * 100 + + (inputButton[inputPosition + 4] - DIGIT_ZERO) * 10 + + (inputButton[inputPosition + 5] - DIGIT_ZERO) - 100; + outputButton[outputPosition + 1] = outputButton[outputPosition + 1] > 0 ? outputButton[outputPosition + 1] : -outputButton[outputPosition + 1]; } // 获取按钮数值 // (inputButton[inputPosition + i] == 0x31) 识别字符是否等于数字的1 -void getDirectionalPad(short *outputButton, char outputPosition, char *inputButton, char inputPosition) +void getDirectionalPad(short *outputButton, char outputPosition, const char *inputButton, char inputPosition) { for (size_t i = 0; i < DIRECTIONAL_PAD_SIZE; i++) { - if (inputButton[inputPosition + i] == 0x31) + if (inputButton[inputPosition + i] == DIGIT_ONE) { outputButton[outputPosition + i] = 1; } @@ -507,113 +517,109 @@ void getDirectionalPad(short *outputButton, char outputPosition, char *inputButt // 获取按钮数值 // (inputButton[inputPosition + i] == 0x31) 识别字符是否等于数字的1 -void getFunctionButtonValue(short *outputButton, char outputPosition, char *inputButton, char inputPosition) +void getFunctionButtonValue(short *outputButton, char outputPosition, const char *inputButton, char inputPosition) { for (size_t i = 0; i < FUNCTION_BUTTON_SIZE; i++) { - if (inputButton[inputPosition + i] == 0x31) + if (inputButton[inputPosition + i] == DIGIT_ONE) { outputButton[outputPosition + i] = 1; } } } -// 遥控器循环模式 -// 数组 outputBuffer[20] 数据格式在枚举 enum LOOP_MODE_ORDER 中定义 -// 返回是数组类型,元素必须大于20个 -short XHZS_RemoteControlLoopMode() +// 截取字符串 +void substring(char *dest, const char *src, size_t start, size_t length) { - short outputBuffer[20] = {0}; // 输出的缓冲区 - char tempBuffer[20] = {0}; // 临时缓冲区 + size_t i; + for (i = 0; i < length && src[start + i] != '\0'; ++i) + { + dest[i] = src[start + i]; + } + dest[i] = '\0'; // 确保字符串以空字符结尾 +} + +/* + * 遥控器的定时模式 + * 功能:对一串有规律的字符串解析处理,放在指定结构体成员中 + * 使用了数组的方式,将结构体当成一个数组来使用,结构体的偏移量来确定成员位置 + */ +structRemoteControlFormat RemoteControlTimerMode(MODULE_SIZE RemoteControlLayoutLeft, MODULE_SIZE RemoteControlLayoutRight) +{ + structRemoteControlFormat outputBuffer = {0}; // 输出的缓冲区 + outputBuffer.begin = 0; + outputBuffer.end = 20; + char tempBuffer[20] = {0}; // 临时缓冲区 + // 判断手柄的方向按钮和摇杆的组合 - char handle = (DataFormat[0] == JOYSTICK_SIZE ? JOYSTICK_AND_DIRECTIONAL_PAD : TWO_DIRECTIONAL_PAD) + - (DataFormat[1] == JOYSTICK_SIZE ? DIRECTIONAL_PAD_AND_JOYSTICK : TWO_DIRECTIONAL_PAD); + char handle = (RemoteControlLayoutLeft == JOYSTICK_SIZE ? JOYSTICK_AND_DIRECTIONAL_PAD : DIRECTIONAL_PAD) + + (RemoteControlLayoutRight == JOYSTICK_SIZE ? DIRECTIONAL_PAD_AND_JOYSTICK : DIRECTIONAL_PAD); size_t data_len = strlen(Uart_getReceiveData()); // 获取长度用于复制 memcpy(tempBuffer, Uart_getReceiveData(), data_len); // 内存复制 + //// 尝试使用 cmd 串口改变,手柄的组合,失败 + // if (tempBuffer[0] == 's' && tempBuffer[1] == 'e' && tempBuffer[2] == 't') + // { + // char *end; + // char tempBufferCopy[data_len]; + + // substring(tempBufferCopy, tempBuffer, 4, 4); // 截取字符串 + // tempBufferCopy[0] = (char)strtol(tempBufferCopy, &end, 16); // 字符串转换十六进制 + // // SerialBT.printf("%s-%d\n", "pad", tempBufferCopy[0]); + + // if (tempBufferCopy[0] == 0x00 || tempBufferCopy[0] == 0x01 || tempBufferCopy[0] == 0x10 || tempBufferCopy[0] == 0x11) + // { + // // handle = *tempBufferCopy; + // handle = tempBufferCopy[0]; + // tempBufferCopy[0] = 100; + // SerialBT.printf("%s-%d\n", "ok", tempBufferCopy[0]); + // } + // } + // 确定,方向按钮和摇杆组合方式 switch (handle) { - case TWO_DIRECTIONAL_PAD: - getDirectionalPad(outputBuffer, 0, tempBuffer, 0); - getFunctionButtonValue(outputBuffer, 8, tempBuffer, 8); + case DIRECTIONAL_PAD: + // 获取结构体的首地址,在基础上移动到指定位置,进行赋值或者读取操作 + getDirectionalPad(&outputBuffer.begin, 1, tempBuffer, 0); + getDirectionalPad(&outputBuffer.begin, 5, tempBuffer, 4); + getFunctionButtonValue(&outputBuffer.begin, 10, tempBuffer, 8); break; case DIRECTIONAL_PAD_AND_JOYSTICK: - getDirectionalPad(outputBuffer, 0, tempBuffer, 0); - getJoystickValue(outputBuffer, 16, tempBuffer, 4); - getFunctionButtonValue(outputBuffer, 8, tempBuffer, 10); + getDirectionalPad(&outputBuffer.begin, 1, tempBuffer, 0); + getJoystickValue(&outputBuffer.begin, 18, tempBuffer, 4); + getFunctionButtonValue(&outputBuffer.begin, 10, tempBuffer, 10); break; case JOYSTICK_AND_DIRECTIONAL_PAD: - getJoystickValue(outputBuffer, 14, tempBuffer, 0); - getDirectionalPad(outputBuffer, 4, tempBuffer, 6); - getFunctionButtonValue(outputBuffer, 8, tempBuffer, 10); + getJoystickValue(&outputBuffer.begin, 16, tempBuffer, 0); + getDirectionalPad(&outputBuffer.begin, 5, tempBuffer, 6); + getFunctionButtonValue(&outputBuffer.begin, 10, tempBuffer, 10); break; - case TWO_JOYSTICKS: - getJoystickValue(outputBuffer, 14, tempBuffer, 0); - getJoystickValue(outputBuffer, 16, tempBuffer, 6); - getFunctionButtonValue(outputBuffer, 8, tempBuffer, 12); + case JOYSTICKS: + getJoystickValue(&outputBuffer.begin, 16, tempBuffer, 0); + getJoystickValue(&outputBuffer.begin, 18, tempBuffer, 6); + getFunctionButtonValue(&outputBuffer.begin, 10, tempBuffer, 12); break; } - return *outputBuffer; - - // #if true - // 不同的遥控器组合,使用不同显示 // 打印在串口监视器中 - switch (handle) - { - case TWO_DIRECTIONAL_PAD: - Serial.printf("up: %d down: %d left: %d right: %d - up: %d down: %d left: %d right: %d ", - outputBuffer[LOOP_LEFT_UP], outputBuffer[LOOP_LEFT_DOWN], outputBuffer[LOOP_LEFT_LEFT], outputBuffer[LOOP_LEFT_RIGHT], - outputBuffer[LOOP_RIGHT_UP], outputBuffer[LOOP_RIGHT_DOWN], outputBuffer[LOOP_RIGHT_LEFT], outputBuffer[LOOP_RIGHT_RIGHT]); - - break; - case DIRECTIONAL_PAD_AND_JOYSTICK: - Serial.printf("up: %d down: %d left: %d right: %d - x: %d y: %d ", - outputBuffer[LOOP_LEFT_UP], outputBuffer[LOOP_LEFT_DOWN], outputBuffer[LOOP_LEFT_LEFT], outputBuffer[LOOP_LEFT_RIGHT], - outputBuffer[LOOP_RIGHT_X], outputBuffer[LOOP_RIGHT_Y]); - break; - case JOYSTICK_AND_DIRECTIONAL_PAD: - Serial.printf(" x: %d y: %d - up: %d down: %d left: %d right: %d ", - outputBuffer[LOOP_LEFT_X], outputBuffer[LOOP_LEFT_Y], - outputBuffer[LOOP_RIGHT_UP], outputBuffer[LOOP_RIGHT_DOWN], outputBuffer[LOOP_RIGHT_LEFT], outputBuffer[LOOP_RIGHT_RIGHT]); - break; - case TWO_JOYSTICKS: - Serial.printf("x: %d y: %d - x: %d y: %d ", - outputBuffer[LOOP_LEFT_X], outputBuffer[LOOP_LEFT_Y], - outputBuffer[LOOP_RIGHT_X], outputBuffer[LOOP_RIGHT_Y]); - break; - } - Serial.printf(" A: %d B: %d C: %d D: %d E: %d F: %d \n", - outputBuffer[LOOP_BUTTON_A], - outputBuffer[LOOP_BUTTON_B], - outputBuffer[LOOP_BUTTON_C], - outputBuffer[LOOP_BUTTON_D], - outputBuffer[LOOP_BUTTON_E], - outputBuffer[LOOP_BUTTON_F]); - // #endif -} - -// 遥控器中断模式 -void XHZS_RemoteControlInterruptMode() -{ - // 准备整合 + return outputBuffer; } /************************* XHZS end *************************/ // -/************************* example funtion begin *************************/ +/************************* example begin *************************/ -// 开启串口回调函数,需要在蓝牙初始化之前调用 // isEnable = true 开启,false 关闭 -// 串口(蓝牙)接收到数据触发回调函数 Uart_onDataReceive() -// 底层 blueTooth 库中 onData() 函数绑定回调函数 Uart_onDataReceive() 函数作为触发调用 -// 找到 Uart_onDataReceive() 在里面写你的逻辑代码,不要有延时操作,中断函数中不能有延时操作 -// 在不使用串口功能时,请关闭防止与其它功能模块的冲突 -void test_serial_port_callback_function(bool isEnable) +/** + * 此函数应在蓝牙初始化前调用,当 isEnable 数值为 true 时开启,false 则禁用。 + * 在底层蓝牙库中,onData() 函数将绑定 Uart_onDataReceive() 作为其回调,从而在接收到数据时触发相应的处理逻辑。 + * 串口回调时实现自己的代码逻辑,找到 Uart_onDataReceive() 修改里面代码 + */ +void test_serial_port_callback_enable(bool isEnable) { - SERIAL_PORT_CALLBACK_FUNCTION_ENABLE = isEnable; + SERIAL_PORT_CALLBACK_ENABLE = isEnable; } // 发送波形数据的函数例子 @@ -622,14 +628,19 @@ void test_oscilloscope_send_wave() SendWave(); } -// 示波器输入和输出案例 -void test_oscilloscope_input_and_output() +/** + * 示波器发送和接收函数示例 + * 数据类型:字符串,通道数量:4,开始接收 + * 参数调试:开启定时发送,选择参数调整 + */ +void test_oscilloscope_send_and_Receive() { float floatValue1, floatValue2, floatValue3, floatValue4; // 准备数据类型 - char *charData = Uart_getReceiveData(); + char *charData = Uart_getReceiveData(); // 获取蓝牙串口的数据 + // 给通道四输出波形数据 floatValue4 = (floatValue4 > 33 ? -22 : (floatValue4 += 0.1)); - // 将字符串中的字段的数值提取出来 + // 将字符串中的字段的数值提取出来,字符串格式为:下方 // c11:14.12,c12:22,c13:33,c14: 55.66, // c13字段,数值为33 OscGetValue(charData, "c11", &floatValue1); @@ -638,11 +649,49 @@ void test_oscilloscope_input_and_output() OscGetValue(charData, "c14", &floatValue4); SerialBT.printf("w:%0.2f,%0.2f,%0.2f,%0.2f\r\n", floatValue1, floatValue2, floatValue3, floatValue4); - vTaskDelay(50 / portTICK_PERIOD_MS); // 延时函数,可以注释掉 + delay(50); // 延时函数,可以注释掉 +} + +/* + * 此函数应在蓝牙初始化前调用,当 isEnable 数值为 true 时开启,false 则禁用。 + * 在底层蓝牙库中,onData() 函数将绑定 RemoteControlOnDataReceive() 作为其回调,从而在接收到数据时触发相应的处理逻辑。 + * 串口回调时实现自己的代码逻辑,找到 RemoteControlOnDataReceive() 修改里面代码 + */ +void test_remote_control_callback_enable(bool isEnable) +{ + REMOTE_CONTROL_CALLBACK_ENABLE = isEnable; +} + +/** + * 遥控器的定时发送模式,函数的参数决定摇杆和方向按钮组合 + * 摇杆:JOYSTICK_SIZE and 方向按钮:DIRECTIONAL_PAD_SIZE + * 手柄组合有4种,配合学会助手的遥控器功能一起使用 + */ +void test_remote_control_Timer_function() +{ + structRemoteControlFormat buffer = RemoteControlTimerMode(DIRECTIONAL_PAD_SIZE, DIRECTIONAL_PAD_SIZE); + + short *ptr = &buffer.begin; + for (size_t i = 0; i < 20, i < buffer.end; i++) + { + Serial.printf("%d-%d ", i, ptr[i]); + } + Serial.println(); + + // delay(50); // 延时函数可以删除 } -/************************* example funtion end *************************/ + +/************************* example end *************************/ // /************************* test begin *************************/ +#if false +/* +在处理十六进制的时候发现一个问题,如何把 0x10 and 0x20 转化成数字的 1 and 2, +第一想到的字节的移位操作,但是这样最少操作四次,一个字节八位, +在计算十六进制大小发现一个规律,高位每加一位相差15 +0x50 升一位需要加15,降一位需要15 +*/ + struct myStruct { char a; @@ -652,6 +701,11 @@ struct myStruct char e; }; +/* +如何把结构体像数组一样使用?可以做到,前提条件时是结构体成员是单一类型时,结构体内部就像一个数组, +获取结构体的首地址,在基础上进行偏移,可以像数组一样访问了 +问题来了,结构体的大小,或者说时长度问题,需要手动计算,使用for循环遍历警惕循环次数 +*/ void test_struct_array() { myStruct box = {}; @@ -666,22 +720,24 @@ void test_struct_array() Serial.printf("%d-%d- ", i, *(ptr + i)); } Serial.printf("a: %d b: %d c: %d d: %d e: %d\n", box.a, box.b, box.c, box.d, box.e); - delay(100); + delay(10); } -/* -struct MyStruct { +struct MyStruct +{ int a; int b; int c; // 假设a, b, c是连续存储的 }; - -MyStruct s; -int* ptr = &s.a; // 获取a的地址 -for (int i = 0; i < 3; ++i) { - *(ptr + i) = i; // 通过指针偏移访问,尽管能工作但不推荐 +void test_struct_move() +{ + MyStruct s; + int *ptr = &s.a; // 获取a的地址 + for (int i = 0; i < 3; ++i) + { + *(ptr + i) = i; // 通过指针偏移访问,尽管能工作但不推荐 + } } -*/ - +#endif /************************* test end *************************/ diff --git a/Arduino_ESP32_oscilloscope/myBlueTooth.h b/Arduino_ESP32_oscilloscope/myBlueTooth.h index 5f8096a2e54327dd3be7f06fc38f6ffabd3cc841..386311711cb35de05d76d0ec409d1bdb6622e5f5 100644 --- a/Arduino_ESP32_oscilloscope/myBlueTooth.h +++ b/Arduino_ESP32_oscilloscope/myBlueTooth.h @@ -9,57 +9,62 @@ #define MYBLUETOOTH_H_ #include -#include // 字符串操作库 -#include // ESP32蓝牙库 +#include +#include -// 遥控器循环指令枚举定义 -enum LOOP_MODE_ORDER +// 定义遥控器输出结构体 +struct structRemoteControlFormat { - LOOP_LEFT_UP = 0, // 左上方向 - LOOP_LEFT_DOWN = 1, // 左下方向 - LOOP_LEFT_LEFT = 2, // 左方向 - LOOP_LEFT_RIGHT = 3, // 右方向 - - LOOP_RIGHT_UP = 4, // 右上方向 - LOOP_RIGHT_DOWN = 5, // 右下方向 - LOOP_RIGHT_LEFT = 6, // 右左方向 - LOOP_RIGHT_RIGHT = 7, // 右右方向 - - LOOP_BUTTON_A = 8, // 按钮A - LOOP_BUTTON_B = 9, // 按钮B - LOOP_BUTTON_C = 10, // 按钮C - LOOP_BUTTON_D = 11, // 按钮D - LOOP_BUTTON_E = 12, // 按钮E - LOOP_BUTTON_F = 13, // 按钮F - - LOOP_LEFT_X = 14, // 左摇杆X轴 - LOOP_LEFT_Y = 15, // 左摇杆Y轴 - LOOP_RIGHT_X = 16, // 右摇杆X轴 - LOOP_RIGHT_Y = 17 // 右摇杆Y轴 + short begin; + + short LEFT_up; // 向上 // 1 + short LEFT_down; // 向下 + short LEFT_left; // 向左 + short LEFT_right; // 向右 + + short RIGHT_up; // 向上 // 5 + short RIGHT_down; // 向下 + short RIGHT_left; // 向左 + short RIGHT_right; // 向右 + + short middle; + + short A; // 按钮A // 10 + short B; // 按钮B + short C; // 按钮C + short D; // 按钮D + short E; // 按钮E + short F; // 按钮F + + short LEFT_x; // 左摇杆X轴 // 16 + short LEFT_y; // 左摇杆Y轴 + short RIGHT_x; // 右摇杆X轴 + short RIGHT_y; // 右摇杆Y轴 + + short end; // 结束标志位 // 20 }; // 遥控器中断指令枚举定义 enum INTERRUPT_MODE_ORDER { - // 按键状态指令 INTERRUPT_BUTTON_RELEASE = 0X00, // 按键释放指令 INTERRUPT_BUTTON_PRESS = 0X01, // 按键按下指令 - // 左侧方向键指令 INTERRUPT_LEFT_UP = 0X10, // 左侧方向键上 INTERRUPT_LEFT_DOWN = 0X20, // 左侧方向键下 INTERRUPT_LEFT_LEFT = 0X30, // 左侧方向键左 INTERRUPT_LEFT_RIGHT = 0X40, // 左侧方向键右 - // 右侧方向键指令 INTERRUPT_RIGHT_UP = 0X50, // 右侧方向键上 INTERRUPT_RIGHT_DOWN = 0X60, // 右侧方向键下 INTERRUPT_RIGHT_LEFT = 0X70, // 右侧方向键左 INTERRUPT_RIGHT_RIGHT = 0X80, // 右侧方向键右 - INTERRUPT_LEFT_X_Y = 0X9A, - INTERRUPT_RIGHT_X_Y = 0X9C, - // 左右功能按键指令 + INTERRUPT_LEFT_X = 0X9A, // 摇杆的指令 + INTERRUPT_LEFT_Y = 0X9B, + INTERRUPT_RIGHT_X = 0X9C, + INTERRUPT_RIGHT_Y = 0X9D, + INTERRUPT_BUTTON_A = 0XA0, // 左侧A功能键 INTERRUPT_BUTTON_B = 0XB0, // 左侧B功能键 INTERRUPT_BUTTON_C = 0XC0, // 右侧C功能键 @@ -74,88 +79,104 @@ typedef enum MODULE_SIZE JOYSTICK_SIZE = 6, // 手柄摇杆,占位6 DIRECTIONAL_PAD_SIZE = 4, // 方向按钮,占位4 FUNCTION_BUTTON_SIZE = 6, // 功能按键,占位6 - BUTTON_SIZE = 1, // 按键,占位1 - SWITCH_SIZE = 1 // 开关,占位1 + } INTERFACE_SIZE; // 遥控器的方向按钮和摇杆组合 enum POLYTYPE { - TWO_DIRECTIONAL_PAD = 0x00, // 0x00 + DIRECTIONAL_PAD = 0x00, // 0x00 DIRECTIONAL_PAD_AND_JOYSTICK = 0x01, // 0x01 JOYSTICK_AND_DIRECTIONAL_PAD = 0x10, // 0x10 - TWO_JOYSTICKS = 0x11 // 0x11 + JOYSTICKS = 0x11 // 0x11 }; -extern bool SERIAL_PORT_CALLBACK_FUNCTION_ENABLE; -/************************* 蓝牙功能核心接口 *************************/ +/************************* 蓝牙功能相关函数 *************************/ -// 设定蓝牙名称,默认为"mini_bot" +// **初始化蓝牙模块**,设置设备名,默认为"mini_bot" void BTinitialize(const String &deviceName = "mini_bot"); -// 将浮点数转换字符串通过蓝牙发送 +// **发送浮点数**通过蓝牙 void BTsendFloatVia(const float *data); -// 发送字符串到蓝牙连接的设备 +// **发送字符串**到蓝牙连接的设备 void BTsendStringVia(const char *stringData); -// 返回一个指针指向接收到的字符串数据。 +// **获取蓝牙接收的字符串** char *BTgetReceivedData(); -/************************* 高级数据处理接口 ************************/ +/************************* 串口通讯辅助函数 ************************/ -// 当通过UART接收到数据时,此函数将被调用 +// 串口数据接收回调,当有数据通过UART接收到时调用 void Uart_onDataReceive(const uint8_t *dataBuffer, size_t dataSize); -// 获取接收到的数据 +// 获取串口接收数据 char *Uart_getReceiveData(); -// 通过UART发送一个字节的数据 +// 发送单个字节,通过UART void Uart_SendByte(const uint8_t *byte); -// 通过UART发送一个字节数组 +// 发送字节数组,通过UART void Uart_SendArray(const uint8_t *array, size_t arraySize); -// 发送指定数据格式 -void XHZS_SendWave(const void *waveAddr, uint16_t waveSize); +// 发送特定格式数据,如波形数据 +void XHZS_SendWave(const uint8_t *waveAddr, uint16_t waveSize); + +/************************* 示波器相关函数 ************************/ // 发送波形数据的函数 void SendWave(); -// 输入 char *p 解析为 float *value +// 解析字符串为浮点数 char OscGetFloat(const char *p, float *value); -// 从示波器获取的数据格式,按字段解析为数值 +// 从特定格式数据中提取浮点数 char OscGetValue(const char *p, const char *name, float *value); -/************************* 演示示例函数 ************************/ +/************************* 遥控器交互相关函数 ************************/ + +// 遥控器数据接收处理回调 +void RemoteControlOnDataReceive(const uint8_t *buffer, size_t size); + +// 处理遥控器中断模式下的命令 +void RemoteControlInterruptMode22(structRemoteControlFormat *structBuffer); + +// 处理遥控器中断模式下的命令 // 备用 +void RemoteControlInterruptMode33(uint8_t *cmd, uint8_t *data, short left_X, short left_Y, short right_X, short right_Y); + +// 获取遥控器定时模式的数据 +structRemoteControlFormat RemoteControlTimerMode(MODULE_SIZE RemoteControlLayoutLeft, MODULE_SIZE RemoteControlLayoutRight); + +/************************* 示例与测试函数 ************************/ + +// 启用串口函数回调功能,在蓝牙初始化前调用 +void test_serial_port_callback_enable(bool isEnable = false); -void test_serial_port_callback_function(bool isEnable = false); // 开启串口回调函数,需要在蓝牙初始化之前调用 +// 测试发送波形数据到其他设备 +void test_oscilloscope_send_wave(); -void test_oscilloscope_send_wave(); // 发送波形数据的函数 +// 示例:示波器数据收发互动 +void test_oscilloscope_send_and_Receive(); -void test_oscilloscope_input_and_output(); // 示波器输入和输出案例 +// 启用遥控器函数回调函数,在蓝牙初始化前调用 +void test_remote_control_callback_enable(bool isEnable = false); -/************************* 其它模块适配,适配中... ************************/ +// 遥控器定时模式下的功能 +void test_remote_control_Timer_function(); -void test_remote_control(const uint8_t *buffer, size_t size); // 遥控器 +/************************* 功能测试,适配中... ************************/ -void XHZS_RemoteControlIntialization(INTERFACE_SIZE isDirectionalPad1, - INTERFACE_SIZE isDirectionalPad2, - INTERFACE_SIZE isButtonA = BUTTON_SIZE, - INTERFACE_SIZE isButtonB = BUTTON_SIZE, - INTERFACE_SIZE isButtonC = BUTTON_SIZE, - INTERFACE_SIZE isButtonD = BUTTON_SIZE, - INTERFACE_SIZE isSwitchE = SWITCH_SIZE, - INTERFACE_SIZE isSwitchF = SWITCH_SIZE); +// // 遥控器数据处理测试函数 +// void test_remote_control(const uint8_t *buffer, size_t size); -void XHZS_RemoteControlIntialization(); // 遥控器初始化 -// void XHZS_RemoteControlLoopMode(); // 遥控器循环模式 -void XHZS_RemoteControlInterruptMode(); // 遥控器中断模式 +// // 测试遥控器中断模式下的功能 +// void XHZS_RemoteControlInterruptMode(); -short XHZS_RemoteControlLoopMode(); +// // 结构体数组的使用示例 +// void test_struct_array(); -void test_struct_array(); +// // 结构体移动示例 +// void test_struct_move(); #endif diff --git a/PlatformIO_ESP32_oscilloscope/lib/myBlueTooth/myBlueTooth.cpp b/PlatformIO_ESP32_oscilloscope/lib/myBlueTooth/myBlueTooth.cpp index 12775e410ed6ceb7c67b7826efb9ab40ff52a896..dd48703d4a5e20f81f702629aa0480f5d8935126 100644 --- a/PlatformIO_ESP32_oscilloscope/lib/myBlueTooth/myBlueTooth.cpp +++ b/PlatformIO_ESP32_oscilloscope/lib/myBlueTooth/myBlueTooth.cpp @@ -481,8 +481,10 @@ void RemoteControlOnDataReceive(const uint8_t *buffer, size_t size) cmd[0] = cmd[0] * 16; } // 选择一个函数使用 - RemoteControlInterruptMode22(&outputBuffer); // 使用结构体的成员方法 - // RemoteControlInterruptMode33(cmd, data, outputBuffer.LEFT_x, outputBuffer.LEFT_y, outputBuffer.RIGHT_x, outputBuffer.RIGHT_y); // 使用 switch case 模式 + // 使用结构体的成员方法 + RemoteControlInterruptMode22(&outputBuffer); + // 使用 switch case 模式 + // RemoteControlInterruptMode33(cmd, data, outputBuffer.LEFT_x, outputBuffer.LEFT_y, outputBuffer.RIGHT_x, outputBuffer.RIGHT_y); } // 获取摇杆数值 @@ -556,7 +558,7 @@ structRemoteControlFormat RemoteControlTimerMode(MODULE_SIZE RemoteControlLayout size_t data_len = strlen(Uart_getReceiveData()); // 获取长度用于复制 memcpy(tempBuffer, Uart_getReceiveData(), data_len); // 内存复制 - //// 尝试使用串口改变,手柄的组合,失败 + //// 尝试使用 cmd 串口改变,手柄的组合,失败 // if (tempBuffer[0] == 's' && tempBuffer[1] == 'e' && tempBuffer[2] == 't') // { // char *end; diff --git a/PlatformIO_ESP32_oscilloscope/lib/myBlueTooth/myBlueTooth.h b/PlatformIO_ESP32_oscilloscope/lib/myBlueTooth/myBlueTooth.h index a7ea9daebb55ba1d4785de67943956dad83d8a8a..e33945cbd8bff59f4805875f3ed30722211bea9c 100644 --- a/PlatformIO_ESP32_oscilloscope/lib/myBlueTooth/myBlueTooth.h +++ b/PlatformIO_ESP32_oscilloscope/lib/myBlueTooth/myBlueTooth.h @@ -41,7 +41,7 @@ struct structRemoteControlFormat short RIGHT_x; // 右摇杆X轴 short RIGHT_y; // 右摇杆Y轴 - short end; + short end; // 结束标志位 // 20 }; // 遥控器中断指令枚举定义 @@ -108,19 +108,19 @@ char *BTgetReceivedData(); /************************* 串口通讯辅助函数 ************************/ -// **串口数据接收回调**,当有数据通过UART接收到时调用 +// 串口数据接收回调,当有数据通过UART接收到时调用 void Uart_onDataReceive(const uint8_t *dataBuffer, size_t dataSize); -// **获取串口接收数据** +// 获取串口接收数据 char *Uart_getReceiveData(); -// **发送单个字节**通过UART +// 发送单个字节,通过UART void Uart_SendByte(const uint8_t *byte); -// **发送字节数组**通过UART +// 发送字节数组,通过UART void Uart_SendArray(const uint8_t *array, size_t arraySize); -// **发送特定格式数据**,如波形数据 +// 发送特定格式数据,如波形数据 void XHZS_SendWave(const uint8_t *waveAddr, uint16_t waveSize); /************************* 示波器相关函数 ************************/ @@ -128,10 +128,10 @@ void XHZS_SendWave(const uint8_t *waveAddr, uint16_t waveSize); // **实际发送波形数据的函数** void SendWave(); -// **解析字符串为浮点数** +// 解析字符串为浮点数 char OscGetFloat(const char *p, float *value); -// **从特定格式数据中提取浮点数** +// 从特定格式数据中提取浮点数 char OscGetValue(const char *p, const char *name, float *value); /************************* 遥控器交互相关函数 ************************/ @@ -162,10 +162,10 @@ void test_oscilloscope_send_and_Receive(); // 启用遥控器函数回调函数,在蓝牙初始化前调用 void test_remote_control_callback_enable(bool isEnable = false); -// 示例:遥控器定时模式下的功能 +// 遥控器定时模式下的功能 void test_remote_control_Timer_function(); -/************************* 其它模块适配,适配中... ************************/ +/************************* 功能测试,适配中... ************************/ // // 遥控器数据处理测试函数 // void test_remote_control(const uint8_t *buffer, size_t size); diff --git a/PlatformIO_ESP32_oscilloscope/src/main.cpp b/PlatformIO_ESP32_oscilloscope/src/main.cpp index 7bbfd76a08262e3537ca36a6ac8380aaa2b0048a..70687caeedf289a51a98c7e80a093201671cf7a5 100644 --- a/PlatformIO_ESP32_oscilloscope/src/main.cpp +++ b/PlatformIO_ESP32_oscilloscope/src/main.cpp @@ -10,6 +10,9 @@ BluetoothSerial SerialBlueTooth; // 定义蓝牙串口对象 +// 串口回调函数和遥控器回调函数不能同时使用 +// 回调函数和示波器和遥控器功能不能同时使用 + // 串口回调函数和遥控器回调函数不能同时使用 // 回调函数和示波器和遥控器功能不能同时使用 void setup()