3958|5

931

帖子

3

TA的资源

纯净的硅(中级)

楼主
 

SHT31测评+尝试读取传感器I2C总线数据 [复制链接]

 

    原计划修改范例,增加串口输出温、湿度数据的功能,但我暂时没有J-LINK下载工具,同时又看到坛友尝试下载烧录未成功,转而一想还不如直接截取I2C总线上的数据,这样对原评测板不需要做任何变动,仅仅通过我的扩展板就行,于是我就用了一块现成的STM32L412板子进行实验,下图为实验装置:

    通过逻辑分析仪获取了评测板上的I2C数据,评测板是以每秒为周期对传感器进行一次读写操作:

    实际操作是先写入命令,然后等近1秒再读出,所以从逻辑分析仪截取的时序图是读在前、写在后:

    读操作是先发出地址码139,然后连续读出6个字节数据:

    从数据手册上得知前3个字节是温度数据,即16位的温度数据加1个字节的校验码,后3个字节是湿度数据,同样也是16的湿度数据加1个字节的校验码:

   写入的则是16位的命令,地址码是138:

    根据这些资料写了一段代码,这6个字节的数据读了出来,下面是读取I2C总线的代码:

    读一个字节:

/******************************************************
*程 序 名:Read_I2C
*作    用:读取I2C总线上的数据 
*输入参数:无
*返回参数:读到的数据(1字节)
******************************************************/
uint8_t Read_I2C(void)
{
    uint8_t dat,i;
    //开始读一字节数据
    for(i=0;i<8;i++){
        while(HAL_GPIO_ReadPin(SI2C_SCL_GPIO_Port,SI2C_SCL_Pin) == 0);
        dat <<= 1;
        if(HAL_GPIO_ReadPin(SI2C_SDA_GPIO_Port,SI2C_SDA_Pin) == 1) dat |= 0x01;
        while(HAL_GPIO_ReadPin(SI2C_SCL_GPIO_Port,SI2C_SCL_Pin) == 1);
    }
    return dat;
}

 

    下面是读全部数据的代码:

/******************************************************
*程 序 名:Intercept_I2C
*作    用:截取I2C总线上的读数据 
*输入参数:无
*返回参数:
******************************************************/
void Intercept_I2C(void)
{
    uint8_t i,d[7];
    uint32_t temp=0,hum=0;
    uint32_t d_t,d_h;
    //等待I2C开始信号
    while(HAL_GPIO_ReadPin(SI2C_SCL_GPIO_Port,SI2C_SCL_Pin)==1){
        while(HAL_GPIO_ReadPin(SI2C_SDA_GPIO_Port,SI2C_SDA_Pin)==1);
    }

//    while(Read_I2C() != 139)    //I2C总线上出现读地址
        for(i = 0; i < 7; i++)
            d = Read_I2C();
/*
        temp = Read_I2C();  //取高八位
        temp <<= 8;
        temp |= (uint16_t )Read_I2C();
        hum = Read_I2C();   //校验字节(弃用)
        hum = Read_I2C();
        hum <<= 8;
        hum |= (uint16_t )Read_I2C();
*/
        d_t = d[1];
        d_t <<= 8;
        d_t |= d[2];
//        temp = (d_t * 175 / 65535) - 45;
        temp = d_t *1000 / 267 - 4500;
        d_h = d[4];
        d_h <<= 8;
        d_h |= d[5];
        hum = d_h * 10000 / 65535; 
        LCD_write_value(12,3,5,0,1,temp);
        LCD_write_value(12,4,5,0,1,hum);
        LCD_write_value(50,3,5,0,1,d_t);
        LCD_write_value(50,4,5,0,1,d_h);
    
    LCD_write_value(0,0,3,0,1,d[0]);
//    LCD_write_value(24,0,3,0,1,d[0]);
    LCD_write_value(0,1,3,0,1,d[1]);
    LCD_write_value(24,1,3,0,1,d[2]);
    LCD_write_value(50,1,3,0,1,d[3]);
    LCD_write_value(0,2,3,0,1,d[4]);
    LCD_write_value(24,2,3,0,1,d[5]);
    LCD_write_value(50,2,3,0,1,d[6]);
    HAL_Delay(2);
}

    经过反复测试,这些数据基本是读出了,但似乎不太正确,尤其是计算过程不正确,计算出的温、湿度数据与实际显示的大相径庭。下图中第1行是读取到的地址码,第2~3行分别是温、湿度数据及校验码,蓝色圈起的分别是读出的温、湿度数据,红色圈起的是计算出的温、湿度数值,与实际显示的不一致,尤其是湿度数据跳跃变动,不稳定。

    根据数据手册,温、湿度的计算公式如下:

   可是我按照这个公式写的代码计算出的数据却与手工计算的不同,也不知道代码那里错了,下面是代码:

        d_t = d[1];
        d_t <<= 8;
        d_t |= d[2];
