2016-02-17 1 views
1

J'espère que l'un de vous là-bas peut m'aider! J'essaie d'utiliser la carte Adafruit SHT31-D (un périphérique i2c) avec mon Pi2. Je vais partir de this datasheet pour guider mes efforts de codage. J'utilise Wiring Pi (wiringpi.com) pour faciliter les choses.Adafruit SHT31-D et Raspberry Pi2 - Impossible de lire les données du capteur

Je suis en mesure d'ouvrir une connexion à l'appareil avec succès, et l'envoi de commandes semble fonctionner correctement, mais je suis incapable de lire les données! Voici la petite mini-bibliothèque que j'ai rassemblée. J'espère que l'un d'entre vous pourrait avoir une expérience avec ce genre de chose et être capable de m'aider à voir où je me suis trompé.

Pour exclure d'éventuels problèmes avec le matériel du capteur, je l'ai testé avec mon Arduino UNO et cela fonctionne sans problèmes.

Voici mon code C++:

SHT3x.h

#pragma once 

/* Sensor Commands */ 
#define DEFAULT_SHT_ADDR 0x44 
#define MEAS_HREP_STRETCH 0x2C06 
#define MEAS_MREP_STRETCH 0x2C0D 
#define MEAS_LREP_STRETCH 0x2C10 
#define MEAS_HREP 0x2400 
#define MEAS_MREP 0x240B 
#define MEAS_LREP 0x2416 

#include <cstdint> 


class SHT3x { 

    public: 
    SHT3x(const uint8_t& i2cAddr); 
    float readHumidity(const uint16_t& command) const; 
    float readTempC(const uint16_t& command) const; 
    float readTempF(const uint16_t& command) const; 

    private: 
    int8_t _fd; 
    uint8_t _header; 
    uint32_t getMeasurement(const uint16_t& command) const; 
    void sendCommand(const uint16_t& command) const; 
    uint32_t receiveData(void) const; 
}; 

SHT3x.cpp

#include <stdexcept> 
#include <wiringPi.h> 
#include <wiringPiI2C.h> 
#include "SHT3x.h" 


SHT3x::SHT3x(const uint8_t& i2cAddr) { 
    _fd = wiringPiI2CSetup(i2cAddr); 
    _header = i2cAddr << 1; 
    if (_fd < 0) { 
     throw std::runtime_error("Unable to connect"); 
    } 
} 

float SHT3x::readHumidity(const uint16_t& command) const { 
    uint32_t raw_data = getMeasurement(command); 
    if (!raw_data) { 
     throw std::runtime_error("Bad Reading."); 
    } 
    uint16_t raw_humidity = raw_data & 0xFFFF; 
    float humidity = 100.0 * ((float) raw_humidity/(float) 0xFFFF); 
    return humidity; 
} 

float SHT3x::readTempC(const uint16_t& command) const { 
    uint32_t raw_data = getMeasurement(command); 
    if (!raw_data) { 
     throw std::runtime_error("Bad Reading."); 
    } 
    uint16_t raw_temp = raw_data >> 16; 
    float tempC = -45.0 + (175.0 * ((float) raw_temp/(float) 0xFFFF)); 
    return tempC; 
} 

float SHT3x::readTempF(const uint16_t& command) const { 
    uint32_t raw_data = getMeasurement(command); 
    if (!raw_data) { 
     throw std::runtime_error("Bad Reading."); 
    } 
    uint16_t raw_temp = raw_data >> 16; 
    float tempF = -49.0 + (315.0 * ((float) raw_temp/(float) 0xFFFF)); 
    return tempF; 
} 

uint32_t SHT3x::getMeasurement(const uint16_t& command) const { 
    try { 
     sendCommand(command); 
    } catch (std::runtime_error& e) { 
     throw; 
    } 
    return receiveData(); 
} 

