找回密码
 立即注册
查看: 464|回复: 6

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

[复制链接]
  • 打卡等级:偶尔看看III
  • 打卡总天数:50
  • 最近打卡:2025-05-01 11:24:23

13

主题

95

回帖

294

积分

中级会员

积分
294
发表于 2024-8-18 23:16:14 | 显示全部楼层 |阅读模式
本帖最后由 DebugLab 于 2024-8-19 00:21 编辑

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

时序如下图所示:
截图202408182247052619.jpg

截图202408182249319807.jpg

如何使用IO模拟I2C
关键是起始,停止和应答
代码如下:
  1. void aht_sleep_us(unsigned int n) //24mhz
  2. {
  3.     while (n--)
  4.     {
  5.         NOP24();
  6.     }
  7. }
  8. void aht_sleep_ms(unsigned int  n)
  9. {
  10.     while (n--)
  11.         aht_sleep_us(1000);
  12. }
  13. #define I2C_TIMEOUT_TIMES 100        //超时倍数
  14. //延时 用于等待应答时的超时判断 移植时需修改
  15. void i2c_timeout_delay(void)        
  16. {
  17.     aht_sleep_ms(1);
  18. }
  19. void i2c_delay()        //每步的间隔 用于等待电平稳定和控制通讯速率
  20. {
  21.     aht_sleep_us(5);
  22. }
  23. //SCL拉高 移植时需修改
  24. void I2C_SCL_H(void)
  25. {
  26.         I2C_SCL = 1;
  27. }
  28. //SCL拉低 移植时需修改
  29. void I2C_SCL_L(void)
  30. {
  31.         I2C_SCL = 0;
  32. }
  33. //SDA拉高 移植时需修改
  34. void I2C_SDA_H(void)
  35. {
  36.         I2C_SDA = 1;
  37. }
  38. //SDA拉低 移植时需修改
  39. void I2C_SDA_L(void)
  40. {
  41.         I2C_SDA = 0;
  42. }
  43. //读取SDA 移植时需修改
  44. unsigned char I2C_SDA_Read(void)
  45. {
  46.         return I2C_SDA;
  47. }
  48. /*******************************************************************************
  49. * 函 数 名       : i2c_start
  50. * 函数功能                 : 产生I2C起始信号
  51. * 输    入       : 无
  52. * 输    出             : 无
  53. *******************************************************************************/
  54. void i2c_start(void)
  55. {
  56.         I2C_SDA_H();
  57.     I2C_SCL_H();
  58.     i2c_delay();
  59.     I2C_SDA_L();        //当SCL为高电平时,SDA由高变为低
  60.     i2c_delay();
  61.     I2C_SCL_L();        //钳住I2C总线,准备发送或接收数据
  62. }
  63. /*******************************************************************************
  64. * 函 数 名         : i2c_stop
  65. * 函数功能                   : 产生I2C停止信号
  66. * 输    入         : 无
  67. * 输    出         : 无
  68. *******************************************************************************/
  69. void i2c_stop(void)
  70. {
  71.         I2C_SDA_L();
  72.     I2C_SCL_H();
  73.     i2c_delay();
  74.     I2C_SDA_H();        //当SCL为高电平时,SDA由低变为高
  75.     i2c_delay();
  76. }
  77. /*******************************************************************************
  78. * 函 数 名         : i2c_ack
  79. * 函数功能                   : 产生ACK应答
  80. * 输    入         : 无
  81. * 输    出         : 无
  82. *******************************************************************************/
  83. void i2c_ack(void)
  84. {
  85.     I2C_SCL_L();
  86.     I2C_SDA_L();        //SDA为低电平
  87.     i2c_delay();
  88.     I2C_SCL_H();
  89.     i2c_delay();
  90.     I2C_SCL_L();
  91.         I2C_SDA_H();        
  92. }
  93. /*******************************************************************************
  94. * 函 数 名         : i2c_nack
  95. * 函数功能                   : 产生NACK非应答
  96. * 输    入         : 无
  97. * 输    出         : 无
  98. *******************************************************************************/
  99. void i2c_nack(void)
  100. {
  101.     I2C_SCL_L();
  102.     I2C_SDA_H();        //SDA为高电平
  103.     i2c_delay();
  104.     I2C_SCL_H();
  105.     i2c_delay();
  106.     I2C_SCL_L();
  107. }
  108. /*******************************************************************************
  109. * 函 数 名         : i2c_wait_ack
  110. * 函数功能                   : 等待应答信号到来
  111. * 输    入         : 无
  112. * 输    出         : 1,接收应答失败
  113.                                  0,接收应答成功
  114. *******************************************************************************/
  115. unsigned char i2c_wait_ack(void)
  116. {
  117.     unsigned int time_temp = 0;
  118.     I2C_SCL_H();
  119.     i2c_delay();
  120.     while(I2C_SDA_Read())                                //等待SDA为低电平
  121.     {
  122.         time_temp++;
  123.                 i2c_timeout_delay();
  124.         if(time_temp > I2C_TIMEOUT_TIMES)        //超时则强制结束I2C通信
  125.         {
  126.             i2c_stop();
  127.             return 1;
  128.         }
  129.     }
  130.     I2C_SCL_L();
  131.     return 0;
  132. }
  133. /*******************************************************************************
  134. * 函 数 名         : i2c_write_byte
  135. * 函数功能                   : I2C发送一个字节
  136. * 输    入         : dat:发送一个字节
  137. * 输    出         : 无
  138. *******************************************************************************/
  139. void i2c_write_byte(unsigned char dat)
  140. {
  141.     unsigned char i = 0;
  142.     I2C_SCL_L();
  143.     for(i = 0; i<8; i++)        //循环8次将一个字节传出,先传高再传低位
  144.     {
  145.         if((dat & 0x80) > 0)
  146.             I2C_SDA_H();
  147.         else
  148.             I2C_SDA_L();
  149.         dat <<= 1;
  150.         i2c_delay();
  151.         I2C_SCL_H();
  152.         i2c_delay();
  153.         I2C_SCL_L();
  154.         i2c_delay();
  155.     }
  156. }
  157. /*******************************************************************************
  158. * 函 数 名         : i2c_read_byte
  159. * 函数功能                   : I2C读一个字节
  160. * 输    入         : ack = 1时,发送ACK,ack = 0,发送nACK
  161. * 输    出         : 应答或非应答
  162. *******************************************************************************/
  163. unsigned char i2c_read_byte(unsigned char ack)
  164. {
  165.     unsigned char i = 0, receive = 0;
  166.     for(i = 0; i < 8; i++ )        //循环8次将一个字节读出,先读高再传低位
  167.     {
  168.         I2C_SCL_L();
  169.         i2c_delay();
  170.         I2C_SCL_H();
  171.         receive <<= 1;
  172.         if(I2C_SDA_Read())
  173.                         receive++;
  174.         i2c_delay();
  175.     }
  176.     if (!ack)
  177.         i2c_nack();
  178.     else
  179.         i2c_ack();
  180.     return receive;
  181. }
  182. /*******************************************************************************
  183. * 函 数 名         : i2c_mem_write
  184. * 函数功能                   : I2C对指定器件、指定寄存器连续写入
  185. * 输    入         : 器件地址、器件寄存器地址、待输入数据首地址、待输入数据长度
  186. * 输    出         : 0: 成功 1:失败
  187. *******************************************************************************/
  188. unsigned char i2c_mem_write(unsigned char DevAddress, unsigned char MemAddress, unsigned char *pData, unsigned int Len)
  189. {
  190.         i2c_start();
  191.         i2c_write_byte(DevAddress << 1);
  192.         if(i2c_wait_ack())
  193.                 return 1;
  194.         i2c_write_byte(MemAddress);
  195.         if(i2c_wait_ack())
  196.                 return 1;
  197.         while(Len--)
  198.         {
  199.                 i2c_write_byte(*pData++);
  200.                 if(i2c_wait_ack())
  201.                         return 1;
  202.         }
  203.         i2c_stop();
  204.         return 0;
  205. }
  206. /*******************************************************************************
  207. * 函 数 名         : i2c_mem_read
  208. * 函数功能                   : I2C对指定器件、指定寄存器连续读取
  209. * 输    入         : 器件地址、器件寄存器地址、数据缓冲区首地址、数据长度
  210. * 输    出         : 0: 成功 1:失败
  211. *******************************************************************************/
  212. unsigned char i2c_mem_read(unsigned char DevAddress, unsigned char MemAddress, unsigned char *pBuffer, unsigned int Len)
  213. {                                 
  214.     i2c_start();  
  215.         i2c_write_byte(DevAddress << 1);                //发送写命令           
  216.         if(i2c_wait_ack())
  217.                 return 1;
  218.     i2c_write_byte(MemAddress);                         //发送字地址  
  219.         if(i2c_wait_ack())
  220.                 return 1;   
  221.         i2c_start();                     
  222.         i2c_write_byte(DevAddress << 1 | 1);         //进入接收模式                                    
  223.         if(i2c_wait_ack())
  224.                 return 1;
  225.         while(Len--)
  226.         {
  227.                 *pBuffer++ = i2c_read_byte(Len!=0);        //读取字节        
  228.         }
  229.     i2c_stop();                                                                //产生一个停止条件  
  230.         return 0;
  231. }
