高级会员

- 积分
- 514
- 金钱
- 514
- 注册时间
- 2017-5-21
- 在线时间
- 82 小时
|
发表于 2019-7-16 21:58:32
|
显示全部楼层
本帖最后由 Anyint 于 2019-7-16 22:48 编辑
- /**
- * @brief SHT30读数据
- * @param None
- * @retval None
- */
- void Sht30_ReadData(void)
- {
- u8 crc_result;
- u16 data;
- u8 Buff1[3],Buff2[3];
- Sht30_WriteCmd(0x21,0x26); //数据采集频率1 m/s
- i2c_Start();//起始信号
- i2c_SendByte(0x88+1); //发送设备地址+读信号
- while (i2c_WaitAck());//CPU产生一个时钟,并读取器件的ACK应答信号
- Buff1[0]=i2c_ReadByte();//读取温度高八位并且发送一个ack
- i2c_Ack();
- Buff1[1]=i2c_ReadByte(); //低八位
- i2c_Ack();
- Buff1[2]=i2c_ReadByte(); //校验位发送ACK8位
- i2c_Ack();
- Buff2[0] = i2c_ReadByte(); //湿度发送ACK高8位
- i2c_Ack();
- Buff2[1] = i2c_ReadByte(); //湿度低八位
- i2c_Ack();
- Buff2[2] = i2c_ReadByte(); //校验位之后发送nack具体见数据手册
- i2c_NAck();
- i2c_Stop(); // CPU发起I2C总线停止信号
- //delay_ms(5);
-
- crc_result=sht30_crc8_check(Buff1,2,Buff1[2]);
- if(crc_result==0)
- {
- //把2个8位数据拼接为一个16位的数据
- data=((u16)Buff1[0] << 8) | Buff1[1];
- //温度转换,将16位温度数据转化为10进制的温度数据,这里保留了一位小数,data_process.SHT30_temperature这是一个全局变量,至于为什么变量名字里面有个.不懂得各位可以百度一下c语言结构体的相关说明。
- Temperature = (float)175*(data)/65535-45;
- }
- crc_result=sht30_crc8_check(Buff2,2,Buff2[2]);
- if(crc_result==0)
- {
- //把2个8位数据拼接为一个16位的数据
- data=((u16)Buff2[0] << 8) | Buff2[1];
- //温度转换,将16位温度数据转化为10进制的温度数据,这里保留了一位小数,data_process.SHT30_temperature这是一个全局变量,至于为什么变量名字里面有个.不懂得各位可以百度一下c语言结构体的相关说明。
- Humidity = (float)100*(data)/65535;
- }
- }
复制代码
- int crc8_compute(u8 *check_data, u8 num_of_data)
- {
- 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 < num_of_data; byteCtr++) {
- crc ^= (check_data[byteCtr]);
- //crc校验,最高位是1就^0x31
- for(bit = 8; bit > 0; --bit) {
- if(crc & 0x80) {
- crc = (crc << 1) ^ 0x31;
- } else {
- crc = (crc << 1);
- }
- }
- }
- return crc;
- }
- int sht30_crc8_check(u8 *p,u8 num_of_data,u8 CrcData)
- {
- uint8_t crc;
- crc = crc8_compute(p, num_of_data);// calculates 8-Bit checksum
- if(crc != CrcData)
- {
- return 1;
- }
- return 0;
- }
复制代码
楼主我后来改了一下,你的读取代码,我发现缺少一个CRC校验,有了CRC校验的话,这样读取的数据就会稳定,这个SHT30传感器它好像读取速度不是很快,看了很多帖子,发现如果读的太快的话,它寄存器的值就会有问题,具体现象:我这边的精英板温度显示130,如果在读取的时候不加delay,一直都是这个值。所以我认为缺少了校验的过程,校验是去除那些错误的值,那么显示就是正确的。楼主的代码读取速度很快,在加个CRC校验也是很快的,所以能满足实时读取温度的要求,其次能保证数据的瞬间读取(隔开多久读一次没关系,最重要的是读一次的时间不能出现明显的大delay)。再次感谢楼主的代码,稳!
补充:之前分析那个读取数据一直显示130,就是说BUFF1 和 BUFF2 都是0xff,带入楼主的代码的计算公式,那么温度就显示130℃了,湿度显示100%。。。,网上又搜索一遍后,发现是SDA的锅,在读取BUFF之前要拉高SDA,解决地址:http://www.openedv.com/forum.php?mod=viewthread&tid=273662
更新代码:
EEPROM_I2C_SDA_1();//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!一定要在地址后应答后面拉高SDA 请注意这一行代码
- /**
- * @brief SHT30读数据
- * @param None
- * @retval None
- */
- int Sht30_ReadData(float *t,float *h)
- {
- u8 crc_result;
- u16 data;
- u8 Buff1[3],Buff2[3];
- Sht30_WriteCmd(0x21,0x26); //数据采集频率1 m/s
- i2c_Start();//起始信号
- i2c_SendByte(0x88+1); //发送设备地址+读信号
- while (i2c_WaitAck());//CPU产生一个时钟,并读取器件的ACK应答信号
- EEPROM_I2C_SDA_1();//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!一定要在地址后应答后面拉高SDA
- Buff1[0]=i2c_ReadByte();//读取温度高八位并且发送一个ack
- i2c_Ack();
- Buff1[1]=i2c_ReadByte(); //低八位
- i2c_Ack();
- Buff1[2]=i2c_ReadByte(); //校验位发送ACK8位
- i2c_Ack();
- Buff2[0] = i2c_ReadByte(); //湿度发送ACK高8位
- i2c_Ack();
- Buff2[1] = i2c_ReadByte(); //湿度低八位
- i2c_Ack();
- Buff2[2] = i2c_ReadByte(); //校验位之后发送nack具体见数据手册
- i2c_NAck();
- i2c_Stop(); // CPU发起I2C总线停止信号
- //delay_ms(5);
-
- crc_result=sht30_crc8_check(Buff1,2,Buff1[2]);
- if(crc_result==0)
- {
- //把2个8位数据拼接为一个16位的数据
- data=((u16)Buff1[0] << 8) | Buff1[1];
- //温度转换,将16位温度数据转化为10进制的温度数据,这里保留了一位小数,data_process.SHT30_temperature这是一个全局变量,至于为什么变量名字里面有个.不懂得各位可以百度一下c语言结构体的相关说明。
- *t = (float)175*(data)/65535-45;
- }
- else
- return 1;
- crc_result=sht30_crc8_check(Buff2,2,Buff2[2]);
- if(crc_result==0)
- {
- //把2个8位数据拼接为一个16位的数据
- data=((u16)Buff2[0] << 8) | Buff2[1];
- //温度转换,将16位温度数据转化为10进制的温度数据,这里保留了一位小数,data_process.SHT30_temperature这是一个全局变量,至于为什么变量名字里面有个.不懂得各位可以百度一下c语言结构体的相关说明。
- *h = (float)100*(data)/65535;
- return 0;
- }
- else
- return 1;
- }
复制代码 再次补充:发现一个神奇的事情,在while死循环中,我要读取温度数据,又要发串口的时候,这个要屏蔽这句代码:EEPROM_I2C_SDA_1();,这样才可以便显示温度便发串口,不然就会出现温度又是130的情况,这真的有点不明白了,如果你要不屏蔽这句代码的话,那么你发串口的前提条件就是CRC校验一定要成功的时候才能发串口数据,代码如下:- if(!Sht30_ReadData(&Temperature,&Humidity)){
-
- printf("t:%.2fC h:%.0f%%RH\r\n",Temperature,Humidity);}
复制代码
|
|