void SHT3x::sendCommand(const uint16_t& command) const { 
    // break command into bytes 
    uint8_t MSB = command >> 8; 
    uint8_t LSB = command & 0xFF; 

    // send header 
    int8_t ack = wiringPiI2CWrite(_fd, _header); 

    // send command 
    ack &= wiringPiI2CWrite(_fd, MSB); 
    ack &= wiringPiI2CWrite(_fd, LSB); 

    // handle errors 
    if (ack) { 
     throw std::runtime_error("Sending command failed."); 
    } 
} 

uint32_t SHT3x::receiveData(void) const { 
    uint32_t data; 

    // send header 
    uint8_t read_header = _header | 0x01; 
    int8_t ack = wiringPiI2CWrite(_fd, read_header); 

    // handle errors 
    if (ack) throw std::runtime_error("Unable to read data."); 

    // read data 
    data = wiringPiI2CRead(_fd); 
    for (size_t i = 0; i < 4; i++) { 
     printf("Data: %d\n", data); 
     data <<= 8; 
     if (i != 1) { 
      data |= wiringPiI2CRead(_fd); 
     } else { 
      wiringPiI2CRead(_fd); // skip checksum 
     } 
    } 
    wiringPiI2CRead(_fd); // second checksum 
    return data; 
} 
+0

Que fait votre code pour indiquer qu'il n'a pas réussi à lire? par exemple. lance-t-il une erreur d'exécution "Impossible de lire les données", ou lance "Mauvaise lecture", ou autre chose? –

+0

@MattJordan: Il lance "Mauvaise lecture". Je reçois toujours juste une valeur zéro –

Répondre

2

Le SHT31 utilise lire et écrire 16bit, plutôt que d'utiliser 2 8bit écrit que vous pourriez être mieux en utilisant l'écriture 16bit de wiringpi. câblagePiI2CWriteReg16(). La même chose s'applique à la lecture. Ci-dessous est une copie très tôt de ce que j'ai fait pour lire le sht31-d sur un IP. Il n'a pas de dépendances sauf i2c-dev. Chauffage activer/désactiver ne fonctionne pas, mais softreset, clearstatus, geterial & obtenir temp/humide sont très bien.

/* 
* Referances 
* https://www.kernel.org/doc/Documentation/i2c/dev-interface 
* https://github.com/adafruit/Adafruit_SHT31 
* https://www.sensirion.com/fileadmin/user_upload/customers/sensirion/Dokumente/Humidity_and_Temperature_Sensors/Sensirion_Humidity_and_Temperature_Sensors_SHT3x_Datasheet_digital.pdf 
* 
* This depends on i2c dev lib 
* sudo apt-get install libi2c-dev 
* 
* Below is also a good one to have, but be careful i2cdump from the below cause the sht31 interface to become unstable for me 
* and requires a hard-reset to recover correctly. 
* sudo apt-get install i2c-tools 
* 
* on PI make sure below 2 commands are in /boot/config.txt 
* dtparam=i2c_arm=on 
* dtparam=i2c1_baudrate=10000 
* I know we are slowing down the baurate from optimal, but it seems to be the most stable setting in my testing. 
* add another 0 to the above baudrate for max setting, ie dtparam=i2c1_baudrate=100000 
*/ 

#include <linux/i2c-dev.h> 
#include <time.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <sys/types.h> 
#include <fcntl.h> 
#include <elf.h> 
#include <unistd.h> 

#define SHT31_INTERFACE_ADDR  1 
#define SHT31_DEFAULT_ADDR   0x44 
#define SHT31_READ_SERIALNO  0x3780 
#define SHT31_MEAS_HIGHREP_STRETCH 0x2C06 // Doesn't work on PI 
#define SHT31_MEAS_MEDREP_STRETCH 0x2C0D // Seems to work on PI but shouldn't 
#define SHT31_MEAS_LOWREP_STRETCH 0x2C10 // Seems to work on PI but shouldn't 
#define SHT31_MEAS_HIGHREP   0x2400 // Doesn't work on PI 
#define SHT31_MEAS_MEDREP   0x240B 
#define SHT31_MEAS_LOWREP   0x2416 
#define SHT31_READSTATUS   0xF32D 
#define SHT31_CLEARSTATUS   0x3041 
#define SHT31_SOFTRESET   0x30A2 
#define SHT31_HEATER_ENABLE  0x306D 
#define SHT31_HEATER_DISABLE  0x3066 

