欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  网络运营

RS485通信协议温湿度传感器探头

程序员文章站 2022-03-08 15:17:52
<笔记> 温湿度传感器探头&485通信协议前言这是一个自己做的温湿度探头,符合标准的标准的MODUS_RTU协议。包含:硬件PCB(AD) & HAL库源码(keil+CubeMx)Drawn By:67373UPUP硬件部分1.1 原理图1.2 PCB1.3 3D零件图嵌入式程序2.1 程序流程图2.2 cube配置2.2.1 看门狗配置2.2.2 定时器配置2.3 主要程序解析2.3.1 CRC校验部分//CRC16校验算法 适用...

<笔记> 温湿度传感器探头(SHT30)&485通信协议

前言

这是一个自己做的温湿度探头,符合标准的标准的MODUS_RTU协议。
包含:硬件PCB(AD) & HAL库源码(keil+CubeMx) & 3D零件(soildworks)

Drawn By:67373UPUP

硬件部分

1.1 原理图

RS485通信协议温湿度传感器探头

1.2 PCB

RS485通信协议温湿度传感器探头
RS485通信协议温湿度传感器探头
RS485通信协议温湿度传感器探头

1.3 3D零件图

RS485通信协议温湿度传感器探头

嵌入式程序

2.1 程序流程图

RS485通信协议温湿度传感器探头

2.2 cube配置
2.2.1 看门狗配置

RS485通信协议温湿度传感器探头

2.2.2 定时器配置

RS485通信协议温湿度传感器探头

2.3 主要程序解析
2.3.1 CRC校验部分
//CRC16校验算法 适用于16进制处理
uint16_t CRC_16_HEX(uint8_t *Buf, uint8_t CRC_CNT)
{
    unsigned long CRC_Temp;
    unsigned char i,j;
    CRC_Temp = 0xffff;
    for (i=0; i<CRC_CNT; i++) {
        //printf("%x@",Buf[i]);
        CRC_Temp ^= Buf[i];
        for (j=0; j<8; j++) {
            if (CRC_Temp & 0x01)
                CRC_Temp = (CRC_Temp >>1 ) ^ 0xa001;
            else
                CRC_Temp = CRC_Temp >> 1;
        }
    }

    return(CRC_Temp>>8|CRC_Temp<<8);  
}
2.3.2读取一次温湿度
/**
 * @brief	将SHT30接收的6个字节数据进行CRC校验,并转换为温度值和湿度值
 * @param	dat  —— 存储接收数据的地址(6个字节数组)
 * @retval	校验成功  —— 返回0
 * 			校验失败  —— 返回1,并设置温度值和湿度值为0
*/
uint8_t SHT30_Dat_To_HEX(uint8_t* const dat, float* temperature, float* humidity)
{
    uint16_t recv_temperature = 0;
    uint16_t recv_humidity = 0;

    /* 校验温度数据和湿度数据是否接收正确 */
    if(CheckCrc8(dat, 0xFF) != dat[2] || CheckCrc8(&dat[3], 0xFF) != dat[5])
        return 1;

    /* 转换温度数据 */
    recv_temperature = ((uint16_t)dat[0]<<8)|dat[1];
    *temperature = ((-45 + 175*((float)recv_temperature/65535))*10);//将温度换算成摄氏温度*100
	if(*temperature>0)
	{
    temp_buf[0] = ((uint16_t)(*temperature))>>8;//将温度高八位存到temp_buf[0]
    temp_buf[1] = ((uint16_t)(*temperature))&0xff;//将温度低八位存到temp_buf[1]
	}
	else if (*temperature<0)
	{
	//如果温湿度为负将采用补码的方式传输数据
    temp_buf[0] = ((-((uint16_t)(*temperature))+0xFFFF)+0x000A)>>8;//将温度高八位存到temp_buf[0]
    temp_buf[1] = ((-((uint16_t)(*temperature))+0xFFFF)+0X000A)&0xFF;//将温度低八位存到temp_buf[1]	
	}
    /* 转换湿度数据 */
    recv_humidity = ((uint16_t)dat[3]<<8)|dat[4];
    *humidity = 1000 * ((float)recv_humidity / 65535);//将湿度转换成百分比*100
    hum_buf[0] = ((uint16_t)(*humidity))>>8;//将湿度高八位存到hum_buf[0]
    hum_buf[1] = ((uint16_t)(*humidity))&0xff;//将湿度高八位存到hum_buf[1]
    return 0;
}
/**
 * @brief	读取温湿度
 * @param	如果读取失败,软重启温湿度传感器
 * @retval	none
*/
void Read_SHT30(void)
{
    if(SHT30_Read_Dat(recv_dat) == HAL_OK)
    {
        SHT30_Dat_To_HEX(recv_dat, &temperature, &humidity);
	}
	else if(SHT30_Read_Dat(recv_dat) == HAL_BUSY)
    {
    }
}
2.3.3定时器产生一次中断,就读取一次温湿度
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
  if (htim->Instance == htim3.Instance)
    {
		Read_SHT30();
    }
}
2.3.4设置波特率
/***********************************************************
函数功能:设置波特率(如果地址设置非0-5,波特率会设置为默认的9600)
返回值:地址  波特率
		0x01==2400
		0x02==4800
		0x03==9600
		0x04==19200
		0x05==115200
***********************************************************/
uint32_t Set_Baud(void)
{
    STMFLASH_Read(STM32_FLASH_BASE_2,&Read_Buff,1);
    if(Read_Buff==0x0003|Read_Buff==0xFFFF) return 9600;
    else if (Read_Buff==0x0002) return 4800;
    else if (Read_Buff==0x0001) return 2400;
    else if (Read_Buff==0x0004) return 19200;
    else if (Read_Buff==0x0005) return 115200;
    else return 9600;
}
2.3.5读取Flash存的地址
/***********************************************************
函数功能:读取FLASH存储的485地址
返回值:  Address_Buff
***********************************************************/
uint8_t Read_Address_Flash(void)
{
    STMFLASH_Read(STM32_FLASH_BASE_1,&Read_Buff,1);
    if(Read_Buff!=0xFFFF)
    {
        Address_Buff[0] = Read_Buff;
    }
    else if(Read_Buff == 0xFFFF)
    {
        Address_Buff[0] = 0x01;
    }
    return 0;
}
2.3.6读取Flash存的波特率
/***********************************************************
函数功能:读取FLASH存储的波特率
返回值:  Baud_Buff
***********************************************************/
uint8_t Read_Baud_Flash(void)
{
    STMFLASH_Read(STM32_FLASH_BASE_2,&Read_Buff,1);
    if(Read_Buff!=0xFFFF)
    {
        Band_Buff[0] = Read_Buff;
    }
    else if(Read_Buff == 0xFFFF)
    {
        Band_Buff[0] = 0x03;
    }
    return 0;
}
2.3.7主任务(485通信)
/***********************************************************
函数功能:扫描命令
返回值:#define CMD_Read_SHT30   	1	//读取温湿度命令
		#define CMD_Read_address	2	//读取地址命令
		#define CMD_Change_address	3	//更改地址命令
		#define CMD_Read_Baud	    4	//读取波特率命令
		#define CMD_Change_Baud     5	//更改波特率命令
***********************************************************/

