IIC协议之TH09传感器采样
- 0. 写在前面
- 1.IIC协议
- 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
- 2.2 时序图
- 3.TH09 CRC
- 4.采集结果
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
- 首先应该明确CRC检验的input和return。
- 其次应明确CRC的流程。从下图截取的TH09手册看,crc_result = crc7(val),若数据帧中的crc== crc_result,校验通过。
- 接着介绍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; // 有一位是validcrc_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 0000uint32_t crc7_compute(uint32_t crcData){uint32_t bit = DATA7MSB; // 循环变量(指示要测试哪一位,从最高位开始)uint32_t pol = CRC7POLY;pol = pol << (DATA7WIDTH - CRC7WIDTH - 1); //设置多项式//留空间给crc valuecrcData = crcData << CRC7WIDTH; bit = bit << CRC7WIDTH; //最高位为1pol = pol << CRC7WIDTH;// 插入初始向量crcData |= CRC7IVEC; //7位1加到低位// DEBUG("crcData2:%02x\r\n",crcData);// 这边crc算了24位// CRC 算法的主要循环while (bit & (DATA7MASK << CRC7WIDTH)) {// 如果位为1,执行异或操作if (bit & crcData){ //该位不为0crcData ^= pol;}// 位右移一位bit >>= 1;// 多项式右移一位pol >>= 1;}return crcData; //7位crc校验值}
4.采集结果
采集数据使用数码管显示。
使用SecureCRT在终端显示采集数据。为了采集数据的小数位输出,扩大了10倍。