#define CHECK_BIT(var,pos) (((var)>>(pos)) & 1) 

/* 
* delay: 
* Wait for some number of milliseconds 
********************************************************************************* 
*/ 

void delay (unsigned int howLong) 
{ 
    struct timespec sleeper, dummy ; 

    sleeper.tv_sec = (time_t)(howLong/1000) ; 
    sleeper.tv_nsec = (long)(howLong % 1000) * 1000000 ; 

    nanosleep (&sleeper, &dummy) ; 
} 

/* 
* 
* CRC-8 formula from page 14 of SHT spec pdf 
* 
* Test data 0xBE, 0xEF should yield 0x92 
* 
* Initialization data 0xFF 
* Polynomial 0x31 (x8 + x5 +x4 +1) 
* Final XOR 0x00 
*/ 
uint8_t crc8(const uint8_t *data, int len) 
{ 
    const uint8_t POLYNOMIAL = 0x31; 
    uint8_t crc = 0xFF; 
    int j; 
    int i; 

    for (j = len; j; --j) { 
    crc ^= *data++; 

    for (i = 8; i; --i) { 
     crc = (crc & 0x80) 
      ? (crc << 1)^POLYNOMIAL 
      : (crc << 1); 
    } 
    } 
    return crc; 
} 


/* 
* 
* buffer should return with data read, size defined by readsize 
********************************************************************************* 
*/ 

int writeandread(int fd, uint16_t sndword, uint8_t *buffer, int readsize) 
{ 
    int rtn; 
    uint8_t snd[3]; 
    // Split the 16bit word into two 8 bits that are flipped. 
    snd[0]=(sndword >> 8) & 0xff; 
    snd[1]=sndword & 0xff; 

    rtn = write(fd, snd, 2); 
    if (rtn != 2) { 
    return 1; 
    } 

    if (readsize > 0) { 
    delay(10); 
    rtn = read(fd, buffer, readsize); 
    if (rtn < readsize) { 
     return 2; 
    } 
    } 

    return 0; 
} 

void printserialnum(int file) 
{ 
    uint8_t buf[10]; 
    int rtn; 

    rtn = writeandread(file, SHT31_READ_SERIALNO, buf, 6); 
    if (rtn != 0) 
    printf("ERROR:- Get serial i2c %s failed\n",(rtn==1?"write":"read")); 
    else { 
    if (buf[2] != crc8(buf, 2) || buf[5] != crc8(buf+3, 2)) 
     printf("WARNING:- Get serial CRC check failed, don't trust result\n"); 

    uint32_t serialNo = ((uint32_t)buf[0] << 24) 
    | ((uint32_t)buf[1] << 16) 
    | ((uint32_t)buf[3] << 8) 
    | (uint32_t)buf[4]; 
    printf("Serial# = %d\n",serialNo); 
    } 
} 

