打印
[技术问答]

请教下HC32F460读SHT30,实在是搞不定了。

[复制链接]
2466|18
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
HC32F460  模拟I2C 读SHT30,实在是搞不定了。那位大佬做过类似的,可以参考下吗?

1.png (218.25 KB )

1.png

使用特权

评论回复
沙发
suncat0504| | 2024-11-19 10:18 | 只看该作者
建议你先用Arduino搞通,然后对比时序信号。主要侧重于脉冲周期、ACK/NACK上。

使用特权

评论回复
板凳
wang369| | 2024-11-19 13:42 | 只看该作者
你先试一下你的模拟IIC信号是否对?基本就是时序周期等一类的问题

使用特权

评论回复
地板
qinlu123| | 2024-11-19 15:51 | 只看该作者
要不我给你个SHT30的驱动

使用特权

评论回复
5
qinlu123| | 2024-11-19 16:01 | 只看该作者
下边是I2C.c
#include "I2C.h"

#define Delay_Time 2

void I2C_delay_nus(uint16_t time)
{     
   uint8_t i=0;   
   while(time--)
   {
      i=1;
      while(i--) ;     
   }  
}
static void Set_I2C1_SCL(uint8_t a)
{
    if(a!=0)
    {
        PHout(5)=1;
    }
    else
    {
        PHout(5)=0;
    }
}
static void Set_I2C1_SDA(uint8_t a)
{
    if(a!=0)
    {
        PAout(4)=1;
    }
    else
    {
        PAout(4)=0;
    }
}
static uint8_t Get_I2C1_SDA(void)
{
    return PAin(4);
}
static void Set_I2C2_SCL(uint8_t a)
{
    if(a!=0)
    {
        PBout(7)=1;
    }
    else
    {
        PBout(7)=0;
    }
}
static void Set_I2C2_SDA(uint8_t a)
{
    if(a!=0)
    {
        PBout(8)=1;
    }
    else
    {
        PBout(8)=0;
    }
}
static uint8_t Get_I2C2_SDA(void)
{
    return PBin(8);
}
static void Set_I2C3_SCL(uint8_t a)
{
    if(a!=0)
    {
        PEout(2)=1;
    }
    else
    {
        PEout(2)=0;
    }
}
static void Set_I2C3_SDA(uint8_t a)
{
    if(a!=0)
    {
        PEout(3)=1;
    }
    else
    {
        PEout(3)=0;
    }
}
static uint8_t Get_I2C3_SDA(void)
{
    return PEin(3);
}

