STM32 RS485读取SHT20

硬件配置

采用RS3485芯片,供电电压3V3,EN引脚连接GPIOA1(可更改)

采用SHT20芯片RS485版本,V+接5V,V-接GND;

另外单片机再接一路串口给电脑用来显示。

引脚设置

PA1设置为GPIO_OUTPUT,默认拉低

USART1使能,配置默认;

USART2使能,波特率改为9600并开启NVIC中断;

协议知识

RS485是一种硬件电气标准,它定义了设备之间如何进行物理连接和信号传输。你可以把它想象成一条专为工业环境设计的高速公路。

一条RS485总线可以连接多个设备(理论上最多32个标准负载,使用中继器可扩展至更多),形成总线型网络,大大简化了布线。

在大多数应用中,RS485采用半双工模式,即数据在同一时间只能单向传输,要么发,要么收,这简化了总线结构并避免了冲突。

Modbus是一种通信协议,它定义了设备之间交换数据的格式和规则。如果说RS485是路,Modbus就是路上车辆必须遵守的交通规则,确保所有设备都能"说同一种语言"。

通信流程:

  • 主芯片想要读取1号从站(如温度传感器)的数据。
  • 主站按照Modbus协议的规则,打包一个请求报文,其中包含从站地址(1)、功能码(如"读寄存器")等信息。
  • 这个报文通过RS485接口转换成电信号,在总线上广播出去。
  • 总线上所有设备都能收到信号,但只有地址为1的从站会识别并处理这个请求。
  • 1号从站将温度值打包成Modbus响应报文,通过RS485接口发回给主站。

本次所用到的是标准Modbus RTU协议

代码编写

逻辑比较简单,发送指令,收到指令开启中断并将结果拷贝通过另一路串口发送到电脑

cpp 复制代码
#ifndef __SHT20_H
#define __SHT20_H

#include "main.h"
#include <string.h>
#include "usart.h"
//------------------------数据变量定义------------------------------------
extern uint8_t uart2_rx_buf[];
extern uint8_t uart1_tx_buf[];
//------------------------外部接口函数------------------------------------
void UART2_To_UART1_Forward(void);
void RS485_Send(uint8_t *data, uint16_t len);
void Test_Sht20(void);
//------------------------硬件接口配置------------------------------------
#define RS485_EN_GPIO_Port  GPIOA
#define RS485_EN_Pin        GPIO_PIN_1
#define RS485_RX_MODE()     HAL_GPIO_WritePin(RS485_EN_GPIO_Port, RS485_EN_Pin, GPIO_PIN_RESET)   // 低电平=接收
#define RS485_TX_MODE()     HAL_GPIO_WritePin(RS485_EN_GPIO_Port, RS485_EN_Pin, GPIO_PIN_SET)     // 高电平=发送
//-----------------------------------------------------------------------
#endif
cpp 复制代码
#include "sht20.h"

//------------------------数据变量定义------------------------------------
uint8_t uart2_rx_buf[16];
uint8_t uart1_tx_buf[16];
volatile uint16_t rx_len = 0;

const uint8_t SHT20_CMD_READ_TEMP[8] = {0x01, 0x04, 0x00, 0x01, 0x00, 0x01, 0x60, 0x0A};
const uint8_t SHT20_CMD_READ_HUMI[8] = {0x01, 0x04, 0x00, 0x02, 0x00, 0x01, 0x90, 0x0A};
const uint8_t SHT20_CMD_READ_BOTH[8] = {0x01, 0x04, 0x00, 0x01, 0x00, 0x02, 0x20, 0x0B};
const uint8_t SHT20_CMD_READ_ADDR[8] = {0x01, 0x03, 0x01, 0x01, 0x00, 0x01, 0x20, 0x0B};

//-----------------------具体函数实现------------------------------------
void UART2_To_UART1_Forward(void)
{
    if (rx_len == 0) return;
    memcpy(uart1_tx_buf, uart2_rx_buf, rx_len);
    HAL_UART_Transmit(&huart1, uart1_tx_buf, rx_len, 100); 
    rx_len = 0;
}
//-----------------------------------------------------------------------
void RS485_Send(uint8_t *data, uint16_t len)
{
    RS485_TX_MODE();  //切换为发送模式
    HAL_UART_Transmit(&huart2, data, len, 100);
    while (__HAL_UART_GET_FLAG(&huart2, UART_FLAG_TC) == RESET);  
    RS485_RX_MODE();  //切回接收
}
//-----------------------------------------------------------------------
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
    static uint16_t rx_index = 0;
    static uint32_t last_rx_time = 0;
    
    if (huart->Instance == USART2)
    {
        uint32_t now = HAL_GetTick();
        if (now - last_rx_time > 10 && rx_index > 0)  rx_index = 0;
        last_rx_time = now;
        if (rx_index < 16 - 1) rx_index++;		
        HAL_UART_Receive_IT(&huart2, &uart2_rx_buf[rx_index], 1);
		
        if (rx_index >= 7) {  
            rx_len = rx_index;
            rx_index = 0;
            UART2_To_UART1_Forward();  
        }
    }
}
//-----------------------------------------------------------------------
void Test_Sht20(void)
{
	HAL_UART_Receive_IT(&huart2, uart2_rx_buf, 1);
	while(1)
	{
		RS485_Send((uint8_t *)SHT20_CMD_READ_TEMP, 8);
		HAL_Delay(1000);
		RS485_Send((uint8_t *)SHT20_CMD_READ_HUMI, 8);
		HAL_Delay(1000);
		RS485_Send((uint8_t *)SHT20_CMD_READ_BOTH, 8);
		HAL_Delay(1000);	
	}
}

测试结果

以上就完成了模块的测试,后续优化可参考

①目前是根据字节数判断截止,但是返回字节数量并不固定,可以用时间戳来实现

②后续不可能都在节点1上,可以考虑自动CRC生成,但器件少的情况更建议手动配置数组

相关推荐
LCG元3 小时前
噪声检测系统:STM32F4驱动MEMS麦克风,FFT频谱分析实战
stm32·单片机·嵌入式硬件
charlie1145141914 小时前
嵌入式C++教程实战之Linux下的单片机编程:从零搭建 STM32 开发工具链(2) —— HAL 库获取、启动文件坑位与目录搭建
linux·开发语言·c++·stm32·单片机·学习·嵌入式
v先v关v住v获v取4 小时前
多功能割草装置的结构设计8张cad+三维图+设计说明书
科技·单片机·51单片机
leiming64 小时前
信号量为什么“不占CPU“
单片机·嵌入式硬件
爱喝纯牛奶的柠檬4 小时前
【已验证】基于STM32F103的土壤湿度传感器驱动
stm32·单片机·嵌入式硬件
Zevalin爱灰灰5 小时前
零基础入门学用物联网(ESP8266) 第二部分 MQTT基础篇(三)
单片机·物联网·mqtt·嵌入式·esp8266
AnalogElectronic5 小时前
树莓派pico,VS1838B红外接收实验
嵌入式硬件
llilian_165 小时前
ptp从时钟 ptp授时模块 如何挑选PTP从时钟授时协议模块 ptp从时钟模块
数据库·功能测试·单片机·嵌入式硬件·测试工具
Truffle7电子6 小时前
STM32理论 —— FreeRTOS:中断管理、列表
stm32·单片机·嵌入式硬件·rtos