找回密码
 立即注册
查看: 374|回复: 2

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

[复制链接]

该用户从未签到

1

主题

1

回帖

17

积分

新手上路

积分
17
发表于 2023-8-20 16:57:22 | 显示全部楼层 |阅读模式
本人一个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[3]=1时才去读数据。如果Bit[3]不等于1 ,发软件复位0xBA给AHT10,再重新初始化AHT10,直至Bit[3]=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);
        
}

回复 送花

使用道具 举报

该用户从未签到

552

主题

9492

回帖

1万

积分

管理员

积分
14057
发表于 2023-8-20 17:48:06 | 显示全部楼层
只是建议:
1,SCL/SDA, 外部要有 10K上拉电阻
2,  STC15系列同频比STC89C52RC快很多,加12倍的延时
回复 支持 反对 送花

使用道具 举报

该用户从未签到

1

主题

1

回帖

17

积分

新手上路

积分
17
 楼主| 发表于 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;
        }

  
}
回复 支持 反对 送花

使用道具 举报

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

本版积分规则

QQ|手机版|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

GMT+8, 2024-5-17 20:04 , Processed in 0.058609 second(s), 38 queries .

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

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