/*
 * STM32F407 串口双向透传
 * ------------------------------------------------------------
 * 485主机接口  : PB6(RX)/PB7(TX)/PB5(EN)  9600
 * 井下数据口   : PA2(USART2_TX)/PA3(USART2_RX)  300
 * 调试口       : PA9/PA10(USART1) 115200
 */

#include <Arduino.h>
#include <SoftwareSerial.h>


// ==================== 硬件配置 ====================
#define RS485_RX PB7
#define RS485_TX PB6
#define RS485_EN PB5

#define EEPROM_BASE 0x080E0000  //flash 转EPROM 起始地址

// ==================== 引脚定义 ====================
// 开关 控制引脚
#define CL_0 PB0  // PB0 长短缆切换
#define CL_1 PB1  // PB1 长短缆切换
#define KZ PE10   // PE10 KZ1

// 增益  编码输出引脚 (1-16)
#define ENCODE_PB2 PB2  // PB2 (最高位)
#define ENCODE_PE7 PE7  // PE7
#define ENCODE_PE8 PE8  // PE8
#define ENCODE_PE9 PE9  // PE9 (最低位)

// ADC 输入引脚

#define ADC1_PIN PA5  // PA5/ADC1 长短缆检测
#define DS_PIN PA6  // PA6/ADC2 控制器输出电压
#define CS_PIN PA7  // PA7/ADC3 控制器输出电流

// 解码管脚
#define PA1_PIN PA1
#define PA0_PIN PA0

// 使用你的方式定义串口
Uart Serial1(USART1);  //调试用
//Uart JxSerial(USART2); //井下
SoftwareSerial rs485(RS485_RX, RS485_TX);
SoftwareSerial JxSerial(PA3, PA2);  // RX,TX




uint8_t cdzyBuf[4];  //长短缆 增益设置

bool readRs485(uint8_t* buffer, uint16_t maxLen, uint16_t* len, uint32_t timeoutMs);
bool readTypec(uint8_t* buffer, uint16_t maxLen, uint16_t* len, uint32_t timeoutMs);
void processReceivedData(byte* receivedData, int length);

// ============================================================
// 1. rs485数据接收回调函数
// ============================================================
// ==================== 485方向控制 ====================
void rs485SetReceive() {
  digitalWrite(RS485_EN, LOW);
  delayMicroseconds(10);
}
void rs485SetTransmit() {
  digitalWrite(RS485_EN, HIGH);
  delayMicroseconds(10);
}
// ==================== RS485发送 ====================
void rs485Write(uint8_t data) {
  rs485SetTransmit();
  rs485.write(data);
  rs485.flush();
  rs485SetReceive();
}
void rs485WriteBuffer(uint8_t* buf, uint16_t len) {
  rs485SetTransmit();
  rs485.write(buf, len);
  rs485.flush();
  rs485SetReceive();
}


// ============================================================
// 2. Flash写多个字节
// ============================================================

// 保存数据到Flash(2字节对齐)
void saveData(uint8_t* data, uint16_t len) {
  HAL_FLASH_Unlock();
  // 擦除扇区
  FLASH_EraseInitTypeDef e = {};
  e.TypeErase = FLASH_TYPEERASE_SECTORS;
  e.Sector = 11;
  e.NbSectors = 1;
  e.VoltageRange = FLASH_VOLTAGE_RANGE_3;
  uint32_t err;
  HAL_FLASHEx_Erase(&e, &err);
  // 2字节对齐写入
  for (int i = 0; i < len; i += 2) {
    uint16_t w = 0xFFFF;
    if (i < len) w = data[i];
    if (i + 1 < len) w |= (data[i + 1] << 8);
    HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, EEPROM_BASE + i, w);
  }
  HAL_FLASH_Lock();
}

// =============== 读取数据 ===============
void loadData(uint8_t* buf, uint16_t len) {
  for (int i = 0; i < len; i++) {
    buf[i] = *(uint8_t*)(EEPROM_BASE + i);
  }
}

// ============================================================
// ============================================================
// 3. 长短缆管脚赋值   增益管脚赋值
// ============================================================

// 长短缆管脚赋值
void setDecode(uint8_t val) {
  digitalWrite(CL_0, val & 0x01);
  digitalWrite(CL_1, (val >> 1) & 0x01);
}

// 增益管脚赋值
void setEncode(uint8_t val) {
  digitalWrite(ENCODE_PE9, val & 0x01);
  digitalWrite(ENCODE_PE8, (val >> 1) & 0x01);
  digitalWrite(ENCODE_PE7, (val >> 2) & 0x01);
  digitalWrite(ENCODE_PB2, (val >> 3) & 0x01);
}

