]> jspc29.x-matter.uni-frankfurt.de Git - avr.git/commitdiff
add BME280 to sensor board code
authorJan Michel <j.michel@gsi.de>
Sun, 22 Apr 2018 14:23:27 +0000 (16:23 +0200)
committerJan Michel <j.michel@gsi.de>
Sun, 22 Apr 2018 14:23:27 +0000 (16:23 +0200)
add flag to select type of PCB
TSL2591 included but not yet working

sensors/MagneticFieldSensor/BME280.c [new file with mode: 0644]
sensors/MagneticFieldSensor/BME280.h [new file with mode: 0644]
sensors/MagneticFieldSensor/Makefile
sensors/MagneticFieldSensor/TSL2591.c [new file with mode: 0644]
sensors/MagneticFieldSensor/TSL2591.h [new file with mode: 0644]
sensors/MagneticFieldSensor/main.c
sensors/MagneticFieldSensor/main.h
sensors/MagneticFieldSensor/readme

diff --git a/sensors/MagneticFieldSensor/BME280.c b/sensors/MagneticFieldSensor/BME280.c
new file mode 100644 (file)
index 0000000..75169d8
--- /dev/null
@@ -0,0 +1,183 @@
+#include "main.h"\r
+\r
+uint8_t InitBME(BME280* bme280){\r
+\r
+       uint8_t dataToWrite = 0;  //Temporary variable\r
+       \r
+       //Reading all compensation data, range 0x88:A1, 0xE1:E7\r
+       bme280->calibration.dig_T1 = ((uint16_t)((readRegister(bme280->settings.I2CAddress,BME280_DIG_T1_MSB_REG) << 8) + readRegister(bme280->settings.I2CAddress,BME280_DIG_T1_LSB_REG)));\r
+       bme280->calibration.dig_T2 = ((int16_t)((readRegister(bme280->settings.I2CAddress,BME280_DIG_T2_MSB_REG) << 8) + readRegister(bme280->settings.I2CAddress,BME280_DIG_T2_LSB_REG)));\r
+       bme280->calibration.dig_T3 = ((int16_t)((readRegister(bme280->settings.I2CAddress,BME280_DIG_T3_MSB_REG) << 8) + readRegister(bme280->settings.I2CAddress,BME280_DIG_T3_LSB_REG)));\r
+\r
+       bme280->calibration.dig_P1 = ((uint16_t)((readRegister(bme280->settings.I2CAddress,BME280_DIG_P1_MSB_REG) << 8) + readRegister(bme280->settings.I2CAddress,BME280_DIG_P1_LSB_REG)));\r
+       bme280->calibration.dig_P2 = ((int16_t)((readRegister(bme280->settings.I2CAddress,BME280_DIG_P2_MSB_REG) << 8) + readRegister(bme280->settings.I2CAddress,BME280_DIG_P2_LSB_REG)));\r
+       bme280->calibration.dig_P3 = ((int16_t)((readRegister(bme280->settings.I2CAddress,BME280_DIG_P3_MSB_REG) << 8) + readRegister(bme280->settings.I2CAddress,BME280_DIG_P3_LSB_REG)));\r
+       bme280->calibration.dig_P4 = ((int16_t)((readRegister(bme280->settings.I2CAddress,BME280_DIG_P4_MSB_REG) << 8) + readRegister(bme280->settings.I2CAddress,BME280_DIG_P4_LSB_REG)));\r
+       bme280->calibration.dig_P5 = ((int16_t)((readRegister(bme280->settings.I2CAddress,BME280_DIG_P5_MSB_REG) << 8) + readRegister(bme280->settings.I2CAddress,BME280_DIG_P5_LSB_REG)));\r
+       bme280->calibration.dig_P6 = ((int16_t)((readRegister(bme280->settings.I2CAddress,BME280_DIG_P6_MSB_REG) << 8) + readRegister(bme280->settings.I2CAddress,BME280_DIG_P6_LSB_REG)));\r
+       bme280->calibration.dig_P7 = ((int16_t)((readRegister(bme280->settings.I2CAddress,BME280_DIG_P7_MSB_REG) << 8) + readRegister(bme280->settings.I2CAddress,BME280_DIG_P7_LSB_REG)));\r
+       bme280->calibration.dig_P8 = ((int16_t)((readRegister(bme280->settings.I2CAddress,BME280_DIG_P8_MSB_REG) << 8) + readRegister(bme280->settings.I2CAddress,BME280_DIG_P8_LSB_REG)));\r
+       bme280->calibration.dig_P9 = ((int16_t)((readRegister(bme280->settings.I2CAddress,BME280_DIG_P9_MSB_REG) << 8) + readRegister(bme280->settings.I2CAddress,BME280_DIG_P9_LSB_REG)));\r
+\r
+       bme280->calibration.dig_H1 = ((uint8_t)(readRegister(bme280->settings.I2CAddress,BME280_DIG_H1_REG)));\r
+       bme280->calibration.dig_H2 = ((int16_t)((readRegister(bme280->settings.I2CAddress,BME280_DIG_H2_MSB_REG) << 8) + readRegister(bme280->settings.I2CAddress,BME280_DIG_H2_LSB_REG)));\r
+       bme280->calibration.dig_H3 = ((uint8_t)(readRegister(bme280->settings.I2CAddress,BME280_DIG_H3_REG)));\r
+       bme280->calibration.dig_H4 = ((int16_t)((readRegister(bme280->settings.I2CAddress,BME280_DIG_H4_MSB_REG) << 4) + (readRegister(bme280->settings.I2CAddress,BME280_DIG_H4_LSB_REG) & 0x0F)));\r
+       bme280->calibration.dig_H5 = ((int16_t)((readRegister(bme280->settings.I2CAddress,BME280_DIG_H5_MSB_REG) << 4) + ((readRegister(bme280->settings.I2CAddress,BME280_DIG_H4_LSB_REG) >> 4) & 0x0F)));\r
+       bme280->calibration.dig_H6 = ((uint8_t)readRegister(bme280->settings.I2CAddress,BME280_DIG_H6_REG));   \r
+\r
+       //Set the oversampling control words.\r
+       //config will only be writeable in sleep mode, so first insure that.\r
+       writeRegister(bme280->settings.I2CAddress,BME280_CTRL_MEAS_REG, 0x00);\r
+\r
+       //Set the config word\r
+       dataToWrite = (bme280->settings.tStandby << 0x5) & 0xE0;\r
+       dataToWrite |= (bme280->settings.filter << 0x02) & 0x1C;\r
+       writeRegister(bme280->settings.I2CAddress,BME280_CONFIG_REG, dataToWrite);\r
+       \r
+       //Set ctrl_hum first, then ctrl_meas to activate ctrl_hum\r
+       dataToWrite = bme280->settings.humidOverSample & 0x07; //all other bits can be ignored\r
+       writeRegister(bme280->settings.I2CAddress,BME280_CTRL_HUMIDITY_REG, dataToWrite);\r
+       \r
+       //set ctrl_meas\r
+       //First, set temp oversampling\r
+       dataToWrite = (bme280->settings.tempOverSample << 0x5) & 0xE0;\r
+       //Next, pressure oversampling\r
+\r
+       dataToWrite |= (bme280->settings.pressOverSample << 0x02) & 0x1C;\r
+       //Last, set mode\r
+       dataToWrite |= (bme280->settings.runMode) & 0x03;\r
+       //Load the byte\r
+       writeRegister(bme280->settings.I2CAddress,BME280_CTRL_MEAS_REG, dataToWrite);\r
+\r
+   return readRegister(bme280->settings.I2CAddress,0xD0);\r
+}\r
+\r
+\r
+//Strictly resets.  Run .begin() afterwards\r
+void reset( BME280* bme280)\r
+{\r
+       writeRegister(bme280->settings.I2CAddress,BME280_RST_REG, 0xB6);\r
+}\r
+\r
+\r
+float readFloatPressure( BME280 *bme280)\r
+{\r
+\r
+       // Returns pressure in Pa as unsigned 32 bit integer in Q24.8 format (24 integer bits and 8 fractional bits).\r
+       // Output value of “24674867” represents 24674867/256 = 96386.2 Pa = 963.862 hPa\r
+       int32_t adc_P = ((uint32_t)readRegister(bme280->settings.I2CAddress,BME280_PRESSURE_MSB_REG) << 12) | ((uint32_t)readRegister(bme280->settings.I2CAddress,BME280_PRESSURE_LSB_REG) << 4) | ((readRegister(bme280->settings.I2CAddress,BME280_PRESSURE_XLSB_REG) >> 4) & 0x0F);\r
+       \r
+       int64_t var1, var2, p_acc;\r
+       var1 = ((int64_t)bme280->t_fine) - 128000;\r
+       var2 = var1 * var1 * (int64_t)bme280->calibration.dig_P6;\r
+       var2 = var2 + ((var1 * (int64_t)bme280->calibration.dig_P5)<<17);\r
+       var2 = var2 + (((int64_t)bme280->calibration.dig_P4)<<35);\r
+       var1 = ((var1 * var1 * (int64_t)bme280->calibration.dig_P3)>>8) + ((var1 * (int64_t)bme280->calibration.dig_P2)<<12);\r
+       var1 = (((((int64_t)1)<<47)+var1))*((int64_t)bme280->calibration.dig_P1)>>33;\r
+       if (var1 == 0)\r
+       {\r
+               return 0; // avoid exception caused by division by zero\r
+       }\r
+       p_acc = 1048576 - adc_P;\r
+       p_acc = (((p_acc<<31) - var2)*3125)/var1;\r
+       var1 = (((int64_t)bme280->calibration.dig_P9) * (p_acc>>13) * (p_acc>>13)) >> 25;\r
+       var2 = (((int64_t)bme280->calibration.dig_P8) * p_acc) >> 19;\r
+       p_acc = ((p_acc + var1 + var2) >> 8) + (((int64_t)bme280->calibration.dig_P7)<<4);\r
+       \r
+       return (float)p_acc / 256.0;\r
+       \r
+}\r
+\r
+\r
+float readFloatHumidity( BME280* bme280 )\r
+{\r
+       // Returns humidity in %RH as unsigned 32 bit integer in Q22. 10 format (22 integer and 10 fractional bits).\r
+       // Output value of “47445” represents 47445/1024 = 46. 333 %RH\r
+       int32_t adc_H = ((uint32_t)readRegister(bme280->settings.I2CAddress,BME280_HUMIDITY_MSB_REG) << 8) | ((uint32_t)readRegister(bme280->settings.I2CAddress,BME280_HUMIDITY_LSB_REG));\r
+       \r
+       int32_t var1;\r
+       var1 = (bme280->t_fine - ((int32_t)76800));\r
+       var1 = (((((adc_H << 14) - (((int32_t)bme280->calibration.dig_H4) << 20) - (((int32_t)bme280->calibration.dig_H5) * var1)) +\r
+       ((int32_t)16384)) >> 15) * (((((((var1 * ((int32_t)bme280->calibration.dig_H6)) >> 10) * (((var1 * ((int32_t)bme280->calibration.dig_H3)) >> 11) + ((int32_t)32768))) >> 10) + ((int32_t)2097152)) *\r
+       ((int32_t)bme280->calibration.dig_H2) + 8192) >> 14));\r
+       var1 = (var1 - (((((var1 >> 15) * (var1 >> 15)) >> 7) * ((int32_t)bme280->calibration.dig_H1)) >> 4));\r
+       var1 = (var1 < 0 ? 0 : var1);\r
+       var1 = (var1 > 419430400 ? 419430400 : var1);\r
+\r
+       return (float)(var1>>12) / 1024.0;\r
+}\r
+\r
+\r
+float readTempC( BME280* bme280 )\r
+{\r
+       // Returns temperature in DegC, resolution is 0.01 DegC. Output value of “5123” equals 51.23 DegC.\r
+       // t_fine carries fine temperature as global value\r
+\r
+       //get the reading (adc_T);\r
+       int32_t adc_T = ((uint32_t)readRegister(bme280->settings.I2CAddress,BME280_TEMPERATURE_MSB_REG) << 12) | ((uint32_t)readRegister(bme280->settings.I2CAddress,BME280_TEMPERATURE_LSB_REG) << 4) | ((readRegister(bme280->settings.I2CAddress,BME280_TEMPERATURE_XLSB_REG) >> 4) & 0x0F);\r
+\r
+       //By datasheet, calibrate\r
+       int64_t var1, var2;\r
+\r
+       var1 = ((((adc_T>>3) - ((int32_t)bme280->calibration.dig_T1<<1))) * ((int32_t)bme280->calibration.dig_T2)) >> 11;\r
+       var2 = (((((adc_T>>4) - ((int32_t)bme280->calibration.dig_T1)) * ((adc_T>>4) - ((int32_t)bme280->calibration.dig_T1))) >> 12) *\r
+       ((int32_t)bme280->calibration.dig_T3)) >> 14;\r
+       bme280->t_fine = var1 + var2;\r
+       float output = (bme280->t_fine * 5 + 128) >> 8;\r
+\r
+       output = output / 100;\r
+       \r
+       return output;\r
+}\r
+\r
+\r
+void readRegisterRegion(uint8_t Addr, uint8_t *outputPointer , uint8_t offset, uint8_t length)\r
+{\r
+       //define pointer that will point to the external space\r
+       ///uint8_t i = 0;\r
+       uint8_t c = 0;\r
+       twi_writeTo(Addr,&offset,1,1,true);\r
+\r
+       for(int i = 0 ; i<length;i++){\r
+         // request bytes from slave device\r
+          if (i < length-1){\r
+            twi_readFrom(Addr, &c, 1, false);\r
+         }else {\r
+            twi_readFrom(Addr, &c, 1, true);\r
+         }\r
+         *outputPointer = c;\r
+         outputPointer++;\r
+       }\r
+\r
+}\r
+\r
+uint8_t readRegister(uint8_t Addr, uint8_t offset)\r
+{\r
+       //Return value\r
+       uint8_t result;\r
+\r
+        twi_writeTo(Addr, &offset,1,1,true);\r
+        twi_readFrom(Addr, &result, 1, true);\r
+\r
+       \r
+       return result;\r
+}\r
+\r
+int16_t readRegisterInt16(uint8_t Addr, uint8_t offset )\r
+{\r
+       uint8_t myBuffer[2];\r
+       readRegisterRegion(Addr, myBuffer, offset, 2);  //Does memory transfer\r
+       int16_t output = (int16_t)myBuffer[0] | (int16_t)(myBuffer[1] << 8);\r
+       \r
+       return output;\r
+}\r
+\r
+void writeRegister(uint8_t Addr,uint8_t offset, uint8_t dataToWrite)\r
+{\r
+       //Write the byte\r
+       uint8_t value[2];\r
+       value[0]=offset;\r
+       value[1]=dataToWrite;\r
+       twi_writeTo(Addr,value,2,1,true);\r
+}\r
diff --git a/sensors/MagneticFieldSensor/BME280.h b/sensors/MagneticFieldSensor/BME280.h
new file mode 100644 (file)
index 0000000..2c8cbcf
--- /dev/null
@@ -0,0 +1,167 @@
+/******************************************************************************\r
+SparkFunBME280.h\r
+BME280 Arduino and Teensy Driver\r
+Marshall Taylor @ SparkFun Electronics\r
+May 20, 2015\r
+https://github.com/sparkfun/BME280_Breakout\r
+\r
+Resources:\r
+Uses Wire.h for i2c operation\r
+Uses SPI.h for SPI operation\r
+\r
+Development environment specifics:\r
+Arduino IDE 1.6.4\r
+Teensy loader 1.23\r
+\r
+This code is released under the [MIT License](http://opensource.org/licenses/MIT).\r
+Please review the LICENSE.md file included with this example. If you have any questions \r
+or concerns with licensing, please contact techsupport@sparkfun.com.\r
+Distributed as-is; no warranty is given.\r
+******************************************************************************/\r
+\r
+// Test derived class for base class SparkFunIMU\r
+#ifndef __BME280_H__\r
+#define __BME280_H__\r
+\r
+//#include "stdint.h"\r
+#include "main.h"\r
+\r
+#define I2C_MODE 0\r
+#define SPI_MODE 1\r
+\r
+//Register names:\r
+#define BME280_DIG_T1_LSB_REG                  0x88\r
+#define BME280_DIG_T1_MSB_REG                  0x89\r
+#define BME280_DIG_T2_LSB_REG                  0x8A\r
+#define BME280_DIG_T2_MSB_REG                  0x8B\r
+#define BME280_DIG_T3_LSB_REG                  0x8C\r
+#define BME280_DIG_T3_MSB_REG                  0x8D\r
+#define BME280_DIG_P1_LSB_REG                  0x8E\r
+#define BME280_DIG_P1_MSB_REG                  0x8F\r
+#define BME280_DIG_P2_LSB_REG                  0x90\r
+#define BME280_DIG_P2_MSB_REG                  0x91\r
+#define BME280_DIG_P3_LSB_REG                  0x92\r
+#define BME280_DIG_P3_MSB_REG                  0x93\r
+#define BME280_DIG_P4_LSB_REG                  0x94\r
+#define BME280_DIG_P4_MSB_REG                  0x95\r
+#define BME280_DIG_P5_LSB_REG                  0x96\r
+#define BME280_DIG_P5_MSB_REG                  0x97\r
+#define BME280_DIG_P6_LSB_REG                  0x98\r
+#define BME280_DIG_P6_MSB_REG                  0x99\r
+#define BME280_DIG_P7_LSB_REG                  0x9A\r
+#define BME280_DIG_P7_MSB_REG                  0x9B\r
+#define BME280_DIG_P8_LSB_REG                  0x9C\r
+#define BME280_DIG_P8_MSB_REG                  0x9D\r
+#define BME280_DIG_P9_LSB_REG                  0x9E\r
+#define BME280_DIG_P9_MSB_REG                  0x9F\r
+#define BME280_DIG_H1_REG                              0xA1\r
+#define BME280_CHIP_ID_REG                             0xD0 //Chip ID\r
+#define BME280_RST_REG                                 0xE0 //Softreset Reg\r
+#define BME280_DIG_H2_LSB_REG                  0xE1\r
+#define BME280_DIG_H2_MSB_REG                  0xE2\r
+#define BME280_DIG_H3_REG                              0xE3\r
+#define BME280_DIG_H4_MSB_REG                  0xE4\r
+#define BME280_DIG_H4_LSB_REG                  0xE5\r
+#define BME280_DIG_H5_MSB_REG                  0xE6\r
+#define BME280_DIG_H6_REG                              0xE7\r
+#define BME280_CTRL_HUMIDITY_REG               0xF2 //Ctrl Humidity Reg\r
+#define BME280_STAT_REG                                        0xF3 //Status Reg\r
+#define BME280_CTRL_MEAS_REG                   0xF4 //Ctrl Measure Reg\r
+#define BME280_CONFIG_REG                              0xF5 //Configuration Reg\r
+#define BME280_PRESSURE_MSB_REG                        0xF7 //Pressure MSB\r
+#define BME280_PRESSURE_LSB_REG                        0xF8 //Pressure LSB\r
+#define BME280_PRESSURE_XLSB_REG               0xF9 //Pressure XLSB\r
+#define BME280_TEMPERATURE_MSB_REG             0xFA //Temperature MSB\r
+#define BME280_TEMPERATURE_LSB_REG             0xFB //Temperature LSB\r
+#define BME280_TEMPERATURE_XLSB_REG            0xFC //Temperature XLSB\r
+#define BME280_HUMIDITY_MSB_REG                        0xFD //Humidity MSB\r
+#define BME280_HUMIDITY_LSB_REG                        0xFE //Humidity LSB\r
+\r
+\r
+//Class SensorSettings.  This object is used to hold settings data.  The application\r
+//uses this classes' data directly.  The settings are adopted and sent to the sensor\r
+//at special times, such as .begin.  Some are used for doing math.\r
+//\r
+//This is a kind of bloated way to do this.  The trade-off is that the user doesn't\r
+//need to deal with #defines or enums with bizarre names.\r
+//\r
+//A power user would strip out SensorSettings entirely, and send specific read and\r
+//write command directly to the IC. (ST #defines below)\r
+//\r
+typedef struct\r
+{\r
+  //Main Interface and mode settings\r
+    uint8_t commInterface;\r
+    uint8_t I2CAddress;\r
+    uint8_t chipSelectPin;\r
+    uint8_t runMode;\r
+    uint8_t tStandby;\r
+    uint8_t filter;\r
+    uint8_t tempOverSample;\r
+    uint8_t pressOverSample;\r
+    uint8_t humidOverSample;\r
+} SensorSettings;\r
+\r
+//Used to hold the calibration constants.  These are used\r
+//by the driver as measurements are being taking\r
+typedef struct\r
+{\r
+    uint16_t dig_T1;\r
+    int16_t dig_T2;\r
+    int16_t dig_T3;    \r
+\r
+    uint16_t dig_P1;\r
+    int16_t dig_P2;\r
+    int16_t dig_P3;\r
+    int16_t dig_P4;\r
+    int16_t dig_P5;\r
+    int16_t dig_P6;\r
+    int16_t dig_P7;\r
+    int16_t dig_P8;\r
+    int16_t dig_P9;\r
+       \r
+    uint8_t dig_H1;\r
+    int16_t dig_H2;\r
+    uint8_t dig_H3;\r
+    int16_t dig_H4;\r
+    int16_t dig_H5;\r
+    uint8_t dig_H6;    \r
+} SensorCalibration;\r
+\r
+//This is the man operational class of the driver.\r
+\r
+typedef struct {\r
+    //settings\r
+    SensorSettings settings;\r
+    SensorCalibration calibration;\r
+    int32_t t_fine;\r
+} BME280;\r
+\r
+    \r
+    //Init Sensor    \r
+    uint8_t InitBME(BME280* bme280);\r
+\r
+    //Software reset routine\r
+    void reset( BME280* bme280);\r
+\r
+    //Returns the values as floats.\r
+    float readFloatPressure( BME280* bme280 );\r
+       \r
+    float readFloatHumidity( BME280* bme280 );\r
+\r
+    float readTempC( BME280* bme280 );\r
+\r
+    //The following utilities read and write\r
+\r
+    //ReadRegisterRegion takes a uint8 array address as input and reads\r
+    //a chunk of memory into that array.\r
+    void readRegisterRegion(uint8_t Addr, uint8_t*, uint8_t, uint8_t );\r
+    //readRegister reads one register\r
+    uint8_t readRegister(uint8_t, uint8_t);\r
+    //Reads two regs, LSByte then MSByte order, and concatenates them\r
+    //Used for two-byte reads\r
+    int16_t readRegisterInt16(uint8_t Addr,  uint8_t offset );\r
+    //Writes a byte;\r
+    void writeRegister(uint8_t, uint8_t, uint8_t);\r
+   \r
+#endif  // End of __BME280_H__ definition check\r
index 626dfd14e552cb5229b5ff401c516bf855b7dc2b..3b99831e2bd86ebdc729cdd5b8ab3509524dc86a 100644 (file)
@@ -9,7 +9,7 @@
 MCU = atmega328p\r
 FORMAT = ihex\r
 TARGET = main\r
