哈哈哈哈 发表于 2024-8-18 23:16:14

AI8051U AHT25 温湿度传感器 偶遇问题

本帖最后由 DebugLab 于 2024-8-19 00:21 编辑

AHT25 温湿度传感器 采用I2C通信

时序如下图所示:




如何使用IO模拟I2C
关键是起始,停止和应答
代码如下:
void aht_sleep_us(unsigned int n) //24mhz
{
    while (n--)
    {
      NOP24();
    }
}


void aht_sleep_ms(unsigned intn)
{
    while (n--)
      aht_sleep_us(1000);
}


#define I2C_TIMEOUT_TIMES 100      //超时倍数

//延时 用于等待应答时的超时判断 移植时需修改
void i2c_timeout_delay(void)      
{
    aht_sleep_ms(1);
}

void i2c_delay()      //每步的间隔 用于等待电平稳定和控制通讯速率
{
    aht_sleep_us(5);
}

//SCL拉高 移植时需修改
void I2C_SCL_H(void)
{
      I2C_SCL = 1;
}

//SCL拉低 移植时需修改
void I2C_SCL_L(void)
{
      I2C_SCL = 0;
}

//SDA拉高 移植时需修改
void I2C_SDA_H(void)
{
      I2C_SDA = 1;
}

//SDA拉低 移植时需修改
void I2C_SDA_L(void)
{
      I2C_SDA = 0;
}

//读取SDA 移植时需修改
unsigned char I2C_SDA_Read(void)
{
      return I2C_SDA;
}

/*******************************************************************************
* 函 数 名       : i2c_start
* 函数功能               : 产生I2C起始信号
* 输    入       : 无
* 输    出             : 无
*******************************************************************************/
void i2c_start(void)
{
      I2C_SDA_H();
    I2C_SCL_H();
    i2c_delay();

    I2C_SDA_L();      //当SCL为高电平时,SDA由高变为低
    i2c_delay();
    I2C_SCL_L();      //钳住I2C总线,准备发送或接收数据
}

/*******************************************************************************
* 函 数 名         : i2c_stop
* 函数功能                   : 产生I2C停止信号
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/
void i2c_stop(void)
{
      I2C_SDA_L();
    I2C_SCL_H();
    i2c_delay();

    I2C_SDA_H();      //当SCL为高电平时,SDA由低变为高
    i2c_delay();
}

/*******************************************************************************
* 函 数 名         : i2c_ack
* 函数功能                   : 产生ACK应答
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/
void i2c_ack(void)
{
    I2C_SCL_L();
    I2C_SDA_L();      //SDA为低电平
    i2c_delay();

    I2C_SCL_H();
    i2c_delay();
    I2C_SCL_L();
      I2C_SDA_H();      
}

/*******************************************************************************
* 函 数 名         : i2c_nack
* 函数功能                   : 产生NACK非应答
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/
void i2c_nack(void)
{
    I2C_SCL_L();
    I2C_SDA_H();      //SDA为高电平
    i2c_delay();

    I2C_SCL_H();
    i2c_delay();
    I2C_SCL_L();
}

/*******************************************************************************
* 函 数 名         : i2c_wait_ack
* 函数功能                   : 等待应答信号到来
* 输    入         : 无
* 输    出         : 1,接收应答失败
                                 0,接收应答成功
*******************************************************************************/
unsigned char i2c_wait_ack(void)
{
    unsigned int time_temp = 0;

    I2C_SCL_H();
    i2c_delay();
    while(I2C_SDA_Read())                              //等待SDA为低电平
    {
      time_temp++;
                i2c_timeout_delay();
      if(time_temp > I2C_TIMEOUT_TIMES)      //超时则强制结束I2C通信
      {
            i2c_stop();
            return 1;
      }
    }
    I2C_SCL_L();
    return 0;
}

/*******************************************************************************
* 函 数 名         : i2c_write_byte
* 函数功能                   : I2C发送一个字节
* 输    入         : dat:发送一个字节
* 输    出         : 无
*******************************************************************************/
void i2c_write_byte(unsigned char dat)
{
    unsigned char i = 0;

    I2C_SCL_L();
    for(i = 0; i<8; i++)      //循环8次将一个字节传出,先传高再传低位
    {
      if((dat & 0x80) > 0)
            I2C_SDA_H();
      else
            I2C_SDA_L();
      dat <<= 1;
      i2c_delay();
      I2C_SCL_H();
      i2c_delay();
      I2C_SCL_L();
      i2c_delay();
    }
}

/*******************************************************************************
* 函 数 名         : i2c_read_byte
* 函数功能                   : I2C读一个字节
* 输    入         : ack = 1时,发送ACK,ack = 0,发送nACK
* 输    出         : 应答或非应答
*******************************************************************************/
unsigned char i2c_read_byte(unsigned char ack)
{
    unsigned char i = 0, receive = 0;

    for(i = 0; i < 8; i++ )      //循环8次将一个字节读出,先读高再传低位
    {
      I2C_SCL_L();
      i2c_delay();
      I2C_SCL_H();
      receive <<= 1;
      if(I2C_SDA_Read())
                        receive++;
      i2c_delay();
    }
    if (!ack)
      i2c_nack();
    else
      i2c_ack();

    return receive;
}