// ============================================================
// 4. ----------超时接收  包含 485 和 设置串口----------
// ============================================================
// 超时接收(精简版)
bool readRs485(uint8_t* buffer, uint16_t maxLen, uint16_t* len, uint32_t timeoutMs = 5) {
  *len = 0;
  if (!buffer || maxLen == 0 || !rs485.available()) return false;
  uint32_t start = millis();
  while (*len < maxLen && (millis() - start) < timeoutMs) {
    if (rs485.available()) {
      buffer[(*len)++] = rs485.read();
      start = millis();  // 收到数据重置超时
    }
    delayMicroseconds(50);
  }
  return (*len > 0);
}

// 超时接收(精简版)
bool readTypec(uint8_t* buffer, uint16_t maxLen, uint16_t* len, uint32_t timeoutMs = 5) {
  *len = 0;
  if (!buffer || maxLen == 0 || !Serial1.available()) return false;
  uint32_t start = millis();
  while (*len < maxLen && (millis() - start) < timeoutMs) {
    if (Serial1.available()) {
      buffer[(*len)++] = Serial1.read();
      start = millis();  // 收到数据重置超时
    }
    delayMicroseconds(50);
  }
  return (*len > 0);
}


// ==================== 数据转发 ====================
// void forwardData() {
//   // 1. RS485 -> 调试口 + 井下口
//   while (rs485.available()) {
//     uint8_t data = rs485.read();
//     Serial1.write(data);
//     JxSerial.write(data);
//   }

//   // 2. 调试口 -> RS485 + 井下口
//   while (Serial1.available()) {
//     uint8_t data = Serial1.read();
//     rs485Write(data);
//     JxSerial.write(data);
//   }

//   // 3. 井下口 -> RS485 + 调试口
//   while (JxSerial.available()) {
//     uint8_t data = JxSerial.read();
//     rs485Write(data);
//     Serial1.write(data);
//   }
// }

// ============================================================
// 5. ----------crc 校验处理----------
// ============================================================

uint16_t Modbus_crc16(uint8_t* snd, uint16_t num) {
  uint16_t Cal_Crc_i, Cal_Crc_j;
  uint16_t c, crc = 0xFFFF;
  for (Cal_Crc_i = 0; Cal_Crc_i < num; Cal_Crc_i++) {
    c = snd[Cal_Crc_i] & 0x00FF;
    crc ^= c;
    for (Cal_Crc_j = 0; Cal_Crc_j < 8; Cal_Crc_j++) {
      if (crc & 0x0001) {
        crc >>= 1;
        crc ^= 0xA001;
      } else {
        crc >>= 1;
      }
    }
  }
  return crc;
}







// ==================== 系统时钟配置 ====================
extern "C" void SystemClock_Config(void) {
  RCC_OscInitTypeDef RCC_OscInitStruct = {};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {};

  __HAL_RCC_PWR_CLK_ENABLE();
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);

  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLM = 12;
  RCC_OscInitStruct.PLL.PLLN = 336;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
  RCC_OscInitStruct.PLL.PLLQ = 7;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
    Error_Handler();
  }

  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK) {
    Error_Handler();
  }

  SystemCoreClock = 168000000UL;
}

// ============================================================
// 7. ADC读电压信号
// ============================================================
void readADC(int& ch1, int& ch2, int& ch3) {
  ch1 = analogRead(ADC1_PIN);
  ch2 = analogRead(DS_PIN);
  ch3 = analogRead(CS_PIN);
}



// ============================================================
// 8. 解码配置
// ============================================================



//全局变量
bool bh = 0;
bool fs = 0;
bool js = 1;

/* 时间常数 */
const unsigned long TIME_UNIT = 310;
const unsigned long TIME_MIN = 290;
const unsigned long TIME_MAX = 330;

/* 上升沿时间戳环形缓冲 */
#define TIMEBUF_SIZE 512
volatile unsigned long timeBuf[TIMEBUF_SIZE];
volatile uint8_t timeHead = 0;
volatile uint8_t timeTail = 0;

unsigned long lastCaptureTime = 0;
bool waitingForFirstBit = true;

/* 原始比特缓冲 */
#define MAX_DATA_SIZE 300
bool dataBuffer[MAX_DATA_SIZE];
int dataBufferIndex = 0;

/* -------------------- 新增:解码结果缓冲 -------------------- */
#define DECODED_BUFFER_SIZE 128
uint8_t decodedBuffer[DECODED_BUFFER_SIZE];
int decodedBufferIndex = 0;
/* ---------------------------------------------------------- */