//        temp = (d_t * 175 / 65535) - 45;
        temp = d_t *1000 / 267 - 4500;
        d_h = d[4];
        d_h <<= 8;
        d_h |= d[5];
        hum = d_h * 10000 / 65535; //按保留两位小数

    我将变量的类型从16位无符号数改成32位无符号数,结果仍然不对。

    我用手工计算也无法对应到正确的温、湿度数值,不知道是那里还有问题。

    在读写I2C总线数据时,我忽略了每个字节后面的ACK,会不会是这个原因造成取数不正确?从时序图上分析,1 个ACK是3微秒,再到下个字节开始的时间是5.125微秒,总共是8.125微秒。不知道从读字节函数返回到下次再进入的时间需要多少,但这不应该会影响到同步,因为读下个字节是依据SCL时钟,除非返回到下次再进入的时间少于3微秒。

    

 

 


此内容由EEWORLD论坛网友hujj原创,如需转载或用于商业用途需征得作者同意并注明出处

I2C_test_5.jpg (414.21 KB, 下载次数: 0)

I2C_test_5.jpg

I2C_test_6.jpg (372.14 KB, 下载次数: 0)

I2C_test_6.jpg

I2C_test_7.jpg (376.38 KB, 下载次数: 0)

I2C_test_7.jpg

最新回复

可能还是时序问题,捕捉的数据有错误   详情 回复 发表于 2020-1-20 21:35
点赞 关注
 
 

回复
举报

1万

帖子

25

TA的资源

版主

沙发
 

是数据溢出造成的吗?

点评

好象不是,我用的数据类型是32位无符号,对于16位的数据进行乘175后再除65535,按理不会溢出啊。    详情 回复 发表于 2020-1-20 16:59
 
 
 

回复

931

帖子

3

TA的资源

纯净的硅(中级)

板凳
 
dcexpert 发表于 2020-1-20 16:42 是数据溢出造成的吗?

好象不是,我用的数据类型是32位无符号,对于16位的数据进行乘175后再除65535,按理不会溢出啊。

 

 
 
 

回复

1万

帖子

25

TA的资源

版主

4
 

可能还是时序问题,捕捉的数据有错误

点评

可是读出的地址数据是正确的,并没有出错。  详情 回复 发表于 2020-1-20 22:30
 
 
 

回复

931

帖子

3

TA的资源

纯净的硅(中级)

5
 
dcexpert 发表于 2020-1-20 21:35 可能还是时序问题,捕捉的数据有错误

可是读出的地址数据是正确的,并没有出错。

 
 
 

回复

931

帖子

3

TA的资源

纯净的硅(中级)

6
 

    经过仔细排查,没能获得正确数据的原因还是我忽略的ACK引起的,我在读I2C数据中加入了等待ACK的代码,获得的数据就正确了,代码如下:

/******************************************************
*程 序 名:Read_I2C
*作    用:读取I2C总线上的数据 
*输入参数:无
*返回参数:读到的数据(1字节)
******************************************************/
uint8_t Read_I2C(void)
{
    uint8_t dat,i;
    //开始读一字节数据
    for(i=0;i<8;i++){
        while(HAL_GPIO_ReadPin(SI2C_SCL_GPIO_Port,SI2C_SCL_Pin) == 0);
        dat <<= 1;
        if(HAL_GPIO_ReadPin(SI2C_SDA_GPIO_Port,SI2C_SDA_Pin) == 1) dat |= 0x01;
        while(HAL_GPIO_ReadPin(SI2C_SCL_GPIO_Port,SI2C_SCL_Pin) == 1);
    }
    while(HAL_GPIO_ReadPin(SI2C_SCL_GPIO_Port,SI2C_SCL_Pin) == 0);
    while(HAL_GPIO_ReadPin(SI2C_SCL_GPIO_Port,SI2C_SCL_Pin) == 1);  //等待ACK
    return dat;
}

    下面是STM32L412开发板获得的温、湿度数据:

    有时会出现少许误差,这应该是两者刷新不完全同步所致:

    至此,这个测试是成功了。截取数据用的是STM32L412KB开发板,显示屏是LCD5110。

 

 
 
 

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

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/10 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表