最近更新产品功能的时候使用到Sensirion的SHT30(温湿度传感器),虽说官网上有例程(STM32F100RB),但用的是软件模拟I2C时序控制SHT30进行温湿度读取,我用的是S9KEA128的硬件I2C:

1、引脚定义好了,话不多说,开始看数据手册:

PIN

Name

Comments

1

SDA

数据引脚;上拉10K电阻到VDD

2

ADDR

地址选择引脚;

接GND地址为0x44;

接VDD地址为0x45

3

ALERT

不用必须悬空!!!(可以设置温度、湿度值,超过对应值会输出)

4

SCL

时钟引脚;上拉10K电阻到VDD

5

VDD

电源:2.15V-5.5V

6

nRESET

复位引脚;未使用,需通过一个大于2kΩ的电阻连接到VDD,但是!!!数据手册又说,能不已经上拉了一个50kΩ的电阻到VDD了

7

R

未使用,连接到VDD

8

VSS

GND

2、工作模式

2.1 单次数据采集模式:

单次数据采集模式按照可重复性分为3类:High、Medium、Low

按照clock stretching可分为2类:enabled clock stretching和disabled clock stretching

主机发送开始信号--->主机发送地址(写)--->等待应答--->主机发送指令的高8位0x2C--->等待应答--->主机发送指令的低8位0x06--->等待应答--->主机发送停止信号--->SCL free(延时1ms)--->主机发送开始信号--->主机发送地址(读)--->分为两种模式:单次数据采集过程:(以指令0x2C06为例):

enabled clock stretching:

等待应答--->SCL pulled low--->主机读温度高8位--->主机发送应答--->主机读温度低8位--->主机发送应答--->主机读温度校验值--->主机发送应答--->主机读湿度高8位--->主机发送应答--->主机读湿度低8位--->主机发送应答--->主机读湿度校验值--->主机发送不应答--->主机发送停止信号

disabled clock stretching:

主机等待不应答信号--->主机发送停止信号--->SCL free(延时1ms)--->主机发送开始信号--->主机发送地址(读)--->等待应答--->主机读温度高8位--->主机发送应答--->主机读温度低8位--->主机发送应答--->主机读温度校验值--->主机发送应答--->主机读湿度高8位--->主机发送应答--->主机读湿度低8位--->主机发送应答--->主机读湿度校验值--->主机发送不应答--->主机发送停止信号

定期数据采集模式:(以指令0x2130为例):

注:0x2130是1s采集1次数据项目中用的就是定期数据采集模式:

主机发送开始信号--->主机发送地址(写)--->主机等待应答--->主机发送定期采集数据模式指令高8位0x21--->主机等待应答--->主机发送定期采集数据模式指令低8位0x30--->主机等待应答

上面是如何将SHT30设置为1s采集1次数据,程序中需要不停的给SHT30写读取数据指令0xE000来读取数据:

主机发送开始信号--->主机发送地址(写)--->主机等待应答--->主机发送读取数据指令的高8位0xE000--->主机等待应答--->主机发送读取数据指令的低8位0x00--->主机等待应答--->主机发送开始信号--->主机发送地址(读)--->主机等待应答--->主机读温度高8位--->主机发送应答--->主机读温度低8位--->主机发送应答--->主机读温度校验值--->主机发送应答--->主机读湿度高8位--->主机发送应答--->主机读湿度低8位--->主机发送应答--->主机读湿度校验值--->主机发送不应答--->主机发送停止信号

上代码:

void Init_I2C(void)

{

// ICS_ConfigType ICS_set={0};/* Declaration of ICS_setup structure */

// ICS_set.u8ClkMode=ICS_CLK_MODE_FEI;

// ICS_set.bdiv=0;

// ICS_Init(&ICS_set);/*Initialization of Core clock at 48 MHz, Bus Clock at 24 MHz*/

SIM->SCGC |= SIM_SCGC_I2C1_MASK;

I2C1->C1 |= 1<<7;//使能IIC。

I2C1->F = 0x1e;//设置IIC的波特率为100Khz

I2C baud rate = I2C module clock speed (Hz)/(mul × SCL divider)

注:因为BUS是20Mhz 所以查数据手册只有0x1e算出来最接近100Khz

如果BUS是24Mhz,可以选择0x1f

}

