[STM32L4] STM32L4 通过 UART 转 SDI-12 电平转换芯片与传感器通信无应答

[复制链接]
35|9
我的牙白 发表于 2026-6-25 14:54 | 显示全部楼层 |阅读模式
我在 STM32L4 上对接 SDI-12 传感器。MCU 为 3.3V 电平,SN74LVC1G240 缓冲器实现 UART 转 SDI-12 单总线;
MOSFET 将 MCU 3.3V 信号抬升至 SDI-12 标准 5V 电平;
已确认硬件接线、电压输出全部正常。
UART5 配置代码如下:
static void MX_UART5_Init(void)
{
/* USER CODE BEGIN UART5_Init 0 */
/* USER CODE END UART5_Init 0 */
/* USER CODE BEGIN UART5_Init 1 */
/* USER CODE END UART5_Init 1 */
huart5.Instance = UART5;
huart5.Init.BaudRate = 1200;
huart5.Init.WordLength = UART_WORDLENGTH_8B; // Including parity
huart5.Init.StopBits = UART_STOPBITS_1;
huart5.Init.Parity = UART_PARITY_EVEN;
huart5.Init.Mode = UART_MODE_TX_RX;
huart5.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart5.Init.OverSampling = UART_OVERSAMPLING_16;
huart5.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
huart5.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
if (HAL_UART_Init(&huart5) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN UART5_Init 2 */
/* USER CODE END UART5_Init 2 */
}
参考官方电路方案:缓冲器 OE 拉低时输出 5V 总线,UART TX 电平同步映射到 SDI12 数据线。规范要求发送命令后最多 15ms 传感器回复,但当前完全收不到应答。传感器供电 12V 正常。
SDI-12 协议要求先发 12ms Break 低电平、再发 8.3ms Mark 高电平,我已在代码实现该时序;示波器观测 SDI-12 总线波形时序电平都符合标准,但传感器对任何指令均无回应。测试指令:0!-0 号传感器 ping、?!-查询在线传感器地址,均无返回。
发送指令函数核心逻辑:
static HAL_StatusTypeDef _SDI12_send_command(const char cmd[], const uint8_t cmd_len, char response_buffer[], uint8_t res_len)
{
        HAL_StatusTypeDef res;
// Step 1: Configure GPIO for break
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = GPIO_PIN_12;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
// Step 2: Select SDI-12
HAL_GPIO_WritePin(SDI12_SELECT_GPIO_Port, SDI12_SELECT_Pin, GPIO_PIN_RESET);
//HAL_Delay(1);
// Step 3: Send break (low for at least 12 ms)
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_12, GPIO_PIN_SET);
HAL_Delay(12);
// Step 4: Marking condition (high for at least 8.3 ms)
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_12, GPIO_PIN_RESET);
HAL_Delay(12);
// Step 5: Reconfigure the GPIO pin for UART TX
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Alternate = GPIO_AF_UART;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
HAL_Delay(1); // Set it to normilize the osciloscope outpu.
// Step 6: Transmit the command
res = HAL_UART_Transmit(&huart5, (uint8_t*)&cmd, cmd_len, 1000);
if (res != HAL_OK) {
printf("Error in transmitting UART data\r\n");
return HAL_ERROR;
}
// Step 7: Deselect SDI-12
HAL_GPIO_WritePin(SDI12_SELECT_GPIO_Port, SDI12_SELECT_Pin, GPIO_PIN_SET);
// Step 8: Wait for the sensor's response
uint8_t count = 0;
res = _SDI12_ReceiveLine(response_buffer, res_len, &count); // Make sure this function is correctly implemented
printf("response_buffer[0]=%d\r\n", response_buffer[0]);
printf("response_buffer[1]=%d\r\n", response_buffer[1]);
printf("response_buffer[2]=%d\r\n", response_buffer[2]);
return res;
}
我试过多种修改:切换 7 位数据位、反转比特序、调整高低位优先,全部无效。

今天会画卧蚕吗 发表于 2026-6-25 16:28 | 显示全部楼层
Break信号用GPIO翻转实现的,但你用的是HAL_Delay做12ms,这个函数在UART发送期间如果被中断打断,实际低电平时间可能偏长或偏短,用硬件定时器更准。

classroom 发表于 2026-6-25 16:58 | 显示全部楼层
示波器看到的总线波形电平符合标准,但Break的下降沿到第一个数据位的起始位之间,Mark高电平到底有没有保持够8.3ms?这个时序差了传感器就不认。
cr315 发表于 2026-6-25 17:29 | 显示全部楼层
UART配置里WordLength是8B含校验位,但SDI-12是7位数据+1位偶校验,实际有效数据7位,你得确认传感器那边认不认这种打包方式。
duo点 发表于 2026-6-25 18:00 | 显示全部楼层
你发Break之前把GPIO重配成推挽输出,发完之后再配回UART AF,这个切换过程里有没有产生一个多余的脉冲?示波器上可能看不出来,但传感器可能被误触发了。
flycamelaaa 发表于 2026-6-25 19:35 | 显示全部楼层
建议发完命令后在接收线程里用中断方式收数据,配合超时定时器来判断15ms内有没有收到起始字符,比阻塞等待更可靠。
onlycook 发表于 2026-6-25 21:46 | 显示全部楼层
你每次发命令之前都把GPIO重新初始化一遍,但HAL_UART_Init只在初始化时调用了一次,GPIO重配之后UART外设的引脚连接可能已经断开了,发出去的数据根本没到总线上。
powerantone 发表于 2026-6-25 22:32 | 显示全部楼层
检查一下 SDI-12 总线的上拉电阻,标准要求总线空闲时是 5V 高电平,如果上拉电阻太大,总线拉高速度慢,传感器可能认不出 Mark 信号。
stormwind123 发表于 2026-6-26 11:57 | 显示全部楼层
示波器上看到总线波形符合标准,那传感器完全没回应很可能不是时序问题,查一下传感器供电是否稳定,有些 12V 传感器对纹波很敏感。
probedog 发表于 2026-6-26 16:32 | 显示全部楼层
代码里 Break 期间把引脚改成 GPIO Output 模式,Mark 结束又重新配成 UART AF 模式,但中间没有任何引脚电平缓冲,这两个模式切换的瞬间可能会有毛刺,引起传感器误判。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

160

主题

161

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部
0