IIC协议之TH09传感器采样

发布时间:2024年01月03日

0. 写在前面

AT32F415+TH09+BSP库
实现需了解:
1.IIC协议的软件模拟。本文不多介绍,跟着这篇学)
IIC
2. 启动传感器采集
3. 传感器时序图的理解与代码实现
4. 传感器的CRC检验理解与代码实现

1.IIC协议

懒得复制,基于master,参考上面链接编写

1.1 BSP_I2C_Start

1.2 BSP_I2C_Stop

1.3 BSP_I2C_waitAck

1.4 BSP_I2C_Send_Byte

1.5 BSP_IIC_Read_Byte

2. TH09

2.1 Init

首先查手册获得两个地址,(1)IIC从机地址,即传感器设备的地址(2)传感器启动温湿度采集的寄存器地址

#define TH09_ADDR 0X43 
#define START_REG 0X22

还需明确,TH09_ADDR 只是7 bit ,最低位来确定操作是读(1)还是写(0)
0x43<<1 =0x86
read = 0x86 | 1
write = 0x86 |0
在这里插入图片描述

在这里插入图片描述
SENS_START 寄存器有2 bit,分别设置温度与湿度,需设置两个为1,即应该通过IIC接口向TH09(0X43)的SENS_START (0x22)的写入(0)data(0x03)来启动温湿度采集。

代码实现如下:

uint8_t BSP_IIC_writeReg(uint8_t i2cId, uint8_t addr, uint8_t reg, uint8_t *pData, uint16_t len)
{
    /* 发送起始信号 */
    BSP_I2C_Start(i2cId);
    /* 发送地址 W */
    BSP_I2C_Send_Byte(i2cId, addr | I2C_WR ); // 7位地址和1位写(0)
    if (BSP_I2C_waitAck(i2cId) == 0) {
        return (0);
    }
    /* 发送寄存器地址 */
    BSP_I2C_Send_Byte(i2cId, reg);
    if (BSP_I2C_waitAck(i2cId) == 0) {
        return (0);
    }

    /* 发送数据 */
    for (uint16_t i = 0; i < len; i++) {
        BSP_I2C_Send_Byte(i2cId, pData[i]);
        if (BSP_I2C_waitAck(i2cId) == 0) {
            return (0);
        }
    }
    // DEBUG("PData : %02x \r\n",pData[0]);// 03 没错
    BSP_I2C_Stop(i2cId);
    return (1);
}

2.2 时序图

在这里插入图片描述
这边是要去读取slave(TH09)采集的温湿度数据,看(b)。

在这里插入图片描述
读取事务首先从写寄存器开始,这个寄存器为存储采集温湿度数据的T_VAL和H_VAL寄存器。

在这里插入图片描述
在这里插入图片描述
写结束后有一个s表示sleep,需要给时间让传感器对采集数据进行处理,如果没有sleep可能得到的采集数据会出错。
之后就是一个字节读然后等ack,最后一帧不需要回复ack。
时序图实现就是对着图用IIC的代码进行看图写话。代码实现:

uint8_t BSP_IIC09_readData(uint8_t i2cId, uint8_t addr,uint8_t reg,uint8_t *pData, uint16_t len){
    /* 发送起始信号 */
    BSP_I2C_Start(i2cId);
    /* 发送地址  R */
    BSP_I2C_Send_Byte(i2cId, addr | I2C_WR); 
    // DEBUG("slave addr : %02x \r\n",addr | I2C_WR);

    /* 等待应答 */
    if (BSP_I2C_waitAck(i2cId) == 0) {
        return (0);
    }

    /* 发送寄存器地址 */
    BSP_I2C_Send_Byte(i2cId, reg);// 写read reg的地址0x30
    // DEBUG("reg addr : %02x \r\n",reg); 


    /* 等待应答 */
    if (BSP_I2C_waitAck(i2cId) == 0) {
        return (0); 
    }

     /* 发送起始信号 */
    BSP_I2C_Start(i2cId);
   
    /* 发送地址  R */
    BSP_I2C_Send_Byte(i2cId, addr | I2C_RD);// I2C_RD 1 为读,设置读取位
    // DEBUG("slave addr : %02x \r\n",addr | I2C_RD);
    /* 等待应答 */
    if (BSP_I2C_waitAck(i2cId) == 0) {
        return (0);
    }

    for (uint16_t i = 0; i < len; i++) {
        if (i == (len - 1)) {
            pData[i] = BSP_IIC_Read_Byte(i2cId, 0); /* 最后一个字节不发送应答指令 */ 
            // DEBUG("PData : %02x \r\n",pData[i]);
        } 
        
        else {
            pData[i] = BSP_IIC_Read_Byte(i2cId, 1);
   
        }
    }
    BSP_I2C_Stop(i2cId);
    return (1);
    
}

