找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 419|回复: 5
打印 上一主题 下一主题
收起左侧

stm32f103zet6单片机接sht35温湿度传感器数据波动巨大无比不稳定

[复制链接]
跳转到指定楼层
楼主
某一个宝买了一个SHT35模块,直接用STM32ZET6的正点原子开发板接的,数据波动巨大无比,各位大佬帮忙,下面是单片机代码
/*
设定温度阈值范围:-20℃——125℃
设定相对湿度范围:0%——100%
*/
#include"stm32f103xe.h"
#include"SHT30.h"
#include"stdio.h"
#include "usb_device.h"
#include "usbd_cdc_if.h"
#include "usbd_ctlreq.h"
#include "hw_config.h"
#include "usbd_core.h"
#include "usart.h"
#include <stdbool.h> // 引入标准布尔类型定义
#define write 0 //IIC设备地址一般是7位,也有10位,本程序使用7位IIC设备地址,第8位是写命令
#define read  1 //IIC设备地址一般是7位,也有10位,本程序使用7位IIC设备地址,第8位是读命令
// SHT30标准单次高精度测量命令
//#define MEAS_HIGHREP_STRETCH 0x2C06
//IIC总线接口定义
#define SCL PBout(6)//设置时钟端口
//SHT30数据SDA传输口,有输出也有输入,所以需配置它的输入和输出
#define SDA_OUT PBout(7)//设置输出数据端口
#define SDA_IN PBin(7)//设置输入数据端口
//设置端口高8位的工作模式(具体可以参照端口位配置表),即I/O输入输出方向设置,先用与(&)对PB7引脚的四个位清0,再用或(|)置1
#define IIC_INPUT_MODE_SET()  {GPIOB->CRL&=0X0FFFFFFF;GPIOB->CRL|=8<<28;}//改变PB7对应位为1000(CNF[1:0]MODE[1:0]),设置成上拉或者下拉输入
#define IIC_OUTPUT_MODE_SET() {GPIOB->CRL&=0X0FFFFFFF;GPIOB->CRL|=3<<28;}//改变PB7对应位为0011,设置成通用推挽输出
//#define IIC_INPUT_MODE_SET()  {GPIOB->CRH&=0XFFFF0FFF;GPIOB->CRH|=8<<12;}//改变PB7对应位为1000(CNF[1:0]MODE[1:0]),设置成上拉或者下拉输入
//#define IIC_OUTPUT_MODE_SET() {GPIOB->CRH&=0XFFFF0FFF;GPIOB->CRH|=3<<12;}//改变PB7对应位为0011,设置成通用推挽输出

//定义温湿度存储变量
u8 humiture_buff1[20];

void SHT30_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStruct;

  __HAL_RCC_GPIOB_CLK_ENABLE();

  GPIO_InitStruct.Pin = GPIO_PIN_6 | GPIO_PIN_7;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  //GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

  HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6, GPIO_PIN_SET);
  HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7, GPIO_PIN_SET);
}
//主机发送确认字符ACK
void IIC_ACK(void)//IIC协议,需要主机发送确认字符ACK来判断数据是否接收无误
{
  IIC_OUTPUT_MODE_SET();//配置PB7的SDA输出为推挽输出模式
  SCL=0;
  delay_us(2);
  SDA_OUT=0;
  delay_us(2);     
  SCL=1;//数据接收完成之后,将SCL拉高,以便与后面主机发送ACK给从机
  delay_us(2);                  
  SCL=0;//数据接收完成,主机发送ACK                     
  delay_us(1);   
}
//主机不发送确认字符ACK
void IIC_NACK(void)//IIC协议,数据传输未完成或者数据传输有误,主机不发送确认字符ACK
{
  IIC_OUTPUT_MODE_SET();//配置PB7的SDA输出为推挽输出模式
  SCL=0;
  delay_us(2);
  SDA_OUT=1;
  delay_us(2);      
  SCL=1;
  delay_us(2);                  
  SCL=0;                     
  delay_us(1);   
}
//主机等待从机的确认字符ACK
u8 IIC_wait_ACK(void)//主机等待从机发送ACK,从而判断数据是否接收完成
{
    u8 t = 200;
    IIC_OUTPUT_MODE_SET();
    SDA_OUT=1;//8位发送完后释放数据线,准备接收应答位
    delay_us(1);
    SCL=0;
    delay_us(1);
    IIC_INPUT_MODE_SET();
    delay_us(1);
    while(SDA_IN)//等待SHT30应答
    {
        t--;
        delay_us(1);
        if(t==0)
        {
          SCL=0;
          return 1;
        }
        delay_us(1);
    }
    delay_us(1);      
    SCL=1;
    delay_us(1);
    SCL=0;            
    delay_us(1);   
    return 0;        
}