// 定义超时阈值(3ms)
#define TIMEOUT_THRESHOLD 4000  // 3ms in microseconds

void processData() {
  // 等待第一个中断
  if (timeTail == timeHead) {
    return;  // 没有数据,直接返回
  }

  unsigned long startTime = micros();
  bool dataStarted = false;
  dataBufferIndex = 0;
  decodedBufferIndex = 0;
  waitingForFirstBit = true;
  lastCaptureTime = 0;

  while (true) {
    noInterrupts();
    if (timeTail == timeHead) {
      interrupts();
      // 检查是否超时(3ms无新数据)
      if (dataStarted && (micros() - startTime >= TIMEOUT_THRESHOLD)) {
        if (dataBufferIndex > 0) {
          decodeAndStore(dataBuffer, dataBufferIndex);
        }
        if (decodedBufferIndex > 0) {
          rs485WriteBuffer(decodedBuffer, decodedBufferIndex);
        }
        break;
      }
      continue;
    }

    // 有新的中断数据
    unsigned long edgeTime = timeBuf[timeTail];
    timeTail = (timeTail + 1) & (TIMEBUF_SIZE - 1);
    interrupts();

    // 标记数据开始
    if (!dataStarted) {
      dataStarted = true;
      startTime = micros();  // 重置超时计时
    }

    unsigned long interval = (lastCaptureTime == 0) ? 0 : (edgeTime - lastCaptureTime);

    // 无效窄脉冲(仅在已有上次捕获时判断)
    if (lastCaptureTime != 0 && interval < TIME_MIN) {
      lastCaptureTime = edgeTime;
      startTime = micros();  // 重置超时计时
      continue;
    }

    // 如果是第一个比特或超时后的第一个1
    if (waitingForFirstBit) {
      if (dataBufferIndex < MAX_DATA_SIZE)
        dataBuffer[dataBufferIndex++] = true;
      waitingForFirstBit = false;
    } else {
      // 处理正常数据间隔
      if (interval > TIME_MAX) {
        float units = (float)interval / TIME_UNIT;
        int zeros = round(units) - 1;
        if (zeros < 1) zeros = 0;
        for (int i = 0; i < zeros; ++i)
          if (dataBufferIndex < MAX_DATA_SIZE)
            dataBuffer[dataBufferIndex++] = false;
        if (dataBufferIndex < MAX_DATA_SIZE)
          dataBuffer[dataBufferIndex++] = true;
      } else if (interval >= TIME_MIN) {
        if (dataBufferIndex < MAX_DATA_SIZE)
          dataBuffer[dataBufferIndex++] = true;
      }
    }

    lastCaptureTime = edgeTime;
    startTime = micros();  // 每次中断都重置超时计时
  }

  // 跳出循环后的清理(如果需要)
  dataBufferIndex = 0;
  decodedBufferIndex = 0;
}

/* -------------------- 10-bit 解码 -------------------- */
// 直接解码:enc[0..7] 是 d0..d7(LSB 先发),不做差分
static uint8_t decodeEncodedByte(const bool* enc) {
  uint8_t val = 0;
  for (int i = 0; i < 8; ++i) {
    if (enc[i]) val |= (1u << i);  // LSB 先发:enc[0] -> bit0
  }
  return val;
}

// 扫描 bool 数组,将所有完整 10-bit 帧的解码字节存入 decodedBuffer
static void decodeAndStore(const bool* buf, int len) {
  for (int i = 0; i + 9 < len; ++i) {
    // 起始位和结束位必须是 1(低电平)
    if (!buf[i] || !buf[i + 9]) continue;

    uint8_t val = decodeEncodedByte(buf + i + 1);  // 取 i+1 .. i+8 共 8 位

    if (decodedBufferIndex < DECODED_BUFFER_SIZE) {
      decodedBuffer[decodedBufferIndex++] = val;
    }

    i += 9;  // 跳过这 10 位
  }
}


// ============================================================
// 6.  --------- 数据----------处理------------
// ============================================================

