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生成,但器件少的情况更建议手动配置数组

相关推荐
FreakStudio5 天前
W55MH32L-EVB 上手测评:硬件 TCP/IP 加持的以太网单片机,MicroPython 零门槛开发
python·单片机·嵌入式·大学生·面向对象·并行计算·电子diy·电子计算机
✎ ﹏梦醒͜ღ҉繁华落℘10 天前
单片机基础知识---stm32单片机的优先级
stm32·单片机·mongodb
u1521096484910 天前
S.S.Audio PRO A2音频隔离器
嵌入式硬件·音视频·实时音视频·视频编解码·视频
zd84510150010 天前
RS485 总线详解
单片机·嵌入式硬件
半条-咸鱼10 天前
【STM32】I2C协议原理、HAL读写与OLED显示操作
嵌入式硬件·c·信息与通信
牛根生同志10 天前
SPI数据收发的时候 TXE与RXNE标志位置位的时机
stm32·spi·transfer
wohoo_wangzi10 天前
苏州晟雅泰电子:关于W25Q128JVSIQ这个芯片物料的参数,规格及应用领域
嵌入式硬件
goldenrolan11 天前
学习型红外控制系统稳定性挂测工装专项总结
软件测试·python·stm32·嵌入式·红外
✎ ﹏梦醒͜ღ҉繁华落℘11 天前
编程基础 --高内聚,低耦合
c语言·单片机
科芯创展11 天前
1A,1MHz,30VIN,XZ4115,降压恒流LED驱动芯片
单片机·嵌入式硬件