void IIC_Start(void)//启动IIC通讯 标准库
{
  IIC_OUTPUT_MODE_SET();//设置PB7的SDA为推挽输出
  SDA_OUT=1;//根据SHT30时序,启动之前,SDA配置为高电平
  SCL=1;//根据SHT30时序,启动之前,SCL配置为高电平
  delay_us(4);//延时4us,给硬件一个反应时间
  SDA_OUT=0;//SDA引脚拉低,开始数据的传输
  delay_us(4);
  SCL=0;//SCL拉低,与SDA对应,响应SDA数据的拉低,表示正式开始数据的传输
}

//结束IIC总线通讯,发送IIC通讯的结束条件
void IIC_Stop(void)
{
        IIC_OUTPUT_MODE_SET();
        SCL=0;//结束IIC通讯之前,查看SCL是否是拉低状态
        SDA_OUT=0;//结束IIC通讯之前,查看SDA是否是拉低状态  
        delay_us(4);        
        SCL=1;//将时钟拉高,表示已经结束IIC通讯
        delay_us(4);
        SDA_OUT=1;//将数据传输引脚拉高,表示正式结束数据的传输
        delay_us(4);
}

//将byte数据发送出去
void  IIC_SendByte(u8 byte)
{
        u8  Count;
        IIC_OUTPUT_MODE_SET();
        SCL=0;//将时钟拉低,开始数据的传输
        for(Count=0;Count<8;Count++)//要传送的数据长度为8位
        {
                if(byte&0x80) SDA_OUT=1;//判断发送位,发送位为1,则还未发送数据
                else SDA_OUT=0; //判断发送位为0,则开始数据的发送
                byte<<=1;
                delay_us(2);
                SCL=1;
                delay_us(2);
                SCL=0;
                delay_us(2);
        }
}

// 用来接收从器件传来的数据   
u8 IIC_RcvByte(void)
{
  u8 retc;
  u8 Count;
  retc=0;
  IIC_INPUT_MODE_SET();//配置数据线为输入方式
  delay_us(1);                    
  for(Count=0;Count<8;Count++)
  {  
        SCL=0;//配置时钟线为低,准备接收数据位
        delay_us(1);               
        SCL=1;//配置时钟线为高使数据线上数据有效  
        delay_us(1);      
        retc=retc<<1;
        if(SDA_IN) retc |=1;//读数据位,接收的数据位放入retc中
        delay_us(1);
  }
  SCL=0;   
  return(retc);
}