复制代码
然后直接读数据,看数据手册写
  1. void AHT10_Read(unsigned int t,unsigned int h)
  2. {
  3.     char timeout = 0;
  4.     unsigned char buff[7] = {0};
  5.     volatile unsigned long int dat = 0;
  6.    
  7.     unsigned char cmd[2];
  8.     cmd[0] = 0x33;
  9.     cmd[1] = 0x00;
  10.    
  11.     i2c_mem_write(ATH20_SLAVE_ADDRESS,AHT20_TrigMeasure_REG,cmd,2);
  12.     i2c_mem_read(ATH20_SLAVE_ADDRESS,AHT20_STATUS_REG,buff,7);
  13.     //高位在前
  14.     dat = buff[1];dat = dat<<8;dat+=buff[2];dat=dat<<8;dat+=buff[3];dat=dat>>4;
  15.     hum = dat * 100 / rate;
  16.     dat = buff[3]&0x0F;dat = dat<<8;dat+=buff[4];dat=dat<<8;dat+=buff[5];
  17.     tem = dat * 200 / rate - 50;
  18. }
复制代码

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


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

回复

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:429
  • 最近打卡:2025-05-07 09:00:58
已绑定手机

77

主题

4863

回帖

8480

积分

超级版主

DebugLab

积分
8480
发表于 2024-8-19 00:25:02 | 显示全部楼层

