|
|
虽然我已经把铁塔的电池连接APP已经写的基本等于完美了,但是白天的时候看电池电量悬浮窗还是费劲的,于是拿着大厦龙雀的DX-WF25(ESP32-C2)做了个电量表解析到数码管
材料:
- 大厦龙雀DX-WF25 成本约 1元 ( 可能涨价了 我用的开发板会贵点 没有开发板需要把io9拉低进入烧录模式)
- [可选] 大厦龙雀2.4G主从透传模块*2 (没花钱 用券薅的) (用来无线连接BMS的,主要是我有多个电池多台电动车需要热切换)
- [可选] (用来当自动关闭开关的(天邦达可能会失效))电平信号MOS管模块(单MOS也行 上面的mos型号 D4184(信号放大MOS管) )
- 中盛Modbus主从显示数码管(TTL版本) 约9.9 (我用的) 如果不在乎成本可以选中盛Ascii数码管(不需要手动调浮点 可以花式切换电量和百分比模式)
- [直连串口则可选] 485转TTL模块 2-10元
- [可选] 5V稳压电源 , 3.3V稳压电源 (BMS上面也能取电 我取的3.3和12V)
- [可选] 环氧树脂 2块 我用来灌胶的 防水用的 不管目前还没灌胶因为我感觉还有需要优化的地方
设备电压备注:
- DX-WF25 3.3V
- 2.4G主从透传模块 3.3V
- 中盛Modbus主从显示数码管 3.3V - 36V (官方说的是5V 我实测3.3V 50ma以上也能正常工作(但是可能很容易坏))
- 485转TTL模块 3.3-5V (我的是2.8-33V的)
- 电平信号MOS管 过电上限好像是36V 至于电流忽略不计
备注:我对硬件不太了解,可能会有说错的地方多担待
步骤
1. 下载Arduino(自开发的话) 可以参考这篇帖子 :arduino烧录成功DX-WF25 可以避开很多坑 我用的 3.13 的
2.直接烧录的话 下载我编译好的bin (自行找 ---flash_download_tool_3.9.3--烧录工具 大厦龙雀DX-WF25资料包里面有 )
下载链接:https://x-1300389275.cos.ap-shan ... %9B%BA%E4%BB%B6.zip
参考这个配置方式:
单片机源代码:
- // 定义第二个串口的引脚
- #define UART1_RX_PIN 4 // 从设备1读取数据
- #define UART1_TX_PIN 5 // 向设备1发送数据
- #define COM_SWITCH GPIO_NUM_2 // 向设备1发送数据
- int LOOP_COUNT = 0;
- bool IS_RS_ONCE = false;
- void loopSendRSCode() {
- uint8_t data[8] = { 0x01, 0x03, 0x00, 0x00, 0x00, 0x1D, 0x85, 0xC3 };
- Serial.write(data, 8);
- }
- // CRC校验函数 (Modbus CRC-16)
- bool isCrc16Valid(uint8_t *data, int len) {
- if (len < 3) return false;
- uint16_t crc = 0xFFFF;
- for (int i = 0; i < len - 2; i++) {
- crc ^= (uint16_t)data[i];
- for (int j = 0; j < 8; j++) {
- crc = (crc & 0x0001) ? ((crc >> 1) ^ 0xA001) : (crc >> 1);
- }
- }
- uint16_t receivedCrc = (data[len - 1] << 8) | data[len - 2];
- return (crc == receivedCrc);
- }
- // 获取SOC值 (索引8-9)
- uint16_t getSOC(uint8_t *buffer) {
- return (buffer[7] << 8) | buffer[8];
- }
- // 获取电流值 (索引13-14)
- // 01 03 3C 19 FF 00 14 00 5A 06 5E 00 5A 00 00 00 1D 00 1C 00 1D 0C FD 0C FD 0C FA 0C FA 0C FA 0C FB 0C FE 0C FE 0C FE 0C FD 0C FB 0C FD 0C FD 0C FB 0C FB 0D 01 0D 03 0D 04 0D 03 0D 03 00 1D 8A 50
- float getCurrent(uint8_t *buffer) {
- int16_t raw = (buffer[13] << 8) | buffer[14];
- if (raw == 0) {
- return 0.0f;
- } else if (raw > 0 && raw < 25536) {
- return raw / 100.0f;
- } else {
- return (raw - 65536) / 100.0f;
- }
- }
- bool isCurrent(uint8_t *buffer) {
- return (buffer[13] + buffer[14]) != 0;
- }
- // Modbus数据包生成函数
- void sendSocModbusInDigitalTube(int num) {
- uint8_t data[6] = { 0x01, 0x06, 0x00, 0x00 };
- data[4] = (num >> 8) & 0xFF;
- data[5] = num & 0xFF;
- uint16_t crc = 0xFFFF;
- for (int i = 0; i < 6; i++) {
- crc ^= (uint16_t)data[i];
- for (int j = 0; j < 8; j++) {
- crc = (crc & 0x0001) ? ((crc >> 1) ^ 0xA001) : (crc >> 1);
- }
- }
- uint8_t packet[8];
- memcpy(packet, data, 6);
- packet[6] = crc & 0xFF;
- packet[7] = (crc >> 8) & 0xFF;
- Serial1.write(packet, 8);
- }
- // 从串口缓冲区解析Modbus响应
- void parseModbusResponse() {
- int len = Serial.available();
- //清空不符合条件的包 避免内存溢出
- if (len < 63) {
- while (Serial.available() > 0) {
- Serial.read();
- }
- return;
- }
- static uint8_t buffer[64]; // 静态缓冲区,保存完整帧
- int bufferIndex = 0;
- while (Serial.available() > 0 && bufferIndex < sizeof(buffer)) {
- buffer[bufferIndex++] = Serial.read();
- }
- bool foundHeader = false;
- // 01 03 3C (2.0版本)
- // 01 03 3A (1.0版本)
- // 两个版本 位置是一样的
- if (buffer[0] == 0x01 && buffer[1] == 0x03 && (buffer[2] == 0x3A || buffer[2] == 0x3C)) {
- foundHeader = true;
- }
-
- // 清空其他数据
- while (Serial.available() > 0) {
- Serial.read();
- }
- if (!foundHeader || !isCrc16Valid(buffer, 63)) {
- return;
- }
- uint16_t soc = getSOC(buffer);
- if (isCurrent(buffer)) {
- LOOP_COUNT = 0;
- gpio_set_level(COM_SWITCH, 1);
- delay(500);
- }
- sendSocModbusInDigitalTube(soc);
- }
- void gpio_init(void) {
- // 配置GPIO为输出模式
- gpio_config_t io_conf = {
- .pin_bit_mask = (1ULL << COM_SWITCH),
- .mode = GPIO_MODE_OUTPUT, // 输出模式
- .pull_up_en = GPIO_PULLUP_DISABLE, // 不上拉
- .pull_down_en = GPIO_PULLDOWN_DISABLE, // 不下拉
- .intr_type = GPIO_INTR_DISABLE // 禁用中断
- };
- // 应用配置
- gpio_config(&io_conf);
- // 初始状态设为低电平
- gpio_set_level(COM_SWITCH, 0);
- }
- void setup() {
- //波特率
- Serial.begin(9600);
- gpio_init();
- delay(1000);
- // 數碼管串口
- Serial1.begin(9600, SERIAL_8N1, UART1_RX_PIN, UART1_TX_PIN);
- gpio_set_level(COM_SWITCH, 1);
- }
- void loop() {
- // 发送查询
- loopSendRSCode();
- parseModbusResponse();
- delay(5000);
- LOOP_COUNT++;
- // 约1分钟没有电流时候自动关闭数码管
- if ((LOOP_COUNT % 15) == 0) {
- gpio_set_level(COM_SWITCH, 0);
- }
- }
复制代码
我对WF25的引脚定义:
- IO2 数码管供电MOS 电平信号 (高电平开启)
- IO4 数码管TX(A标识)
- IO5 数码管 RX(B标识)
- TX 默认 接485
- RX 默认 接485
- 3.3 默认 接电源
- GND 接电源(如果是那种两块一片的可能需要接电池GND)
|
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有账号?立即注册
x
打赏
-
查看全部打赏
|