Problem to turn on and of sensors.

niki2013

Feb 21, 2021
13
Joined
Feb 21, 2021
Messages
13
Hi all
I have create an air monitoring project. I use a PIC16F18346, BMP280, SCD40 and BH1750. The project is working ok no issues there. I decide to use 2n3904 to switch off the BMP280 and the SCD40 to save energy. I create a circuit for that which is attached in pdf. Now the problem explanation. When i use these circuits separate with the PIC working fine, means that the bjt turns on the measurement is taken and then is turning off. But when i compine these 2 together (BMP280 and SDC40) with the PIC, the program runs normally at the beginning initializing and recognizing both of the sensors. Then is starting the main function. Start the reading BMP280 function. Turning on the sensor and stack there. If in that point if i skip the BJT of the BMP280 sensor(permanent ON) and restart the PIC, then reading BMP280 normaly and after proceeding to the SCD40 and also reading it successfully.
Because as i said in the beginning the code runs ok i enclose only the drawing with the 2N3904. Is there any idea about that?
 

Attachments

  • Screenshot 2025-03-16 195839.png
    Screenshot 2025-03-16 195839.png
    32.3 KB · Views: 8

Harald Kapp

Moderator
Moderator
Nov 17, 2011
14,271
Joined
Nov 17, 2011
Messages
14,271
Two issues here:
  1. Turning off gnd is not a good idea. Since Vcc is still connected, the sensors will make a gnd connection internally through the signal pins.
  2. If you were to switch Vcc, that would, for the same argument, be a bad idea, too. The sensors will then connect to Vcc via the signal inputs.
If you need to turn off the sensors, you will also have to disconnect the signal lines to avoid the complications described above. Better use the built-in power saving functions:

BMP280: sleep mode current is 0.1 µA only.
BH1750: power down mode < 0.1 µA (datasheet, figure 10)
 

niki2013

Feb 21, 2021
13
Joined
Feb 21, 2021
Messages
13
Two issues here:
  1. Turning off gnd is not a good idea. Since Vcc is still connected, the sensors will make a gnd connection internally through the signal pins.
  2. If you were to switch Vcc, that would, for the same argument, be a bad idea, too. The sensors will then connect to Vcc via the signal inputs.
If you need to turn off the sensors, you will also have to disconnect the signal lines to avoid the complications described above. Better use the built-in power saving functions:

BMP280: sleep mode current is 0.1 µA only.
BH1750: power down mode < 0.1 µA (datasheet, figure 10)
Hi
Thank you for the answer. I understand what you mean. I may assume that this issue is in every device using I2C?
 

Harald Kapp

Moderator
Moderator
Nov 17, 2011
14,271
Joined
Nov 17, 2011
Messages
14,271
This is not I2C related, it is a common issue with almost all chips. Input and output pins are protected by diodes. These diodes apply power from the signal pins to Vcc and GND in case the chip is not powered. See e.g. here.
 

ahsrabrifat

Jan 18, 2025
76
Joined
Jan 18, 2025
Messages
76
Hi all
I have create an air monitoring project. I use a PIC16F18346, BMP280, SCD40 and BH1750. The project is working ok no issues there. I decide to use 2n3904 to switch off the BMP280 and the SCD40 to save energy. I create a circuit for that which is attached in pdf. Now the problem explanation. When i use these circuits separate with the PIC working fine, means that the bjt turns on the measurement is taken and then is turning off. But when i compine these 2 together (BMP280 and SDC40) with the PIC, the program runs normally at the beginning initializing and recognizing both of the sensors. Then is starting the main function. Start the reading BMP280 function. Turning on the sensor and stack there. If in that point if i skip the BJT of the BMP280 sensor(permanent ON) and restart the PIC, then reading BMP280 normaly and after proceeding to the SCD40 and also reading it successfully.
Because as i said in the beginning the code runs ok i enclose only the drawing with the 2N3904. Is there any idea about that?
I think your power supply is not supplying enough voltage and current to your setup when you combine BMP280 and SDC40.
 

Harald Kapp

Moderator
Moderator
Nov 17, 2011
14,271
Joined
Nov 17, 2011
Messages
14,271
I think your power supply is not supplying enough voltage and current to your setup when you combine BMP280 and SDC40.
Unlikely:
  1. The program initially runs fine, according to the op.
  2. These sensors draw very little power. If the combined power dissipation of these sensors would overload the power supply, the mcu would reset, not stall.
 

