cavrlight-sensor

How to read data result from light sensor using interrupts


I'm using Arduino mega 2560 and light sensor BH1750FVI. to show result i'm using minicom, work on Ubuntu 16.04 LTS

I write code and it's work and send me data result reading from light sensor, i can read info only once. I don't understand how i make it work through interrupts (TWI_vect) and display the results every time using my uart.

#include "my_header.h"

#define I2C_STATUS_MASK                 0xF8
#define START_COND_TRANSMITTED          0x08
#define REPEATED_START_COND_TRANSMITTED 0x10
#define SLA_W_TRANSMITTED_ACK_RECEIVED  0x18
#define DATA_TRANSMITTED_ACK_RECEIVED   0x28
#define SLA_R_TRANSMITTED_ACK_RECEIVED  0x40
#define DATA_RECEIVED_ACK_RETURNED      0x50
#define DATA_RECEIVED_NACK_RETURNED     0x58
volatile int light_intensity = 0; // var for read data from sensor

ISR(USART0_UDRE_vect) {
  if (!bufferIsEmpty(&buffer)) //if we have something to read do it
    UDR0 = popFromBuff(&buffer);
  else
    UCSR0B &= ~_BV(UDRIE0); //disallow interrupts
}



int     main(void) {
  cli();
  init_port(); //initialize my port
  init_buffer(&buffer, BUFF_SIZE); //init ring_buffer for uart
  init_uart();
  TWI_init();
  sei();

  TWI_start(); //send start 
  TWI_send_SLA(WRITE); //send SLA+W to light sensor 
  TWI_sendData(0b00010000); //opecode for Measurement
  TWI_stop(); //stop

  TWI_start(); //send start 
  TWI_send_SLA(READ); // send SLA+R to sensor
  TWI_readData(); // read data from it light_intensity = TWDR
  TWI_stop(); // stop 
  u_printnumbers(light_intensity); /*my func that send data to ring_buffer and later
                      *using interrupts send it form buffer to UDR
                      */
  u_print("\n");

  while (1) {
    if (!bufferIsEmpty(&buffer)) /*if buffer is not empty allow interrupts for uart*/
      UCSR0B |= _BV(UDRIE0);
  }
}

So this code work and i receive data from sensor and all fine. But i want using it with interrupts (TWI_vect) and receive data all the time from sensor like in while(). i read a lot of info but don't understand how it should look. Can you show me the right way using my code with interrupts (TWI_vect) some little example. Thx for help!


Solution

  • To use the Two-Wirte interface (I²C; TWI) interrupt-driven, you will have to implement some sort of state machine inside the TWI ISR.

    Atmel Application Note AVR135 give a slight idea how this can be done. You will have to have buffers ready and abstract transactions into a struct of some sort. For example, you can have a

    struct i2c_transfer {
        uint8_t        i2c_sla; /* slave address */
        const uint8_t *txbuf;
        size_t         txbytes;
        uint8_t       *rxbuf;
        size_t         rxbytes;
    }
    

    That you set up, then have a function start transmitting I2C and check if you're done via checking if txbytes == 0 && rxbytes == 0 or an error occurred. Your ISR would then need to check its state and act appropriately depending on the number of bytes it's supposed to write and read.