struct I2C_Device I2C_1=
{
    .Set_SDA = Set_I2C1_SDA,
    .Set_SCL = Set_I2C1_SCL,
    .Get_SDA = Get_I2C1_SDA,
    .delayus = I2C_delay_nus
};
struct I2C_Device I2C_2=
{
    .Set_SDA = Set_I2C2_SDA,
    .Set_SCL = Set_I2C2_SCL,
    .Get_SDA = Get_I2C2_SDA,
    .delayus = I2C_delay_nus
};
struct I2C_Device I2C_3=
{
    .Set_SDA = Set_I2C3_SDA,
    .Set_SCL = Set_I2C3_SCL,
    .Get_SDA = Get_I2C3_SDA,
    .delayus = I2C_delay_nus
};
/*
    IIC Driver
*/
void I2C_Start(struct I2C_Device *IIcBus)
{
    IIcBus->Set_SDA(1);
    IIcBus->delayus(Delay_Time);
    IIcBus->Set_SCL(1);
    IIcBus->delayus(Delay_Time);
    IIcBus->Set_SDA(0);
    IIcBus->delayus(Delay_Time);
    IIcBus->Set_SCL(0);
}
void I2C_Stop(struct I2C_Device *IIcBus)
{
    IIcBus->Set_SDA(0);
    IIcBus->delayus(Delay_Time);
    IIcBus->Set_SCL(1);
    IIcBus->delayus(Delay_Time);
    IIcBus->Set_SDA(1);
}
uint8_t Receive_ACK(struct I2C_Device *IIcBus)
{
    uint32_t i;
   
    IIcBus->Set_SCL(0);//一定把时钟设为低电平再释放总线等待ACK
    IIcBus->delayus(Delay_Time);
    IIcBus->Set_SDA(1);//释放总线
    IIcBus->delayus(Delay_Time);
    while(IIcBus->Get_SDA()!=0)
    {
        i++;
        if(i>10)
        {
            return 0;
        }
        IIcBus->delayus(Delay_Time);
    }
    IIcBus->Set_SCL(1);
    IIcBus->delayus(Delay_Time);
    IIcBus->Set_SCL(0);
    return 1;
}
void I2C_WriteOneByte(struct I2C_Device *IIcBus,uint8_t Write_Data)
{
    uint8_t i;
    uint8_t Data=0;
    Data=Write_Data;
    for(i=0;i<8;i++)
    {
        IIcBus->Set_SDA(Data & 0x80);
        IIcBus->delayus(Delay_Time);
        IIcBus->Set_SCL(1);
        IIcBus->delayus(Delay_Time);
        IIcBus->Set_SCL(0);
        IIcBus->delayus(Delay_Time);
        Data <<= 1;
    }
}
/**************Send ACK**************/
void I2C_SendACK(struct I2C_Device *IIcBus)
{
    IIcBus->Set_SCL(0);
    IIcBus->delayus(Delay_Time);
    IIcBus->Set_SDA(0);//发送ACK
    IIcBus->delayus(Delay_Time);
    IIcBus->Set_SCL(1);//拉高时钟线再拉低时钟线完成一个读周期
    IIcBus->delayus(Delay_Time);
    IIcBus->Set_SCL(0);//空闲时保证时钟线为低
    IIcBus->delayus(Delay_Time);
    IIcBus->Set_SDA(1);//发送完ACK后释放总线
}
void I2C_SendNACK(struct I2C_Device *IIcBus)
{
    IIcBus->Set_SCL(0);
    IIcBus->delayus(Delay_Time);
    IIcBus->Set_SCL(1);
    IIcBus->delayus(Delay_Time);
    IIcBus->Set_SCL(0);
}

uint8_t I2C_ReadOneByte(struct I2C_Device *IIcBus,uint8_t Ack)
{
    uint8_t i;
    uint8_t Data=0;

    IIcBus->Set_SDA(1);//释放总线
    IIcBus->delayus(Delay_Time);
    for(i=0;i<8;i++)
    {
      Data <<= 1;
        IIcBus->Set_SCL(0);
        IIcBus->delayus(Delay_Time);
        IIcBus->Set_SCL(1);
        IIcBus->delayus(Delay_Time);
        if(IIcBus->Get_SDA())
        {
            Data++;
        }
    }
    IIcBus->Set_SCL(0);
    if(Ack)
    {
        I2C_SendACK(IIcBus);
    }
    else
    {
        I2C_SendNACK(IIcBus);
    }
    return Data;
}
下边是I2C.h
#ifndef __IIC_H
#define __IIC_H

#include "Header.h"

struct I2C_Device
{
    void (*Set_SDA)(uint8_t a);
    void (*Set_SCL)(uint8_t a);
    uint8_t (*Get_SDA)(void);
    void (*delayus)(uint16_t us);
};

extern struct I2C_Device I2C_1,I2C_2,I2C_3;

void I2C_delay_nus(uint16_t time);
void I2C_Start(struct I2C_Device *IIcBus);
void I2C_Stop(struct I2C_Device *IIcBus);
uint8_t Receive_ACK(struct I2C_Device *IIcBus);
void I2C_WriteOneByte(struct I2C_Device *IIcBus,uint8_t Write_Data);
void I2C_SendACK(struct I2C_Device *IIcBus);
void I2C_SendNACK(struct I2C_Device *IIcBus);
uint8_t I2C_ReadOneByte(struct I2C_Device *IIcBus,uint8_t Ack);