void processReceivedData(byte* receivedData, int length) {
  if (length > 30 || length < 8) return;                                              //数据超长 丢掉
  uint16_t receivedCrc = (receivedData[length - 1] << 8) | receivedData[length - 2];  // 检查CRC校验
  uint16_t calculatedCrc = Modbus_crc16(receivedData, length - 2);
  if (receivedCrc != calculatedCrc) {
    return;
  }
  unsigned int crc16;
  unsigned char DataSend[24];  // 用于存储要发送的数据

  if (receivedData[0] == 0xAA) {
    // CommandExcute(data, length);  //处理通讯协议    处理客户给定的协议。
    byte address = receivedData[0];
    if ((receivedData[1] == 0x03)) {
      uint16_t regAddress = (receivedData[2] << 8) | receivedData[3];
      // 根据地址范围处理
      switch (regAddress) {
        //读控制器电压电流
        case 0x0018:
          {
            //读长短缆
            DataSend[0] = address;
            DataSend[1] = 0x03;
            DataSend[2] = (receivedData[4] * 256 + receivedData[5]) * 2;
            ///读取示例如下
            int adc1, ds, cs;
            readADC(adc1, ds, cs);  // 执行后三个变量被赋值

            // 将 0-4095 的读数转换为电压值 (假设参考电压 VREF+ 为 3.3V)
            float voltage5 = adc1 * (3.3 / 4095.0);
            float voltage6 = ds * 0.3065;  //10倍
            float voltage7 = cs * 0.1007;  //100倍

            uint16_t v5 = (uint16_t)(voltage5 + 0.5f);
            uint16_t v6 = (uint16_t)(voltage6 + 0.5f);
            uint16_t v7 = (uint16_t)(voltage7 + 0.5f);

            DataSend[3] = (v6 >> 8) & 0xFF;
            DataSend[4] = v6 & 0xFF;
            DataSend[5] = (v7 >> 8) & 0xFF;
            DataSend[6] = v7 & 0xFF;

            crc16 = Modbus_crc16(&DataSend[0], 7);
            DataSend[7] = crc16 % 256;
            DataSend[8] = crc16 / 256;
           // Serial1.write(&DataSend[0], 9);
            rs485WriteBuffer(&DataSend[0], 9);
            break;
          }

          ///////////// 控制器信息 /////////////
        case 0x0020:
          //读长短缆
          DataSend[0] = address;
          DataSend[1] = 0x03;
          DataSend[2] = (receivedData[4] * 256 + receivedData[5]) * 2;
          DataSend[3] = cdzyBuf[0];  //ram中 长短缆 的值
          DataSend[4] = cdzyBuf[1];
          crc16 = Modbus_crc16(&DataSend[0], 5);
          DataSend[5] = crc16 % 256;
          DataSend[6] = crc16 / 256;
         // Serial1.write(&DataSend[0], 7);
          rs485WriteBuffer(&DataSend[0], 7);
          break;
        case 0x0021:
          //读增益
          DataSend[0] = address;
          DataSend[1] = 0x03;
          DataSend[2] = (receivedData[4] * 256 + receivedData[5]) * 2;
          DataSend[3] = cdzyBuf[2];  //ram中 长短缆 的值
          DataSend[4] = cdzyBuf[3];
          crc16 = Modbus_crc16(&DataSend[0], 5);
          DataSend[5] = crc16 % 256;
          DataSend[6] = crc16 / 256;
          //Serial1.write(&DataSend[0], 7);
          rs485WriteBuffer(&DataSend[0], 7);
          break;
        default:
          break;
      }
    }

    if ((receivedData[1] == 0x10)) {  //写多个寄存器
      uint16_t regAddress = (receivedData[2] << 8) | receivedData[3];
      // 根据地址范围处理
      switch (regAddress) {
        case 0x0020:
          //长短缆设置

          cdzyBuf[0] = receivedData[7];
          cdzyBuf[1] = receivedData[8];

          setDecode(cdzyBuf[1]);  //获取到数据后 更改gpio 低位有效
          // 设置增益: 0x0A (1010)

          saveData(cdzyBuf, sizeof(cdzyBuf));  // 存储到flash

          DataSend[0] = receivedData[0];  // 层位
          DataSend[1] = receivedData[1];  //功能码
          DataSend[2] = receivedData[2];  // 寄存器 高位
          DataSend[3] = receivedData[3];  // 寄存器 低位
          DataSend[4] = receivedData[4];  // 数据高位
          DataSend[5] = receivedData[5];  //
          crc16 = Modbus_crc16(&DataSend[0], 6);
          DataSend[6] = crc16 % 256;
          DataSend[7] = crc16 / 256;
          //Serial1.write(&DataSend[0], 8);
          rs485WriteBuffer(&DataSend[0], 8);
          break;
        case 0x0021:
          //增益设置
          cdzyBuf[2] = receivedData[7];
          cdzyBuf[3] = receivedData[8];
          setEncode(cdzyBuf[3]);               //获取到数据后 更改gpio 低位有效
          saveData(cdzyBuf, sizeof(cdzyBuf));  // 存储到flash

          DataSend[0] = receivedData[0];  // 层位
          DataSend[1] = 0x10;             //功能码
          DataSend[2] = receivedData[2];  // 寄存器 高位
          DataSend[3] = receivedData[3];  // 寄存器 低位
          DataSend[4] = receivedData[4];  // 数据高位
          DataSend[5] = receivedData[5];  //
          crc16 = Modbus_crc16(&DataSend[0], 6);
          DataSend[6] = crc16 % 256;
          DataSend[7] = crc16 / 256;
          //Serial1.write(&DataSend[0], 8);
          rs485WriteBuffer(&DataSend[0], 8);
          break;

        default:
          break;
      }
    }
  }
  if (receivedData[0] != 0xAA) {  // 如果是设置井下的,直接透传
    //rs485Write(0x09);  
   // Serial1.write(receivedData, length);
    JxSerial.write(receivedData, length);  //到井下
    rs485Write(0x00); 
    //Serial1.write(0x01);
    //delay(10); 
  }
  memset(receivedData, 0, length);  // 修正:使用length而不是sizeof(data)
}