niki2013

Feb 21, 2021
13
Joined
Feb 21, 2021
Messages
13
Unlikely:
  1. The program initially runs fine, according to the op.
  2. These sensors draw very little power. If the combined power dissipation of these sensors would overload the power supply, the mcu would reset, not stall.
You are correct i think. Because when it stalls in the same setup(quriocity board with PIC16F18346) i give permanent ground bypassing the BJT's and works fine.IMG_20250318_125130.jpgScreenshot 2025-03-18 125359.png
 

niki2013

Feb 21, 2021
13
Joined
Feb 21, 2021
Messages
13
This is not I2C related, it is a common issue with almost all chips. Input and output pins are protected by diode. These diodes apply power from the signal pinss to Vcc and GND in case the chip is not powered. See e.g. here.
THis PDF is a gold mine thanks.
 

niki2013

Feb 21, 2021
13
Joined
Feb 21, 2021
Messages
13
We will do better than that!
Post your code. :)
Hi.
As you request i am posting the main.c and the c files of the sensors. The timer 0 flag is activating every 15min.
Code:
#include "mcc_generated_files/mcc.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "common.h"
#include "BMP280_Lib.h"
#include "BH1750.h"
#include "SCD4x_CO2.h"
#include "MQ_SENSORS_Lib.h"
#include "I2C.h"
/******************************************************************************/
/* User Global Variable Declaration                                           */
/******************************************************************************/

/*
                         Main application
 */
/******************************************************************************/
/* User Global Variable Declaration                                           */
/******************************************************************************/

char timer0_flag = 0;
/*
                         Main application
 */
void main(void)
{
    // initialize the device
    SYSTEM_Initialize();
    I2C_Master_Init();
    
    __delay_ms(2000);

    // When using interrupts, you need to set the Global and Peripheral Interrupt Enable bits
    // Use the following macros to:

    // Enable the Global Interrupts
    INTERRUPT_GlobalInterruptEnable();

    // Enable the Peripheral Interrupts
    INTERRUPT_PeripheralInterruptEnable();

    // Disable the Global Interrupts
    //INTERRUPT_GlobalInterruptDisable();

    // Disable the Peripheral Interrupts
    //INTERRUPT_PeripheralInterruptDisable();
    
    initializing_MQsensors();
    initializing_SCD4x();
    
    __delay_ms(100);
    UART_new_line();
    UART_send_string((char*)" System starts in normal mode");
    __delay_ms(2000);

    timer0_flag = 1;
    __delay_ms(1000);

    while (1)
    {
        // Add your application code
        
        if(timer0_flag)
        {
            initialize_BMP280();
            
            UART_new_line();
            UART_new_line();
            UART_send_string((char*)" Flag Activated");
            TMR0_StopTimer();
            timer0_flag = 0;
            display_sd4x();
            MQ131_read();
            display_BH1750();
            display_BMP280();
            UART_new_line();
            UART_send_string((char*)" Flag Deactivated");
            TMR0_StartTimer();
        }
    }
}
/**
 End of File
*/
Code:
#include <xc.h> // include processor files - each processor file is guarded.
#include "BH1750.h"
#include "mcc_generated_files/mcc.h"
#include "common.h"
#include "I2C.h"
#include <stdio.h>
#include <stdlib.h>


void GY302_Write(unsigned char cmd){
    I2C_Master_Start();
    I2C_Master_Write(GY302_WRITE_addr);
    I2C_Master_Write(cmd);
    __delay_ms(180);
    I2C_Master_Stop();
}

unsigned char GY302_Read(){
    uint8_t dat[2] = {0};
    
    I2C_Master_Start();
    I2C_Master_Write(GY302_READ_addr);

    dat[0] = I2C_Master_Read(1);
    dat[1] = I2C_Master_Read(0);
    __delay_ms(180);
    I2C_Master_Stop();
    
    int value = ((((dat[0] <<8) | dat[1]) * 10) / 12);
    
    return value;
}

unsigned long get_lux_value(unsigned char mode){
    
    int Lux_value = 0;
    
    GY302_Write(POWER_ON);
    GY302_Write(mode);
    
    Lux_value = GY302_Read();
    __delay_ms(180);
    GY302_Write(POWER_DOWN);
    
    return Lux_value;
}