void printtempandhumidity(int file) 
{ 
    uint8_t buf[10]; 
    int rtn; 

    rtn = writeandread(file, SHT31_MEAS_MEDREP_STRETCH, buf, 6); 

    if (rtn != 0) 
    printf("ERROR:- Get temp/humidity i2c %s failed\n",(rtn==1?"write":"read")); 
    else { 
    if (buf[2] != crc8(buf, 2) || buf[5] != crc8(buf+3, 2)) 
     printf("WARNING:- Get temp/humidity CRC check failed, don't trust results\n"); 

    uint16_t ST, SRH; 
    ST = buf[0]; 
    ST <<= 8; 
    ST |= buf[1]; 

    SRH = buf[3]; 
    SRH <<= 8; 
    SRH |= buf[4]; 

    double stemp = ST; 
    stemp *= 175; 
    stemp /= 0xffff; 
    stemp = -45 + stemp; 

    double stempf = ST; 
    stempf *= 315; 
    stempf /= 0xffff; 
    stempf = -49 + stempf; 

    printf("Temperature %.2fc - %.2ff\n",stemp,stempf); 

    double shum = SRH; 
    shum *= 100; 
    shum /= 0xFFFF; 

    printf("Humidity %.2f%%\n",shum); 
    } 
} 

void printBitStatus(uint16_t stat) 
{ 
    printf("Status\n"); 
    printf(" Checksum status %d\n", CHECK_BIT(stat,0)); 
    printf(" Last command status %d\n", CHECK_BIT(stat,1)); 
    printf(" Reset detected status %d\n", CHECK_BIT(stat,4)); 
    printf(" 'T' tracking alert %d\n", CHECK_BIT(stat,10)); 
    printf(" 'RH' tracking alert %d\n", CHECK_BIT(stat,11)); 
    printf(" Heater status %d\n", CHECK_BIT(stat,13)); 
    printf(" Alert pending status %d\n", CHECK_BIT(stat,15)); 
} 

void printstatus(int file) 
{ 
    uint8_t buf[10]; 
    int rtn; 

    rtn = writeandread(file, SHT31_READSTATUS, buf, 3); 
    if (rtn != 0) 
    printf("ERROR:- readstatus %s failed\n",(rtn==1?"write":"read")); 
    else { 
    if (buf[2] != crc8(buf, 2)) 
     printf("WARNING:- Get status CRC check failed, don't trust results\n"); 

    uint16_t stat = buf[0]; 
    stat <<= 8; 
    stat |= buf[1]; 
    printBitStatus(stat); 
    } 
} 



void clearstatus(int file) 
{ 
    if(writeandread(file, SHT31_CLEARSTATUS, NULL, 0) != 0) 
    printf("ERROR:- sht31 clear status failed\n"); 
    else 
    printf("Clearing status - ok\n"); 
} 

void softreset(int file) 
{ 
    if(writeandread(file, SHT31_SOFTRESET, NULL, 0) != 0) 
    printf("ERROR:- sht31 soft reset failed\n"); 
    else 
    printf("Soft reset - ok\n"); 
} 

void enableheater(int file) 
{ 
    if(writeandread(file, SHT31_HEATER_ENABLE, NULL, 0) != 0) 
    printf("ERROR:- sht31 heater enable failed\n"); 
    else 
    printf("Enabiling heater - ok\n"); 
} 

void disableheater(int file) 
{ 
    if(writeandread(file, SHT31_HEATER_DISABLE, NULL, 0) != 0) 
    printf("ERROR:- sht31 heater enable failed\n"); 
    else 
    printf("Disableing heater - ok\n"); 
} 

int main() 
{ 

    int file; 
    char filename[20]; 

    snprintf(filename, 19, "/dev/i2c-%d", SHT31_INTERFACE_ADDR); 
    file = open(filename, O_RDWR); 
    if (file < 0) { 
    printf("ERROR:- Can't open %s\n",filename); 
    exit(1); 
    } 

    if (ioctl(file, I2C_SLAVE, SHT31_DEFAULT_ADDR) < 0) { 
    printf("ERROR:- Connecting to sht31 I2C address 0x%02hhx\n", SHT31_DEFAULT_ADDR); 
    exit(1); 
    } 

    softreset(file); 
    printtempandhumidity(file); 
    printstatus(file); 

    close(file); 

    return 0; 
} 
+0

Merci beaucoup pour votre aide. Je vais étudier cela et la spécification i2c afin que je puisse mieux comprendre cela. –