#endif
下边是SHT3x.c

#include "Sht3x.h"

struct sht3xObj sht31_1 =
{
    .HardWare = &I2C_1
};
struct sht3xObj sht31_2 =
{
    .HardWare = &I2C_2
};

static uint8_t sht31_mode_set(struct sht3xObj *PARA, uint8_t mode_h,uint8_t mode_l)
{
    I2C_Start(PARA->HardWare);
    I2C_WriteOneByte(PARA->HardWare,SHT31_RHT_W);
    if(Receive_ACK(PARA->HardWare)!=1)
    {
        return 0;
    }
    I2C_WriteOneByte(PARA->HardWare,Mode_Set_H);
    if(Receive_ACK(PARA->HardWare)!=1)
    {
        return 0;
    }
    I2C_WriteOneByte(PARA->HardWare,Mode_Set_L);
    if(Receive_ACK(PARA->HardWare)!=1)
    {
        return 0;
    }   
    I2C_Stop(PARA->HardWare);
    return 1;
}

uint8_t soft_reset_sensor(struct sht3xObj *PARA)
{
  I2C_Start(PARA->HardWare);
  I2C_WriteOneByte(PARA->HardWare,SHT31_RHT_W);
  if(Receive_ACK(PARA->HardWare)!=1)
    {
        return 0;
    }
  I2C_WriteOneByte(PARA->HardWare,RESET_SET_H);
  if(Receive_ACK(PARA->HardWare)!=1)
  {
    return 0;
  }
  I2C_WriteOneByte(PARA->HardWare,RESET_SET_L);
  if(Receive_ACK(PARA->HardWare)!=1)
  {
    return 0;
  }
  I2C_Stop(PARA->HardWare);
  return 1;
}

uint8_t StartReadRHTemperature(struct sht3xObj *PARA)
{
    I2C_Start(PARA->HardWare);
    I2C_WriteOneByte(PARA->HardWare,SHT31_RHT_W);
    if(Receive_ACK(PARA->HardWare)!=1)
    {
      return 0;
    }
    I2C_WriteOneByte(PARA->HardWare,0xE0);
    if(Receive_ACK(PARA->HardWare)!=1)
    {
      return 0;
    }
    I2C_WriteOneByte(PARA->HardWare,0x00);
    if(Receive_ACK(PARA->HardWare)!=1)
    {
      return 0;
    }
    return 1;
}


uint8_t sht31ReadRHTemperature(struct sht3xObj *PARA)
{
    uint8_t   T_Data_MSB, T_Data_LSB, RH_Data_MSB, RH_Data_LSB;
    uint8_t   CRC8_1, CRC8_2;
    uint16_t  data_t, data_rh;
        
    I2C_Start(PARA->HardWare);
    I2C_WriteOneByte(PARA->HardWare,SHT31_RHT_R);
    if(Receive_ACK(PARA->HardWare)!=1)
    {
        return 0;
    }
        
    T_Data_MSB = I2C_ReadOneByte(PARA->HardWare,ACK);
    T_Data_LSB = I2C_ReadOneByte(PARA->HardWare,ACK);
    CRC8_1 = I2C_ReadOneByte(PARA->HardWare,ACK);

    RH_Data_MSB = I2C_ReadOneByte(PARA->HardWare,ACK);
    RH_Data_LSB = I2C_ReadOneByte(PARA->HardWare,ACK);
    CRC8_2 = I2C_ReadOneByte(PARA->HardWare,NACK);
    I2C_Stop(PARA->HardWare);

    data_rh = (RH_Data_MSB<<8)|(RH_Data_LSB);
    PARA->Humidty = 100*((float)data_rh/65535);

    data_t = (T_Data_MSB<<8)|(T_Data_LSB);
    PARA->Temperture = -45 + 175*((float)data_t/65535);
   
    return 1;
}
void sht31_thread(struct sht3xObj *PARA)
{
    switch(PARA->RH_Status)
    {
    case 0:
    {
            if(CheckDelay(&PARA->Delay_Time)==0)
            {
                if(sht31_mode_set(PARA,Mode_Set_H,Mode_Set_L) != 0)
                {
                    PARA->RH_Status++;
                }
                else
                {
                    Set_Delay_Time(1500,&PARA->Delay_Time);
                }
            }
    }break;
        case 1://启动温湿度检测
        {
      if(CheckDelay(&PARA->Delay_Time)==0)
      {
        if(StartReadRHTemperature(PARA)!=0)
        {
                    Set_Delay_Time(1000,&PARA->Delay_Time);
                    PARA->RH_Read_Time = 0;
                    PARA->RH_Status++;
        }
        else
        {
          I2C_Stop(PARA->HardWare);
          PARA->RH_Read_Time++;
                    Set_Delay_Time(100,&PARA->Delay_Time);
          if(PARA->RH_Read_Time > 5)
          {
            PARA->RH_Read_Time = 0;
            PARA->RH_Status = 0;
          }
        }
      }
        }break;
        case 2:
        {
            if(CheckDelay(&PARA->Delay_Time)==0)
            {
                if(sht31ReadRHTemperature(PARA) != 0)
                {
                    PARA->RH_Status = 1;
                }
                else
                {
                    PARA->RH_Status = 0;
                }
            }
        }break;
        default:
        {
            PARA->RH_Status = 0;
        }break;
    }
}
下边是sht3x.h