uint8_t Command_Scan(void)
{
    if(usart1_rx_flag == 1)
    {
        CRC_Buff [0] = (CRC_16_HEX(usart1_rx_buffer,6)>>8);
        CRC_Buff [1] = (CRC_16_HEX(usart1_rx_buffer,6)&0xFF);

        if(usart1_rx_buffer[0]==Address_Buff[0]&&usart1_rx_buffer[1]==RS485_REC_Buff[1]&&usart1_rx_buffer[3]==RS485_REC_Buff[3])
        {
            RS485_REC_Buff[0]=Address_Buff[0];
            CRC_REC_Buff[0] = (CRC_16_HEX(RS485_REC_Buff,6)>>8);
            CRC_REC_Buff[1] = (CRC_16_HEX(RS485_REC_Buff,6)&0xFF);
            if(CRC_REC_Buff[0] == CRC_Buff[0]&CRC_REC_Buff[1] == CRC_Buff[1])
                return CMD_Read_SHT30;
            else return 0;
        }
        else if(usart1_rx_buffer[0]==Read_Address_Buff[0]&&usart1_rx_buffer[1]==Read_Address_Buff[1]&&usart1_rx_buffer[3]==Read_Address_Buff[3]&&usart1_rx_buffer[6]==Read_Address_Buff[6]&&usart1_rx_buffer[7]==Read_Address_Buff[7])
            return CMD_Read_address;
        else if(usart1_rx_buffer[0]==Set_Address_Buff[0]&&usart1_rx_buffer[1]==Set_Address_Buff[1]&&usart1_rx_buffer[3]==Set_Address_Buff[3])
        {
			Set_Address_Buff[5] = usart1_rx_buffer[5];
            CRC_Address_Buff[0] = (CRC_16_HEX(Set_Address_Buff,6)>>8);
            CRC_Address_Buff[1] = (CRC_16_HEX(Set_Address_Buff,6)&0xFF);
            if(CRC_Address_Buff[0] == CRC_Buff[0]&&CRC_Address_Buff[1] == CRC_Buff[1])
            {
                return CMD_Set_address;
            }
            else return 0;
        }
        else if(usart1_rx_buffer[0]==Read_Baud_Buff[0]&&usart1_rx_buffer[1]==Read_Baud_Buff[1]&&usart1_rx_buffer[3]==Read_Baud_Buff[3]&&usart1_rx_buffer[6]==Read_Baud_Buff[6]&&usart1_rx_buffer[7]==Read_Baud_Buff[7])
            return CMD_Read_Baud;
        else if(usart1_rx_buffer[0]==Set_Baud_Buff[0]&&usart1_rx_buffer[1]==Set_Baud_Buff[1]&&usart1_rx_buffer[3]==Set_Baud_Buff[3])
        {
            Set_Baud_Buff[5]=usart1_rx_buffer[5];
            CRC_Baud_Buff [0] = (CRC_16_HEX(Set_Baud_Buff,6)>>8);
            CRC_Baud_Buff [1] = (CRC_16_HEX(Set_Baud_Buff,6)&0xFF);
            if(CRC_Baud_Buff [0] == CRC_Buff [0]&CRC_Baud_Buff [1] == CRC_Buff [1])
                return CMD_Set_Baud;
        }
        else return 0;
    }
    return 0;
}

