xzczg 发表于 2023-8-20 16:57:22

求助:stc15w408使用AHT10测量温度 | 已解决

本人一个AHT10湿度 测量程序,使用IIC,
在89C52测试正常,移植到STC15w408后,测量不出数值,读取的值均为0xFF。
但用STC15w408测试SHT30时正常,也是IIC方式。
请高人指点。

下面是测量代码:

#include <intrins.h>
#include "stc15.h"
#include "aht10.h"
#include <stdio.h>
sbit SCL = P1^0;
sbit SDA = P1^1;

//声明ACKflag 为字节变量
/*I2C通信初始化*/
void I2C_Start()    //起始信号
{
SCL = 1;
SDA = 1;
delay5us();
SDA = 0;
delay5us();
}
void I2C_Stop()    //停止信号
{
SCL = 0;
SDA = 0;
SCL = 1;
delay5us();
SDA = 1;
delay5us();
}
/*I2C应答和非应答*/

//I2C主机读从机应答
bit ReadACK()
{
SCL = 0;
SCL = 1;
delay5us();
if(SDA)//非应答
{
    SCL = 0;
    return (0);
}
else//应答
{
    SCL = 0;
    return(1);
}
}
//I2C主机发送应答
void sendACK(bit i)
{
SCL = 0;
if(i)
    SDA = 1;
else
    SDA = 0;
SCL = 1;
delay5us();
SCL = 0;
SDA = 1;//释放数据总线
}
uchar I2cReadByte()
{
uchar j,DAT;
for(j = 0;j<8;j++)
{
    DAT <<=1;
    SCL = 0;
    SCL = 1;
    if(SDA)
      DAT |= 0X01;
}
return (DAT);
      delay5us();
}
void I2CSendByte(uchar DAT)   //发送一个字节
{
uchar i;
for(i = 0;i < 8; i++)
{
    SCL = 0;    //拉低时钟线才能允许数据变化
    if(DAT & 0X80)
      SDA = 1;
    else
      SDA = 0;
    SCL = 1;
    DAT <<= 1;
}
SCL = 0;
SDA = 1;//释放数据总线
}

/*1.延时40ms函数2.延时5微秒函数*/
void delayms()
{unsigned char i, j, k;

      _nop_();
      _nop_();
      i = 1;
      j = 26;
      k = 223;
      do
      {
                do
                {
                        while (--k);
                } while (--j);
      } while (--i);


}
void delay5us()
{      unsigned char i;

      _nop_();
      i = 11;
      while (--i);
}
//*******************************
uchar JH_Read_Status(void) //读取AHT10的状态寄存器
{

      uchar Byte_first;
      I2C_Start();
      I2CSendByte(0x71);
      if (!ReadACK()) { //检测应答
                return 0;
      }
      
      Byte_first = I2cReadByte();
      sendACK(1);//此处为回复NOACK,意思为停止读操作
      I2C_Stop();
      
      return Byte_first;
}
uchar JH_Read_Cal_Enable(void)//查询cal enable位有没有使能?
{
      uchar val = 0;//ret = 0,

      val = JH_Read_Status();
      if ((val & 0x68) == 0x08)//判断NOR模式和校准输出是否有效
                return 1;
      else
                return 0;
}
void JH_SendAC(void) //向AHT10发送AC命令
{

      I2C_Start();
      I2CSendByte(0x70);
      if (!ReadACK()) { //检测应答
                return;
      }
      I2CSendByte(0xac);
      if (!ReadACK()) { //检测应答
                return;
      }
      I2CSendByte(0x33);
      if (!ReadACK()) { //检测应答
                return;
      }
      I2CSendByte(0x00);
      sendACK(0);
      I2C_Stop();

}

