#include "cmsis_os.h" #include "cmsis_os2.h" #include "main.h" #include "stdio.h" #include "usb_device.h" #include #include #include typedef struct { const char *cmd; int cmd_id; } CmdTable; /* 自定义协议 帧头 0xAA 55 帧长度 1字节 帧序号 1字节 帧类型 1字节 数据域 N字节 帧校验 1字节 | 帧头 | 命令 | 长度 | 帧号 | 数据 (128B) | CRC16 | |--------|------|--------|------|-------------|--------| | AA 55 | 01 | 00 80 | 01 | [0xXX...] | 2字节 | | 帧头 | 命令 | 长度 | 帧号 | 数据 (128B) | CRC16 | |--------|------|--------|------|-------------|--------| | AA 55 | 04 | 00 80 | FF | 00 | */ // extern uint8_t Uart_ReadCache[128]; // extern _Bool ReadFlag; // uint8_t CPk = 0; // 当前包计数 // void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) // { // UNUSED(huart); // __HAL_UART_CLEAR_OREFLAG(huart); // __HAL_UART_CLEAR_IDLEFLAG(huart); // if(__HAL_UART_GET_FLAG(huart, UART_FLAG_IDLE) != RESET) // // 空闲中断标记被置位 // { // __HAL_UART_CLEAR_IDLEFLAG(huart); // 清除中断标记 // HAL_UART_DMAStop(huart); // 停止DMA接收 // CPk = __HAL_DMA_GET_COUNTER(huart->hdmarx); // 总数据量 // HAL_UARTEx_ReceiveToIdle_DMA(huart, Uart_ReadCache, 128); // // 重新启动DMA接收 // } // // if ((Uart_ReadCache[0] == 'C') && (Uart_ReadCache[1] == 'M') && // (Uart_ReadCache[2] == 'D')) // // { // // char buf[10]; // // uint16_t i,j,k= 0; // // HAL_GPIO_WritePin( GPIOA, GPIO_PIN_8, GPIO_PIN_SET); // // for( k = 0; k < 8; k ++ ) // // { // // for( i = 0; i < 3; i ++) // // { // // for( j = 0; j < 98; j ++) // // { // // sprintf( buf, "%.4f\r\n", OutPut1[k][i][j]); // // HAL_UART_Transmit(&huart, (uint8_t // *)buf,strlen(buf),0xFFFF); // // while(HAL_UART_GetState(&huart) == // HAL_UART_STATE_BUSY_TX);//锟斤拷锟経ART锟斤拷锟酵斤拷锟斤拷 // // } // // } // // } // // ReadFlag = 1; // // HAL_GPIO_WritePin( GPIOA, GPIO_PIN_8, GPIO_PIN_RESET); // // } // // HAL_UARTEx_ReceiveToIdle_IT(&huart1, (uint8_t *)&Uart_ReadCache, 100); // //锟劫匡拷锟斤拷锟斤拷锟斤拷锟叫讹拷 // } // #include "command.h" // 假设每个通道每个频率点4字节(float),每帧最大数据长度为120字节(30个float) #define MAX_FRAME_DATA_LEN 120 // 指令的最小长度 #define COMMAND_MIN_LENGTH 4 // 循环缓冲区大小 #define BUFFER_SIZE 121 // 循环缓冲区 uint8_t buffer[BUFFER_SIZE]; // 循环缓冲区读索引 uint8_t readIndex = 0; // 循环缓冲区写索引 uint8_t writeIndex = 0; /** * @brief 增加读索引 * @param length 要增加的长度 */ void Command_AddReadIndex(uint8_t length) { readIndex += length; readIndex %= BUFFER_SIZE; } /** * @brief 读取第i位数据 超过缓存区长度自动循环 * @param i 要读取的数据索引 */ uint8_t Command_Read(uint8_t i) { uint8_t index = i % BUFFER_SIZE; return buffer[index]; } /** * @brief 计算未处理的数据长度 * @return 未处理的数据长度 * @retval 0 缓冲区为空 * @retval 1~BUFFER_SIZE-1 未处理的数据长度 * @retval BUFFER_SIZE 缓冲区已满 */ // uint8_t Command_GetLength() { // // 读索引等于写索引时,缓冲区为空 // if (readIndex == writeIndex) { // return 0; // } // // 如果缓冲区已满,返回BUFFER_SIZE // if (writeIndex + 1 == readIndex || (writeIndex == BUFFER_SIZE - 1 && // readIndex == 0)) { // return BUFFER_SIZE; // } // // 如果缓冲区未满,返回未处理的数据长度 // if (readIndex <= writeIndex) { // return writeIndex - readIndex; // } else { // return BUFFER_SIZE - readIndex + writeIndex; // } // } uint8_t Command_GetLength() { return (writeIndex + BUFFER_SIZE - readIndex) % BUFFER_SIZE; } /** * @brief 计算缓冲区剩余空间 * @return 剩余空间 * @retval 0 缓冲区已满 * @retval 1~BUFFER_SIZE-1 剩余空间 * @retval BUFFER_SIZE 缓冲区为空 */ uint8_t Command_GetRemain() { return BUFFER_SIZE - Command_GetLength(); } /** * @brief 向缓冲区写入数据 * @param data 要写入的数据指针 * @param length 要写入的数据长度 * @return 写入的数据长度 */ uint8_t Command_Write(uint8_t *data, uint16_t length) { // 如果缓冲区不足 则不写入数据 返回0 if (Command_GetRemain() < length) { return 0; } // 使用memcpy函数将数据写入缓冲区 if (writeIndex + length < BUFFER_SIZE) { memcpy(buffer + writeIndex, data, length); writeIndex += length; } else { uint8_t firstLength = BUFFER_SIZE - writeIndex; memcpy(buffer + writeIndex, data, firstLength); memcpy(buffer, data + firstLength, length - firstLength); writeIndex = length - firstLength; } return length; } /** * @brief 尝试获取一条指令 * @param command 指令存放指针 * @return 获取的指令长度 * @retval 0 没有获取到指令 */ uint8_t Command_GetCommand(uint8_t *command) { /* | 帧头 | 命令 | 长度 | 帧号 | 数据 (128B) | CRC16 | |--------|------|--------|------|-------------|--------| | AA 55 | 04 | 80 | FF | 00 | */ // 寻找完整指令 while (1) { // 如果缓冲区长度小于COMMAND_MIN_LENGTH 则不可能有完整的指令 if (Command_GetLength() < COMMAND_MIN_LENGTH) { return 0; } // 如果不是包头 则跳过 重新开始寻找 if (((Command_Read(readIndex) != 0xAA) || (Command_Read(readIndex + 1) != 0x55))) { Command_AddReadIndex(1); continue; } // 如果缓冲区长度小于指令长度 则不可能有完整的指令 uint8_t length = Command_Read(readIndex + 3); if (Command_GetLength() < length) { return 0; } // 如果校验和不正确 则跳过 重新开始寻找 uint16_t sum = 0; for (uint8_t i = 0; i < length - 2; i++) { sum += Command_Read(readIndex + i); } if (sum != (Command_Read(readIndex + length - 2) << 8 | Command_Read(readIndex + length - 1))) { Command_AddReadIndex(1); continue; } // 如果找到完整指令 则将指令写入command 返回指令长度 for (uint8_t i = 0; i < length; i++) { command[i] = Command_Read(readIndex + i); } Command_AddReadIndex(length); return length; } } extern osSemaphoreId_t Command_Semaphore; extern UART_HandleTypeDef huart1; extern uint16_t CLKHZ[98]; extern void CLKHZSET(uint16_t Deep); extern float LineCheckF[32]; union { float ufloat; uint32_t u32; uint16_t u16[2]; uint8_t u8[4]; } uDataCover; uint16_t FramePack(uint8_t *buf, uint8_t cmd, uint8_t frameNum, uint8_t *data, uint16_t dataLength) { uint8_t Lenth = 0; uint16_t crcSum = 0; memset(buf, 0, 128); buf[0] = 0xAA; // 帧头 buf[1] = 0x55; // 帧头 buf[2] = cmd; // 命令 buf[3] = 0x00; // 长度 buf[4] = frameNum; // 帧号 Lenth = 7; for (uint8_t i = 0; i < 5; i++) { crcSum += buf[i]; } for (uint8_t i = 0; i < dataLength; i++) { buf[i + 5] = data[i]; crcSum += data[i]; Lenth += 1; } buf[3] = Lenth; // 更新长度 crcSum +=Lenth; buf[Lenth - 2] = crcSum >> 8; // CRC高字节 buf[Lenth - 1] = crcSum & 0xFF; // CRC低字节 return Lenth; } struct uCommunication CommunicationData; extern float OutPut1[8][4][98]; extern float OutPut2[8][4][98]; extern float OutPut3[8][4][98]; extern float OutPut4[8][4][98]; extern uint8_t Uart_ReadCache[128]; uint8_t command[50]; uint8_t SendBuf[128]; int commandLength = 0; uint8_t dtime = 10; void Command_Deal(void) { osSemaphoreAcquire(Command_Semaphore, osWaitForever); // 等待命令信号量 do { memset(command,0,50); commandLength = Command_GetCommand(command); if (commandLength == 0) { return; } uint8_t cmd = command[2]; // 获取命令 uint8_t SenDataLenth = 0; switch (cmd) { case 1: // 开始测试命令 HAL_GPIO_WritePin(GPIOI, GPIO_PIN_7, GPIO_PIN_RESET); osDelay(50); HAL_GPIO_WritePin(GPIOI, GPIO_PIN_7, GPIO_PIN_SET); CommunicationData.MeasurementPrecision = 0; CommunicationData.MeasurementFlag = 1; break; case 2: // 终止测试命令 CommunicationData.MeasurementPrecision = 0; CommunicationData.MeasurementFlag = 0; break; case 3: // 设定深度 CommunicationData.Deep = (command[5] << 8) | command[6]; CLKHZSET(CommunicationData.Deep); break; case 4: // 设置增益 CommunicationData.Gain = command[5]; break; case 5: // 设定通道数量 CommunicationData.ChannelNum = command[5]; break; case 6: // 道接地信号强度测试命令 CommunicationData.SingelStrengthMeasurementFlag = 1; CommunicationData.MeasurementPrecision = 0; break; case 7: // 获取通道接地信号强度 if (CommunicationData.MeasurementPrecision == 100.0f) { SenDataLenth = FramePack(SendBuf, 0x07, 0x01, (uint8_t *)LineCheckF, 16 * 4); HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_SET); HAL_UART_Transmit(&huart1, SendBuf, SenDataLenth, HAL_MAX_DELAY); while (HAL_UART_GetState(&huart1) == HAL_UART_STATE_BUSY_TX) ; // 等待UART发送完成 osDelay(50); SenDataLenth = FramePack(SendBuf, 0x07, 0xFF, (uint8_t *)(LineCheckF + 16), 16 * 4); HAL_UART_Transmit(&huart1, SendBuf, SenDataLenth, HAL_MAX_DELAY); while (HAL_UART_GetState(&huart1) == HAL_UART_STATE_BUSY_TX) ; HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_RESET); osDelay(100); HAL_UARTEx_ReceiveToIdle_DMA(&huart1, Uart_ReadCache, 128); // 重新启动DMA接收 } break; case 8: // 获取测量进度 { SenDataLenth = FramePack(SendBuf, 0x08, 0xFF, (uint8_t *)&CommunicationData.MeasurementPrecision, 1); HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_SET); HAL_UART_Transmit(&huart1, SendBuf, SenDataLenth, HAL_MAX_DELAY); while (HAL_UART_GetState(&huart1) == HAL_UART_STATE_BUSY_TX) ; // 等待UART发送完成 HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_RESET); break; } case 9: // 获取测量结果 if (CommunicationData.MeasurementPrecision == 100.0f) { uint8_t totalChannels = CommunicationData.ChannelNum; uint8_t totalFreqs = 0; for (uint8_t i = 0; i < 98; i++) { if (CLKHZ[i] != 0) totalFreqs++; else break; } uint32_t totalDataLen = totalChannels * totalFreqs * 4; uint8_t frameNum = 1; uint32_t sentLen = 0; while (sentLen < totalDataLen) { /** * 根据剩余待发送数据长度,计算本次发送的数据长度,并组装数据帧。 * * 1. 计算本次发送的数据长度 sendLen,不超过 MAX_FRAME_DATA_LEN。 * 2. 初始化数据缓冲区 dataBuf。 * 3. 遍历每个待发送的 float 数据(每 4 字节为一个 float),根据 globalIdx 计算通道号 ch 和频点 freq。 * 4. 根据通道号 ch 从对应的 OutPut 数组中获取数据 val。 * - ch < 8: 从 OutPut1 取数据 * - ch < 16: 从 OutPut2 取数据 * - ch < 24: 从 OutPut3 取数据 * - ch < 32: 从 OutPut4 取数据 * 5. 将获取到的 float 数据 val 拷贝到 dataBuf 中,准备发送。 * * 参数说明: * - totalDataLen: 总数据长度(字节) * - sentLen: 已发送的数据长度(字节) * - MAX_FRAME_DATA_LEN: 单帧最大数据长度(字节) * - totalChannels: 总通道数 * - OutPut1~4: 四组输出数据数组 */ uint32_t remain = totalDataLen - sentLen; uint8_t sendLen = (remain > MAX_FRAME_DATA_LEN) ? MAX_FRAME_DATA_LEN : remain; uint8_t dataBuf[MAX_FRAME_DATA_LEN]; // 组装数据 uint32_t dataIdx = 0; uint32_t globalIdx = sentLen / 4; HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_SET); osDelay(dtime); for (uint8_t i = 0; i < sendLen / 4; i++) { uint8_t ch = (globalIdx % totalChannels); uint8_t freq = (globalIdx / totalChannels); float val = 0.0f; if (ch < 8) val = OutPut1[ch][0][freq]; else if (ch < 16) val = OutPut2[ch - 8][0][freq]; else if (ch < 24) val = OutPut3[ch - 16][0][freq]; else if (ch < 32) val = OutPut4[ch - 24][0][freq]; memcpy(&dataBuf[dataIdx], &val, 4); dataIdx += 4; globalIdx++; } uint8_t thisFrameNum = (sentLen + sendLen >= totalDataLen) ? 0xFF : frameNum; SenDataLenth = FramePack(SendBuf, 0x09, thisFrameNum, dataBuf, sendLen); HAL_UART_Transmit(&huart1, SendBuf, SenDataLenth, HAL_MAX_DELAY); while (HAL_UART_GetState(&huart1) == HAL_UART_STATE_BUSY_TX) ; sentLen += sendLen; frameNum++; } HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_RESET); osDelay(100); HAL_UARTEx_ReceiveToIdle_DMA(&huart1, Uart_ReadCache, 128); // 重新启动DMA接收 } break; case 10: // 获取电池电压 SenDataLenth = FramePack(SendBuf, 0x0A, 0x01, (uint8_t *)&CommunicationData.BatteryVoltage, 4); HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_SET); HAL_UART_Transmit(&huart1, SendBuf, SenDataLenth, HAL_MAX_DELAY); while (HAL_UART_GetState(&huart1) == HAL_UART_STATE_BUSY_TX) ; // 等待UART发送完成 HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_RESET); break; case 11: // 获取电流 SenDataLenth = FramePack(SendBuf, 0x0B, 0x01, (uint8_t *)&CommunicationData.BatteryCurrent, 4); HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_SET); HAL_UART_Transmit(&huart1, SendBuf, SenDataLenth, HAL_MAX_DELAY); while (HAL_UART_GetState(&huart1) == HAL_UART_STATE_BUSY_TX) ; // 等待UART发送完成 HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_RESET); break; } } while(commandLength != 0); } /* | 帧头 | 命令 | 长度 | 帧号 | 数据 (128B) | CRC16 | |--------|------|--------|------|-------------|--------| | AA 55 | 04 | 80 | FF | 00 | 设定频率 设置增益 设定通道数量 道接地信号强度测试命令 获取通道接地信号强度 开始测试命令 终止测试命令 获取测量进度 获取测量结果 获取电池电压 获取电流 CmdTable cmd_table[] = { {"CMD_START", 1}, // 开始测试命令 {"CMD_STOP", 2}, // 终止测试命令 {"CMD_SET_FREQ", 3}, // 设定深度 {"CMD_SET_GAIN", 4}, // 设置增益 {"CMD_SET_CHANNELS", 5}, // 设定通道数量 {"CMD_TEST_GROUND", 6}, // 道接地信号强度测试命令 {"CMD_GET_GROUND", 7}, // 获取通道接地信号强度 {"CMD_GET_PROGRESS", 8}, // 获取测量进度 {"CMD_GET_RESULT", 9}, // 获取测量结果 {"CMD_GET_BATTERY_VOLTAGE", 10}, // 获取电池电压 {"CMD_GET_CURRENT", 11}, // 获取电流 // ...更多命令 }; */