void display_BH1750()
{
    char temp[17];
    
    float Light_Intencity = (float)(get_lux_value(CONTINUOUS_HIGH_RES_MODE ) * 1.2);
    memset(temp, '\0', sizeof(temp));
    Float2Ascii (Light_Intencity, temp, 2);
    UART_new_line();
    UART_send_string((char*)" lux value: ");
    UART_send_string(temp);
    UART_send_string((char*)"   lux");
}
Code:
#include "mcc_generated_files/mcc.h"
#include "common.h"
#include "BMP280_Lib.h"
#include "I2C.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

// writes 1 byte '_data' to register 'reg_addr'
void BMP280_Write8(uint8_t reg_addr, uint8_t _data)
{
    BMP280_Start();
    BMP280_Write(BMP280_I2C_ADDRESS);
    BMP280_Write(reg_addr);
    BMP280_Write(_data);
    BMP280_Stop();
}

// reads 8 bits from register 'reg_addr'
uint8_t BMP280_Read8(uint8_t reg_addr)
{
    uint8_t ret;

    BMP280_Start();
    BMP280_Write(BMP280_I2C_ADDRESS);
    BMP280_Write(reg_addr);
    BMP280_Start();
    BMP280_Write(BMP280_I2C_ADDRESS | 1);
    ret = BMP280_Read(0);
    BMP280_Stop();

    return ret;
}

// reads 16 bits from register 'reg_addr'
uint16_t BMP280_Read16(uint8_t reg_addr)
{
    union
    {
      uint8_t  b[2];
      uint16_t w;
    } ret;

    BMP280_Start();
    BMP280_Write(BMP280_I2C_ADDRESS);
    BMP280_Write(reg_addr);
    BMP280_Start();
    BMP280_Write(BMP280_I2C_ADDRESS | 1);
    ret.b[0] = BMP280_Read(1);
    ret.b[1] = BMP280_Read(0);
    BMP280_Stop();

    return(ret.w);
}

uint32_t BMP280_Read24(uint8_t reg_addr)
{
    uint32_t value;
    
    BMP280_Start();
    BMP280_Write(BMP280_I2C_ADDRESS);
    BMP280_Write(reg_addr);
    BMP280_Start();
    BMP280_Write(BMP280_I2C_ADDRESS | 1);
    value = BMP280_Read(1)<<16;
    value |= BMP280_Read(1)<<8;
    value |= BMP280_Read(1);
    BMP280_Stop();
    
    value >>4;

    return(value);
}

// BMP280 sensor configuration function
void BMP280_Configure(BMP280_mode mode, BMP280_sampling T_sampling,
                      BMP280_sampling P_sampling, BMP280_filter filter, standby_time standby)
{
    //uint8_t  _ctrl_meas, _config;

    _config = ((standby << 5) | (filter << 2)) & 0xFC;
    _ctrl_meas = (T_sampling << 5) | (P_sampling << 2) | mode;

    BMP280_Write8(BMP280_REG_CONFIG,  _config);
    BMP280_Write8(BMP280_REG_CONTROL, _ctrl_meas);
}