/***********************************************************
函数功能:主任务函数
返回值:无
***********************************************************/
uint8_t Task(void)
{	
	HAL_Delay(10);
    CMD=Command_Scan();
    if(CMD!=0)
    {
        switch(CMD)
        {
        case 1:
            /*将读取出来的温湿度存到RS485_Send_Buff中*/
            RS485_Send_Buff[0] = Address_Buff[0];
            RS485_Send_Buff[3] = temp_buf[0];
            RS485_Send_Buff[4] = temp_buf[1];
            RS485_Send_Buff[5] = hum_buf[0];
            RS485_Send_Buff[6] = hum_buf[1];
            /*计算出RS485_Send_Buff的CRC校验值(MODBUS协议的CRC校验)*/
            CRC_Buff[0] = (CRC_16_HEX(RS485_Send_Buff,7)>>8);
            CRC_Buff[1] = (CRC_16_HEX(RS485_Send_Buff,7)&0xFF);
            /*将CRC校验值存到RS485_Send_Buff中*/
            RS485_Send_Buff[7] = CRC_Buff[0];
            RS485_Send_Buff[8] = CRC_Buff[1];
			HAL_Delay(50);
            Send_485_Buff(RS485_Send_Buff);
            usart1_rx_flag = 0;
            break;
        case 2:
            Send_Address_Buff[0] = Address_Buff[0];
            CRC_Address_Buff [0] = (CRC_16_HEX(Send_Address_Buff,7)>>8);
            CRC_Address_Buff [1] = (CRC_16_HEX(Send_Address_Buff,7)&0xFF);
            Send_Address_Buff[7] = CRC_Address_Buff[0];
            Send_Address_Buff[8] = CRC_Address_Buff[1];
            Send_485_Buff(Send_Address_Buff);
            usart1_rx_flag = 0;
            break;
        case 3:
            Write_Buff = usart1_rx_buffer[5];
            STMFLASH_Write(STM32_FLASH_BASE_1,&Write_Buff,1);
            STMFLASH_Read(STM32_FLASH_BASE_1,&Read_Buff,1);
            Address_Buff[0] = Read_Buff;
            Send_Address_Buff[0] = Address_Buff[0];
            CRC_Address_Buff[0] = (CRC_16_HEX(Send_Address_Buff,7)>>8);
            CRC_Address_Buff[1] = (CRC_16_HEX(Send_Address_Buff,7)&0xFF);
            Send_Address_Buff[7] = CRC_Address_Buff[0];
            Send_Address_Buff[8] = CRC_Address_Buff[1];
            Send_485_Buff(Send_Address_Buff);
            usart1_rx_flag = 0;
            break;
        case 4:
            Send_Baud_Buff[0] = Band_Buff[0];
            CRC_Baud_Buff[0] = (CRC_16_HEX(Send_Baud_Buff,7)>>8);
            CRC_Baud_Buff[1] = (CRC_16_HEX(Send_Baud_Buff,7)>>8);
            Send_Baud_Buff[7] = CRC_Baud_Buff[0];
            Send_Baud_Buff[8] = CRC_Baud_Buff[1];
            Send_485_Buff(Send_Baud_Buff);
            usart1_rx_flag = 0;
            break;
        case 5:
            Write_Buff = usart1_rx_buffer[5];
            STMFLASH_Write(STM32_FLASH_BASE_2,&Write_Buff,1);
            STMFLASH_Read(STM32_FLASH_BASE_2,&Read_Buff,1);
            Band_Buff[0] = Read_Buff;
            Send_Baud_Buff[0] = Band_Buff[0];
            CRC_Baud_Buff[0] = (CRC_16_HEX(Send_Baud_Buff,7)>>8);
            CRC_Baud_Buff[1] = (CRC_16_HEX(Send_Baud_Buff,7)>>8);
            Send_Baud_Buff[7] = CRC_Baud_Buff[0];
            Send_Baud_Buff[8] = CRC_Baud_Buff[1];
            Send_485_Buff(Send_Baud_Buff);
            usart1_rx_flag = 0;	
            break;
        default:
            usart1_rx_flag = 0;
        }
    }
    else
    {
        usart1_rx_flag = 0;
    }
    return 0;
}

通信协议

RS485通信协议温湿度传感器探头

误码率测试

RS485通信协议温湿度传感器探头
测试通过,成功率100%

参考资料

3D封装下载地址
SHT30驱动参考
Cube如何配置
MODBUS_RTU协议详解
PCB文件&原理图(等我会用码云再上传)
嵌入式程序&Cube配置文件(等我会用码云再上传)
在没上传到码云前我先上传到百度云(提取码: 7bnp)

本文地址:https://blog.csdn.net/qq_42722691/article/details/108583129

相关标签: 笔记 stm32