-SRC = $(TARGET).c  uart/uart.c twi/twi.c MagnetSensor.c\r
+SRC = $(TARGET).c  uart/uart.c twi/twi.c MagnetSensor.c BME280.c TSL2591.c\r
 ASRC = \r
 OPT = 2\r
 \r
diff --git a/sensors/MagneticFieldSensor/TSL2591.c b/sensors/MagneticFieldSensor/TSL2591.c
new file mode 100644 (file)
index 0000000..e79da1d
--- /dev/null
@@ -0,0 +1,203 @@
+/*#include <avr/pgmspace.h>
+#include <util/delay.h>
+#include <stdlib.h>
+*/
+#include "TSL2591.h"
+
+void Init_TSL2591(TSL2591* tsl)
+{
+  tsl->_initialized = true;
+  tsl->_integration = TSL2591_INTEGRATIONTIME_100MS;
+  tsl->_gain        = TSL2591_GAIN_MED;
+  TSL2591_setTiming(tsl, tsl->_integration);
+  TSL2591_setGain(tsl, tsl->_gain);
+  TSL2591_disable();
+}
+
+
+void TSL2591_enable()
+{
+  // Enable the device by setting the control bit to 0x01
+  TSL2591_write8(TSL2591_COMMAND_BIT | TSL2591_REGISTER_ENABLE, TSL2591_ENABLE_POWERON | TSL2591_ENABLE_AEN | TSL2591_ENABLE_AIEN | TSL2591_ENABLE_NPIEN);
+}
+
+void TSL2591_disable()
+{
+  // Disable the device by setting the control bit to 0x00
+  TSL2591_write8(TSL2591_COMMAND_BIT | TSL2591_REGISTER_ENABLE, TSL2591_ENABLE_POWEROFF);
+}
+
+void TSL2591_setGain(TSL2591* tsl, tsl2591Gain_t gain)
+{
+  TSL2591_enable();
+  tsl->_gain = gain;
+  TSL2591_write8(TSL2591_COMMAND_BIT | TSL2591_REGISTER_CONTROL, tsl->_integration | tsl->_gain);
+  TSL2591_disable();
+}
+
+tsl2591Gain_t TSL2591_getGain(TSL2591* tsl)
+{
+  return tsl->_gain;
+}
+
+void TSL2591_setTiming(TSL2591* tsl, tsl2591IntegrationTime_t integration)
+{
+  TSL2591_enable();
+  tsl->_integration = integration;
+  TSL2591_write8(TSL2591_COMMAND_BIT | TSL2591_REGISTER_CONTROL, tsl->_integration | tsl->_gain);
+  TSL2591_disable();
+}
+
+tsl2591IntegrationTime_t TSL2591_getTiming(TSL2591* tsl)
+{
+  return tsl->_integration;
+}
+
+uint32_t TSL2591_calculateLux(TSL2591* tsl, uint16_t ch0, uint16_t ch1)
+{
+  float    atime, again;
+  float    cpl, lux1, lux2, lux;
+  uint32_t chan0, chan1;
+
+  // Check for overflow conditions first
+  if ((ch0 == 0xFFFF) | (ch1 == 0xFFFF))
+  {
+    // Signal an overflow
+    return 0;
+  }
+
+  // Note: This algorithm is based on preliminary coefficients
+  // provided by AMS and may need to be updated in the future
+
+  switch (tsl->_integration)
+  {
+    case TSL2591_INTEGRATIONTIME_100MS :
+      atime = 100.0F;
+      break;
+    case TSL2591_INTEGRATIONTIME_200MS :
+      atime = 200.0F;
+      break;
+    case TSL2591_INTEGRATIONTIME_300MS :
+      atime = 300.0F;
+      break;
+    case TSL2591_INTEGRATIONTIME_400MS :
+      atime = 400.0F;
+      break;
+    case TSL2591_INTEGRATIONTIME_500MS :
+      atime = 500.0F;
+      break;
+    case TSL2591_INTEGRATIONTIME_600MS :
+      atime = 600.0F;
+      break;
+    default: // 100ms
+      atime = 100.0F;
+      break;
+  }
+
+  switch (tsl->_gain)
+  {
+    case TSL2591_GAIN_LOW :
+      again = 1.0F;
+      break;
+    case TSL2591_GAIN_MED :
+      again = 25.0F;
+      break;
+    case TSL2591_GAIN_HIGH :
+      again = 428.0F;
+      break;
+    case TSL2591_GAIN_MAX :
+      again = 9876.0F;
+      break;
+    default:
+      again = 1.0F;
+      break;
+  }
+
+  // cpl = (ATIME * AGAIN) / DF
+  cpl = (atime * again) / TSL2591_LUX_DF;
+
+  lux1 = ( (float)ch0 - (TSL2591_LUX_COEFB * (float)ch1) ) / cpl;
+  lux2 = ( ( TSL2591_LUX_COEFC * (float)ch0 ) - ( TSL2591_LUX_COEFD * (float)ch1 ) ) / cpl;
+  lux = lux1 > lux2 ? lux1 : lux2;
+
+  // Alternate lux calculation
+  //lux = ( (float)ch0 - ( 1.7F * (float)ch1 ) ) / cpl;
+
+  // Signal I2C had no errors
+  return (uint32_t)lux;
+}
+
+uint32_t TSL2591_getFullLuminosity (TSL2591* tsl)
+{
+  // Enable the device
+  TSL2591_enable();
+
+  // Wait x ms for ADC to complete
+  for (uint8_t d=0; d<=tsl->_integration; d++)
+  {
+    _delay_ms(120);
+  }
+
+  uint32_t x;
+  x = TSL2591_read16(TSL2591_COMMAND_BIT | TSL2591_REGISTER_CHAN1_LOW);
+  x <<= 16;
+  x |= TSL2591_read16(TSL2591_COMMAND_BIT | TSL2591_REGISTER_CHAN0_LOW);
+
+  TSL2591_disable();
+
+  return x;
+}
+
+uint16_t TSL2591_getLuminosity (TSL2591* tsl, uint8_t channel)
+{
+  uint32_t x = TSL2591_getFullLuminosity(tsl);
+
+  if (channel == TSL2591_FULLSPECTRUM)
+  {
+    // Reads two byte value from channel 0 (visible + infrared)
+    return (x & 0xFFFF);
+  }
+  else if (channel == TSL2591_INFRARED)
+  {
+    // Reads two byte value from channel 1 (infrared)
+    return (x >> 16);
+  }
+  else if (channel == TSL2591_VISIBLE)
+  {
+    // Reads all and subtracts out just the visible!
+    return ( (x & 0xFFFF) - (x >> 16));
+  }
+
+  // unknown channel!
+  return 0;
+}
+
+
+uint8_t TSL2591_read8(uint8_t reg)
+{
+  uint8_t x;
+  twi_writeTo(TSL2591_ADDR, &reg, 1,1, true);
+  twi_readFrom(TSL2591_ADDR, &x, 1, true);
+
+  return x;
+}
+
+uint16_t TSL2591_read16(uint8_t reg)
+{
+  uint16_t x[2];
+
+  twi_writeTo(TSL2591_ADDR, &reg, 1,1, true);
+  twi_readFrom(TSL2591_ADDR, x, 2, true);
+
+  x[1] <<= 8;
+  x[1] |= x[0];
+  return x;
+}
+
+void TSL2591_write8 (uint8_t reg, uint8_t value)
+{
+  uint8_t write_val[2] = {reg, value};
+  twi_writeTo(TSL2591_ADDR, reg, 2,1, true);
+}
+
+
diff --git a/sensors/MagneticFieldSensor/TSL2591.h b/sensors/MagneticFieldSensor/TSL2591.h
new file mode 100644 (file)
index 0000000..8da5cac
--- /dev/null
@@ -0,0 +1,121 @@
+#include "main.h"
+
+#ifndef _TSL2591_H_
+#define _TSL2591_H_
+
+#define TSL2591_VISIBLE           (2)       // channel 0 - channel 1
+#define TSL2591_INFRARED          (1)       // channel 1
+#define TSL2591_FULLSPECTRUM      (0)       // channel 0
+
+#define TSL2591_ADDR              (0x29)
+#define TSL2591_READBIT           (0x01)
+
+#define TSL2591_COMMAND_BIT       (0xA0)    // 1010 0000: bits 7 and 5 for 'command normal'
+#define TSL2591_CLEAR_INT         (0xE7)
+#define TSL2591_TEST_INT          (0xE4)
+#define TSL2591_WORD_BIT          (0x20)    // 1 = read/write word (rather than byte)
+#define TSL2591_BLOCK_BIT         (0x10)    // 1 = using block read/write
+
+#define TSL2591_ENABLE_POWEROFF   (0x00)
+#define TSL2591_ENABLE_POWERON    (0x01)
+#define TSL2591_ENABLE_AEN        (0x02)    // ALS Enable. This field activates ALS function. Writing a one activates the ALS. Writing a zero disables the ALS.
+#define TSL2591_ENABLE_AIEN       (0x10)    // ALS Interrupt Enable. When asserted permits ALS interrupts to be generated, subject to the persist filter.
+#define TSL2591_ENABLE_NPIEN      (0x80)    // No Persist Interrupt Enable. When asserted NP Threshold conditions will generate an interrupt, bypassing the persist filter
+
+#define TSL2591_LUX_DF            (408.0F)
+#define TSL2591_LUX_COEFB         (1.64F)  // CH0 coefficient 
+#define TSL2591_LUX_COEFC         (0.59F)  // CH1 coefficient A
+#define TSL2591_LUX_COEFD         (0.86F)  // CH2 coefficient B
+
+enum
+{
+  TSL2591_REGISTER_ENABLE             = 0x00,
+  TSL2591_REGISTER_CONTROL            = 0x01,
+  TSL2591_REGISTER_THRESHOLD_AILTL    = 0x04, // ALS low threshold lower byte
+  TSL2591_REGISTER_THRESHOLD_AILTH    = 0x05, // ALS low threshold upper byte
+  TSL2591_REGISTER_THRESHOLD_AIHTL    = 0x06, // ALS high threshold lower byte
+  TSL2591_REGISTER_THRESHOLD_AIHTH    = 0x07, // ALS high threshold upper byte
+  TSL2591_REGISTER_THRESHOLD_NPAILTL  = 0x08, // No Persist ALS low threshold lower byte
+  TSL2591_REGISTER_THRESHOLD_NPAILTH  = 0x09, // etc
+  TSL2591_REGISTER_THRESHOLD_NPAIHTL  = 0x0A,
+  TSL2591_REGISTER_THRESHOLD_NPAIHTH  = 0x0B,
+  TSL2591_REGISTER_PERSIST_FILTER     = 0x0C,
+  TSL2591_REGISTER_PACKAGE_PID        = 0x11,
+  TSL2591_REGISTER_DEVICE_ID          = 0x12,
+  TSL2591_REGISTER_DEVICE_STATUS      = 0x13,
+  TSL2591_REGISTER_CHAN0_LOW          = 0x14,
+  TSL2591_REGISTER_CHAN0_HIGH         = 0x15,
+  TSL2591_REGISTER_CHAN1_LOW          = 0x16,
+  TSL2591_REGISTER_CHAN1_HIGH         = 0x17
+};
+
+typedef enum
+{
+  TSL2591_INTEGRATIONTIME_100MS     = 0x00,
+  TSL2591_INTEGRATIONTIME_200MS     = 0x01,
+  TSL2591_INTEGRATIONTIME_300MS     = 0x02,
+  TSL2591_INTEGRATIONTIME_400MS     = 0x03,
+  TSL2591_INTEGRATIONTIME_500MS     = 0x04,
+  TSL2591_INTEGRATIONTIME_600MS     = 0x05,
+}
+tsl2591IntegrationTime_t;
+
+typedef enum
+{
+  //  bit 7:4: 0
+  TSL2591_PERSIST_EVERY             = 0x00, // Every ALS cycle generates an interrupt
+  TSL2591_PERSIST_ANY               = 0x01, // Any value outside of threshold range
+  TSL2591_PERSIST_2                 = 0x02, // 2 consecutive values out of range
+  TSL2591_PERSIST_3                 = 0x03, // 3 consecutive values out of range
+  TSL2591_PERSIST_5                 = 0x04, // 5 consecutive values out of range
+  TSL2591_PERSIST_10                = 0x05, // 10 consecutive values out of range
+  TSL2591_PERSIST_15                = 0x06, // 15 consecutive values out of range
+  TSL2591_PERSIST_20                = 0x07, // 20 consecutive values out of range
+  TSL2591_PERSIST_25                = 0x08, // 25 consecutive values out of range
+  TSL2591_PERSIST_30                = 0x09, // 30 consecutive values out of range
+  TSL2591_PERSIST_35                = 0x0A, // 35 consecutive values out of range
+  TSL2591_PERSIST_40                = 0x0B, // 40 consecutive values out of range
+  TSL2591_PERSIST_45                = 0x0C, // 45 consecutive values out of range
+  TSL2591_PERSIST_50                = 0x0D, // 50 consecutive values out of range
+  TSL2591_PERSIST_55                = 0x0E, // 55 consecutive values out of range
+  TSL2591_PERSIST_60                = 0x0F, // 60 consecutive values out of range
+}
+tsl2591Persist_t;
+
+typedef enum
+{
+  TSL2591_GAIN_LOW                  = 0x00,    // low gain (1x)
+  TSL2591_GAIN_MED                  = 0x10,    // medium gain (25x)
+  TSL2591_GAIN_HIGH                 = 0x20,    // medium gain (428x)
+  TSL2591_GAIN_MAX                  = 0x30,    // max gain (9876x)
+}
+tsl2591Gain_t;
+
+typedef struct {
+  tsl2591Gain_t _gain;
+  tsl2591IntegrationTime_t _integration;
+  bool _initialized;
+} 
+TSL2591;
+
+
+  void      Init_TSL2591    ( TSL2591* tsl );
+  
+  void      TSL2591_enable  ( void );
+  void      TSL2591_disable ( void );
+  void      TSL2591_write8  ( uint8_t r, uint8_t v );
+  uint16_t  TSL2591_read16  ( uint8_t reg );
+  uint8_t   TSL2591_read8   ( uint8_t reg );
+
+  uint32_t  TSL2591_calculateLux  (TSL2591* tsl, uint16_t ch0, uint16_t ch1 );
+  void      TSL2591_setGain       (TSL2591* tsl, tsl2591Gain_t gain );
+  void      TSL2591_setTiming     (TSL2591* tsl, tsl2591IntegrationTime_t integration );
+  uint16_t  TSL2591_getLuminosity (TSL2591* tsl, uint8_t channel );
+  uint32_t  TSL2591_getFullLuminosity (TSL2591* tsl );
+
+  tsl2591IntegrationTime_t TSL2591_getTiming(TSL2591* tsl);
+  tsl2591Gain_t            TSL2591_getGain(TSL2591* tsl);
+
+   
+#endif
+
index 0ec2d45e434d08c70027b05d2b4c4b3300640284..96ea472d563813f42c17d8e26c7007541fa79ddd 100644 (file)
@@ -14,13 +14,16 @@ volatile uint8_t mode = 0;
 int main(void)\r
 {   char s[30];\r
     char SerNum[10];\r
-    uint8_t Status[4]={0,0,0,0};\r
+    uint8_t Status[5]={0,0,0,0,0};\r
     uint8_t TC_Enabled[4]={0,0,0,0};\r
     uint8_t Status_Mag[4]={0,0,0,0};\r
     uint16_t TRef[4]={0,0,0,0};\r
     float SensX[4];\r
     float SensY[4];\r
     float SensZ[4];\r
+    BME280 bme280;\r
+    TSL2591 tsl;\r
+\r
     \r
     //For CLK setting\r
     CLKPR = (1<<CLKPCE);  // No prescale\r
@@ -35,10 +38,30 @@ int main(void)
 \r
     //Init Magnetic field Sensor\r
     Status[0] = InitMagSensor(ADDR_MAG_0, &TRef[0], &SensX[0], &SensY[0], &SensZ[0], &TC_Enabled[0]);\r
+#if MULTISENSE == 0\r
     Status[1] = InitMagSensor(ADDR_MAG_1, &TRef[1], &SensX[1], &SensY[1], &SensZ[1], &TC_Enabled[1]);\r
     Status[2] = InitMagSensor(ADDR_MAG_2, &TRef[2], &SensX[2], &SensY[2], &SensZ[2], &TC_Enabled[2]);\r
     Status[3] = InitMagSensor(ADDR_MAG_3, &TRef[3], &SensX[3], &SensY[3], &SensZ[3], &TC_Enabled[3]);\r
+#endif\r
+    //Init BME280 Sensor Variables\r
+#if MULTISENSE == 1\r
+    bme280.settings.commInterface = I2C_MODE;\r
+    bme280.settings.I2CAddress = ADDR_ENV;\r
+    bme280.settings.runMode = 3; //Normal mode\r
+    bme280.settings.tStandby = 0;\r
+    bme280.settings.filter = 1;\r
+    bme280.settings.tempOverSample = 1;\r
+    bme280.settings.pressOverSample = 4;\r
+    bme280.settings.humidOverSample = 4;\r
+\r
+    Status[1] = InitBME(&bme280); \r
+\r
+    tsl._gain = TSL2591_GAIN_MAX;\r
+    tsl._integration = TSL2591_INTEGRATIONTIME_200MS;\r
+    Init_TSL2591(&tsl);\r
 \r
+    \r
+#endif \r
      // sprintf(s,"%u", Status[0]);\r
      //uputs(s);\r
     _delay_ms(300);\r
@@ -55,9 +78,11 @@ int main(void)
            } else if (strcmp(uart_string,"END") == 0 ) {\r
              mode = 0;\r
              InitMagSensor(ADDR_MAG_0, &TRef[0], &SensX[0], &SensY[0], &SensZ[0], &TC_Enabled[0]);\r
+#if MULTISENSE == 0              \r
              InitMagSensor(ADDR_MAG_1, &TRef[1], &SensX[1], &SensY[1], &SensZ[1], &TC_Enabled[1]);\r
              InitMagSensor(ADDR_MAG_2, &TRef[2], &SensX[2], &SensY[2], &SensZ[2], &TC_Enabled[2]);\r
              InitMagSensor(ADDR_MAG_3, &TRef[3], &SensX[3], &SensY[3], &SensZ[3], &TC_Enabled[3]);\r
+#endif              \r
            } else if (strcmp(uart_string,"EXIT") == 0 ) {\r
              status2 = twi_writeTo(0x0C, 0x80, 1,1, true);\r
              sprintf(s,"Status:0x%x",status2);\r
@@ -182,13 +207,30 @@ int main(void)
            // normal running mode\r
            if (Status[0] == 0) { MeasureMagSens(ADDR_MAG_0, TRef[0], &SensX[0], &SensY[0], &SensZ[0], TC_Enabled[0]);}\r
            else { uputs("ERR Mag ");sprintf(SerNum,"%2u ",SERIALNUM);uputs(SerNum); uputsnl("0 NO_DEVICE"); }\r
+#if MULTISENSE == 0\r
            if (Status[1] == 0) { MeasureMagSens(ADDR_MAG_1, TRef[1], &SensX[1], &SensY[1], &SensZ[1], TC_Enabled[1]);}\r
            else { uputs("ERR Mag ");sprintf(SerNum,"%2u ",SERIALNUM);uputs(SerNum); uputsnl("1 NO_DEVICE"); }\r
            if (Status[2] == 0) { MeasureMagSens(ADDR_MAG_2, TRef[2], &SensX[2], &SensY[2], &SensZ[2], TC_Enabled[2]);}\r
            else { uputs("ERR Mag ");sprintf(SerNum,"%2u ",SERIALNUM);uputs(SerNum); uputsnl("2 NO_DEVICE"); }\r
            if (Status[3] == 0) { MeasureMagSens(ADDR_MAG_3, TRef[3], &SensX[3], &SensY[3], &SensZ[3], TC_Enabled[3]);}\r
            else { uputs("ERR Mag ");sprintf(SerNum,"%2u ",SERIALNUM);uputs(SerNum); uputsnl("3 NO_DEVICE"); }\r
-           \r
+#endif\r
+#if MULTISENSE == 1\r
+            char Temp[30]; char Pres[30]; char Hum[30];\r
+            sprintf(Temp,"%3.2f",readTempC(&bme280));\r
+            sprintf(Pres,"%6.3f",readFloatPressure(&bme280));\r
+            sprintf(Hum,"%4.3f",readFloatHumidity(&bme280));\r
+            uputs("Temp: ");uputs(Temp);uputs("  Pres: ");uputs(Pres);uputs("  Humid: ");uputsnl(Hum);\r
+            \r
+            uint32_t lum = TSL2591_getFullLuminosity(&tsl);\r
+            uint16_t ir = lum >> 16;\r
+            uint16_t full = lum & 0xFFFF;\r
+            \r
+            uputs("Bright: ");\r
+            sprintf(s,"%u",full); uputs(s);\r
+            uputs(" / ");\r
+            sprintf(s,"%u",ir); uputsnl(s);\r
+#endif\r
            _delay_ms(500);\r
          } else {// CONFIG MODE\r
            //Setting:  I2C Address, Mode, RegAddr, Data Byte Low, Data byte high.\r
index 8d79d03218e8ca4d8a9c31e9de9d9baa291292ca..c9e87e748bd0af5f6b824be22f26e3fe90dbab89 100644 (file)
@@ -21,6 +21,8 @@
 #include <math.h>\r
 #include "uart/uart.h"\r
 #include "MagnetSensor.h"\r
+#include "BME280.h"\r
+#include "TSL2591.h"\r
 #include "twi/twi.h"\r
 #include <avr/interrupt.h>\r
 #include <avr/pgmspace.h>\r
@@ -39,7 +41,9 @@
 #define ADDR_MAG_3   0x0F\r
 \r
 \r
+#define ADDR_ENV   0x76\r
 \r
+#define MULTISENSE 1    //0: 4 magnetic sensors, 1: 1x magnetic, environment\r
 \r
 #ifndef __AVR_ATmega168P__\r
 #define __AVR_ATmega168P__\r
index 07dea39088ab0a83c080de6187c971c4bd720871..16e8bf7a2a588aae8a480a3bcd9638401401e5da 100644 (file)
@@ -4,6 +4,8 @@ The microcontroller runs off an external 16MHz oscillator.
 The board can be powered with 3V3 or 5V.
 3V3 operation is only stable with 8MHz. Thus, a prescaler of 2 for the main clock is applied in the early startup of the uC.
 
+In main.h, set MULTISENSE to define the type of board
+
 Each board will get a serial number that is being compiled into the firmware.
 It needs to be specified at compile time: