Difference between revisions of "Grove I2C High Accuracy Temerature Sensor - Seeed"
From Teknologisk videncenter
m |
m (→Linux example code) |
||
(9 intermediate revisions by the same user not shown) | |||
Line 20: | Line 20: | ||
* | * | ||
* REMEMBER: Install the libi2c-dev package to compile this file | * REMEMBER: Install the libi2c-dev package to compile this file | ||
− | * Compile this example with: gcc | + | * Compile this example with: gcc i2c_MCP9808-example1.c -o i2c_MCP9808-example1 -li2c |
+ | * | ||
+ | * See also: https://www.kernel.org/doc/Documentation/i2c/dev-interface | ||
*/ | */ | ||
#include <stdio.h> | #include <stdio.h> | ||
Line 143: | Line 145: | ||
</source> | </source> | ||
--> | --> | ||
− | + | <!---- | |
− | * | + | Another aproach: |
− | * | + | |
− | *[ | + | /* |
− | * | + | * Module...: MCP9808example1.c |
− | [[Category:Grove]] | + | * Version..: 0.1 (Beta - unfinished) |
+ | * Author...: Henrik Thomsen/Mercantec <heth@mercantec.dk | ||
+ | * Date.....: 24. nov 2020 | ||
+ | * | ||
+ | * Abstract.: Implementation of Seeed Grove Sensor "I2C High | ||
+ | * Accuracy Temperature sensor" based on MCP-9808 | ||
+ | * Implementet in user space using libi2c | ||
+ | * Mod. log.: 01-06-2021: Could not compile. Got i2c_smbus_read_word_data undefined. | ||
+ | Include <i2c/smbus.h> should be include. (Worked in 2020) | ||
+ | |||
+ | * License..: Free open software but WITHOUT ANY WARRANTY. | ||
+ | * Terms....: see http://www.gnu.org/licenses | ||
+ | * | ||
+ | * Documentation - see https://mars.merhot.dk/w/index.php/Grove_I2C_High_Accuracy_Temerature_Sensor_-_Seeed | ||
+ | * | ||
+ | * REMEMBER: Install the libi2c-dev package to compile this file | ||
+ | * Compile this example with: gcc -li2c i2c_MCP9808-example1.c -o i2c_MCP9808-example1 | ||
+ | * | ||
+ | * See also: https://www.kernel.org/doc/Documentation/i2c/dev-interface | ||
+ | */ | ||
+ | #include <stdio.h> | ||
+ | #include <unistd.h> | ||
+ | #include <stdint.h> | ||
+ | #include <fcntl.h> | ||
+ | #include <sys/ioctl.h> | ||
+ | #include <stdlib.h> | ||
+ | #include <errno.h> | ||
+ | #include <string.h> | ||
+ | #include <linux/i2c-dev.h> | ||
+ | #include <i2c/smbus.h> // Added 01062021 HeTh | ||
+ | #include <byteswap.h> | ||
+ | |||
+ | /* The MCP9808 Digital temperature sensor IC from Microchip is a i2c/SMBus compatible | ||
+ | * device. To understand this code you need access to MCP9808 Datasheet from Microchip | ||
+ | * | ||
+ | * The device is implementet on Seeed Studios Grove I2C high accuracy Temperature Sensor | ||
+ | * | ||
+ | * Links and supplemental information can be found on tthe documentation link in this | ||
+ | * files header. | ||
+ | * | ||
+ | * The MCP9808 contains severel registers: | ||
+ | * | ||
+ | * Register addresses: | ||
+ | * 0x00: RFU - (Reserved for future use) Read only | ||
+ | * 0x01: CONFIG - Configuration register | ||
+ | * 0x02: Tupper - Alert temperature Upper boundary trip register | ||
+ | * 0x03: Tlower - Alert temperature Lower boundary trip register | ||
+ | * 0x04: Tcrit - Critical temperature trip register | ||
+ | * 0x05: Ta - Temperature register | ||
+ | * 0x06: - Manufacurer ID register (Reads 0x54) | ||
+ | * 0x07: - Device ID/Revision register | ||
+ | * 0x08: - Resolution register | ||
+ | * 0x09-0x0F - Reserved.... | ||
+ | */ | ||
+ | |||
+ | #define CONFIG_REG 0x01 | ||
+ | #define TUPPER_REG 0x02 | ||
+ | #define TLOWER_REG 0x03 | ||
+ | #define TCRIT_REG 0x04 | ||
+ | #define TA_REG 0x05 | ||
+ | #define MANID_REG 0x06 | ||
+ | #define DEVID_REG 0x07 | ||
+ | #define RES_REG 0x08 | ||
+ | |||
+ | //Device specific information. (Perhaps better as command options or config file) | ||
+ | #define MPC9808_BUS "/dev/i2c-2" | ||
+ | #define MPC9808_ADR 0x18 | ||
+ | |||
+ | struct MCP9808_tareg { | ||
+ | unsigned deg_fraction :4; | ||
+ | unsigned deg :8; | ||
+ | unsigned sign :1; | ||
+ | unsigned t_lower :1; | ||
+ | unsigned t_upper :1; | ||
+ | unsigned t_crit :1; | ||
+ | }; | ||
+ | |||
+ | typedef union { | ||
+ | uint16_t reg16; | ||
+ | struct MCP9808_tareg field; | ||
+ | } ta_t; | ||
+ | |||
+ | |||
+ | |||
+ | |||
+ | //Solution 1 | ||
+ | float solution1(int32_t ta_reg) { | ||
+ | |||
+ | float temperature; | ||
+ | ta_t ta; | ||
+ | ta.reg16 = (uint16_t) ta_reg; | ||
+ | |||
+ | temperature = ta.field.deg + (float) ta.field.deg_fraction/16; | ||
+ | if (ta.field.sign == 1) | ||
+ | temperature = -temperature; | ||
+ | return(temperature); | ||
+ | } | ||
+ | |||
+ | |||
+ | int i2c_init(char *bus, unsigned int address) { | ||
+ | int file; | ||
+ | |||
+ | file = open(bus, O_RDWR); | ||
+ | if (file < 0) { // If error | ||
+ | fprintf(stderr, "ERROR: opening %s - %s\n", bus, strerror(errno)); | ||
+ | exit(1); | ||
+ | } | ||
+ | |||
+ | if (ioctl(file, I2C_SLAVE, address) == -1 ) { // If error | ||
+ | fprintf(stderr, "ERROR: setting address %d on i2c bus %s with ioctl() - %s", address, bus, strerror(errno) ); | ||
+ | exit(1); | ||
+ | } | ||
+ | return(file); | ||
+ | } | ||
+ | /* TODO | ||
+ | * anden c fil med read/write 8/16 og init | ||
+ | * Der skal være konfigurerbar recovery mulighed returner uint8/16_t data direkte eller exit'er (Er bswapet) | ||
+ | * Måske funktioner der returnerer int_32 med -1 ved fejl | ||
+ | */ | ||
+ | int main( void ) { | ||
+ | char revision; //To store MCP9808 revision ID - Perhaps useful in the future | ||
+ | int file; | ||
+ | char buf[20]; | ||
+ | int32_t reg32; | ||
+ | uint16_t * const reg16poi = (uint16_t *) ®32; //Address reg32 wordwise | ||
+ | uint8_t * const reg8poi = (uint8_t *) ®32; //Address reg32 bytewise | ||
+ | file = i2c_init(MPC9808_BUS, MPC9808_ADR); | ||
+ | |||
+ | // Read manufactorer ID | ||
+ | // Note: i2c_smbus_read_word_data returns in big-endian | ||
+ | // bit 0-7 = reg8poi[1] and bit 8-15 = reg8poi[0] | ||
+ | reg32 = i2c_smbus_read_word_data(file, MANID_REG); | ||
+ | if ( reg32 < 0 ) { | ||
+ | fprintf(stderr, "ERROR: Read failed on i2c bus register %d - %s\n", MANID_REG,strerror(errno) ); | ||
+ | exit(1); | ||
+ | } | ||
+ | if ( bswap_16(reg16poi[0]) != 0x0054 ) { // Check manufactorer ID - Big endian 5400 and not 0054 | ||
+ | fprintf(stderr, "Manufactorer ID wrong is 0x%x should be 0x54\n",reg16poi[0]); | ||
+ | exit(1); | ||
+ | } | ||
+ | // Read device ID and revision | ||
+ | reg32 = i2c_smbus_read_word_data(file, DEVID_REG); | ||
+ | if ( reg32 < 0 ) { | ||
+ | fprintf(stderr, "ERROR: Read failed on i2c bus register %d - %s\n", DEVID_REG,strerror(errno) ); | ||
+ | exit(1); | ||
+ | } | ||
+ | if ( reg8poi[0] != 0x04 ) { // Check device ID - Big endian 0400 and not 0004 | ||
+ | fprintf(stderr, "Manufactorer ID OK but device ID wrong is 0x%x should be 0x4\n",reg8poi[0]); | ||
+ | exit(1); | ||
+ | } | ||
+ | revision = reg8poi[1]; | ||
+ | /*DEBUG*/ printf("All good :-)\n"); | ||
+ | |||
+ | // Read temperature... | ||
+ | float temperature; | ||
+ | reg32 = i2c_smbus_read_word_data(file, TA_REG); | ||
+ | |||
+ | // Solution 1 | ||
+ | temperature = solution1(reg32); | ||
+ | printf("Solution 1 temperature: %.2f\n",temperature); | ||
+ | |||
+ | // Solution 2 | ||
+ | reg8poi[1] &= 0x1f; | ||
+ | temperature = (float) reg8poi[1] * 16 + (float) reg8poi[0] / 16; | ||
+ | printf("Solution 2 temperature: %.2f\n",temperature); | ||
+ | |||
+ | return(0); | ||
+ | } | ||
+ | --> | ||
+ | [[Category:C]][[Category:Linux]][[Category:Grove]] |
Latest revision as of 10:08, 5 April 2024
Seeds I2C High Accuracy Temerature Sensor is based on the device MCP9808 from Microchip.
Linux example code
/*
* Module...: MCP9808example1.c
* Version..: 0.1 (Beta - unfinished)
* Author...: Henrik Thomsen/Mercantec <heth@mercantec.dk
* Date.....: 24. nov 2020
*
* Abstract.: Implementation of Seeed Grove Sensor "I2C High
* Accuracy Temperature sensor" based on MCP-9808
* Implementet in user space using libi2c
* Mod. log.: 01-06-2021: Could not compile. Got i2c_smbus_read_word_data undefined.
Include <i2c/smbus.h> should be include. (Worked in 2020)
* License..: Free open software but WITHOUT ANY WARRANTY.
* Terms....: see http://www.gnu.org/licenses
*
* Documentation - see https://mars.merhot.dk/w/index.php/Grove_I2C_High_Accuracy_Temerature_Sensor_-_Seeed
*
* REMEMBER: Install the libi2c-dev package to compile this file
* Compile this example with: gcc i2c_MCP9808-example1.c -o i2c_MCP9808-example1 -li2c
*
* See also: https://www.kernel.org/doc/Documentation/i2c/dev-interface
*/
#include <stdio.h>
#include <unistd.h>
#include <stdint.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <linux/i2c-dev.h>
#include <i2c/smbus.h> // Added 01062021 HeTh
#include <byteswap.h>
/* The MCP9808 Digital temperature sensor IC from Microchip is a i2c/SMBus compatible
* device. To understand this code you need access to MCP9808 Datasheet from Microchip
*
* The device is implementet on Seeed Studios Grove I2C high accuracy Temperature Sensor
*
* Links and supplemental information can be found on tthe documentation link in this
* files header.
*
* The MCP9808 contains severel registers:
*
* Register addresses:
* 0x00: RFU - (Reserved for future use) Read only
* 0x01: CONFIG - Configuration register
* 0x02: Tupper - Alert temperature Upper boundary trip register
* 0x03: Tlower - Alert temperature Lower boundary trip register
* 0x04: Tcrit - Critical temperature trip register
* 0x05: Ta - Temperature register
* 0x06: - Manufacurer ID register (Reads 0x54)
* 0x07: - Device ID/Revision register
* 0x08: - Resolution register
* 0x09-0x0F - Reserved....
*/
#define CONFIG_REG 0x01
#define TUPPER_REG 0x02
#define TLOWER_REG 0x03
#define TCRIT_REG 0x04
#define TA_REG 0x05
#define MANID_REG 0x06
#define DEVID_REG 0x07
#define RES_REG 0x08
//Device specific information. (Perhaps better as command options or config file)
#define MPC9808_BUS "/dev/i2c-2"
#define MPC9808_ADR 0x18
int i2c_init(char *bus, unsigned int address) {
int file;
file = open(bus, O_RDWR);
if (file < 0) { // If error
fprintf(stderr, "ERROR: opening %s - %s\n", bus, strerror(errno));
exit(1);
}
if (ioctl(file, I2C_SLAVE, address) == -1 ) { // If error
fprintf(stderr, "ERROR: setting address %d on i2c bus %s with ioctl() - %s", address, bus, strerror(errno) );
exit(1);
}
return(file);
}
/* TODO
* anden c fil med read/write 8/16 og init
* Der skal være konfigurerbar recovery mulighed returner uint8/16_t data direkte eller exit'er (Er bswapet)
* Måske funktioner der returnerer int_32 med -1 ved fejl
*/
int main( void ) {
char revision; //To store MCP9808 revision ID - Perhaps useful in the future
int file;
char buf[20];
int32_t reg32;
uint16_t * const reg16poi = (uint16_t *) ®32; //Address reg32 wordwise
uint8_t * const reg8poi = (uint8_t *) ®32; //Address reg32 bytewise
file = i2c_init(MPC9808_BUS, MPC9808_ADR);
// Read manufactorer ID
// Note: i2c_smbus_read_word_data returns in big-endian
// bit 0-7 = reg8poi[1] and bit 8-15 = reg8poi[0]
reg32 = i2c_smbus_read_word_data(file, MANID_REG);
if ( reg32 < 0 ) {
fprintf(stderr, "ERROR: Read failed on i2c bus register %d - %s\n", MANID_REG,strerror(errno) );
exit(1);
}
if ( bswap_16(reg16poi[0]) != 0x0054 ) { // Check manufactorer ID - Big endian 5400 and not 0054
fprintf(stderr, "Manufactorer ID wrong is 0x%x should be 0x54\n",__bswap_16(reg16poi[0]));
exit(1);
}
// Read device ID and revision
reg32 = i2c_smbus_read_word_data(file, DEVID_REG);
if ( reg32 < 0 ) {
fprintf(stderr, "ERROR: Read failed on i2c bus register %d - %s\n", DEVID_REG,strerror(errno) );
exit(1);
}
if ( reg8poi[0] != 0x04 ) { // Check device ID - Big endian 0400 and not 0004
fprintf(stderr, "Manufactorer ID OK but device ID wrong is 0x%x should be 0x4\n",reg8poi[0]);
exit(1);
}
revision = reg8poi[1];
/*DEBUG*/ printf("All good :-)\n");
// Read temperature...
return(0);