• admin
    /*
     * STM32F407 串口双向透传
     * ------------------------------------------------------------
     * 485主机接口  : PB6(RX)/PB7(TX)/PB5(EN)  9600
     * 井下数据口   : PA2(TX)/PA3(RX)  300 (软件 bit-bang 发送)
     * 调试口       : PA9/PA10(USART1) 9600
     *
     * 调试开关: DBG 改 0 关闭全部调试打印
     */
    
    #include <Arduino.h>
    #include <SoftwareSerial.h>
    
    // ==================== 调试开关 ====================
    #define DBG 1
    
    #if DBG
      #define DBG_PRINT(x)     Serial1.print(x)
      #define DBG_PRINTLN(x)   Serial1.println(x)
      #define DBG_PRINTHEX(x)  do { if ((x) < 0x10) Serial1.print('0'); Serial1.print((x), HEX); } while (0)
    #else
      #define DBG_PRINT(x)     do { } while (0)
      #define DBG_PRINTLN(x)   do { } while (0)
      #define DBG_PRINTHEX(x)  do { } while (0)
    #endif
    
    // ==================== 硬件配置 ====================
    #define RS485_RX PB7
    #define RS485_TX PB6
    #define RS485_EN PB5
    
    #define EEPROM_BASE   0x080E0000
    #define EEPROM_SECTOR 11
    
    // ==================== 引脚定义 ====================
    #define CL_0 PB0
    #define CL_1 PB1
    #define KZ   PE10
    
    #define ENCODE_PB2 PB2
    #define ENCODE_PE7 PE7
    #define ENCODE_PE8 PE8
    #define ENCODE_PE9 PE9
    
    #define ADC1_PIN PA5
    #define DS_PIN   PA6
    #define CS_PIN   PA7
    
    #define PCODE_PIN PA1
    #define NCODE_PIN PA0
    
    #define LED_PIN PD6
    
    // 井下口 (软件 bit-bang)
    #define JX_TX_PIN PA2
    #define JX_RX_PIN PA3
    #define JX_BAUD   300UL
    
    // ==================== 串口对象 ====================
    Uart Serial1(USART1);                       // 调试口
    SoftwareSerial rs485(RS485_RX, RS485_TX);   // RS485
    
    // ==================== 协议常量 ====================
    static const uint8_t  PROTO_ADDR_AA       = 0xAA;
    static const uint8_t  FUNC_READ_HOLDING   = 0x03;
    static const uint8_t  FUNC_WRITE_MULTI    = 0x10;
    
    static const uint16_t REG_VOLTAGE_CURRENT = 0x0018;
    static const uint16_t REG_CABLE_LENGTH    = 0x0020;
    static const uint16_t REG_GAIN            = 0x0021;
    
    static const int MAX_FRAME_LEN = 30;
    static const int MIN_FRAME_LEN = 8;
    
    // ==================== 全局配置缓存 ====================
    uint8_t cdzyBuf[4];
    
    // ==================== 调试计数器 ====================
    static uint32_t g_frameCnt = 0;
    static uint32_t g_jxTxCnt  = 0;
    static uint32_t g_rsTxCnt  = 0;
    
    // ==================== 前置声明 ====================
    void processReceivedData(uint8_t* data, int length);
    
    // ============================================================
    // RS485 方向控制
    // ============================================================
    static inline void rs485SetReceive() {
      digitalWrite(RS485_EN, LOW);
      delayMicroseconds(10);
    }
    
    static inline void rs485SetTransmit() {
      digitalWrite(RS485_EN, HIGH);
      delayMicroseconds(10);
    }
    
    // ============================================================
    // RS485 发送
    // ============================================================
    void rs485WriteBuffer(const uint8_t* buf, uint16_t len) {
      g_rsTxCnt++;
      DBG_PRINT("[485] TX cnt=");
      DBG_PRINT(g_rsTxCnt);
      DBG_PRINT(" len=");
      DBG_PRINTLN(len);
    
      rs485SetTransmit();
      rs485.write(buf, len);
      rs485.flush();
      delay(1);
      rs485SetReceive();
    
      DBG_PRINTLN("[485] TX done");
    }
    
    // ============================================================
    // PA2 软件 bit-bang 发送 (300bps)
    // ============================================================
    static void jxSendByte(uint8_t b) {
      uint32_t bitUs = 1000000UL / JX_BAUD;   // 3333us
    
      // 起始位
      digitalWrite(JX_TX_PIN, LOW);
      delayMicroseconds(bitUs);
    
      // 8 个数据位 (LSB first)
      for (int i = 0; i < 8; i++) {
        digitalWrite(JX_TX_PIN, (b >> i) & 1);
        delayMicroseconds(bitUs);
      }
    
      // 停止位
      digitalWrite(JX_TX_PIN, HIGH);
      delayMicroseconds(bitUs);
    }
    
    static void jxSendBuffer(const uint8_t* data, int length) {
      for (int i = 0; i < length; i++) {
        jxSendByte(data[i]);
      }
    }
    
    // ============================================================
    // 透传到井下口
    // ============================================================
    static void forwardToDownhole(uint8_t* data, int length) {
      g_jxTxCnt++;
      DBG_PRINT("[JX] forward #");
      DBG_PRINT(g_jxTxCnt);
      DBG_PRINT(" len=");
      DBG_PRINTLN(length);
    
      pinMode(JX_TX_PIN, OUTPUT);
      digitalWrite(JX_TX_PIN, HIGH);
      delayMicroseconds(10);
    
      jxSendBuffer(data, length);
    
      // 发送完毕, 让 PA2 空闲为高电平 (空闲态)
      digitalWrite(JX_TX_PIN, HIGH);
    }
    
    // ============================================================
    // Flash 读写
    // ============================================================
    void saveData(const uint8_t* data, uint16_t len) {
      HAL_FLASH_Unlock();
      FLASH_EraseInitTypeDef e = {};
      e.TypeErase    = FLASH_TYPEERASE_SECTORS;
      e.Sector       = EEPROM_SECTOR;
      e.NbSectors    = 1;
      e.VoltageRange = FLASH_VOLTAGE_RANGE_3;
      uint32_t err;
      HAL_FLASHEx_Erase(&e, &err);
      for (uint16_t i = 0; i < len; i += 2) {
        uint16_t 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 (uint16_t i = 0; i < len; i++) {
        buf[i] = *(volatile uint8_t*)(EEPROM_BASE + i);
      }
    }
    
    // ============================================================
    // GPIO 控制
    // ============================================================
    void setCableLength(uint8_t val) {
      digitalWrite(CL_0, (val >> 0) & 0x01);
      digitalWrite(CL_1, (val >> 1) & 0x01);
    }
    
    void setGain(uint8_t val) {
      digitalWrite(ENCODE_PE9, (val >> 0) & 0x01);
      digitalWrite(ENCODE_PE8, (val >> 1) & 0x01);
      digitalWrite(ENCODE_PE7, (val >> 2) & 0x01);
      digitalWrite(ENCODE_PB2, (val >> 3) & 0x01);
    }
    
    // ============================================================
    // 超时接收
    // ============================================================
    bool readWithTimeout(Stream& port, uint8_t* buffer, uint16_t maxLen,
                         uint16_t* len, uint32_t timeoutMs) {
      *len = 0;
      if (!buffer || maxLen == 0) return false;
      if (!port.available()) return false;
    
      uint32_t start = millis();
      while (*len < maxLen && (millis() - start) < timeoutMs) {
        if (port.available()) {
          buffer[(*len)++] = port.read();
          start = millis();
        }
        delayMicroseconds(50);
      }
      return (*len > 0);
    }
    
    // ============================================================
    // Modbus CRC16
    // ============================================================
    uint16_t modbusCRC16(const uint8_t* data, uint16_t len) {
      uint16_t crc = 0xFFFF;
      for (uint16_t i = 0; i < len; i++) {
        crc ^= data[i];
        for (uint8_t j = 0; j < 8; j++) {
          if (crc & 0x0001) { crc >>= 1; crc ^= 0xA001; }
          else { crc >>= 1; }
        }
      }
      return crc;
    }
    
    static void appendCRC(uint8_t* buf, uint16_t payloadLen) {
      uint16_t crc = modbusCRC16(buf, payloadLen);
      buf[payloadLen]     = crc & 0xFF;
      buf[payloadLen + 1] = (crc >> 8) & 0xFF;
    }
    
    // ============================================================
    // ADC
    // ============================================================
    void readADC(int& cableAdc, int& voltageAdc, int& currentAdc) {
      cableAdc   = analogRead(ADC1_PIN);
      voltageAdc = analogRead(DS_PIN);
      currentAdc = analogRead(CS_PIN);
    }
    
    // ============================================================
    // Modbus 响应构造
    // ============================================================
    static uint16_t buildReadResponse(uint8_t* out, uint8_t addr,
                                      const uint8_t* payload, uint8_t payloadLen) {
      out[0] = addr;
      out[1] = FUNC_READ_HOLDING;
      out[2] = payloadLen;
      memcpy(&out[3], payload, payloadLen);
      appendCRC(out, 3 + payloadLen);
      return 3 + payloadLen + 2;
    }
    
    static uint16_t buildWriteResponse(uint8_t* out, const uint8_t* req) {
      memcpy(out, req, 6);
      appendCRC(out, 6);
      return 8;
    }
    
    // ============================================================
    // 寄存器读处理
    // ============================================================
    static void handleReadVoltageCurrent(uint8_t* req, uint8_t* resp) {
      uint8_t addr = req[0];
      int cableAdc, voltageAdc, currentAdc;
      readADC(cableAdc, voltageAdc, currentAdc);
      uint16_t voltage = (uint16_t)(voltageAdc * 0.3065f + 0.5f);
      uint16_t current = (uint16_t)(currentAdc * 0.1007f + 0.5f);
      uint8_t payload[4];
      payload[0] = (voltage >> 8) & 0xFF;
      payload[1] = voltage & 0xFF;
      payload[2] = (current >> 8) & 0xFF;
      payload[3] = current & 0xFF;
      uint16_t frameLen = buildReadResponse(resp, addr, payload, 4);
      rs485WriteBuffer(resp, frameLen);
    }
    
    static void handleReadCableLength(uint8_t* req, uint8_t* resp) {
      uint8_t addr = req[0];
      uint8_t payload[2] = { cdzyBuf[0], cdzyBuf[1] };
      uint16_t frameLen = buildReadResponse(resp, addr, payload, 2);
      rs485WriteBuffer(resp, frameLen);
    }
    
    static void handleReadGain(uint8_t* req, uint8_t* resp) {
      uint8_t addr = req[0];
      uint8_t payload[2] = { cdzyBuf[2], cdzyBuf[3] };
      uint16_t frameLen = buildReadResponse(resp, addr, payload, 2);
      rs485WriteBuffer(resp, frameLen);
    }
    
    // ============================================================
    // 寄存器写处理
    // ============================================================
    static void handleWriteCableLength(uint8_t* req, uint8_t* resp) {
      cdzyBuf[0] = req[7];
      cdzyBuf[1] = req[8];
      setCableLength(cdzyBuf[1]);
      saveData(cdzyBuf, sizeof(cdzyBuf));
      uint16_t frameLen = buildWriteResponse(resp, req);
      rs485WriteBuffer(resp, frameLen);
    }
    
    static void handleWriteGain(uint8_t* req, uint8_t* resp) {
      cdzyBuf[2] = req[7];
      cdzyBuf[3] = req[8];
      setGain(cdzyBuf[3]);
      saveData(cdzyBuf, sizeof(cdzyBuf));
      uint16_t frameLen = buildWriteResponse(resp, req);
      rs485WriteBuffer(resp, frameLen);
    }
    
    // ============================================================
    // Modbus 帧处理
    // ============================================================
    static bool handleModbusFrame(uint8_t* data, int length) {
      if (length < MIN_FRAME_LEN || length > MAX_FRAME_LEN) return false;
    
      uint16_t recvCRC = (data[length - 1] << 8) | data[length - 2];
      uint16_t calcCRC = modbusCRC16(data, length - 2);
      if (recvCRC != calcCRC) return false;
    
      uint8_t  func       = data[1];
      uint16_t regAddress = (data[2] << 8) | data[3];
      uint8_t  resp[24];
    
      if (func == FUNC_READ_HOLDING) {
        switch (regAddress) {
          case REG_VOLTAGE_CURRENT: handleReadVoltageCurrent(data, resp); return true;
          case REG_CABLE_LENGTH:    handleReadCableLength(data, resp);    return true;
          case REG_GAIN:            handleReadGain(data, resp);           return true;
          default: return false;
        }
      }
    
      if (func == FUNC_WRITE_MULTI) {
        switch (regAddress) {
          case REG_CABLE_LENGTH: handleWriteCableLength(data, resp); return true;
          case REG_GAIN:         handleWriteGain(data, resp);        return true;
          default: return false;
        }
      }
    
      return false;
    }
    
    // ============================================================
    // 主处理入口
    // ============================================================
    void processReceivedData(uint8_t* data, int length) {
      if (length <= 0) return;
    
      if (data[0] == PROTO_ADDR_AA) {
        DBG_PRINTLN("[PROC] Modbus 0xAA");
        handleModbusFrame(data, length);
      } else {
        DBG_PRINTLN("[PROC] forward to downhole");
        forwardToDownhole(data, length);
        rs485SetReceive();
      }
    }
    
    // ============================================================
    // 系统时钟
    // ============================================================
    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;
    }
    
    // ============================================================
    // 初始化
    // ============================================================
    static void initPins() {
      pinMode(RS485_EN, OUTPUT);
      pinMode(RS485_RX, INPUT_PULLUP);
      pinMode(RS485_TX, OUTPUT);
      rs485SetReceive();
    
      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(LED_PIN, OUTPUT);
    
      pinMode(ADC1_PIN, INPUT_ANALOG);
      pinMode(DS_PIN,   INPUT_ANALOG);
      pinMode(CS_PIN,   INPUT_ANALOG);
      analogReadResolution(12);
    
      // 井下口 PA2: 初始化为输出高 (空闲态)
      pinMode(JX_TX_PIN, OUTPUT);
      digitalWrite(JX_TX_PIN, HIGH);
      pinMode(JX_RX_PIN, INPUT);
    }
    
    static void initSerial() {
      Serial1.begin(9600);   // 调试口
      rs485.begin(9600);     // RS485
    }
    
    static void loadConfigOrDefault() {
      loadData(cdzyBuf, sizeof(cdzyBuf));
      if (cdzyBuf[0] == 0xFF) {
        cdzyBuf[0] = 0x00; cdzyBuf[1] = 0x00;
        cdzyBuf[2] = 0x00; cdzyBuf[3] = 0x03;
      }
      setCableLength(cdzyBuf[1]);
      setGain(cdzyBuf[3]);
    }
    
    void setup() {
      initPins();
      initSerial();
      loadConfigOrDefault();
    
      DBG_PRINTLN("=== BOOT ===");
    }
    
    // ============================================================
    // 主循环
    // ============================================================
    void loop() {
      uint8_t buffer[64];
      uint16_t len = 0;
    
      // RS485 接收 → 透传到井下
      if (readWithTimeout(rs485, buffer, sizeof(buffer), &len, 5)) {
        g_frameCnt++;
    
        DBG_PRINT("[RX] frame#");
        DBG_PRINT(g_frameCnt);
        DBG_PRINT(" len=");
        DBG_PRINT(len);
        DBG_PRINT(" data=");
        for (uint16_t i = 0; i < len; i++) { DBG_PRINTHEX(buffer[i]); DBG_PRINT(' '); }
        DBG_PRINTLN("");
    
        processReceivedData(buffer, len);
        memset(buffer, 0, len);
      }
    
      // 心跳灯 + 心跳打印
      static uint32_t lastBlink = 0;
      if (millis() - lastBlink > 500) {
        lastBlink = millis();
        digitalWrite(LED_PIN, !digitalRead(LED_PIN));
        DBG_PRINT("[HB] frameCnt=");
        DBG_PRINT(g_frameCnt);
        DBG_PRINT(" jxTxCnt=");
        DBG_PRINT(g_jxTxCnt);
        DBG_PRINT(" rsTxCnt=");
        DBG_PRINTLN(g_rsTxCnt);
      }
    }
    主楼
  • admin
    /*
     * STM32F407 串口双向透传(调试口兼具 485 功能)
     * ------------------------------------------------------------
     * 485主机接口  : PB6(RX)/PB7(TX)/PB5(EN)  9600
     * 井下数据口   : PA2(TX)/PA3(RX)  300 (软件 bit-bang 发送)
     * 调试/485口   : PA9/PA10(USART1) 9600
     *
     * 调试开关: DBG 改 0 关闭调试打印(USART1 仍可作为 485 通信口)
     */
    
    #include <Arduino.h>
    #include <SoftwareSerial.h>
    
    // ==================== 调试开关 ====================
    #define DBG 0
    
    #if DBG
      #define DBG_PRINT(x)     Serial1.print(x)
      #define DBG_PRINTLN(x)   Serial1.println(x)
      #define DBG_PRINTHEX(x)  do { if ((x) < 0x10) Serial1.print('0'); Serial1.print((x), HEX); } while (0)
    #else
      #define DBG_PRINT(x)     do { } while (0)
      #define DBG_PRINTLN(x)   do { } while (0)
      #define DBG_PRINTHEX(x)  do { } while (0)
    #endif
    
    // ==================== 硬件配置 ====================
    #define RS485_RX PB7
    #define RS485_TX PB6
    #define RS485_EN PB5
    
    #define EEPROM_BASE   0x080E0000
    #define EEPROM_SECTOR 11
    
    // ==================== 引脚定义 ====================
    #define CL_0 PB0
    #define CL_1 PB1
    #define KZ   PE10
    
    #define ENCODE_PB2 PB2
    #define ENCODE_PE7 PE7
    #define ENCODE_PE8 PE8
    #define ENCODE_PE9 PE9
    
    #define ADC1_PIN PA5
    #define DS_PIN   PA6
    #define CS_PIN   PA7
    
    #define PCODE_PIN PA1
    #define NCODE_PIN PA0
    
    #define LED_PIN PD6
    
    // 井下口 (软件 bit-bang)
    #define JX_TX_PIN PA2
    #define JX_RX_PIN PA3
    #define JX_BAUD   300UL
    
    // ==================== 串口对象 ====================
    Uart Serial1(USART1);                       // 调试/485 复用口
    SoftwareSerial rs485(RS485_RX, RS485_TX);   // RS485
    
    // ==================== 协议常量 ====================
    static const uint8_t  PROTO_ADDR_AA       = 0xAA;
    static const uint8_t  FUNC_READ_HOLDING   = 0x03;
    static const uint8_t  FUNC_WRITE_MULTI    = 0x10;
    
    static const uint16_t REG_VOLTAGE_CURRENT = 0x0018;
    static const uint16_t REG_CABLE_LENGTH    = 0x0020;
    static const uint16_t REG_GAIN            = 0x0021;
    
    static const int MAX_FRAME_LEN = 30;
    static const int MIN_FRAME_LEN = 8;
    
    // ==================== 全局配置缓存 ====================
    uint8_t cdzyBuf[4];
    
    // ==================== 调试计数器 ====================
    static uint32_t g_frameCnt = 0;
    static uint32_t g_jxTxCnt  = 0;
    static uint32_t g_rsTxCnt  = 0;
    static uint32_t g_dbgTxCnt = 0;
    
    // ==================== 请求来源标记 ====================
    // 0 = RS485, 1 = USART1(调试口)
    static uint8_t g_respPort = 0;
    
    // ==================== 前置声明 ====================
    void processReceivedData(uint8_t* data, int length, uint8_t fromPort);
    static void sendResponse(const uint8_t* buf, uint16_t len);
    
    // ============================================================
    // RS485 方向控制
    // ============================================================
    static inline void rs485SetReceive() {
      digitalWrite(RS485_EN, LOW);
      delayMicroseconds(10);
    }
    
    static inline void rs485SetTransmit() {
      digitalWrite(RS485_EN, HIGH);
      delayMicroseconds(10);
    }
    
    // ============================================================
    // RS485 发送
    // ============================================================
    void rs485WriteBuffer(const uint8_t* buf, uint16_t len) {
      g_rsTxCnt++;
      DBG_PRINT("[485] TX cnt=");
      DBG_PRINT(g_rsTxCnt);
      DBG_PRINT(" len=");
      DBG_PRINTLN(len);
    
      rs485SetTransmit();
      rs485.write(buf, len);
      rs485.flush();
      delay(1);
      rs485SetReceive();
    
      DBG_PRINTLN("[485] TX done");
    }
    
    // ============================================================
    // 调试口 USART1 发送原始数据(兼具 485 功能)
    // ============================================================
    void dbgWriteBuffer(const uint8_t* buf, uint16_t len) {
      g_dbgTxCnt++;
      DBG_PRINT("[DBG] TX cnt=");
      DBG_PRINT(g_dbgTxCnt);
      DBG_PRINT(" len=");
      DBG_PRINTLN(len);
    
      Serial1.write(buf, len);
      Serial1.flush();
    
      DBG_PRINTLN("[DBG] TX done");
    }
    
    // ============================================================
    // 统一响应发送:按请求来源口原路返回
    // ============================================================
    static void sendResponse(const uint8_t* buf, uint16_t len) {
      if (g_respPort == 0) {
        rs485WriteBuffer(buf, len);
      } else {
        dbgWriteBuffer(buf, len);
      }
    }
    
    // ============================================================
    // PA2 软件 bit-bang 发送 (300bps)
    // ============================================================
    static void jxSendByte(uint8_t b) {
      uint32_t bitUs = 1000000UL / JX_BAUD;   // 3333us
    
      // 起始位
      digitalWrite(JX_TX_PIN, LOW);
      delayMicroseconds(bitUs);
    
      // 8 个数据位 (LSB first)
      for (int i = 0; i < 8; i++) {
        digitalWrite(JX_TX_PIN, (b >> i) & 1);
        delayMicroseconds(bitUs);
      }
    
      // 停止位
      digitalWrite(JX_TX_PIN, HIGH);
      delayMicroseconds(bitUs);
    }
    
    static void jxSendBuffer(const uint8_t* data, int length) {
      for (int i = 0; i < length; i++) {
        jxSendByte(data[i]);
      }
    }
    
    // ============================================================
    // 透传到井下口
    // ============================================================
    static void forwardToDownhole(uint8_t* data, int length) {
      g_jxTxCnt++;
      DBG_PRINT("[JX] forward #");
      DBG_PRINT(g_jxTxCnt);
      DBG_PRINT(" len=");
      DBG_PRINTLN(length);
    
      pinMode(JX_TX_PIN, OUTPUT);
      digitalWrite(JX_TX_PIN, HIGH);
      delayMicroseconds(10);
    
      jxSendBuffer(data, length);
    
      // 发送完毕, 让 PA2 空闲为高电平 (空闲态)
      digitalWrite(JX_TX_PIN, HIGH);
    }
    
    // ============================================================
    // Flash 读写
    // ============================================================
    void saveData(const uint8_t* data, uint16_t len) {
      HAL_FLASH_Unlock();
      FLASH_EraseInitTypeDef e = {};
      e.TypeErase    = FLASH_TYPEERASE_SECTORS;
      e.Sector       = EEPROM_SECTOR;
      e.NbSectors    = 1;
      e.VoltageRange = FLASH_VOLTAGE_RANGE_3;
      uint32_t err;
      HAL_FLASHEx_Erase(&e, &err);
      for (uint16_t i = 0; i < len; i += 2) {
        uint16_t 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 (uint16_t i = 0; i < len; i++) {
        buf[i] = *(volatile uint8_t*)(EEPROM_BASE + i);
      }
    }
    
    // ============================================================
    // GPIO 控制
    // ============================================================
    void setCableLength(uint8_t val) {
      digitalWrite(CL_0, (val >> 0) & 0x01);
      digitalWrite(CL_1, (val >> 1) & 0x01);
    }
    
    void setGain(uint8_t val) {
      digitalWrite(ENCODE_PE9, (val >> 0) & 0x01);
      digitalWrite(ENCODE_PE8, (val >> 1) & 0x01);
      digitalWrite(ENCODE_PE7, (val >> 2) & 0x01);
      digitalWrite(ENCODE_PB2, (val >> 3) & 0x01);
    }
    
    // ============================================================
    // 超时接收
    // ============================================================
    bool readWithTimeout(Stream& port, uint8_t* buffer, uint16_t maxLen,
                         uint16_t* len, uint32_t timeoutMs) {
      *len = 0;
      if (!buffer || maxLen == 0) return false;
      if (!port.available()) return false;
    
      uint32_t start = millis();
      while (*len < maxLen && (millis() - start) < timeoutMs) {
        if (port.available()) {
          buffer[(*len)++] = port.read();
          start = millis();
        }
        delayMicroseconds(50);
      }
      return (*len > 0);
    }
    
    // ============================================================
    // Modbus CRC16
    // ============================================================
    uint16_t modbusCRC16(const uint8_t* data, uint16_t len) {
      uint16_t crc = 0xFFFF;
      for (uint16_t i = 0; i < len; i++) {
        crc ^= data[i];
        for (uint8_t j = 0; j < 8; j++) {
          if (crc & 0x0001) { crc >>= 1; crc ^= 0xA001; }
          else { crc >>= 1; }
        }
      }
      return crc;
    }
    
    static void appendCRC(uint8_t* buf, uint16_t payloadLen) {
      uint16_t crc = modbusCRC16(buf, payloadLen);
      buf[payloadLen]     = crc & 0xFF;
      buf[payloadLen + 1] = (crc >> 8) & 0xFF;
    }
    
    // ============================================================
    // ADC
    // ============================================================
    void readADC(int& cableAdc, int& voltageAdc, int& currentAdc) {
      cableAdc   = analogRead(ADC1_PIN);
      voltageAdc = analogRead(DS_PIN);
      currentAdc = analogRead(CS_PIN);
    }
    
    // ============================================================
    // Modbus 响应构造
    // ============================================================
    static uint16_t buildReadResponse(uint8_t* out, uint8_t addr,
                                      const uint8_t* payload, uint8_t payloadLen) {
      out[0] = addr;
      out[1] = FUNC_READ_HOLDING;
      out[2] = payloadLen;
      memcpy(&out[3], payload, payloadLen);
      appendCRC(out, 3 + payloadLen);
      return 3 + payloadLen + 2;
    }
    
    static uint16_t buildWriteResponse(uint8_t* out, const uint8_t* req) {
      memcpy(out, req, 6);
      appendCRC(out, 6);
      return 8;
    }
    
    // ============================================================
    // 寄存器读处理
    // ============================================================
    static void handleReadVoltageCurrent(uint8_t* req, uint8_t* resp) {
      uint8_t addr = req[0];
      int cableAdc, voltageAdc, currentAdc;
      readADC(cableAdc, voltageAdc, currentAdc);
      uint16_t voltage = (uint16_t)(voltageAdc * 0.3065f + 0.5f);
      uint16_t current = (uint16_t)(currentAdc * 0.1007f + 0.5f);
      uint8_t payload[4];
      payload[0] = (voltage >> 8) & 0xFF;
      payload[1] = voltage & 0xFF;
      payload[2] = (current >> 8) & 0xFF;
      payload[3] = current & 0xFF;
      uint16_t frameLen = buildReadResponse(resp, addr, payload, 4);
      sendResponse(resp, frameLen);
    }
    
    static void handleReadCableLength(uint8_t* req, uint8_t* resp) {
      uint8_t addr = req[0];
      uint8_t payload[2] = { cdzyBuf[0], cdzyBuf[1] };
      uint16_t frameLen = buildReadResponse(resp, addr, payload, 2);
      sendResponse(resp, frameLen);
    }
    
    static void handleReadGain(uint8_t* req, uint8_t* resp) {
      uint8_t addr = req[0];
      uint8_t payload[2] = { cdzyBuf[2], cdzyBuf[3] };
      uint16_t frameLen = buildReadResponse(resp, addr, payload, 2);
      sendResponse(resp, frameLen);
    }
    
    // ============================================================
    // 寄存器写处理
    // ============================================================
    static void handleWriteCableLength(uint8_t* req, uint8_t* resp) {
      cdzyBuf[0] = req[7];
      cdzyBuf[1] = req[8];
      setCableLength(cdzyBuf[1]);
      saveData(cdzyBuf, sizeof(cdzyBuf));
      uint16_t frameLen = buildWriteResponse(resp, req);
      sendResponse(resp, frameLen);
    }
    
    static void handleWriteGain(uint8_t* req, uint8_t* resp) {
      cdzyBuf[2] = req[7];
      cdzyBuf[3] = req[8];
      setGain(cdzyBuf[3]);
      saveData(cdzyBuf, sizeof(cdzyBuf));
      uint16_t frameLen = buildWriteResponse(resp, req);
      sendResponse(resp, frameLen);
    }
    
    // ============================================================
    // Modbus 帧处理
    // ============================================================
    static bool handleModbusFrame(uint8_t* data, int length) {
      if (length < MIN_FRAME_LEN || length > MAX_FRAME_LEN) return false;
    
      uint16_t recvCRC = (data[length - 1] << 8) | data[length - 2];
      uint16_t calcCRC = modbusCRC16(data, length - 2);
      if (recvCRC != calcCRC) return false;
    
      uint8_t  func       = data[1];
      uint16_t regAddress = (data[2] << 8) | data[3];
      uint8_t  resp[24];
    
      if (func == FUNC_READ_HOLDING) {
        switch (regAddress) {
          case REG_VOLTAGE_CURRENT: handleReadVoltageCurrent(data, resp); return true;
          case REG_CABLE_LENGTH:    handleReadCableLength(data, resp);    return true;
          case REG_GAIN:            handleReadGain(data, resp);           return true;
          default: return false;
        }
      }
    
      if (func == FUNC_WRITE_MULTI) {
        switch (regAddress) {
          case REG_CABLE_LENGTH: handleWriteCableLength(data, resp); return true;
          case REG_GAIN:         handleWriteGain(data, resp);        return true;
          default: return false;
        }
      }
    
      return false;
    }
    
    // ============================================================
    // 主处理入口(增加 fromPort)
    // ============================================================
    void processReceivedData(uint8_t* data, int length, uint8_t fromPort) {
      if (length <= 0) return;
    
      g_respPort = fromPort;   // 记录请求来源,响应时原路返回
    
      if (data[0] == PROTO_ADDR_AA) {
        DBG_PRINTLN("[PROC] Modbus 0xAA");
        handleModbusFrame(data, length);
      } else {
        DBG_PRINTLN("[PROC] forward to downhole");
        forwardToDownhole(data, length);
        rs485SetReceive();
      }
    }
    
    // ============================================================
    // 系统时钟
    // ============================================================
    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;
    }
    
    // ============================================================
    // 初始化
    // ============================================================
    static void initPins() {
      pinMode(RS485_EN, OUTPUT);
      pinMode(RS485_RX, INPUT_PULLUP);
      pinMode(RS485_TX, OUTPUT);
      rs485SetReceive();
    
      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(LED_PIN, OUTPUT);
    
      pinMode(ADC1_PIN, INPUT_ANALOG);
      pinMode(DS_PIN,   INPUT_ANALOG);
      pinMode(CS_PIN,   INPUT_ANALOG);
      analogReadResolution(12);
    
      // 井下口 PA2: 初始化为输出高 (空闲态)
      pinMode(JX_TX_PIN, OUTPUT);
      digitalWrite(JX_TX_PIN, HIGH);
      pinMode(JX_RX_PIN, INPUT);
    }
    
    static void initSerial() {
      Serial1.begin(9600);   // 调试/485 复用口
      rs485.begin(9600);     // RS485
    }
    
    static void loadConfigOrDefault() {
      loadData(cdzyBuf, sizeof(cdzyBuf));
      if (cdzyBuf[0] == 0xFF) {
        cdzyBuf[0] = 0x00; cdzyBuf[1] = 0x00;
        cdzyBuf[2] = 0x00; cdzyBuf[3] = 0x03;
      }
      setCableLength(cdzyBuf[1]);
      setGain(cdzyBuf[3]);
    }
    
    void setup() {
      initPins();
      initSerial();
      loadConfigOrDefault();
    
      DBG_PRINTLN("=== BOOT ===");
    }
    
    // ============================================================
    // 主循环
    // ============================================================
    void loop() {
      uint8_t buffer[64];
      uint16_t len = 0;
    
      // ---------- RS485 接收 ----------
      if (readWithTimeout(rs485, buffer, sizeof(buffer), &len, 5)) {
        g_frameCnt++;
    
        DBG_PRINT("[485 RX] frame#");
        DBG_PRINT(g_frameCnt);
        DBG_PRINT(" len=");
        DBG_PRINT(len);
        DBG_PRINT(" data=");
        for (uint16_t i = 0; i < len; i++) { DBG_PRINTHEX(buffer[i]); DBG_PRINT(' '); }
        DBG_PRINTLN("");
    
        processReceivedData(buffer, len, 0);   // 0 = RS485
        memset(buffer, 0, len);
      }
    
      // ---------- 调试口 USART1 接收(兼具 485 功能) ----------
      len = 0;
      if (readWithTimeout(Serial1, buffer, sizeof(buffer), &len, 5)) {
        g_frameCnt++;
    
        DBG_PRINT("[DBG RX] frame#");
        DBG_PRINT(g_frameCnt);
        DBG_PRINT(" len=");
        DBG_PRINT(len);
        DBG_PRINT(" data=");
        for (uint16_t i = 0; i < len; i++) { DBG_PRINTHEX(buffer[i]); DBG_PRINT(' '); }
        DBG_PRINTLN("");
    
        processReceivedData(buffer, len, 1);   // 1 = USART1
        memset(buffer, 0, len);
      }
    
      // ---------- 心跳灯 + 心跳打印 ----------
      static uint32_t lastBlink = 0;
      if (millis() - lastBlink > 500) {
        lastBlink = millis();
        digitalWrite(LED_PIN, !digitalRead(LED_PIN));
    
        DBG_PRINT("[HB] frameCnt=");
        DBG_PRINT(g_frameCnt);
        DBG_PRINT(" jxTxCnt=");
        DBG_PRINT(g_jxTxCnt);
        DBG_PRINT(" rsTxCnt=");
        DBG_PRINT(g_rsTxCnt);
        DBG_PRINT(" dbgTxCnt=");
        DBG_PRINTLN(g_dbgTxCnt);
      }
    }
    #1

发表回复

登录后回复