[技术问答]

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

[复制链接]
1622|8
手机看帖
扫描二维码
随时随地手机跟帖
starry1028|  楼主 | 2024-11-18 18:42 | 显示全部楼层 |阅读模式
HC32F460  模拟I2C 读SHT30,实在是搞不定了。那位大佬做过类似的,可以参考下吗?
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的驱动

使用特权

评论回复
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
电脑有加密无法发文件凑合看吧 
starry1028|  楼主 | 2024-11-19 17:43 | 显示全部楼层
qinlu123 发表于 2024-11-19 16:01
下边是I2C.c
#include "I2C.h"

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

使用特权

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

使用特权

评论回复
yang377156216| | 2024-12-9 13:55 | 显示全部楼层
可以直接用 rtt,这样就不用自己写驱动了

使用特权

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

本版积分规则

2

主题

3

帖子

0

粉丝