3.TH09 CRC

  1. 首先应该明确CRC检验的input和return。
  2. 其次应明确CRC的流程。从下图截取的TH09手册看,crc_result = crc7(val),若数据帧中的crc== crc_result,校验通过。
    在这里插入图片描述
  3. 接着介绍input和return使用到的参数。其中:
  • input 。val 为 17bit的payload,由1 bit valid和16 bit data 组成
    代码表示为:
data = ((uint16_t)i2c_receiver[1] << 8) | i2c_receiver[0];
val_tmp = (uint16_t)i2c_receiver[2]&0x1;
val = val_tmp<<16|data;
  • crc 。数据帧[2],但是0位为valid位,故使用crc_true = crc >> 1取得crc。最早在这里踩坑,导致检验一直没过·。
    在这里插入图片描述
  • return 。return就是使用crc7的公式对每bit进行运算,最终返回7 bit的crc_result。这边核心代码参考手册,我添加了一个判断crc?=crc_result的函数。
nt TH09_crc7_check(uint32_t data,uint32_t crc) {

    uint32_t crc_result =0 ;
    uint8_t crc_true = crc >> 1;  // 有一位是valid

    crc_result = crc7_compute(data); //使用data计算出crc。然后与原始比较

    // DEBUG("data: %02x\r\n", data);
    // DEBUG("crc: %02x\r\n", crc);
    // DEBUG("crc_result: %02x\r\n", crc_result);

    // 返回 CRC-7 结果 与 CRC比较
    if(crc_true == crc_result){
        return 1;
    }
    else{
        return 0;
    }
    
}


crc7_compute部分参考TH09手册。

//CRC related
#define CRC7WIDTH 7
#define CRC7POLY 0x89 // 二项式
#define CRC7IVEC 0x7F // 0111 1111

#define DATA7WIDTH 17
#define DATA7MASK ((1UL << DATA7WIDTH) - 1) // 0 1111 1111 1111 1111
#define DATA7MSB (1UL << (DATA7WIDTH - 1))  // 1 0000 0000 0000 0000


uint32_t crc7_compute(uint32_t crcData){
    uint32_t bit = DATA7MSB; // 循环变量(指示要测试哪一位,从最高位开始)
    uint32_t pol = CRC7POLY;
    pol = pol << (DATA7WIDTH - CRC7WIDTH - 1); //设置多项式

    //留空间给crc value
    crcData = crcData << CRC7WIDTH; 
    bit  = bit << CRC7WIDTH; //最高位为1
    pol = pol << CRC7WIDTH;

    // 插入初始向量
    crcData |= CRC7IVEC; //7位1加到低位
    // DEBUG("crcData2:%02x\r\n",crcData);


    // 这边crc算了24位

    // CRC 算法的主要循环
    while (bit & (DATA7MASK << CRC7WIDTH)) {
        // 如果位为1,执行异或操作
        if (bit & crcData){ //该位不为0
            crcData ^= pol;
        }
        // 位右移一位
        bit >>= 1;
        // 多项式右移一位
        pol >>= 1;
    }

    return crcData; //7位crc校验值


}

4.采集结果

采集数据使用数码管显示。
在这里插入图片描述

使用SecureCRT在终端显示采集数据。为了采集数据的小数位输出,扩大了10倍。
在这里插入图片描述

文章来源:https://blog.csdn.net/weixin_53116058/article/details/135343462
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。