最近更新产品功能的时候使用到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. Codeforce-CodeCraft-20 (Div. 2)-A. Grade Allocation

    n students are taking an exam. The highest possible score at this exam is m. Let ai be the score of ...

  2. Codeforce 1102 C. Doors Breaking and Repairing

    Descirbe You are policeman and you are playing a game with Slavik. The game is turn-based and each t ...

  3. ACM--[kuangbin带你飞]--专题1-23

    专题一 简单搜索 POJ 1321 棋盘问题POJ 2251 Dungeon MasterPOJ 3278 Catch That CowPOJ 3279 FliptilePOJ 1426 Find T ...

  4. Shell脚本(一)入门

    开始学习Shell脚本. #!/bin/bash ]; then echo "you are not root" else echo "you are root" ...

  5. P1750 出栈序列

    这好像是普及难度的吧~ 感觉再次被小学生吊打了........ \(\color{Red}{----------------------=|(●'◡'●)|=我是手动的分割线------------- ...

  6. Java 将鼠标改为图片的两种方法

    一 图片跟着鼠标移动,鼠标隐藏 int x,y; addMouseMotionListener(this);//设置鼠标监听 public void paint(Graphics g) {  g.dr ...

  7. 自动配置的Springboot内junit测试单元不能运行

    解决测试单元不能运行 问题:测试单元的 @Test 前面没有运行图标 解决 IDEA内:File - Setting - Plugins:搜到JUnitGenerator2.0,安装,重启IDEA 光 ...

  8. vue组件中的“:”、“@”、“.”属性

    冒号属性 :是指令 v-bind 的缩写,是为了动态绑定数据,用于响应式地更新 HTML 特性. 加了冒号,后面是变量或表达式:不加冒号的是字符串. 如图:将Home组件中的 probe-type 的 ...

  9. Dotnet core使用JWT认证授权最佳实践(二)

    最近,团队的小伙伴们在做项目时,需要用到JWT认证.遂根据自己的经验,整理成了这篇文章,用来帮助理清JWT认证的原理和代码编写操作. 第一部分:Dotnet core使用JWT认证授权最佳实践(一) ...

  10. 笨办法学习python-ex41源码加自己注释

    #!/user/bin/env python #-*-coding:utf-8 -*- #Author: qinjiaxi import random from urllib import urlop ...