#include #include #include #include #include #include #include #include #include // --- 协议定义 (必须与STM32端完全一致) --- #pragma pack(push, 1) // 强制1字节对齐 typedef struct { uint16_t voltage; // 电池电压 mV int16_t current; // 电池电流 mA uint8_t capacity; // 电池电量 % int16_t temp; // 电池温度 0.1K (需转换) uint16_t rem_capacity; // 剩余容量 uint16_t chg_voltage; // 充电电压 uint16_t chg_current; // 充电电流 uint8_t status_dsg; // 充放电状态 uint16_t cycle_count; // 循环次数 uint8_t rsoc; // 相对电量 } BMS_Payload_t; #pragma pack(pop) // 常量定义 const uint8_t FRAME_HEADER_0 = 0xAA; const uint8_t FRAME_HEADER_1 = 0x55; const uint8_t FRAME_TAIL_0 = 0x0D; const uint8_t FRAME_TAIL_1 = 0x0A; const uint8_t REQUEST_CMD = 0xA5; // 请求指令 const int EXPECTED_PAYLOAD_LEN = sizeof(BMS_Payload_t); // 应该为 17 // --- 串口配置函数 --- int open_serial_port(const char* portname) { int fd = open(portname, O_RDWR | O_NOCTTY | O_NDELAY); if (fd == -1) { perror("open_serial_port: Unable to open port"); return -1; } struct termios options; tcgetattr(fd, &options); // 设置波特率 115200 cfsetispeed(&options, B115200); cfsetospeed(&options, B115200); // 控制模式 (CLOCAL: 本地连接, CREAD: 开启接收) options.c_cflag |= (CLOCAL | CREAD); // 设置 8N1 (8数据位, 无校验, 1停止位) options.c_cflag &= ~PARENB; // 无校验 options.c_cflag &= ~CSTOPB; // 1停止位 options.c_cflag &= ~CSIZE; options.c_cflag |= CS8; // 8数据位 // *** 关键设置:Raw 模式 *** // 禁用规范模式 (ICANON)、回显 (ECHO)、信号 (ISIG) options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); // 禁用输出处理 (OPOST) options.c_oflag &= ~OPOST; // 禁用输入软件流控 (IXON, IXOFF, IXANY) 和 CR/LF 转换 options.c_iflag &= ~(IXON | IXOFF | IXANY | ICRNL | INLCR | IGNCR); // 设置读取超时 (VMIN=0, VTIME=10 => 非阻塞,读不到数据等待1秒返回) // 这里为了简单演示,使用阻塞式读取一点点数据 options.c_cc[VMIN] = 0; options.c_cc[VTIME] = 1; // 0.1秒超时 tcsetattr(fd, TCSANOW, &options); fcntl(fd, F_SETFL, 0); // 恢复为阻塞模式 (配合 VMIN/VTIME) return fd; } // --- 解析状态机枚举 --- enum State { STATE_WAIT_HEADER_0, STATE_WAIT_HEADER_1, STATE_WAIT_LEN, STATE_READ_PAYLOAD, STATE_WAIT_CHECKSUM, STATE_WAIT_TAIL_0, STATE_WAIT_TAIL_1 }; // --- 主程序 --- int main() { const char* port = "/dev/ttyS4"; int serial_fd = open_serial_port(port); if (serial_fd < 0) return 1; std::cout << "Listening on " << port << " at 115200 baud..." << std::endl; // 解析器状态变量 State current_state = STATE_WAIT_HEADER_0; std::vector payload_buffer; uint8_t expected_len = 0; uint8_t calc_checksum = 0; uint8_t recv_checksum = 0; uint8_t buf[128]; // 临时读取缓冲区 auto last_req_time = std::chrono::steady_clock::now(); bool first_run = true; while (true) { // --- 1. 发送请求逻辑 (每秒一次) --- auto now = std::chrono::steady_clock::now(); // 如果是第一次运行,或者距离上次发送超过 1 秒 (1000ms) if (first_run || std::chrono::duration_cast(now - last_req_time).count() >= 1000) { // 发送指令 0xA5 write(serial_fd, &REQUEST_CMD, 1); // 打印调试信息 (可选) // std::cout << "[TX] Request sent" << std::endl; last_req_time = now; first_run = false; } // --- 2. 接收处理逻辑 (保持不变) --- int n = read(serial_fd, buf, sizeof(buf)); if (n > 0) { for (int i = 0; i < n; i++) { uint8_t byte = buf[i]; switch (current_state) { case STATE_WAIT_HEADER_0: if (byte == FRAME_HEADER_0) current_state = STATE_WAIT_HEADER_1; break; case STATE_WAIT_HEADER_1: if (byte == FRAME_HEADER_1) current_state = STATE_WAIT_LEN; else if (byte == FRAME_HEADER_0) current_state = STATE_WAIT_HEADER_1; else current_state = STATE_WAIT_HEADER_0; break; case STATE_WAIT_LEN: expected_len = byte; if (expected_len == sizeof(BMS_Payload_t)) { payload_buffer.clear(); payload_buffer.reserve(expected_len); current_state = STATE_READ_PAYLOAD; } else { current_state = STATE_WAIT_HEADER_0; } break; case STATE_READ_PAYLOAD: payload_buffer.push_back(byte); if (payload_buffer.size() == expected_len) current_state = STATE_WAIT_CHECKSUM; break; case STATE_WAIT_CHECKSUM: recv_checksum = byte; current_state = STATE_WAIT_TAIL_0; break; case STATE_WAIT_TAIL_0: if (byte == FRAME_TAIL_0) current_state = STATE_WAIT_TAIL_1; else current_state = STATE_WAIT_HEADER_0; break; case STATE_WAIT_TAIL_1: if (byte == FRAME_TAIL_1) { // 计算校验和 uint8_t calc_sum = 0; for (uint8_t b : payload_buffer) calc_sum += b; if (calc_sum == recv_checksum) { BMS_Payload_t* bms = (BMS_Payload_t*)payload_buffer.data(); std::cout << "\n[RX] Data Updated: ------------------------" << std::endl; std::cout << "Voltage: " << bms->voltage << " mV" << std::endl; std::cout << "Current: " << bms->current << " mA" << std::endl; std::cout << "Capacity: " << (int)bms->capacity << " %" << std::endl; std::cout << "Temp: " << (float)bms->temp * 0.1f << " C" << std::endl; std::cout << "Rem Cap: " << bms->rem_capacity << " mAh" << std::endl; std::cout << "Chg Voltage: " << bms->chg_voltage << " mV" << std::endl; std::cout << "Chg Current: " << bms->chg_current << " mA" << std::endl; std::cout << "Status DSG: " << (int)bms->status_dsg << std::endl; std::cout << "Cycle Count: " << bms->cycle_count << std::endl; std::cout << "RSOC: " << (int)bms->rsoc << " %" << std::endl; } else { std::cerr << "Checksum Error!" << std::endl; } } current_state = STATE_WAIT_HEADER_0; break; } } } else { // 短暂休眠避免CPU占用过高,但不要睡太久以免错过数据 usleep(5000); } } close(serial_fd); return 0; }