Vehicle_Road_Counter/read_bms.cpp

195 lines
7.9 KiB
C++
Raw Permalink Normal View History

2025-12-17 13:32:05 +08:00
#include <iostream>
#include <fcntl.h>
#include <unistd.h>
#include <termios.h>
#include <cstring>
#include <cstdint>
#include <vector>
#include <iomanip>
#include <chrono>
// --- 协议定义 (必须与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<uint8_t> 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<std::chrono::milliseconds>(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;
}