增加电池信息读取,文件为read_bms.cpp
This commit is contained in:
parent
f44c8e1ae9
commit
eb47fc2878
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"modbus_rtu_devices": [
|
||||
{
|
||||
"enabled": false,
|
||||
"enabled": true,
|
||||
"device_id": "rtu_temp_sensor_lab",
|
||||
"port_path": "/dev/ttyS7",
|
||||
"baud_rate": 9600,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,195 @@
|
|||
#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;
|
||||
}
|
||||
Loading…
Reference in New Issue