void JH_Send_BA(void) //向AHT10发送BA命令
{

      I2C_Start();
      I2CSendByte(0x70);
      if (!ReadACK()) { //检测应答
                return;
      }
      I2CSendByte(0xba);
      if (!ReadACK()) { //检测应答
                return;
      }
      I2C_Stop();

}
uchar JH_Init(void)   //初始化AHT10
{
JH_Send_BA();
          delayms();
      
      I2C_Start();
      
      I2CSendByte(0x70);
      if (!ReadACK()) {      //检测应答
                return 0;
      }
      I2CSendByte(0xe1);      //写系统配置寄存器
      if (!ReadACK()) {      //检测应答
                return 0;
      }
      I2CSendByte(0x08);
      if (!ReadACK()) {      //检测应答
                return 0;
      }
      I2CSendByte(0x00);
      if (!ReadACK()) {      //检测应答
                return 0;
      }
      I2C_Stop();
      
      
      while (JH_Read_Cal_Enable() == 0)//需要等待状态字status的Bit=1时才去读数据。如果Bit不等于1 ,发软件复位0xBA给AHT10,再重新初始化AHT10,直至Bit=1
      {
                delayms();

                JH_Send_BA();//复位
                //os_delay_us(10000);
                delayms();
                I2C_Start();
                I2CSendByte(0x70);
                if (!ReadACK()) {//检测应答
                        return 0;
                }
                I2CSendByte(0xe1);//写系统配置寄存器
                if (!ReadACK()) {//检测应答
                        return 0;
                }
                I2CSendByte(0x08);
                if (!ReadACK()) {//检测应答
                        return 0;
                }
                I2CSendByte(0x00);
                if (!ReadACK()) {//检测应答
                        return 0;
                }
                I2C_Stop();
               
                delayms();
      }
      
      return 1;
}
void JH_Read_CTdata(unsigned int *Temp,unsigned int*Hum) //读取AHT10的温度和湿度数据
{
      volatile uchar Byte_1th = 0;
      volatile uchar Byte_2th = 0;
      volatile uchar Byte_3th = 0;
      volatile uchar Byte_4th = 0;
      volatile uchar Byte_5th = 0;
      volatile uchar Byte_6th = 0;
      u32 RetuData = 0;
int cnt = 0;
      delayms();
      JH_SendAC();
delayms();
      delayms();
      while (((JH_Read_Status()&0x80)==0x80)) //等待忙状态结束
      {
               
               
      }
      I2C_Start();

      I2CSendByte(0x71); //0x70+1   0x70为设备地址 1为方向位
      
      if (!ReadACK()) { //检测应答
                return;
      }
      Byte_1th = I2cReadByte(); //状态字
      sendACK(0);
      Byte_2th = I2cReadByte(); //湿度字节
      sendACK(0);
      Byte_3th = I2cReadByte(); //湿度字节
      sendACK(0);
      Byte_4th = I2cReadByte(); //高4位为湿度低4位为温度
      sendACK(0);
      Byte_5th = I2cReadByte(); //温度字节
      sendACK(0);
      Byte_6th = I2cReadByte(); //温度字节
      sendACK(1);//此处为回复NOACK,意思为停止读操作
      I2C_Stop();
      

      RetuData = (RetuData | Byte_2th) << 8;
      RetuData = (RetuData | Byte_3th) << 8;
      RetuData = (RetuData | Byte_4th);
      RetuData = RetuData >> 4;
      *Hum =(RetuData*1000/1024/1024);
      RetuData = 0;
      RetuData = (RetuData | Byte_4th) << 8;
      RetuData = (RetuData | Byte_5th) << 8;
      RetuData = (RetuData | Byte_6th);
      RetuData = RetuData & 0xfffff;
*Temp = (RetuData*2000/1024/1024 - 500);
      
}


神农鼎 发表于 2023-8-20 17:48:06

只是建议:
1,SCL/SDA, 外部要有 10K上拉电阻
2,STC15系列同频比STC89C52RC快很多,加12倍的延时

xzczg 发表于 2023-8-20 18:33:25

谢谢,经调整,是IIC的问题,不知什么原因。换了一套模拟IIC正常了,见下面,有兴趣的高手分析一下。:
void I2C_Start()    //起始信号
{

SDA = 1;      //拼接其他块,确保默认是1
      SCL = 1;
      SDA = 0;      //时序上先拉低
      SCL = 0;

}
void I2C_Stop()    //停止信号
{

SDA = 0;      //确保默认0,保证由低电平拉高至高电平
      SCL = 1;
      SDA = 1;


}
/*I2C应答和非应答*/

//I2C主机读从机应答
bit ReadACK()
{
SDA = 1;
SCL = 1;

if(SDA)//非应答
{
    SCL = 0;
    return (0);
}
else//应答
{
    SCL = 0;
    return(1);
}
}
//I2C主机发送应答
void sendACK(bit i)
{

if(i)
    SDA = 1;
else
    SDA = 0;
SCL = 1;

SCL = 0;

}
uchar I2cReadByte()
{unsigned char i,Byte=0x00;
      
      SDA = 1;      //接收之前,先把I2C_SDA置1,释放总线
      for(i=0;i<8;i++)
      {
                SCL = 1;      //拉高SCL,SCL读取SDA
                if(SDA == 1){Byte |= (0x80>>i);}
                        /*如果读取到的SDA为1,把Byte最高位置1,如果读取到的SDA为0,不处理,默认最高位为0,放在循环里从高位到低位依次读取*/
                SCL = 0;      //拉低SCL,结束当前循环
      }
      return Byte;

}
void I2CSendByte(uchar Byte)   //发送一个字节
{
unsigned char i;
//      I2C_SCL = 0;      //起始信号已经拉低了,无需重复
      for (i = 0; i < 8; i ++)
      {               
                SDA = Byte & (0x80>>i);      //把Byte最高位取出,赋值给I2C_SDA,依次从高到底
                SCL = 1;
//                _nop_();_nop_();_nop_();_nop_();_nop_();//需要0.4us
                SCL = 0;
      }


}

yywf2021544699 发表于 2024-5-26 19:50:40

为什么我读出来的温湿度一直都不变是怎么回事啊

神农鼎 发表于 2024-5-27 13:51:16

硬件 I2C快,软件 I2C 慢,一定要加10K上拉电阻,这样速度才能上去
页: [1]
查看完整版本: 求助:stc15w408使用AHT10测量温度 | 已解决