// ============================================================
// 0. ==================== 中断 ====================
// ============================================================
//

void captureISR() {
  uint8_t next = (timeHead + 1) & (TIMEBUF_SIZE - 1);
  if (next != timeTail) {
    timeBuf[timeHead] = micros();
    timeHead = next;
  }
}
// ============================================================
// 0. ==================== Setup ====================
// ============================================================
//
void setup() {
  pinMode(RS485_EN, OUTPUT);
  rs485SetReceive();
  JxSerial.begin(300);  // 井下口
  Serial1.begin(9600);  // 调试口
  rs485.begin(9600);    // RS485
  pinMode(RS485_RX, INPUT_PULLUP);
  pinMode(RS485_TX, OUTPUT);
  //////////////////////////adc设置////////////////////////////
  pinMode(ADC1_PIN, INPUT_ANALOG);
  pinMode(DS_PIN, INPUT_ANALOG);
  pinMode(CS_PIN, INPUT_ANALOG);
  analogReadResolution(12);
  ///////////长短兰///////////////增益////////////////////////////
  pinMode(CL_0, OUTPUT);
  pinMode(CL_1, OUTPUT);
  pinMode(ENCODE_PB2, OUTPUT);
  pinMode(ENCODE_PE7, OUTPUT);
  pinMode(ENCODE_PE8, OUTPUT);
  pinMode(ENCODE_PE9, OUTPUT);
  pinMode(PD6, OUTPUT);  //解码灯
//  pinMode(KZ, OUTPUT);   //控制解码
//  digitalWrite(KZ, 1);   //控制解码 过滤

  pinMode(PA0_PIN, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(PA0_PIN), captureISR, FALLING);
  lastCaptureTime = micros();

  loadData(cdzyBuf, sizeof(cdzyBuf));  // 先从flash读,看是否已经写入,已经写入则按写入调用,如果没有设置默认值
  if (cdzyBuf[0] == 0xFF)              // 第一个字节是0xFF 未写入
  {
    // 默认短缆
    setDecode(0x00);
    // 设置增益: 0x0A (1010)
    setEncode(0x03);
  } else {
    // 设置长短缆: PCODE=1, NCODE=0
    setDecode(cdzyBuf[1]);
    // 设置增益: 0x0A (1010)
    setEncode(cdzyBuf[3]);
  }


  ///////////eprom 写入////////////////////////////
  // 准备4字节数据  可以是编号 长短缆 和增益
  //uint8_t myData[4] = { 0x0A, 0x01, 0x12, 0x34 };
  //saveData(myData, sizeof(myData));
  // Serial1.println("Saved!");
}



// ==================== Loop ====================
void loop() {
  digitalWrite(PD6, !digitalRead(PD6));
  uint8_t buffer[64];
  uint16_t len = 0;
  //===========485 接收:收到并处理完才开启采集===========
  if (js) {
    if (readRs485(buffer, sizeof(buffer), &len, 5)) {
      processReceivedData(buffer, len);
      memset(buffer, 0, len);
	 bh = 1;
    js = 0;
    }
  }
  if (bh) {
    noInterrupts();
    bool hasData = (timeTail != timeHead);
    interrupts();
    if (hasData) {
      processData();
    }
    bh = 0;
    js = 1;
  }
}这个代码可以跑通,看看有优化的没
主楼