// initialises the BMP280 sensor, returns 1 if OK and 0 if error
uint8_t BMP280_begin(BMP280_mode mode,
                    BMP280_sampling T_sampling,
                    BMP280_sampling P_sampling,
                    BMP280_filter filter,
                    standby_time  standby)
{
    if(BMP280_Read8(BMP280_REG_CHIPID) != BMP280_CHIP_ID){
        UART_new_line();
        UART_send_string((char*)" BMP280 connection error or device address wrong!");
        UART_new_line();
        UART_send_string((char*)" Restart device");
      return 0;
    }
    else{
        char ID_buf[30];
        int8_t myID = BMP280_Read8(BMP280_REG_CHIPID);
        memset(BMP_buf, '\0', sizeof(BMP_buf));
        UART_new_line();
        sprintf(ID_buf," Sensor with ID: %X is connected",myID);
        UART_send_string(ID_buf);
    }
    // reset the BMP280 with soft reset
    BMP280_Write8(BMP280_REG_SOFTRESET, 0xB6);
    __delay_ms(100);

    // if NVM data are being copied to image registers, wait 100 ms
    while ( (BMP280_Read8(BMP280_REG_STATUS) & 0x01) == 0x01 )
      __delay_ms(100);

    BMP280_calib.dig_T1 = BMP280_Read16(BMP280_REG_DIG_T1);
    BMP280_calib.dig_T2 = BMP280_Read16(BMP280_REG_DIG_T2);
    BMP280_calib.dig_T3 = BMP280_Read16(BMP280_REG_DIG_T3);

    BMP280_calib.dig_P1 = BMP280_Read16(BMP280_REG_DIG_P1);
    BMP280_calib.dig_P2 = BMP280_Read16(BMP280_REG_DIG_P2);
    BMP280_calib.dig_P3 = BMP280_Read16(BMP280_REG_DIG_P3);
    BMP280_calib.dig_P4 = BMP280_Read16(BMP280_REG_DIG_P4);
    BMP280_calib.dig_P5 = BMP280_Read16(BMP280_REG_DIG_P5);
    BMP280_calib.dig_P6 = BMP280_Read16(BMP280_REG_DIG_P6);
    BMP280_calib.dig_P7 = BMP280_Read16(BMP280_REG_DIG_P7);
    BMP280_calib.dig_P8 = BMP280_Read16(BMP280_REG_DIG_P8);
    BMP280_calib.dig_P9 = BMP280_Read16(BMP280_REG_DIG_P9);

    BMP280_Configure(mode, T_sampling, P_sampling, filter, standby);

    return 1;
}

// Takes a new measurement, for forced mode only!
// Returns 1 if ok and 0 if error (sensor is not in sleep mode)
uint8_t BMP280_ForcedMeasurement()
{
    uint8_t ctrl_meas_reg = BMP280_Read8(BMP280_REG_CONTROL);

    if ( (ctrl_meas_reg & 0x03) != 0x00 )
      return 0;   // sensor is not in sleep mode

    // set sensor to forced mode
    BMP280_Write8(BMP280_REG_CONTROL, ctrl_meas_reg | 1);
    // wait for conversion complete
    while (BMP280_Read8(BMP280_REG_STATUS) & 0x08)
      __delay_ms(1);

    return 1;
}

// read (updates) adc_P, adc_T and adc_H from BMP280 sensor
void BMP280_Update()
{

    union
    {
      uint8_t  b[4];
      uint32_t dw;
    } ret;
    ret.b[3] = 0x00;

    BMP280_Start();
    BMP280_Write(BMP280_I2C_ADDRESS);
    BMP280_Write(BMP280_REG_PRESS_MSB);
    BMP280_Start();
    BMP280_Write(BMP280_I2C_ADDRESS | 1);
    ret.b[2] = BMP280_Read(1);  //msb
    ret.b[1] = BMP280_Read(1);  //lsb
    ret.b[0] = BMP280_Read(1);  //xlsb

    adc_P = (ret.dw >> 4) & 0xFFFFF;

    ret.b[2] = BMP280_Read(1);  //msb
    ret.b[1] = BMP280_Read(1);  //lsb
    ret.b[0] = BMP280_Read(0);  //xlsb
    BMP280_Stop();

    adc_T = (ret.dw >> 4) & 0xFFFFF;

}

// Reads temperature from BMP280 sensor.
// Temperature is stored in hundreds C (output value of "5123" equals 51.23 DegC).
// Temperature value is saved to *temp, returns 1 if OK and 0 if error.
uint8_t BMP280_readTemperature(int32_t *temp)
{
    int32_t var1, var2;
    char t[32];

    BMP280_Update();

    // calculate temperature
    var1 = ((((adc_T / 8) - ((int32_t)BMP280_calib.dig_T1 * 2))) *
           ((int32_t)BMP280_calib.dig_T2)) / 2048;

    var2 = (((((adc_T / 16) - ((int32_t)BMP280_calib.dig_T1)) *
           ((adc_T / 16) - ((int32_t)BMP280_calib.dig_T1))) / 4096) *
           ((int32_t)BMP280_calib.dig_T3)) / 16384;

    t_fine = var1 + var2;

    *temp = (t_fine * 5 + 128) / 256;

    return 1;
}

