查看: 2357|回复: 1

[原创] KEA128+SHT30使用方法+CRC校验

[复制链接]

该用户从未签到

24

主题

82

帖子

0

金牌会员

Rank: 6Rank: 6

积分
1239
最后登录
2022-1-7
发表于 2020-5-28 16:06:28 | 显示全部楼层 |阅读模式
本帖最后由 byxzwz 于 2020-5-28 16:34 编辑

最近更新产品功能的时候使用到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
复位引脚;未使用,需通过一个大于2的电阻连接到VDD,但是!!!数据手册又说,能不已经上拉了一个50的电阻到VDD
7
R
未使用,连接到VDD
8
VSS
GND

2、工作模式
  2.1 单次数据采集模式:
  单次数据采集模式按照可重复性分为3类:HighMediumLow
按照clock stretching可分为2类:enabled clock stretchingdisabled clock stretching 图片1.png
图片怎么发,谁能教教我……奥,会了
单次数据采集过程:(以指令0x2C06为例):

主机发送开始信号--->主机发送地址(写)--->等待应答--->主机发送指令的高80x2C--->等待应答--->主机发送指令的低80x06--->等待应答--->主机发送停止信号--->SCL free(延时1ms--->主机发送开始信号--->主机发送地址(读)--->分为两种模式:
enabled clock stretching
等待应答--->SCL pulled low--->主机读温度高8--->主机发送应答--->主机读温度低8--->主机发送应答--->主机读温度校验值--->主机发送应答--->主机读湿度高8--->主机发送应答--->主机读湿度低8--->主机发送应答--->主机读湿度校验值--->主机发送不应答--->主机发送停止信号

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


定期数据采集模式:(以指令0x2130为例):
图片2.png
项目中用的就是定期数据采集模式:
注:0x21301s采集1次数据
主机发送开始信号--->主机发送地址(写)--->主机等待应答--->主机发送定期采集数据模式指令高80x21--->主机等待应答--->主机发送定期采集数据模式指令低80x30--->主机等待应答
上面是如何将SHT30设置为1s采集1次数据,程序中需要不停的给SHT30写读取数据指令0xE000来读取数据:
主机发送开始信号--->主机发送地址(写)--->主机等待应答--->主机发送读取数据指令的高80xE000--->主机等待应答--->主机发送读取数据指令的低80x00--->主机等待应答--->主机发送开始信号--->主机发送地址(读)--->主机等待应答--->主机读温度高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)
注:因为BUS20Mhz 所以查数据手册只有0x1e算出来最接近100Khz
如果BUS24Mhz,可以选择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-10组成一个新的数据Y
3、Y除以X,得到的余数就是校验码Z(这里的除法为模2除法)余数的位数一定要是比除数位数只能少一位,哪怕前面位是0,甚至是全为0(附带好整除时)也都不能省略
4、在要发送的数据A后加上Z,组成新的数据A1,发送给接收端
5、接收端收到数据A2后,除以X,如果没有余数,则传输正确,否则,出错;
2除法:
1111000除以1101

图片3.png
CRC校验举例:列出10011100的校验码
1、多项式GX = X^3 + X^2 + 1,将多项式转换为二进制,多项式的总位数等于最高次幂+1,3+1=4,多项式中只列出二进制为1的位,所以除数的二进制为1101
2、前面步骤2,组成新的数据就是在10011100后加上30,新的数据为10011100000
3、用新的数据10011100000除以除数1101,得到余数001

微信图片_20200528161249.jpg
4、10011100后加上001组成新的数据10011100001,发送到接收端,接收端接收到的数据除以除数1101,如果没有余数,传输正确,否则,传输出错。
5、有兴趣的可以算算11011100的校验码,多项式GX = X^4 + X^3 + 1







回复

使用道具 举报

该用户从未签到

656

主题

6312

帖子

0

超级版主

Rank: 8Rank: 8

积分
20008
最后登录
2024-4-24
发表于 2020-5-29 09:35:56 | 显示全部楼层
感谢分享
回复

使用道具 举报

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

本版积分规则

关闭

站长推荐上一条 /4 下一条

Archiver|手机版|小黑屋|恩智浦技术社区

GMT+8, 2024-4-25 04:44 , Processed in 0.123798 second(s), 20 queries , MemCache On.

Powered by Discuz! X3.4

Copyright © 2001-2024, Tencent Cloud.

快速回复 返回顶部 返回列表