void Sht30_Start(void)

{

I2C1->C1 |= I2C_C1_TX_MASK;

I2C1->C1 |= I2C_C1_MST_MASK;

}

void Sht30_Stop(void)

{

I2C1->C1 &= ~I2C_C1_MST_MASK;

}

void Sht30_SendByte(uint8_t Byte)

{

// while(!(I2C1->S1 & 0x80)) ;//传输完成标志

I2C1->C1 |= I2C_C1_TX_MASK;//选择发送模式

I2C1->D = Byte;

while(!(I2C1->S1 & 0x02)) ;//中断挂起

I2C1->S1 |= 0x02 ;//清除中断标志

while((I2C1->S1 & 0x01)) ;//等待应答信号

}

void Sht30_ReadByte1(uint8_t *data , uint8_t ack)

{

while(!(I2C1->S1 & 0x80)) ;//传输完成标志

I2C1->C1 &= ~I2C_C1_TX_MASK;//选择接收模式

if(ack)

I2C1->C1 &= ~I2C_C1_TXAK_MASK;

else

I2C1->C1 |= I2C_C1_TXAK_MASK;

*data = I2C1->D ;

while(!(I2C1->S1 & 0x02)) ;//中断挂起

I2C1->S1 |= 0x02 ;//清除中断标志

}

//系统Init的时候调用一次这个函数

void Sht30_InitPeriod(void)

{

Sht30_Start() ;

Sht30_SendByte(0x88) ;

Sht30_SendByte(0x21) ;

Sht30_SendByte(0x30) ;

Sht30_Stop() ;

delay_s1(150) ;

// I2C_MasterSendWait(I2C1,(SHT30ADDR),&Sht3xPeriodInitCommand[0],2) ;

// delay_s1(150) ;

}

void GetData(void)

{

uint8_t check_data = 0 ;

uint16_t rawValueTemp; // temperature raw value from sensor

uint16_t rawValueHumi; // humidity raw value from sensor

Sht30_Start() ;

Sht30_SendByte(0x88) ;

Sht30_SendByte(0xe0) ;

Sht30_SendByte(0x00) ;

delay_s1(50) ;

I2C1->C1 |= 1<<2;//重启IIC

Sht30_Start() ;

Sht30_SendByte(0x89) ;

// delay_s1(1) ;

Sht30_ReadByte1(&SenData[0] , 1) ;//启动I2C数据读取

Sht30_ReadByte1(&SenData[0] , 1) ;

Sht30_ReadByte1(&SenData[1] , 1) ;

Sht30_ReadByte1(&SenData[2] , 1) ;

Sht30_ReadByte1(&SenData[3] , 1) ;

Sht30_ReadByte1(&SenData[4] , 1) ;

Sht30_ReadByte1(&SenData[5] , 0) ;

delay_s1(1) ;

Sht30_Stop() ;

check_data = SenData[2] ;

if(SHT3X_CalcCrc(SenDataPeriod , 2 , check_data))

{

rawValueTemp = ((SenDataPeriod[0] << 8) | SenDataPeriod[1]) ;

}

check_data = SenData[5] ;

if(SHT3X_CalcCrc(&SenDataPeriod[3] , 2 , check_data))

{

rawValueHumi = ((SenDataPeriod[3] << 8) | SenDataPeriod[4]) ;

}

temperature = (uint8_t)SHT3X_CalcTemperature(rawValueTemp);

humidity = (uint8_t)SHT3X_CalcHumidity(rawValueHumi);

uint8_t test_data = 0 ;

}

//CRC校验