// Reads pressure from BMP280 sensor.
// Pressure is stored in Pa (output value of "96386" equals 96386 Pa = 963.86 hPa).
// Pressure value is saved to *pres, returns 1 if OK and 0 if error.
uint32_t BMP280_readPressure(uint32_t *pres)
{
    int32_t var1, var2;
    uint32_t p;

    // calculate pressure
    var1 = (((int32_t)t_fine) / 2) - (int32_t)64000;
    var2 = (((var1/4) * (var1/4)) / 2048 ) * ((int32_t)BMP280_calib.dig_P6);

    var2 = var2 + ((var1 * ((int32_t)BMP280_calib.dig_P5)) * 2);
    var2 = (var2/4) + (((int32_t)BMP280_calib.dig_P4) * 65536);

    var1 = ((((int32_t)BMP280_calib.dig_P3 * (((var1/4) * (var1/4)) / 8192 )) / 8) +
           ((((int32_t)BMP280_calib.dig_P2) * var1)/2)) / 262144;

    var1 =((((32768 + var1)) * ((int32_t)BMP280_calib.dig_P1)) / 32768);

    if (var1 == 0)
      return 0; // avoid exception caused by division by zero

    p = (((uint32_t)(((int32_t)1048576) - adc_P) - (var2 / 4096))) * 3125;

    if (p < 0x80000000)
      p = (p * 2) / ((uint32_t)var1);

    else
      p = (p / (uint32_t)var1) * 2;

    var1 = (((int32_t)BMP280_calib.dig_P9) * ((int32_t)(((p/8) * (p/8)) / 8192))) / 4096;
    var2 = (((int32_t)(p/4)) * ((int32_t)BMP280_calib.dig_P8)) / 8192;

    p = (uint32_t)((int32_t)p + ((var1 + var2 + (int32_t)BMP280_calib.dig_P7) / 16));

    *pres = p;

    return 1;
}

void initialize_BMP280()
{
    UART_new_line();
    UART_send_string((char*)" Initializing BMP280..");
    __delay_ms(10);
    
    if(BMP280_begin(MODE_FORCED, SAMPLING_X1, SAMPLING_X1, FILTER_OFF, STANDBY_0_5) == 0)
    { 
        // connection error or device address wrong!
        UART_new_line();
        UART_send_string((char*)" BMP280 connection error or device address wrong!");
        UART_new_line();
        UART_send_string((char*)" Restart device");
    }
    else {
        UART_new_line();
        UART_send_string((char*)" BMP280 connected");
    }
    __delay_ms(100);
}

void display_BMP280()
{
    BMP280_PWR_RC5_SetHigh();
    __delay_ms(500);

    if(BMP280_begin(MODE_FORCED, SAMPLING_X1, SAMPLING_X1, FILTER_OFF, STANDBY_0_5) == 0)
    { 
        // connection error or device address wrong!
        UART_new_line();
        UART_send_string((char*)" BMP280 connection error or device address wrong!");
        UART_new_line();
        UART_send_string((char*)" Restart device");
    }
    else {
        UART_new_line();
        UART_send_string((char*)" BMP280 connected");
    }
    
    UART_new_line();
    // Read temperature (in hundreds C) and pressure (in Pa)
    if(BMP280_ForcedMeasurement())
    {
        //   values from the BMP280 sensor
        BMP280_readTemperature(&temperature);  // read temperature
        BMP280_readPressure(&pressure);        // read pressure
    
        // print data on the screen
        // 1: print temperature
        if(temperature < 0){
            memset(BMP_buf, '\0', sizeof(BMP_buf));
            Float2Ascii ((float)temperature / 100.0, BMP_buf, 2);
            UART_send_string((char*)" Temperature is:");
            EUSART_Write('-');
            UART_send_string(BMP_buf);
            EUSART_Write('C');
            UART_new_line();
        }
        else{
            memset(BMP_buf, '\0', sizeof(BMP_buf));
            Float2Ascii ((float)temperature / 100.0, BMP_buf, 2);
            UART_send_string((char*)" Temperature is:");
            UART_send_string(BMP_buf);
            EUSART_Write('C');
            UART_new_line();
        }
        // 2: print pressure
        memset(BMP_buf, '\0', sizeof(BMP_buf));
        Float2Ascii ((float)pressure / 100.0, BMP_buf, 2);
        UART_send_string((char*)" Pressure is:");
        UART_send_string(BMP_buf);
        UART_send_string((char*)" hPa");
        UART_new_line();
    }
    else
    {
        UART_send_string((char*)" Forced measurement failed!");
        UART_new_line();
    }
    BMP280_PWR_RC5_SetLow();
}