我也发现了,我的流水灯必须要这样写,写成P1=_crol_(P1,1)不好使
截图202408190023544917.jpg
DebugLab
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:421
  • 最近打卡:2025-05-07 00:05:44
已绑定手机

35

主题

2107

回帖

2247

积分

荣誉版主

积分
2247
发表于 2024-8-19 00:46:21 | 显示全部楼层
可以试试硬件I2C,效率高很多,代码也非常简单。
睁开眼睛做场梦~~~
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:偶尔看看III
  • 打卡总天数:50
  • 最近打卡:2025-05-01 11:24:23

13

主题

95

回帖

294

积分

中级会员

积分
294
发表于 2024-8-19 07:23:13 | 显示全部楼层
晓*** 发表于 2024-8-19 00:46
可以试试硬件I2C,效率高很多,代码也非常简单。

正在学习中
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:偶尔看看III
  • 打卡总天数:50
  • 最近打卡:2025-05-01 11:24:23

13

主题

95

回帖

294

积分

中级会员

积分
294
发表于 2024-8-19 07:23:38 | 显示全部楼层
wnag*** 发表于 2024-8-19 06:35
为什么会这个样子?

编译器的锅
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:428
  • 最近打卡:2025-05-07 00:13:45
已绑定手机

19

主题

3194

回帖

4948

积分

论坛元老

积分
4948
发表于 2024-8-19 14:58:34 来自手机 | 显示全部楼层
什么数据类型
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:偶尔看看III
  • 打卡总天数:50
  • 最近打卡:2025-05-01 11:24:23

13

主题

95

回帖

294

积分

中级会员

积分
294
发表于 2024-8-19 15:16:48 | 显示全部楼层

hum tem 都是long
回复 支持 反对

使用道具 举报 送花

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

本版积分规则

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

GMT+8, 2025-5-7 12:04 , Processed in 0.133651 second(s), 95 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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