#ifndef __SHT3X__H__
#define __SHT3X__H__

#include "I2C.h"
#include "Header.h"
#include "Delay.h"

#define ACK 1
#define NACK 0

#define SHT31_RHT_W   0X88
#define SHT31_RHT_R   0X89

//#define SHT31_RHT_W   0X8C
//#define SHT31_RHT_R   0X8D

//MODE COMMAND  
#define Mode_Set_H    0x21     
#define Mode_Set_L    0x2D

//SOFTRESET COMMAND
#define RESET_SET_H   0x30
#define RESET_SET_L   0xA2

struct sht3xObj
{
    uint16_t Delay_Time;//别忘了需要被DelayTimeCount_ms
    struct I2C_Device *HardWare;

  uint16_t   adc_t;
  uint16_t   adc_rh;
    float   Temperture;
    float   Humidty;   
    uint8_t Status;
    uint8_t RH_Status;
    uint8_t RH_Read_Time;
};

extern struct sht3xObj sht31_1,sht31_2;

void sht31_thread(struct sht3xObj *PARA);


#endif
下边是用到的延时函数

void DelayTimeCount_ms(uint16_t *DelayTime_Count)
{
    if(*DelayTime_Count==0)
    {
        *DelayTime_Count=0;
    }
    else
    {
        *DelayTime_Count-=1;
    }
}
void Set_Delay_Time(uint16_t Time,uint16_t *DelayTime_Count)
{
    *DelayTime_Count=Time;
}
uint8_t CheckDelay(uint16_t *DelayTime_Count)
{
    if(*DelayTime_Count==0)
    {
        return 0;
    }
    else
    {
        return 1;
    }
}
下边是函数调用
#include "TaskMgr.h"

uint8_t Sys_Status=0;
uint16_t Item_OverTime_Count=0;
uint16_t TimeTick_Count=0;
uint8_t Task_1ms_EN=0,Task_2ms_EN=0,Task_5ms_EN=0,Task_10ms_EN=0,Task_20ms_EN=0,Task_50ms_EN=0,Task_100ms_EN=0,Task_500ms_EN=0,Task_1000ms_EN=0,Task_5000ms_EN=0;
uint8_t TCL=0;