// end of driver code.
Code:
/*
 * File:   
 * Author:
 * Comments:
 * Revision history:
 */

#include "mcc_generated_files/mcc.h"
#include "SCD4x_CO2.h"
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

/*** SCD4x I2C BUS COMMUNICATION FUNCTIONS ************************************/
/*
* For the send command sequences, after writing the address and/or data to sensor
* and sending the ACK bit, the sensor needs the execution time to respond to the
* I2C read header with an ACK bit.Hence, it is required to wait the command
* execution time before issuing the read header.
* Commands must not be sent while a previous command is being processed.
*/
void SCD4x_send_command(uint16_t command)
{
    SCD4x_Start();
    SCD4x_Write(SCD4x_I2C_ADDRESS<<1);
    SCD4x_Write((command >> 8) & 0xFF); // MSB
    SCD4x_Write(command & 0xFF);        // LSB
    SCD4x_Stop();
}

/*
* Data sent to and received from the sensor consists of a sequence of 16-bit commands and/or 16-bit words
* (each to be interpreted as unsigned integer, most significant byte transmitted first). Each data word is
* immediately succeeded by an 8-bit CRC. In write direction it is mandatory to transmit the checksum.
* In read direction it is up to the master to decide if it wants to process the checksum.
*/
void SCD4x_send_write(uint16_t command, uint16_t data)
{
    /* TODO calculate the checksum and create a function*/
    SCD4x_Start();
    SCD4x_Write(SCD4x_I2C_ADDRESS<<1);
    SCD4x_Write((command >> 8) & 0xFF);  // COMMAND MSB
    SCD4x_Write(command & 0xFF);         // COMMAND LSB
    SCD4x_Write((data >> 8) & 0xFF);     // DATA MSB
    SCD4x_Write(data & 0xFF);            // DATA LSB
    //SCD4x_Write(CHECKSUM);               // CHECKSUM
    SCD4x_Stop();
}

/*
* Data sent to and received from the sensor consists of a sequence of 16-bit commands and/or 16-bit words
* (each to be interpreted as unsigned integer, most significant byte transmitted first). Each data word is
* immediately succeeded by an 8-bit CRC. In write direction it is mandatory to transmit the checksum.
* In read direction it is up to the master to decide if it wants to process the checksum.
*/
void SCD4x_send_read(uint16_t reg, uint8_t count, uint8_t * dest)
{
    SCD4x_Start();
    SCD4x_Write(SCD4x_I2C_ADDRESS <<1);
    SCD4x_Write((reg >> 8) & 0xFF); // MSB
    SCD4x_Write(reg & 0xFF);        // LSB
    SCD4x_RepeatedStart();
    __delay_us(1500);               // Data-sheet specifies this
    SCD4x_Write((SCD4x_I2C_ADDRESS <<1) | 1);
    // receive data
    for(int k=0;k<(count-1);k++){
            dest[k]=SCD4x_Read(1);  // send NACK
    }
    dest[(count-1)]=SCD4x_Read(0);  // send ACK
    SCD4x_Stop();
}

void SCD4x_send_write_and_fetch_result(uint16_t reg, uint16_t command, 
                                 uint8_t *data, uint32_t num_bytes)
{
    /* TODO write checksum and variables */
    SCD4x_Start();
    SCD4x_Write(SCD4x_I2C_ADDRESS<<1);
    SCD4x_Write((reg >> 8) & 0xFF);     // REG MSB
    SCD4x_Write(reg & 0xFF);            // REG LSB
    SCD4x_Write((command >> 8) & 0xFF); // command DATA MSB
    SCD4x_Write(command & 0xFF);        // command DATA LSB
    //SCD4x_Write(CHECKSUM);              // CHECKSUM
    SCD4x_RepeatedStart;
    
    __delay_us(1000);
    
    SCD4x_Write((SCD4x_I2C_ADDRESS<<1) || 1);
    for(int i=0;i<(num_bytes - 1);i++){
        data[i] = SCD4x_Read(1);          // send NACK
    }
    data[(num_bytes - 1)] = SCD4x_Read(0); // send ACK
    SCD4x_Stop;
}

/**** SCD4x FUNCTIONS *********************************************************/
/******************************************************************************/