#define POLYNOMIAL 0x131 // P(x) = x^8 + x^5 + x^4 + 1 = 100110001

static uint8_t SHT3X_CalcCrc(uint8_t data[], uint8_t nbrOfBytes , uint8_t checksum)

{

uint8_t bit; // bit mask

uint8_t crc = 0xFF; // calculated checksum

uint8_t byteCtr; // byte counter

// calculates 8-Bit checksum with given polynomial

for(byteCtr = 0; byteCtr < nbrOfBytes; byteCtr++)

{

crc ^= (data[byteCtr]);

for(bit = 8; bit > 0; --bit)

{

if(crc & 0x80)

crc = (crc << 1) ^ POLYNOMIAL;

else

crc = (crc << 1);

}

}

if(crc != checksum)

return 0 ;

return crc;

}

CRC校验:

1、选择一个数据X当作除数(这个数可以随意选择,也可以按照标准选择(通过多项式进行选择),但是最高位和最低位都必须为1

2、将X写成二进制(位数为K),在要发送的数据A后加上K-1个0组成一个新的数据Y

3、用Y除以X,得到的余数就是校验码Z(这里的除法为模2除法)余数的位数一定要是比除数位数只能少一位,哪怕前面位是0,甚至是全为0(附带好整除时)也都不能省略

4、在要发送的数据A后加上Z,组成新的数据A1,发送给接收端

5、接收端收到数据A2后,除以X,如果没有余数,则传输正确,否则,出错;

模2除法:

1111000除以1101:


CRC校验举例:列出10011100的校验码
1111000除以1101:

1、多项式G(X) = X^3 + X^2 + 1,将多项式转换为二进制,多项式的总位数等于最高次幂+1,3+1=4,多项式中只列出二进制为1的位,所以除数的二进制为1101

2、前面步骤2,组成新的数据就是在10011100后加上3个0,新的数据为10011100000

3、用新的数据10011100000除以除数1101,得到余数001

4、将10011100后加上001组成新的数据10011100001,发送到接收端,接收端接收到的数据除以除数1101,如果没有余数,传输正确,否则,传输出错。

5、有兴趣的可以算算11011100的校验码,多项式G(X) = X^4 + X^3 + 14、将10011100后加上001组成新的数据10011100001,发送到接收端,接收端接收到的数据除以除数1101,如果没有余数,传输正确,否则,传输出错。

KEA128+SHT30+CRC校验的更多相关文章

  1. 文档:网络通讯包结构(crc校验,加解密)

    一直想把这个流程整理一下. 包结构: 包 对(datacrc+protoID+dataSize)组成的byte[] 进行crc计算而得到 对(数据内容)进行crc计算而得到 协议号 数据内容的字节长度 ...

  2. CRC校验码原理、实例、手动计算

    目录一.CRC16实现代码二.CRC32编码字符表三.CRC校验码的手动计算示例四.CRC校验原理五.CRC的生成多项式参考 一.CRC16实现代码 思路:取一个字符(8bit),逐位检查该字符,如果 ...

  3. 物联网平台设计心得:你所不知道的CRC校验

    在物联网平台设计过程中,我的中间件一方面需要处理来自于硬件端的包,另一方面需要处理来自于用户端的包,用户端包括web端和手机端等等.所以编写一个统一的CRC认证是非常必须要. 那么,在设计开始,CRC ...

  4. CRC校验代码实现

    1.CRC校验简介 CRC就是块数据的计算值,它的全称是“Cyclic Redundancy Check”,中文名是“循环冗余码”.CRC校验是数据通讯中最常采用的校验方式.在嵌入式软件开发中,经常要 ...

  5. CRC校验码

    循环冗余校验码(CRC)的基本原理是:在K位信息码后再拼接R位的校验码,整个编码长度为N位,因此,这种编码也叫(N,K)码.对于一个给定的(N,K)码,可以证明存在一个最高次幂为R的多项式G(x)(R ...

  6. C# CRC校验的一点感悟

    今天在鼓捣一个手持操作器的时候,遇到一点问题,记录一下今天的经验包 由于之前公司产品在校验时基本上都是和校验,今天在准备用C#模拟一个古董操作器的时候,却遇到一个问题,模拟器发出的数据,主板一律不回复 ...

  7. CRC校验源码分析

    这两天做项目,需要用到 CRC 校验.以前没搞过这东东,以为挺简单的.结果看看别人提供的汇编源程序,居然看不懂.花了两天时间研究了一下 CRC 校验,希望我写的这点东西能够帮助和我有同样困惑的朋友节省 ...

  8. 在线CRC校验

    在线CRC校验: http://www.lammertbies.nl/comm/info/crc-calculation.html

  9. CRC校验

    小试一下CRC校验的verilog实现,采用最stupid的直接法. /* date : 2014/06/06 designer : pengxiaoen virsion : Altera-Model ...

随机推荐

  1. Fiddler手机端抓包环境设置与过滤(一)

    一.PC端Fiddler设置 1.安装https 证书 打开Fiddler->Tool->Fiddler Options->HTTPS tab,勾选上并Capture HTTPS C ...

  2. 面试中的volatile关键字

    在Java的面试当中,面试官最爱问的就是volatile关键字相关的内容.经过多次面试之后,你是否思考过,为什么他们那么爱问volatile关键字相关的问题?而对于你,如果作为面试官,是否也会考虑采用 ...

  3. P2764 最小路径覆盖问题 网络流重温

    P2764 最小路径覆盖问题 这个题目之前第一次做的时候感觉很难,现在好多了,主要是二分图定理不太记得了,二分图定理 知道这个之后就很好写了,首先我们对每一个点进行拆点,拆完点之后就是跑最大流,求出最 ...

  4. mybatis实现增删改

    mybatis实现增加数据 1.在dao接口中声明添加方法 2.在mapper文件中实现该方法 3.测试 mybatis实现修改数据 1.在dao接口中声明修改方法 2.在mapper中实现该方法 3 ...

  5. 面试官:你说你懂动态代理,那你知道为什么JDK中的代理类都要继承Proxy吗?

    之前我已经写过了关于动态代理的两篇文章,本来以为这块应该没啥问题,没想到今天又被难住了- 太难了!!! 之前文章的链接: 动态代理学习(一)自己动手模拟JDK动态代理. 动态代理学习(二)JDK动态代 ...

  6. 【HBase】快速了解上手rowKey的设计技巧

    目录 为什么要设计rowKey 三大原则 长度原则 散列原则 唯一原则 热点问题的解决 加盐 哈希 反转 时间戳反转 为什么要设计rowKey 首先要弄明白一点,Regions的分区就是根据数据的ro ...

  7. Android 源码结构分析

    源码版本:AOSP_7.1.1 硬件平台:Rockchip 由于工作要求,需要对rockchip平台的安卓系统进行剪裁.安卓源码比较庞大,会让人感到无从下手,对此,有必要了解一下源码的大致目录结构以及 ...

  8. java web 开发之 office(excel、doc等)文件转pdf

    一.开发工具:office 16.jacob-1.18-M2.jboss 1.6 二.开发配置: 1.解压缩---> 2.配置jacob: A C:\Windows\System32 jacob ...

  9. [uva_la7146 Defeat the Enemy(2014 shanghai onsite)]贪心

    题意:我方n个军队和敌方m个军队进行一对一的对战,每个军队都有一个攻击力和防御力,只要攻击力不小于对方就可以将对方摧毁.问在能完全摧毁敌方的基础上最多能有多少军队不被摧毁. 思路:按防御力从大到小考虑 ...

  10. Redis学习笔记(七) 数据库

    Redis 服务器将所有的数据库都保存在服务器状态redisServer结构的db数组中,db数组的每个项都是一个redisDB: struct redisServer{ //一个数组保存着服务器中的 ...