RS485通信协议温湿度传感器探头
程序员文章站
2022-06-15 22:45:40
<笔记> 温湿度传感器探头&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 原理图
1.2 PCB
1.3 3D零件图
嵌入式程序
2.1 程序流程图
2.2 cube配置
2.2.1 看门狗配置
2.2.2 定时器配置
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;
}
通信协议
误码率测试
测试通过,成功率100%
参考资料
3D封装下载地址
SHT30驱动参考
Cube如何配置
MODBUS_RTU协议详解
PCB文件&原理图(等我会用码云再上传)
嵌入式程序&Cube配置文件(等我会用码云再上传)
在没上传到码云前我先上传到百度云(提取码: 7bnp)
本文地址:https://blog.csdn.net/qq_42722691/article/details/108583129
上一篇: Jenkins插件开发笔记
下一篇: mongo:副本集群配置