//用来接收从器件采集并合成温湿度
void SHT30_read_result(u8 addr)
{
        
    //SHT30有两种读取数值的方法,分别是状态查询和数值查询,这里我使用的是数值查询,发送指令为0x2C06
        u16 tem,hum;//定义存放温湿度计算公式的变量
        u16 buff[6];//定义6个字节的数组,存放温度高、低八位,湿度高、低八位,两个字节的CRC校验位
        float Temperature=0;//定义存放温度拼接的变量Temperature,初始化温度为0
        float Humidity=0;//定义存放湿度拼接的变量Humidity,初始化湿度为0
        //发送指令为0x2C06(默认)
        IIC_Start();
        IIC_SendByte(addr<<1 | write);//写7位I2C设备地址加0作为写取位,1为写取位
        IIC_wait_ACK();
        //delay_us(1);
        IIC_SendByte(0x2C);//前半段发送指令为0x2C
        IIC_wait_ACK();
        //delay_us(1);
        IIC_SendByte(0x06);//后半段发送指令为0x06
        IIC_wait_ACK();
        //delay_us(1);
        IIC_Stop();
        delay_ms(20);//等待传感器读取数据
        IIC_Start();
        IIC_SendByte(addr<<1 | read);//写7位I2C设备地址加1作为读取位,1为读取位

//SHT30返回的数值是6个元素的数组
        if(IIC_wait_ACK()==0)
        {
        delay_us(1);
                buff[0]=IIC_RcvByte();//返回温度高8位
                IIC_ACK();
                buff[1]=IIC_RcvByte();//返回温度低8位
                IIC_ACK();
                buff[2]=IIC_RcvByte();//温度crc校验位
                IIC_ACK();
                buff[3]=IIC_RcvByte();//返回湿度高8位
                IIC_ACK();
                buff[4]=IIC_RcvByte();//返回湿度低8位
                IIC_ACK();
                buff[5]=IIC_RcvByte();//湿度crc校验位
                IIC_NACK();
                IIC_Stop();
        }
    tem = ((buff[0]<<8) | buff[1]);//将buff[0]采集到的温度8位数据与buff[1]采集到的低8位数据相或,实现温度拼接
    hum = ((buff[3]<<8) | buff[4]);//将buff[3]采集到的湿度8位数据与buff[4]采集到的低8位数据相或,实现湿度拼接

    // 将温度和湿度转换为浮点值
    Temperature = -45 + 175 * ((float)tem / 65535.0); // T = -45 + 175 * ST / (2^16-1)
    Humidity = 100 * ((float)hum / 65535.0); // RH = 100 * SRH / (2^16-1)
    if((Temperature>=-20)&&(Temperature<=125)&&(Humidity>=0)&&(Humidity<=100))//设定温度和湿度的阈值,超过这个阈值则返回错误提示
    {
    USB_Printf("\r\n温度:%6.2f℃\r\n",Temperature);
    USB_Printf("湿度:%6.2f%%\r\n",Humidity);
    hum=0;
    tem=0;        
    }
    else
    {
    USB_Printf("\r\n温湿度超过给定阈值!\r\n");
    }
}
3.3V供电,SDA接PB7,SCL接PB6,电脑串口115200,能读到温湿度,但数据稳定性特别差,尝试改了部分代码,也改了电压,但都不太行,手里现在没有别的工具,各位大佬先浅看下代码,我是找不到什么毛病,好难

6a33d1057573061e11a69d2b698a418.jpg (546 KB, 下载次数: 53)

串口工具读到的数据

串口工具读到的数据
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:883242 发表于 2024-2-22 07:41 | 只看该作者
不是波动巨大,而是根本就没有连接成功。
回复

使用道具 举报

板凳
ID:226055 发表于 2024-2-22 16:50 | 只看该作者
    楼上正解,这个实验现象很明显没有正常通信上。原因多方面的,一般软件和硬件上。
    1、软件原因不好帮你排查,但我手上有个测试没有问题的SHT35的代码。单片机也是STM32F103ZET6,所以参考价值很大,程序附件。(硬件是艾克姆的ZET6板子)


    2、如果使用上面软件还没有出现如上图所示的实验现象,那你要考虑硬件原因了。开发板是成品,出问题的概率很小。SHT35模块要考虑是不是好的。




SHT35.7z

199.02 KB, 下载次数: 7

回复

使用道具 举报

地板
ID:341424 发表于 2024-2-25 17:56 | 只看该作者
Hephaestus 发表于 2024-2-22 07:41
不是波动巨大,而是根本就没有连接成功。

是的老哥 软件问题 暴风哭泣
回复

使用道具 举报

5#
ID:341424 发表于 2024-2-25 17:58 | 只看该作者
cocolala 发表于 2024-2-22 16:50
楼上正解,这个实验现象很明显没有正常通信上。原因多方面的,一般软件和硬件上。
    1、软件原因不 ...

感恩的心 确实是软件问题
回复

使用道具 举报

6#
ID:41656 发表于 2024-2-28 16:32 | 只看该作者
说明通信没成功,可以去读取一些芯片ID信息之类的去对比一下看看
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表