Hallo, nachdem ich in C für den TSL2561 (Umgebungslichtsensor I2C) im Netz und auch hier nichts brauchbares gefunden habe (und wenn, dann wars für den Arduino) und ich mir viel Zeit und Diskussionen hätte sparen können, wenn es sowas gegeben hätte, möchte ich ein Beispiel für Anfänger, wie ich, zu Verfügung stellen. Es gibt definitiv noch Verbesserungsbedarf, aber er funktioniert. Dieser Sensor steuert für meine "Wetterstation" einen Ventilator, der sich nur dann einschaltet, wenn die Sonne direkt aufs "Wetterhäußchen" strahlt. Gruss
Ich habe den Ablauf etwas verbessert, so dass nicht 1000mal auf den Eeprom des Sensors zugegriffen wird. Ich denke, so ist es besser. Gruss
Hallo, erstens Danke für das tolle Beispiel. Ich habe aktuell den Drucksensor BMP085 am Laufen und parallel dazu am Bus den TSL2561 angeschlossen - mit dem ich es aber noch nicht geschafft habe zu kommunizieren. Ich habe mir jetzt Dein Beispiel angesehen, und da sind einige Fragen aufgetaucht. a) Wieso machst du ein Shift bei der Slave-Adresse 0x38? Damit kommst Du ja auf 0x70 raus. b) Ich habe bei meinem Quellcode das Phänomen, das ich nach dem Start (0x08) f. den TSL2561 im Zustand 0x48 (SLA+R NACK) bzw. 0x20 (SLA+W NACK)Lande - also ganz eigenartig... Ist dir das Phänomen auch untergekommen? Danke, Gruß
Rober H. schrieb: > a) Wieso machst du ein Shift bei der Slave-Adresse 0x38? Damit kommst Du > ja auf 0x70 raus. I2C? 7-Bit-Adressen ohne r/w ./. 8-Bit-Adresse inklusive r/w. Das ist ein ewiger philosophischer Streitpunkt zwischen I2C-Anwendern.
Hallo, auch von mir erst einmal ein danke für das Beispiel. Ich hatte mich auch schon durch das Datenblatt des TSL2561 und anschließend google gewühlt. Aber dennoch komme ich mit dem Lichtsensor leider nicht weiter. Ich habe deinen Code adaptiert und die beiden Methoden "tsl2561_init" sowie "tsl2561_lux" mit hardcoded Adressen in meine Projekt übernommen. Allerdings bekomme ich beim auslesen der Helligkeit immer 16x eine "0" zurück für Ch0 und Ch1. Kannst du vieleicht mal über meinen Code schauen, wieso es nicht funktioniert?
1 | ret = i2c_start_((0x39<<1)+I2C_WRITE); |
2 | if ( ret ) { |
3 | //Wenn Gerät nicht verfügbar -> Abbruch
|
4 | i2c_stop(); |
5 | LcdAusgabe("TSL N/A", 2); |
6 | _delay_ms(5000); |
7 | }
|
8 | else{ |
9 | i2c_write(0x80); |
10 | i2c_write(0x03); |
11 | i2c_stop(); |
12 | _delay_ms(200); |
13 | |
14 | i2c_start((0x39<<1)+I2C_WRITE); |
15 | i2c_write(0x81); |
16 | i2c_write(0x00); |
17 | i2c_stop(); |
18 | _delay_ms(1000); |
19 | |
20 | i2c_start((0x39<<1)+I2C_WRITE); |
21 | i2c_write(0x8C); |
22 | i2c_rep_start((0x39<<1)+I2C_READ); |
23 | data1 = i2c_readAck(); |
24 | data1 = data1 << 8; |
25 | data1 = data1 | i2c_readAck(); |
26 | |
27 | data2 = i2c_readAck(); |
28 | data2 = data2 << 8; |
29 | data2 = data2 | i2c_readNak(); |
30 | i2c_stop(); |
31 | }
|
:
Bearbeitet durch User
Hallo, das Problem hat sich erledigt :) das Timing Register war im ursprungscode auf den niedrigsten Wert gesetzt. Der Sensor liegt bei mir im halbdunkeln unterm Schreibtisch, dadurch kam nichts bei der Messung raus. Mit der höheren Zeit bekomme ich jetzt entsprechende Werte zurück. Nochmals danke für den Beispielcode, ohne den hätte es vermutlich noch sehr viel länger gedauert, den Sensor zu integrieren...
Hi AVR Programmers I am new buddy in AVR World, i am stuck with i2c Comuunication of TSL2561 with Atmega 328p, i tried one code from Mr. Stefan B from this portal, it executes without errors but stucks in while loops: "while(!(TWCR & (1<<TWINT)))" , i also connected my i2c line on oscilloscope, there is no continuous signal on both SDA and SCL Lines Please Thank you Here is my code for TWI: /* ************************************************************************ * Title: I2C master library using hardware TWI interface * Author: Peter Fleury <pfleury@gmx.ch> http://jump.to/fleury * File: $Id: twimaster.c,v 1.3 2005/07/02 11:14:21 Peter Exp $ * Software: AVR-GCC 3.4.3 / avr-libc 1.2.3 * Target: any AVR device with hardware TWI * Usage: API compatible with I2C Software Library i2cmaster.h ************************************************************************ * #ifndef F_CPU #define F_CPU 16000000UL // processor clock frequency #endif #include <inttypes.h> #include <compat/twi.h> #include <util/delay.h> #include "i2cmaster.h" #include "Uart.h" I2C clock in Hz #define SCL_CLOCK 100000UL ************************************************************************ Initialization of the I2C bus interface. Need to be called only once ************************************************************************ void i2c_init(void) { initialize TWI clock: 100 kHz clock, TWPS = 0 => prescaler = 1 TWSR = 0; // no prescaler TWBR = ((F_CPU/SCL_CLOCK)-16)/2; must be > 10 for stable operation TWBR=72; TWSR=3; } i2c_init ************************************************************************ Issues a start condition and sends address and transfer direction. return 0 = device accessible, 1= failed to access device ************************************************************************ unsigned char i2c_start(unsigned char address) { uint8_t twst; uint16_t err; uint16_t count; // send START condition TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN); // wait until transmission completed while(!(TWCR & (1<<TWINT))) { count++; if(count > 250){ return 2; } } // check value of TWI Status Register. Mask prescaler bits. twst = TW_STATUS & 0xF8; if ( (twst != TW_START) && (twst != TW_REP_START)) return 1; // send device address TWDR = address; TWCR = (1<<TWINT) | (1<<TWEN); // wail until transmission completed and ACK/NACK has been received while(!(TWCR & (1<<TWINT))); // check value of TWI Status Register. Mask prescaler bits. twst = TW_STATUS & 0xF8; if ( (twst != TW_MT_SLA_ACK) && (twst != TW_MR_SLA_ACK) ) return 1; return 0; } i2c_start ************************************************************************ Issues a start condition and sends address and transfer direction. If device is busy, use ack polling to wait until device is ready Input: address and transfer direction of I2C device ************************************************************************ void i2c_start_wait(unsigned char address) { uint8_t twst; uint16_t count; while ( 1 ) { // send START condition TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN); // wait until transmission completed while(!(TWCR & (1<<TWINT))); // check value of TWI Status Register. Mask prescaler bits. twst = TW_STATUS & 0xF8; if ( (twst != TW_START) && (twst != TW_REP_START)) continue; // send device address TWDR = address; TWCR = (1<<TWINT) | (1<<TWEN); // wail until transmission completed while(!(TWCR & (1<<TWINT))); // check value of TWI Status Register. Mask prescaler bits. twst = TW_STATUS & 0xF8; if ( (twst == TW_MT_SLA_NACK )||(twst ==TW_MR_DATA_NACK) ) { device busy, send stop condition to terminate write operation TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO); // wait until stop condition is executed and bus released while(TWCR & (1<<TWSTO)); continue; } //if( twst != TW_MT_SLA_ACK) return 1; break; } } i2c_start_wait ************************************************************************ Issues a repeated start condition and sends address and transfer direction Input: address and transfer direction of I2C device Return: 0 device accessible 1 failed to access device ************************************************************************ unsigned char i2c_rep_start(unsigned char address) { return i2c_start( address ); } i2c_rep_start ************************************************************************ Terminates the data transfer and releases the I2C bus ************************************************************************ void i2c_stop(void) { send stop condition TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO); // wait until stop condition is executed and bus released while(TWCR & (1<<TWSTO)); } i2c_stop ************************************************************************ Send one byte to I2C device Input: byte to be transfered Return: 0 write successful 1 write failed ************************************************************************ unsigned char i2c_write( unsigned char data ) { uint8_t twst; // send data to the previously addressed device TWDR = data; printf("printing Intensity in LUX %lu\n\n", TWDR); TWCR = (1<<TWINT) | (1<<TWEN); // wait until transmission completed while(!(TWCR & (1<<TWINT))); // check value of TWI Status Register. Mask prescaler bits twst = TW_STATUS & 0xF8; if( twst != TW_MT_DATA_ACK) return 1; return 0; } i2c_write ************************************************************************ Read one byte from the I2C device, request more data from device Return: byte read from I2C device ************************************************************************ unsigned char i2c_readAck(void) { TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWEA); while(!(TWCR & (1<<TWINT))); return TWDR; } i2c_readAck ************************************************************************ Read one byte from the I2C device, read is followed by a stop condition Return: byte read from I2C device ************************************************************************ unsigned char i2c_readNak(void) { TWCR = (1<<TWINT) | (1<<TWEN); while(!(TWCR & (1<<TWINT))); return TWDR; } i2c_readNak My Tsl2561 code: #ifndef F_CPU #define F_CPU 16000000UL // processor clock frequency #endif #include <stdio.h> #include <stdlib.h> #include <string.h> #include <math.h> #include <avr/io.h> #include <util/delay.h> #include "tsl2561.h" #include <i2cmaster.h> int TSL2561AddressWrite_Float = 0x39; // Ground set the address 0x29 / 3.3V (vcc) to set the address 0x49 / leave it floating (unconnected) to use address 0x39 unsigned long Ch0DataHigh,Ch0DataLow,Ch1DataHigh,Ch1DataLow; unsigned int ch0,ch1; #define ControlRegister 0x80 #define TurnOnBits 0x03 #define TimingRegister 0x00 // 0x00 = 13.7ms / 0x01 = 101ms / 0x02 = 402ms (default) #define iGain 0x00 // 0x00 = 1x Gain (default) / 0x10 = 16x Gain #define Data0LowByteMode 0x8C //Address the Ch0 lower data register #define Data0HighByteMode 0x8D //Address the Ch0 upper data register #define Data1LowByteMode 0x8E //Address the Ch1 lower data register #define Data1HighByteMode 0x8F //Address the Ch1 upper data register #define LUX_SCALE 14 // scale by 2^14 #define RATIO_SCALE 9 // scale ratio by 2^9 //--------------------------------------------------- // Integration time scaling factors //--------------------------------------------------- #define CH_SCALE 10 // scale channel values by 2^10 #define CHSCALE_TINT0 0x7517 // 322/11 * 2^CH_SCALE #define CHSCALE_TINT1 0x0fe7 // 322/81 * 2^CH_SCALE //--------------------------------------------------- // T Package coefficients //--------------------------------------------------- // For Ch1/Ch0=0.00 to 0.50 // Lux/Ch0=0.0304-0.062*((Ch1/Ch0)^1.4) // piecewise approximation // For Ch1/Ch0=0.00 to 0.125: // Lux/Ch0=0.0304-0.0272*(Ch1/Ch0) // // For Ch1/Ch0=0.125 to 0.250: // Lux/Ch0=0.0325-0.0440*(Ch1/Ch0) // // For Ch1/Ch0=0.250 to 0.375: // Lux/Ch0=0.0351-0.0544*(Ch1/Ch0) // // For Ch1/Ch0=0.375 to 0.50: // Lux/Ch0=0.0381-0.0624*(Ch1/Ch0) // // For Ch1/Ch0=0.50 to 0.61: // Lux/Ch0=0.0224-0.031*(Ch1/Ch0) // // For Ch1/Ch0=0.61 to 0.80: // Lux/Ch0=0.0128-0.0153*(Ch1/Ch0) // // For Ch1/Ch0=0.80 to 1.30: // Lux/Ch0=0.00146-0.00112*(Ch1/Ch0) // // For Ch1/Ch0>1.3: // Lux/Ch0=0 //--------------------------------------------------- #define K1T 0x0040 // 0.125 * 2^RATIO_SCALE #define B1T 0x01f2 // 0.0304 * 2^LUX_SCALE #define M1T 0x01be // 0.0272 * 2^LUX_SCALE #define K2T 0x0080 // 0.250 * 2^RATIO_SCALE #define B2T 0x0214 // 0.0325 * 2^LUX_SCALE #define M2T 0x02d1 // 0.0440 * 2^LUX_SCALE #define K3T 0x00c0 // 0.375 * 2^RATIO_SCALE #define B3T 0x023f // 0.0351 * 2^LUX_SCALE #define M3T 0x037b // 0.0544 * 2^LUX_SCALE #define K4T 0x0100 // 0.50 * 2^RATIO_SCALE #define B4T 0x0270 // 0.0381 * 2^LUX_SCALE #define M4T 0x03fe // 0.0624 * 2^LUX_SCALE #define K5T 0x0138 // 0.61 * 2^RATIO_SCALE #define B5T 0x016f // 0.0224 * 2^LUX_SCALE #define M5T 0x01fc // 0.0310 * 2^LUX_SCALE #define K6T 0x019a // 0.80 * 2^RATIO_SCALE #define B6T 0x00d2 // 0.0128 * 2^LUX_SCALE #define M6T 0x00fb // 0.0153 * 2^LUX_SCALE #define K7T 0x029a // 1.3 * 2^RATIO_SCALE #define B7T 0x0018 // 0.00146 * 2^LUX_SCALE #define M7T 0x0012 // 0.00112 * 2^LUX_SCALE #define K8T 0x029a // 1.3 * 2^RATIO_SCALE #define B8T 0x0000 // 0.000 * 2^LUX_SCALE #define M8T 0x0000 // 0.000 * 2^LUX_SCALE //--------------------------------------------------- // CS package coefficients //--------------------------------------------------- // For 0 <= Ch1/Ch0 <= 0.52 // Lux/Ch0 = 0.0315-0.0593*((Ch1/Ch0)^1.4) // piecewise approximation // For 0 <= Ch1/Ch0 <= 0.13 // Lux/Ch0 = 0.0315-0.0262*(Ch1/Ch0) // For 0.13 <= Ch1/Ch0 <= 0.26 // Lux/Ch0 = 0.0337-0.0430*(Ch1/Ch0) // For 0.26 <= Ch1/Ch0 <= 0.39 // Lux/Ch0 = 0.0363-0.0529*(Ch1/Ch0) // For 0.39 <= Ch1/Ch0 <= 0.52 // Lux/Ch0 = 0.0392-0.0605*(Ch1/Ch0) // For 0.52 < Ch1/Ch0 <= 0.65 // Lux/Ch0 = 0.0229-0.0291*(Ch1/Ch0) // For 0.65 < Ch1/Ch0 <= 0.80 // Lux/Ch0 = 0.00157-0.00180*(Ch1/Ch0) // For 0.80 < Ch1/Ch0 <= 1.30 // Lux/Ch0 = 0.00338-0.00260*(Ch1/Ch0) // For Ch1/Ch0 > 1.30 // Lux = 0 //--------------------------------------------------- #define K1C 0x0043 // 0.130 * 2^RATIO_SCALE #define B1C 0x0204 // 0.0315 * 2^LUX_SCALE #define M1C 0x01ad // 0.0262 * 2^LUX_SCALE #define K2C 0x0085 // 0.260 * 2^RATIO_SCALE #define B2C 0x0228 // 0.0337 * 2^LUX_SCALE #define M2C 0x02c1 // 0.0430 * 2^LUX_SCALE #define K3C 0x00c8 // 0.390 * 2^RATIO_SCALE #define B3C 0x0253 // 0.0363 * 2^LUX_SCALE #define M3C 0x0363 // 0.0529 * 2^LUX_SCALE #define K4C 0x010a // 0.520 * 2^RATIO_SCALE #define B4C 0x0282 // 0.0392 * 2^LUX_SCALE #define M4C 0x03df // 0.0605 * 2^LUX_SCALE #define K5C 0x014d // 0.65 * 2^RATIO_SCALE #define B5C 0x0177 // 0.0229 * 2^LUX_SCALE #define M5C 0x01dd // 0.0291 * 2^LUX_SCALE #define K6C 0x019a // 0.80 * 2^RATIO_SCALE #define B6C 0x0101 // 0.0157 * 2^LUX_SCALE #define M6C 0x0127 // 0.0180 * 2^LUX_SCALE #define K7C 0x029a // 1.3 * 2^RATIO_SCALE #define B7C 0x0037 // 0.00338 * 2^LUX_SCALE #define M7C 0x002b // 0.00260 * 2^LUX_SCALE #define K8C 0x029a // 1.3 * 2^RATIO_SCALE #define B8C 0x0000 // 0.000 * 2^LUX_SCALE #define M8C 0x0000 // 0.000 * 2^LUX_SCALE #define ControlRegister 0x80 #define TurnOnBits 0x03 #define TimingRegister 0x00 // 0x00 = 13.7ms / 0x01 = 101ms / 0x02 = 402ms (default) #define iGain 0x00 // 0x00 = 1x Gain (default) / 0x10 = 16x Gain #define Data0LowByteMode 0x8C //Address the Ch0 lower data register #define Data0HighByteMode 0x8D //Address the Ch0 upper data register #define Data1LowByteMode 0x8E //Address the Ch1 lower data register #define Data1HighByteMode 0x8F //Address the Ch1 upper data register unsigned long tsl2561_init(void) { i2c_start_wait(TSL2561AddressWrite_Float+I2C_WRITE); i2c_write(ControlRegister); i2c_write(TurnOnBits); printf("printing Intensity in LUX %lu\n\n", TurnOnBits); printf("***********Flora sensor Measurement TSL2561 ***********\n"); i2c_stop(); i2c_start_wait(TSL2561AddressWrite_Float+I2C_WRITE); i2c_write(0x81); // i2c_write(iGain); i2c_write(TimingRegister); i2c_stop(); return(0); return(45); } unsigned long tsl2561_lux(void) { tsl2561_init(); i2c_start_wait(TSL2561AddressWrite_Float+I2C_WRITE); printf("***********Flora sensor Measurement TSL2561***********\n"); i2c_write(Data0LowByteMode); // 8 is the command register and C is the data low register of channel 0 i2c_rep_start(TSL2561AddressWrite_Float+I2C_READ); // set device address and read mode printf("***********Flora sensor Measurement TSL2561***********\n"); Ch0DataLow = i2c_readAck(); // read one byte from EEPROM Ch0DataHigh = i2c_readAck(); // read one byte from EEPROM Ch1DataLow = i2c_readAck(); // read one byte from EEPROM Ch1DataHigh = i2c_readNak(); // read one byte from EEPROM i2c_stop(); ch0 = 256 * Ch0DataHigh + Ch0DataLow; //Shift Data0High to upper byte ch1 = 256 * Ch1DataHigh + Ch1DataLow; //Shift Data1High to upper byte // lux equation approximation without floating point calculations //////////////////////////////////////////////////////////////////////// ////// // Routine: unsigned int CalculateLux(unsigned int ch0, unsigned int ch0, int iType) // // Description: Calculate the approximate illuminance (lux) given the raw // channel values of the TSL2560. The equation if implemented // as a piece-wise linear approximation. // // Arguments: unsigned int iGain - gain, where 0:1X, 1:16X // unsigned int tInt - integration time, where 0:13.7mS, 1:100mS, 2:402mS, // 3:Manual // unsigned int ch0 - raw channel value from channel 0 of TSL2560 // unsigned int ch1 - raw channel value from channel 1 of TSL2560 // unsigned int iType - package type (T or CS) // // Return: unsigned int - the approximate illuminance (lux) // //////////////////////////////////////////////////////////////////////// ///// //---------------------------------------------------------------------- -- // first, scale the channel values depending on the gain and integration time // 16X, 402mS is nominal. // scale if integration time is NOT 402 msec unsigned long chScale; unsigned long channel1; unsigned long channel0; switch (tInt) { case 0: // 13.7 msec chScale = CHSCALE_TINT0; break; case 1: // 101 msec chScale = CHSCALE_TINT1; break; default: // assume no scaling chScale = (1 << CH_SCALE); break; } // scale if gain is NOT 16X if (!iGain) chScale = chScale << 4; // scale 1X to 16X // scale the channel values channel0 = (ch0 * chScale) >> CH_SCALE; channel1 = (ch1 * chScale) >> CH_SCALE; //---------------------------------------------------------------------- -- // find the ratio of the channel values (Channel1/Channel0) // protect against divide by zero unsigned long ratio1 = 0; if (channel0 != 0) ratio1 = (channel1 << (RATIO_SCALE+1)) / channel0; // round the ratio value unsigned long ratio = (ratio1 + 1) >> 1; // is ratio <= eachBreak ? switch (iType) { case 0: // T package if ((ratio >= 0) && (ratio <= K1T)) {b=B1T; m=M1T;} else if (ratio <= K2T) {b=B2T; m=M2T;} else if (ratio <= K3T) {b=B3T; m=M3T;} else if (ratio <= K4T) {b=B4T; m=M4T;} else if (ratio <= K5T) {b=B5T; m=M5T;} else if (ratio <= K6T) {b=B6T; m=M6T;} else if (ratio <= K7T) {b=B7T; m=M7T;} else if (ratio > K8T) {b=B8T; m=M8T;} break; case 1:// CS package if ((ratio >= 0) && (ratio <= K1C)) {b=B1C; m=M1C;} else if (ratio <= K2C) {b=B2C; m=M2C;} else if (ratio <= K3C) {b=B3C; m=M3C;} else if (ratio <= K4C) {b=B4C; m=M4C;} else if (ratio <= K5C) {b=B5C; m=M5C;} else if (ratio <= K6C) {b=B6C; m=M6C;} else if (ratio <= K7C) {b=B7C; m=M7C;} else if (ratio > K8C) {b=B8C; m=M8C;} break; } unsigned long temp; temp = ((channel0 * b) - (channel1 * m)); // do not allow negative lux value if (temp < 0) temp = 0; // round lsb (2^(LUX_SCALE-1)) temp += (1 << (LUX_SCALE-1)); // strip off fractional portion unsigned long lux = temp >> LUX_SCALE; if ( lux > 65500) { lux = 65500; } return(lux); return(786); } My Main Code: #ifndef F_CPU #define F_CPU 4000000 // processor clock frequency #endif #include <avr/wdt.h> #include <stdlib.h> #include <avr/io.h> #include <avr/pgmspace.h> #include <util/delay.h> #include <avr/interrupt.h> #include <stdio.h> #include <string.h> #include <math.h> #include "i2cmaster.h" #include "tsl2561.h" #include "Uart.h" /*void TSL();*/ void flora_sensor(); static FILE uart_str = FDEV_SETUP_STREAM(uart_putchar, uart_getchar, _FDEV_SETUP_RW); int main(int argc, char **argv) { stdout = stdin = &uart_str; //sets the output stream of printf to send data over uart uart_init(); /*void wait(void) { for(unsigned char i = 0; i < 100; i++) _delay_ms(10); } */ flora_sensor(); } void flora_sensor(void) { printf("***********Flora sensor Measurement TSL2561***********\n"); unsigned long Lux; while (1) { // TSL2561 Sensor abfragen Lux = tsl2561_lux(); printf("***********Flora sensor Measurement TSL2561***********\n"); printf("printing Intensity in LUX %lu\n\n", Lux); }
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.