/*
* Reading out the serial number can be used to identify the chip and to verify
* the presence of the sensor. The get serial number command returns 3 words, and
* every word is followed by an 8-bit CRC checksum. Together, the 3 words
* constitute a unique serial number with length of 48 bits (big ENDIAN format).
*/
void SCD4x_get_serial_number()
{
    char buf[5];
    uint8_t buffer[9] = {0};
    uint16_t s0 = 0, s1 = 0, s2 = 0;

    SCD4x_send_read(SCD4X_GET_SERIAL_NUMBER, 9, &buffer[0]);
    
    s0 = (uint16_t)buffer[0] << 8 | (uint16_t)buffer[1];
    s1 = (uint16_t)buffer[3] << 8 | (uint16_t)buffer[4];
    s2 = (uint16_t)buffer[6] << 8 | (uint16_t)buffer[7];
    
    sprintf(buf, "%x", s0);
    UART_new_line();
    UART_send_string((char*)" SCD4X SERIAL NUMBER = 0x");
    UART_send_string(buf);
    memset(buf, '\0', sizeof(buf));
    
    sprintf(buf, "%x", s1);
    UART_send_string(buf);
    memset(buf, '\0', sizeof(buf));
    
    sprintf(buf, "%x", s2);
    UART_send_string(buf);
    memset(buf, '\0', sizeof(buf));
    UART_new_line();
}

uint16_t SCD4x_getDataReadyStatus()
{
    char response[3];
    uint16_t result = 0;
    SCD4x_send_read(SCD4X_GET_DATA_READY_STATUS, 3, &response[0]);
    
    result = (((response[0] <<8) + response[1]) & 0x07ff);
    //((data_ready_status.value.msb & 0x0F) == 0x00 && data_ready_status.value.lsb == 0x00)
    
    return result;
}

/**** SCD4x BASIC COMMANDS FUNCTIONS ******************************************/

/** start periodic measurement mode. The signal update interval is 5 seconds **/
void SCD4x_start_periodic_measurement()
{
    SCD4x_send_command(SCD4X_START_PERIODIC_MEASUREMENT);
}

/* Description: stop periodic measurement mode to change the sensor
 * configuration or to save power. Note that the sensor will only respond to
 * other commands 500 MS after the stop_periodic_measurement command has been
 * issued.*/
void SCD4x_stop_periodic_measurement()
{
    SCD4x_send_command(SCD4X_STOP_PERIODIC_MEASUREMENT);

}

/*read sensor output. The measurement data can only be read out once per signal
 * update interval as the buffer is emptied upon read-out. If no data is
 * available in the buffer, the sensor returns a NACK. To avoid a NACK response,
 * the get_data_ready_status can be issued to check data status (see Section
 * 3.8.2 for further details). The I2C master can abort the read transfer with a
 * NACK followed by a STOP condition after any data byte if the user is not
 * interested in subsequent data.
 */
void SCD4x_read_measurement()
{
    char buf[20];
    char buffer[9] = {0};
    uint16_t co2 = 0;

    while(!SCD4x_getDataReadyStatus());

    SCD4x_send_read(SCD4X_READ_MEASUREMENT, 9, &buffer[0]);
    
    
    co2 = (buffer[0] << 8) + buffer[1];
    
    memset(buf, '\0', sizeof(buf));
    Integer_To_String(co2, buf);
    //sprintf(buf, "%d", co2);
    UART_new_line();
    UART_send_string((char*)" CO2: ");
    UART_send_string(buf);
    
}

void SCD4x_stop_autoCallibration()
{
    SCD4x_send_write(0x2416, 0x0000);
    __delay_ms(50);
    SCD4x_send_command(0x3615);
    __delay_ms(1000);
}

void display_sd4x()
{
    SCD40_PWR_RC6_SetHigh();
    __delay_ms(500);

    SCD4x_start_periodic_measurement();
    SCD4x_read_measurement();
    SCD4x_stop_periodic_measurement();
    __delay_ms(100);
  
    SCD40_PWR_RC6_SetLow();
}

void initializing_SCD4x()
{
    SCD40_PWR_RC6_SetHigh();
    __delay_ms(500);
    
    UART_new_line();
    UART_send_string((char*)" initializing_SCD4x");

    SCD4x_stop_periodic_measurement();
    SCD4x_get_serial_number();
    SCD4x_stop_periodic_measurement();
    SCD4x_stop_autoCallibration();
    __delay_ms(100);
    
    SCD40_PWR_RC6_SetLow();
 
}
 
Top