static void SysTimeTikeCounting(void)
{
    TCL = 1;
    if(TimeTick_Count>60000)
    {
        TimeTick_Count=1;
    }
    else
    {
        TimeTick_Count++;
    }
}
static void Task_1ms(void)
{
    TimeCountReceive(&U_D_Uart1);
    DelayTimeCount_ms(&MS8607_Para_1.PT_Thread_Time);
    DelayTimeCount_ms(&MS8607_Para_2.PT_Thread_Time);
    DelayTimeCount_ms(&RS485BusSilentTime1);
    DelayTimeCount_ms(&MMDPort1.DelayTime);
    DelayTimeCount_ms(&PTQ3040.DelayTime);
    DelayTimeCount_ms(&sht31_1.Delay_Time);
    DelayTimeCount_ms(&sht31_2.Delay_Time);
    SmiTimeCount();
}
static void Task_2ms(void)
{
   
}
static void Task_5ms(void)
{
   
}
static void Task_10ms(void)
{
   
}
static void Task_20ms(void)
{
   
}
static void Task_50ms(void)
{
    ReadEleSensorInformationWhenBooting();
}
static void Task_100ms(void)
{

}
static void Task_500ms(void)
{

}
static void Task_1000ms(void)
{
    GetDS18B20Data(&DS18B20_1);
//  GetDS18B20Data(&DS18B20_2);
//  GetDS18B20Data(&DS18B20_3);
//  GetDS18B20Data(&DS18B20_4);
    ReadEleSensorValueEnable();
    ReadLSPMValueEnable();
    ReadWSEnable();
    ReadWDEnable();
    PTQModeSetEnable();
    PTQReadEnable();
}
static void Task_5000ms(void)
{

}
static void TaskPolls(void)
{
    if(TCL)
    {
        TCL = 0;
        
        if((TimeTick_Count%1)==0)
        {
            Task_1ms_EN=1;
        }
        if((TimeTick_Count%2)==0)
        {
            Task_2ms_EN=1;
        }
        if((TimeTick_Count%5)==0)
        {
            Task_5ms_EN=1;
        }
        if((TimeTick_Count%10)==0)
        {
            Task_10ms_EN=1;
        }
        if((TimeTick_Count%20)==0)
        {
            Task_20ms_EN=1;
        }
        if((TimeTick_Count%50)==0)
        {
            Task_50ms_EN=1;
        }
        if((TimeTick_Count%100)==0)
        {
            Task_100ms_EN=1;
        }
        if((TimeTick_Count%500)==0)
        {
            Task_500ms_EN=1;
        }
        if((TimeTick_Count%1000)==0)
        {
            Task_1000ms_EN=1;
        }
        if((TimeTick_Count%5000)==0)
        {
            Task_5000ms_EN=1;
        }
    }
   
    if(Task_1ms_EN)
    {
        Task_1ms_EN=0;
        Task_1ms();
    }
    if(Task_2ms_EN)
    {
        Task_2ms_EN=0;
        Task_2ms();
    }
    if(Task_5ms_EN)
    {
        Task_5ms_EN=0;
        Task_5ms();
    }
    if(Task_10ms_EN)
    {
        Task_10ms_EN=0;
        Task_10ms();
    }
    if(Task_20ms_EN)
    {
        Task_20ms_EN=0;
        Task_20ms();
    }
    if(Task_50ms_EN)
    {
        Task_50ms_EN=0;
        Task_50ms();
    }
    if(Task_100ms_EN)
    {
        Task_100ms_EN=0;
        Task_100ms();
    }
    if(Task_500ms_EN)
    {
        Task_500ms_EN=0;
        Task_500ms();
    }
    if(Task_1000ms_EN)
    {
        Task_1000ms_EN=0;
        Task_1000ms();
    }
    if(Task_5000ms_EN)
    {
        Task_5000ms_EN=0;
        Task_5000ms();
    }
}
void Sys_INIT(void)
{
//  MX_GPIO_Init();
//  MX_TIM1_Init();
//  MX_TIM2_Init();
//  MX_TIM3_Init();
//  MX_USART1_UART_Init();
    UartDebugInit();
    HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_1);
    PTQModeSetEnable();
}
void SYSTICK_Callback(void)
{
    SysTimeTikeCounting();
}
void SystemRun(void)
{   
    TaskPolls();
//  FlowControl(&FlowDust);

    MS8607_PT_Thread(&MS8607_Para_1);
    sht31_thread(&sht31_1);
    MS8607_PT_Thread(&MS8607_Para_2);
    sht31_thread(&sht31_2);
//  
//  SmiRuning(&SM9541_1);
   
    RS485Device1Handle();
}