/*******************************************************************************
* 函 数 名         : i2c_mem_write
* 函数功能                   : I2C对指定器件、指定寄存器连续写入
* 输    入         : 器件地址、器件寄存器地址、待输入数据首地址、待输入数据长度
* 输    出         : 0: 成功 1:失败
*******************************************************************************/
unsigned char i2c_mem_write(unsigned char DevAddress, unsigned char MemAddress, unsigned char *pData, unsigned int Len)
{
      i2c_start();
      i2c_write_byte(DevAddress << 1);
      if(i2c_wait_ack())
                return 1;
      i2c_write_byte(MemAddress);
      if(i2c_wait_ack())
                return 1;
      while(Len--)
      {
                i2c_write_byte(*pData++);
                if(i2c_wait_ack())
                        return 1;
      }
      i2c_stop();
      return 0;
}

/*******************************************************************************
* 函 数 名         : i2c_mem_read
* 函数功能                   : I2C对指定器件、指定寄存器连续读取
* 输    入         : 器件地址、器件寄存器地址、数据缓冲区首地址、数据长度
* 输    出         : 0: 成功 1:失败
*******************************************************************************/
unsigned char i2c_mem_read(unsigned char DevAddress, unsigned char MemAddress, unsigned char *pBuffer, unsigned int Len)
{                                 
    i2c_start();
      i2c_write_byte(DevAddress << 1);                //发送写命令         
      if(i2c_wait_ack())
                return 1;
    i2c_write_byte(MemAddress);                         //发送字地址
      if(i2c_wait_ack())
                return 1;   
      i2c_start();                     
      i2c_write_byte(DevAddress << 1 | 1);         //进入接收模式                                    
      if(i2c_wait_ack())
                return 1;
      while(Len--)
      {
                *pBuffer++ = i2c_read_byte(Len!=0);      //读取字节      
      }
    i2c_stop();                                                                //产生一个停止条件
      return 0;
}然后直接读数据,看数据手册写
void AHT10_Read(unsigned int t,unsigned int h)
{
    char timeout = 0;
    unsigned char buff = {0};
    volatile unsigned long int dat = 0;
   
    unsigned char cmd;
    cmd = 0x33;
    cmd = 0x00;
   
    i2c_mem_write(ATH20_SLAVE_ADDRESS,AHT20_TrigMeasure_REG,cmd,2);
    i2c_mem_read(ATH20_SLAVE_ADDRESS,AHT20_STATUS_REG,buff,7);

    //高位在前
    dat = buff;dat = dat<<8;dat+=buff;dat=dat<<8;dat+=buff;dat=dat>>4;
    hum = dat * 100 / rate;

    dat = buff&0x0F;dat = dat<<8;dat+=buff;dat=dat<<8;dat+=buff;
    tem = dat * 200 / rate - 50;
}坑
正常写数据处理这样写
      //高位在前
      dat = (((buff<<12) | (buff<<4)) | (buff>>4));
      Humidity = dat / 1048576.0 * 100.0;
      
      dat = 0;
      dat = ((buff &0x0F) << 16 ) | ( buff << 8) | buff;
      Temperature = (dat/1048576.0) * 200 - 50;感觉没错,就是结果不对
立马想到 是不是位移超出范围了
改成如下代码
dat = ((unsigned long int)buff << 8) | ((unsigned long int)buff) | ((unsigned long int)(buff >> 4));不行,没变化
这都不能转换?
我直接打开AHT25的官网,下载官网的例子
官网这样写:
dat = buff;dat = dat<<8;dat+=buff;dat=dat<<8;dat+=buff;dat=dat>>4;我修改代码,试了一下,温度湿度立马正确了



但是,我再32里直接用位移可以使用,为啥这里不行了?

DebugLab 发表于 2024-8-19 00:25:02


我也发现了,我的流水灯必须要这样写,写成P1=_crol_(P1,1)不好使

晓飛飛 发表于 2024-8-19 00:46:21

可以试试硬件I2C,效率高很多,代码也非常简单。

哈哈哈哈 发表于 2024-8-19 07:23:13

晓飛飛 发表于 2024-8-19 00:46
可以试试硬件I2C,效率高很多,代码也非常简单。

正在学习中{:4_188:}

哈哈哈哈 发表于 2024-8-19 07:23:38

wnagming 发表于 2024-8-19 06:35
为什么会这个样子?

编译器的锅

soma 发表于 2024-8-19 14:58:34

什么数据类型

哈哈哈哈 发表于 2024-8-19 15:16:48

soma 发表于 2024-8-19 14:58
什么数据类型

hum tem 都是long
页: [1]
查看完整版本: AI8051U AHT25 温湿度传感器 偶遇问题