使用特权

评论回复
评论
qinlu123 2024-11-19 16:09 回复TA
电脑有加密无法发文件凑合看吧 
6
starry1028|  楼主 | 2024-11-19 17:43 | 只看该作者
qinlu123 发表于 2024-11-19 16:01
下边是I2C.c
#include "I2C.h"

感谢,今天排查后解决了。确实是时序还有SDA转换成输入时的问题。

使用特权

评论回复
7
hjl2832| | 2024-12-5 16:42 | 只看该作者
模拟IIC的SDA做输入输出切换时,在有些芯片里会产生问题,要注意切换时的逻辑顺序。用示波器会看到切换时的一个高电平跳变。所以把IO先置0再切换就好了。

使用特权

评论回复
8
yang377156216| | 2024-12-9 13:55 | 只看该作者
可以直接用 rtt,这样就不用自己写驱动了

使用特权

评论回复
9
y1n9an| | 2024-12-17 22:49 | 只看该作者
将SHT30传感器通过适当的接口(如I2C或SPI)连接到HC32F460的相应引脚。确保连接正确无误,包括电源、地线、时钟线(SCL或SDA)和数据线(SDA或SCL)。

使用特权

评论回复
10
q1d0mnx| | 2024-12-17 23:33 | 只看该作者
配置微控制器,根据HC32F460的数据手册配置相应的硬件接口模块(如I2C或SPI模块),以正确与传感器通信。这可能包括设置时钟频率、从地址、波特率等参数。

使用特权

评论回复
11
p0gon9y| | 2024-12-18 21:11 | 只看该作者
通过相应的通信协议向SHT30发送初始化命令,使其准备好接收指令并发送数据。这通常涉及设置传感器的测量模式(如连续模式或单次测量模式)、输出数据速率等。

使用特权

评论回复
12
kaif2n9j| | 2024-12-18 22:48 | 只看该作者
使用HC32F460的通信接口发送读取命令到SHT30传感器,以获取温度和湿度数据。具体的读取命令和格式取决于传感器的数据手册。通常,你需要按照传感器的指令集发送特定的命令序列,然后接收传感器返回的数据。

使用特权

评论回复
13
cen9ce| | 2024-12-19 19:31 | 只看该作者
从传感器接收到的数据可能是原始的,需要进行适当的转换和处理才能得到实际的温度和湿度值。根据SHT30的数据手册,你可能需要解析返回的数据格式,并进行必要的计算以得到最终的温湿度值。

使用特权

评论回复
14
l1uyn9b| | 2024-12-19 20:48 | 只看该作者
具体的实现细节取决于你的硬件连接、微控制器的配置以及传感器的数据手册。

使用特权

评论回复
15
g0d5xs| | 2024-12-19 22:09 | 只看该作者
建议详细阅读HC32F460和SHT30的数据手册,并根据其中的指导进行开发。

使用特权

评论回复
16
zhizia4f| | 2024-12-20 07:17 | 只看该作者
网上有很多关于模拟I2C控制SHT30的例子的,你调整一下时序也就是delay应该就可以了

使用特权

评论回复
17
w2nme1ai7| | 2024-12-20 08:24 | 只看该作者
确实你说的IO配置成输入这个问题,之前我还遇到过IO需要先打开复用时钟的

使用特权

评论回复
18
q1ngt12| | 2024-12-20 09:33 | 只看该作者
其实一般来说模拟I2C不如硬件I2C来的快而且硬件I2C还比较好调试

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

3

主题

4

帖子

0

粉丝