CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to support@ccsinfo.com

int64 with PIC18F87J50
Goto page Previous  1, 2, 3  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
ntrungtruc2003



Joined: 16 Feb 2011
Posts: 42

View user's profile Send private message

The problem with read parameter dig_H4
PostPosted: Wed Aug 02, 2017 10:33 pm     Reply with quote

Dear Sir.

I have a problem when read dig_H4 in BME280 sensor
dig_4 return 29 = 11101
but the value true must be 285
0xE4 = 17 10001
0xE5= 13 1101

285 = 1001 1101 = 0XE4*16 + 0xE5
29 = 11101 = 0xE4 + 0xE5

BMEReadDig_H4 like this
unsigned int16 dig_H4;


Code:

unsigned int16 BME280ReadDig_H4()
{
unsigned int16 temp;
byte msb, lsb;
msb = BME280ReadByte(0xE4);
lsb = BME280ReadByte(0xE5);
temp = msb*16 + lsb;
return temp;
}

ccs compiler v5.015
Ttelmah



Joined: 11 Mar 2010
Posts: 19195

View user's profile Send private message

PostPosted: Thu Aug 03, 2017 1:43 am     Reply with quote

As a comment, it is pointless doing repeated byte reads of these registers. The whole point is that if you read one register, the internal counter increments and a second read without re-addressing will then read the next register. Far better to read the whole block of calibration registers in one operation.

Then you are misunderstanding how the registers have to combined.

The value needs to be put into a signed int16, with the top register rotated left by 4, and only the four bottom bits of the second register used.

So:
Code:

signed int16 BME280ReadDig_H4()
{
   unsigned int16 temp;
   byte msb, lsb;
   msb = BME280ReadByte(0xE4);
   lsb = BME280ReadByte(0xE5);
   temp = ((int16)msb<<4) + (lsb & 0xF);
   return temp;
}


The resulting calibration can be -ve, which is why it is meant to be read as a signed value. However I've never actually seen a -ve value. However Bosch do specify this to be returned as a signed int16.
The register value needs to be moved into a 16bit memory 'space' before you rotate it, and the high bits of the second register should also be removed before combining..
ntrungtruc2003



Joined: 16 Feb 2011
Posts: 42

View user's profile Send private message

Problem with read pressure BME280
PostPosted: Fri Aug 04, 2017 3:48 am     Reply with quote

Dear Sir

The sensor works well with temperature and humidity, but with pressure's value i have a problem.

The pressure's value return is about 1646, it is greater than 1002 (1002 hpa is the true value).
All of dig_P is correct.
Quote:

dig_P1 37621
dig_P2 -10728
dig_P3 3024
dig_P4 8061
dig_P5 -139
dig_P6 -7
dig_P7 9900
dig_P8 -10230
dig_P9 4285
adc_P is about 5164160

I have also tested "step by step" in the function ME280_compensate_P_int32().

Code:

unsigned int32 BME280_compensate_P_int32()
{
unsigned int32 adc_P = BME280Read24(0xF7); //FA THE TEMPERATURE REGISTER

if (adc_P == 0x800000) // value in case temp measurement was disabled
        return 0;
adc_T >>= 4;
signed int32 var1, var2;
unsigned int32 p;
//BME280ReadTemperature(); //must be done to get t_fine

var1 = ((t_fine)>>1) - (unsigned int32)64000;
delay_us(100);
var1_p = var1; //test
var11_p = (int32)(168278)>>1; //test

var2 = (((var1>>2) * (var1>>2)) >> 11 ) * ((signed int32)dig_P6);  // dig_p6 is negative
var2_p = var2; //test
var2 = var2 + ((var1*((signed int32)dig_P5))<<1);   // dig_p5 is negative therefore left shift is OK ? shift left is ok

var3_p = var2; //test
var33_p = ((signed int32)dig_P5)<<1;
var2 = (var2>>2)+(((signed int32)dig_P4)<<16);

var4_p = var2;                                         //test
var44_p = (signed int32)dig_P4<<16;       //test
var444_p = var2>>2;                               //test
var4444_p = ((signed int32)-87129)>>2; //only for test this function
var1 = (((dig_P3 * (((var1>>2) * (var1>>2)) >> 13 )) >> 3) + ((((signed int32)dig_P2) * var1)>>1))>>18;

var5_p = var1; //test
var1 =((((32768+var1))*((signed int32)dig_P1))>>15);
var6_p = var1;   //test
if (var1 == 0)
  {
   return 0; // avoid exception caused by division by zero
  }

p = (((unsigned int32)(((signed int32)1048576)-adc_P)-(var2>>12)))*3125;
 var7_p = p; //test
if (p < 0x80000000)
  {
   p = (p << 1) / ((unsigned int32)var1);
  }
else
  {
   p = (p / (unsigned int32)var1) * 2;
  }

var1 = (((signed int32)dig_P9) * ((signed int32)(((p>>3) * (p>>3))>>13)))>>12;
var8_p = var1; //test
var2 = (((signed int32)(p>>2)) * ((signed int32)dig_P8))>>13;
var9_p = var2; // the test value
p = (unsigned int32)((signed int32)p + ((signed int32)(var1 + var2 + dig_P7) >> 4));

return p/100;
}

After that i have a table to compare, the left column is not true, the right column is true value that i want to achieve.

var1_p(32 bit) 20197------------------------------ 21514
var2_p(32 bit) -87129-----------------------------( -98854)
var3_p(32 bit) -5701895-------------------------- (-6079476)
var4_p(32 bit) 1600602046----------------------- 526765759
var5_p(32 bit) 8879--------------------------------( -436)
var6_p(32 bit) 478814----------------------------- 37120

I have also checked with shift signed int32, it's ok.
Could you please give me some advice.
Thanks you so much.
Gabriel



Joined: 03 Aug 2009
Posts: 1067
Location: Panama

View user's profile Send private message

PostPosted: Fri Aug 04, 2017 6:27 am     Reply with quote

I'm having problems with the Humidity value (i don't trust it at least)..... but i got the pressure spot on....

I'll load up my driver later today and we can possibly make a viable driver merging code.

G.
_________________
CCS PCM 5.078 & CCS PCH 5.093
Ttelmah



Joined: 11 Mar 2010
Posts: 19195

View user's profile Send private message

PostPosted: Fri Aug 04, 2017 7:14 am     Reply with quote

The most likely problem is the one I already pointed out about sign extending on the shifts.

Don't use the default shifts on the signed values.

K&R is quite specific that a shift on a signed number is 'implementation specific'. It is _not_ something that can be moved between processors reliably....
This is also stated in the ANSI C specifications as well.

It just happens that on the most common processors today, when dealing with signed numbers, most perform arithmetic shifts.

Replace the shifts yourself. Safest is to generate a macro to do the shifts:
Code:

#define A_SHRT(x,y) (x>0)?(x>>y):(-((-x)>>y))
#DEFINE A_SHLT(x,y) (x>0)?(x<<y):(-((-x)<<y))


Then where you have (for instance) x>>4 you would use A_SHRT(x,4).

This guarantees an 'arithmetic shift', rather than the PIC standard logical shift.
Gabriel



Joined: 03 Aug 2009
Posts: 1067
Location: Panama

View user's profile Send private message

PostPosted: Fri Aug 04, 2017 8:19 am     Reply with quote

Code:
#define BME280 0x77      //The I2C Address of the Device


void Write_BME_Register(int,int,int);
int Read_BME_Register(int,int);
void Get_BME_Data(int, int);

void Setup_BME();
void Calculate_Temp();
void Calculate_Hum();
void Calculate_Pess();

float Temperature;
signed int32 t_fine;
int32 Pressure;

int32 rawpres;
int32 rawtemp;
int32 rawhum;


int16 Dig_T1;
signed int16 Dig_T2;
signed int16 Dig_T3;

int16 Dig_H1;
signed int16 Dig_H2;
int16 Dig_H3;
signed int16 Dig_H4;
signed int16 Dig_H5;
signed int16 Dig_H6;

int16 Dig_P1;
signed int16 Dig_P2;
signed int16 Dig_P3;
signed int16 Dig_P4;
signed int16 Dig_P5;
signed int16 Dig_P6;
signed int16 Dig_P7;
signed int16 Dig_P8;
signed int16 Dig_P9;

void Setup_BME()
{   
   Write_BME_Register(BME280,0xF4,0x00);   //Put it in sleep mode
   delay_ms(2000);
   Write_BME_Register(BME280,0xF5,0x84);   //Set Config Word
   Write_BME_Register(BME280,0xF2,0x04);   //Set Huidity Control
   Write_BME_Register(BME280,0xF4,0x93);   //Set Temp & Press Control + Mode

   Dig_T1 = make16 (Read_BME_Register(BME280,0x89),Read_BME_Register(BME280,0x88));
   Dig_T2 = make16 (Read_BME_Register(BME280,0x8B),Read_BME_Register(BME280,0x8A));
   Dig_T3 = make16 (Read_BME_Register(BME280,0x8D),Read_BME_Register(BME280,0x8C));

   Dig_H1 = Read_BME_Register(BME280,0xA1);
   Dig_H2 = make16 (Read_BME_Register(BME280,0xE2),Read_BME_Register(BME280,0xE1));
   Dig_H3 = Read_BME_Register(BME280,0xE3);

   Dig_H4=(((int16)Read_BME_Register(BME280,0xE4)<<4)|(Read_BME_Register(BME280,0xE5)& 0x0F));
//   Dig_H5 = make16((Read_BME_Register(BME280,0xE5)>>4), Read_BME_Register(BME280,0xE6));

//   Dig_H4 = make16((Read_BME_Register(BME280,0xE4)<<4),(Read_BME_Register(BME280,0xE5)& 0x0F));
//   Dig_H5 = make16((Read_BME_Register(BME280,0xE6)<<4), ((Read_BME_Register(BME280,0xE5)>>4)&0x0F));

//  Dig_H4 = (Read_BME_Register(BME280,0xE4)<<4|(Read_BME_Register(BME280,0xE5) & 0x0F));
//   Dig_H5 = (Read_BME_Register(BME280,0xE6)<<4|(Read_BME_Register(BME280,0xE5) >>4));
   Dig_H5 = make16((Read_BME_Register(BME280,0xE6)<<4),(Read_BME_Register(BME280,0xE5) >>4));

   Dig_H6 = Read_BME_Register(BME280,0xE7);

   Dig_P1 = make16 (Read_BME_Register(BME280,0x8F),Read_BME_Register(BME280,0x8E));
   Dig_P2 = make16 (Read_BME_Register(BME280,0x91),Read_BME_Register(BME280,0x90));
   Dig_P3 = make16 (Read_BME_Register(BME280,0x93),Read_BME_Register(BME280,0x92));
   Dig_P4 = make16 (Read_BME_Register(BME280,0x95),Read_BME_Register(BME280,0x94));
   Dig_P5 = make16 (Read_BME_Register(BME280,0x97),Read_BME_Register(BME280,0x96));
   Dig_P6 = make16 (Read_BME_Register(BME280,0x99),Read_BME_Register(BME280,0x98));
   Dig_P7 = make16 (Read_BME_Register(BME280,0x9B),Read_BME_Register(BME280,0x9A));
   Dig_P8 = make16 (Read_BME_Register(BME280,0x9D),Read_BME_Register(BME280,0x9C));
   Dig_P9 = make16 (Read_BME_Register(BME280,0x9F),Read_BME_Register(BME280,0x9E));
}

void Write_BME_Register(int Dev_Read_Add, int Register_add, int Data)
{
   //int readbit =1;
   //int writebit =0;
   int tempaddress = 0;

   tempaddress = Dev_Read_Add <<1;    //Left Shift 1 bit to allow space for R/W bit
   //tempaddress |= writebit;         //OR the shifted address with the WRITE Bit
   i2c_start();
   i2c_write(tempaddress);          //Address the device with shifted address with WRITE bit set
   i2c_write(Register_add);         //Tell the Device Which Register you want to read
   i2c_write(Data);   
   i2c_stop();
}

int Read_BME_Register(int Dev_Read_Add, int Register_add)
{
   //int readbit=1;
   //int writebit=0;
   int tempaddress=0;
   int Result_Byte=0;

   tempaddress = Dev_Read_Add <<1;    //Left Shift 1 bit to allow space for R/W bit
//   tempaddress |= 0x00;         //OR the shifted address with the WRITE Bit

   i2c_start();                  //Start I2C sequence
   i2c_write(tempaddress);          //Address the device with shifted address with WRITE bit set
   i2c_write(Register_add);         //Tell the Device Which Register you want to read
   
//   tempaddress = Dev_Read_Add <<1;    //Left Shift 1 bit to allow space for R/W bit
   tempaddress |= 0x01;            //OR the shifted address with the READ Bit

   i2c_start();                  //Start I2C sequence
   i2c_write(tempaddress);          //Address the device with shifted address with READ bit set
   Result_Byte = i2c_read(0);         //READ the data onto a Variable - Device ID in this case
   i2c_stop();                     //Stop The I2C transaction
   
   //fprintf(lcd_putc,"Register:%X\n\r", Result_Byte);    //Print your Data --- For the Win.

   return(Result_Byte);
}

void Calculate_Pess()
{
   float var1, var2, p;
   
   var1 = ((float)t_fine/2.0) - 64000.0;
   var2 = var1 * var1 * ((float)Dig_P6) / 32768.0;
   var2 = var2 + var1 * ((float)Dig_P5) * 2.0;
   var2 = (var2/4.0)+(((float)Dig_P4) * 65536.0);
   var1 = (((float)Dig_P3) * var1 * var1 / 524288.0 + ((float)Dig_P2) * var1) / 524288.0;
   var1 = (1.0 + var1 / 32768.0)*((float)Dig_P1);
   if (var1 == 0.0)
   {
   //return 0; // avoid exception caused by division by zero
   }
   p = 1048576.0 - (float)rawpres;
   p = (p - (var2 / 4096.0)) * 6250.0 / var1;
   var1 = ((float)Dig_P9) * p * p / 2147483648.0;
   var2 = p * ((float)Dig_P8) / 32768.0;
   p = p + (var1 + var2 + ((float)Dig_P7)) / 16.0;

   fprintf(lcd_putc,"PRESSURE: %4.2f\n\r",(p/100.0));    //Print your Data --- For the Win.

}

void Calculate_Hum()
{
   int32 var1;

   var1 = (t_fine - ((int32)76800));
   var1 = (((((rawhum << 14) - (((int32)Dig_H4) << 20) - (((int32)Dig_H5) * var1)) + ((int32)16384)) >> 15) * (((((((var1 * ((int32)Dig_H6)) >> 10) * (((var1 * ((int32)Dig_H3)) >> 11) + ((int32)32768))) >> 10) + ((int32)2097152)) *((int32)Dig_H2) + 8192) >> 14));
   var1 = (var1 - (((((var1 >> 15) * (var1 >> 15)) >> 7) * ((int32)Dig_H1)) >> 4));
   var1 = (var1 < 0 ? 0 : var1);
   var1 = (var1 > 419430400 ? 419430400 : var1);

   var1= var1>>12;
   fprintf(lcd_putc,"HUMIDITY: %3.2f \n\r",((float)var1/1024.0));    //Print your Data --- For the Win.
}


void Calculate_Temp()
{
   float var1, var2, T;

   var1 = (((float)rawtemp)/16384.0 - ((float)Dig_T1)/1024.0) * ((float)Dig_T2);
   var2 = ((((float)rawtemp)/131072.0 - ((float)Dig_T1)/8192.0) *
   (((float)rawtemp)/131072.0 - ((float) Dig_T1)/8192.0)) * ((float)Dig_T3);
   t_fine = (signed int32)(var1 + var2);
   Temperature = (var1 + var2) / 5120.0;

   fprintf(lcd_putc,"TEMPERATURE: %3.2f \n\r",Temperature);    //Print your Data --- For the Win.
}

void Get_BME_Data(int Dev_Read_Add, int Register_add)
{
//   int readbit =1;
//   int writebit =0;
   int tempaddress = 0;
   int Temp[8];

   tempaddress = Dev_Read_Add <<1;    //Left Shift 1 bit to allow space for R/W bit
//   tempaddress |= writebit;         //OR the shifted address with the WRITE Bit
   i2c_start();                  //Start I2C sequence
   i2c_write(tempaddress);          //Address the device with shifted address with WRITE bit set
   i2c_write(Register_add);         //Tell the Device Which Register you want to read
   
//   tempaddress = Dev_Read_Add <<1;    //Left Shift 1 bit to allow space for R/W bit
   tempaddress |= 0x01;            //OR the shifted address with the READ Bit
   i2c_start();                  //Start I2C sequence
   i2c_write(tempaddress);          //Address the device with shifted address with READ bit set
   Temp[0]= i2c_read(1);            //0xF7
   Temp[1]= i2c_read(1);            //0xF8
   Temp[2]= i2c_read(1);            //0xF9
   Temp[3]= i2c_read(1);            //0xFa
   Temp[4]= i2c_read(1);            //0xFb
   Temp[5]= i2c_read(1);            //0xFc
   Temp[6]= i2c_read(1);            //0xFd
   Temp[7]= i2c_read(0);            //0xFe
   i2c_stop();                     //Stop The I2C transaction
   

   rawpres = make32(0x00, Temp[0], Temp[1],Temp[2]);
    rawpres >>= 4;

   rawtemp = make32(0x00, Temp[3], Temp[4],Temp[5]);
    rawtemp >>= 4;

   rawhum = make32(0x00,0x00,Temp[6],Temp[7]);

}



In Main:

Code:
   Setup_BME();


   while(1)
   {
      fprintf(lcd_putc,"\fBME-------------------------------------------------------\n\r");
      Get_BME_Data(BME280, 0xF7);
      Calculate_Temp();
      Calculate_Hum();
      Calculate_Pess();
}

_________________
CCS PCM 5.078 & CCS PCH 5.093
Gabriel



Joined: 03 Aug 2009
Posts: 1067
Location: Panama

View user's profile Send private message

PostPosted: Fri Aug 04, 2017 8:21 am     Reply with quote

I am almost certain my problem is with DIG_H4 and DIG_H5.
I agree with Ttelmah that the shifts may be responsible for the errors.


Please note this is most definitely trial an error code with a lot of "ill fix that once i get it working" - like int functions that i have voided etc... none existant return paths... and the likes...
_________________
CCS PCM 5.078 & CCS PCH 5.093
ntrungtruc2003



Joined: 16 Feb 2011
Posts: 42

View user's profile Send private message

PostPosted: Fri Aug 04, 2017 11:23 am     Reply with quote

Thanks all of you so much

Thanks to Gabriel for your pressure calculating code.
BME280.c

All of sensors in BME280 work perfect for me.
PIC16F887
I2c software
D0------ SCL
D1------SDA
PIC16F

Code:


//************************************************
//  BME280 Barometric Pressure Sensor
//
//  - Datasheet:  https://cdn-shop.adafruit.com/datasheets/BST-BME280_DS001-10.pdf
//
//  - Written in CCS PCH C using floating point math
//  - Several integer math versions of this driver exist but the speed improvement is
//    not warranted in typical weather station type applications
// 
//  - Based on a paper posted to thebackshed.com by 
//    https://learn.adafruit.com/adafruit-bme280-humidity-barometric-pressure-temperature-sensor-breakout/wiring-and-test 
//
//
//    Revision - integer algotihm
//     
//    07/24/2017
//
//  Nguyen Trung Truc
//  08/17/12
//************************************************
// place a #use i2c statement in the main program and comment this out if not applicable
//#define BME280_SDA  PIN_C4
//#define BME280_SCL  PIN_C3
#use i2c(master, sda=PIN_D0, scl=PIN_D1, FORCE_SW)
#define BME280_ADDRESS 0xEE          // I2C address of BME280 VDD
#define A_SHRT(var2,y) (var2>0)?(var2>>y):(-((-var2)>>y))
#define A_SHLT(x,y) (x>0)?(x<<y):(-((-x)<<y))

//#include <math.h>
//#include<stdint.h>
//calibration values of BME280
       
       static unsigned int16 dig_T1;
       static signed int16  dig_T2;
       static signed int16  dig_T3;
       static unsigned int16  dig_P1;// = 37621;
       static signed int16  dig_P2;
       static signed int16  dig_P3;
       static signed int16  dig_P4;
       static signed int16  dig_P5;
       static signed int16  dig_P6;
       static signed int16  dig_P7;
       static signed int16  dig_P8;
       static signed int16  dig_P9;
       static unsigned int8  dig_H1;
       static signed int16  dig_H2;
       static unsigned int8  dig_H3;
       static unsigned int16  dig_H4;
       static signed int16  dig_H5;
       static signed int8   dig_H6;
       static signed int32 t_fine;//var1, var2;
       static signed int32 var1_p, var2_p, var3_p, var4_p, var5_p, var6_p, var7_p, var8_p, var9_p, var11_p, var33_p, var44_p, var444_p, var4444_p;
       static unsigned int32 adc_P, adc_T;
       static unsigned int16 adc_H;
       static int8 data[8];
int8 BME280ReadByte(int8 address);
int16 BME280ReadInt(int8 address) ;
int32 BME280Read24(int8 data);
void BME280WriteByte(int8 address, int8 data) ;
int1 BME280ReadingCalibration(void);
void BME280Calibration();
void BME280SetSampling();

void init_BME280()
{
   output_float(PIN_D0);
   output_float(PIN_D1);
}
int1 BME280Begin()
{
   
    // check if sensor, i.e. the chip ID is correct
    if(BME280ReadByte(0xD0) != 0x60)
        return 0;
    // reset the device using soft-reset
    // this makes sure the IIR is off, etc.
    BME280WriteByte(0xE0, 0xB6);

    // wait for chip to wake up.
    delay_ms(300);

    // if chip is still reading calibration, delay
    while ( BME280ReadingCalibration())
          delay_ms(100);

    BME280Calibration(); // read trimming parameters, see DS 4.2.2

    BME280SetSampling(); // use defaults

    return 1;
}
void BME280SetSampling()
{
 
     BME280WriteByte(0xF2,0x03); // oversampling x 4, ctr_hum
     BME280WriteByte(0xF5,0x68); //011 (250ms tstandby) 0100 (filter coefficient =4) 0 (i2c)
     BME280WriteByte(0xF4,0x6E);// 011 011 10 temperature oversampling x 4, pressure oversampling x 4, force mode
    // you must make sure to also set REGISTER_CONTROL after setting the
    // CONTROLHUMID register, otherwise the values won't be applied (see DS 5.4.3)
    // write8(BME280_REGISTER_CONTROLHUMID, _humReg.get());
    // write8(BME280_REGISTER_CONFIG, _configReg.get());
    // write8(BME280_REGISTER_CONTROL, _measReg.get());
}

int8 BME280ReadID()
//----------------------------------------------
{
int8 data;

   i2c_start();
   i2c_write(0xEE); // 0X77 11101110X IS IC ADDRESS, 0X76 IS 1110 110
   i2c_write(0xD0);
   i2c_start();
   i2c_write(0xEF );
   data=i2c_read(0);
   i2c_stop();
   delay_us(20);
   return(data);
}
//----------------------------------------------
byte BME280ReadByte(int8 address)
//----------------------------------------------
{
byte data;

   i2c_start();
   i2c_write(BME280_ADDRESS);
   i2c_write(address);
   i2c_start();
   i2c_write(BME280_ADDRESS | 0x01 );
   data=i2c_read(0);
   i2c_stop();
   return(data);
}



//----------------------------------------------
int16 BME280Read16(int8 address)
//----------------------------------------------
{
byte msb, lsb;
unsigned int16 temp;

   i2c_start();
   i2c_write(BME280_ADDRESS);
   i2c_write(address);
   i2c_start();
   i2c_write(BME280_ADDRESS | 0x01 );
   msb = i2c_read();
   lsb = i2c_read(0);
   i2c_stop();
   temp = msb*256 + lsb; //(msb<<8)|lsb;
   return ( temp );
}

/**************************************************************************/
/*!
    @brief  Reads a signed 16 bit value over I2C or SPI
*/
/**************************************************************************/
int16 BME280ReadS16(int8 address)
{
    return ((signed int16)BME280Read16(address));
}

unsigned int16 BME280Read16_LE(int8 address)
{
    unsigned int16 temp;
    temp = BME280Read16(address);
    temp = (temp >> 8) | (temp << 8);
    return (unsigned int16)temp;
}
signed int16 BME280ReadS16_LE(int8 address)
{
    return (signed int16)BME280Read16_LE(address);
}

//----------------------------------------------
void BME280WriteByte(int8 address, int8 data)
//----------------------------------------------
{
   i2c_start();
   i2c_write(BME280_ADDRESS);
   i2c_write(address);
   i2c_write(data);
   i2c_stop();
}

signed int16 BME280ReadDig_H4()
{
   unsigned int16 temp;
   byte msb, lsb;
   msb = BME280ReadByte(0xE4);
   lsb = BME280ReadByte(0xE5);
   temp = ((int16)msb<<4) + (lsb & 0xF);
   return temp;
}

void BME280Calibration()
//----------------------------------------------
{   
  dig_T1 = BME280Read16_LE(0x88);
  dig_T2 = BME280ReadS16_LE(0x8A);
  dig_T3 = BME280ReadS16_LE(0x8C);
  dig_P1 = BME280Read16_LE(0x8E);
  dig_P2 = BME280ReadS16_LE(0x90);
  dig_P3 = BME280ReadS16_LE(0x92);
  dig_P4 = BME280ReadS16_LE(0x94);
  dig_P5 = BME280ReadS16_LE(0x96);
  dig_P6 = BME280ReadS16_LE(0x98);
  dig_P7 = BME280ReadS16_LE(0x9A);
  dig_P8 = BME280ReadS16_LE(0x9C);
  dig_P9 = BME280ReadS16_LE(0x9E);
 
  dig_H1 = BME280ReadByte(0xA1);
  dig_H2 = BME280ReadS16_LE(0xE1);
  dig_H3 = BME280ReadByte(0xE3);
  dig_H4 = BME280ReadDig_H4(); //285
  dig_H5 = (BME280ReadByte(0xE6)<<4)|(BME280ReadByte(0xE5) >>4) ;
  dig_H6 = (signed int8)BME280ReadByte(0xE7);
 
}

//----------------------------------------------


// Read the uncompensated temperature value
//----------------------------------------------

void BurstRead()
{
     // int8 data[8]; 
      i2c_start();
      i2c_write(BME280_ADDRESS);
      i2c_write(0xF7);
     
      i2c_start();
      i2c_write(BME280_ADDRESS | 0x01);
      data[0] = i2c_read();
      data[1] = i2c_read();
      data[2] = i2c_read();
      data[3] = i2c_read();
      data[4] = i2c_read();
      data[5] = i2c_read();
      data[6] = i2c_read();
      data[7] = i2c_read();   
      i2c_stop();
     //ata[5]=data[5]&0xF0;
      adc_P = make32(0,data[0],data[1],data[2]);
     // adc_T = make32(0,data[3],data[4]);
      adc_T  = make32(0,data[3],data[4],data[5]);
      adc_H = make16(data[6],data[7]);
     
      // Read register 0xF6 (MSB), 0xF7 (LSB), and 0xF8 (XLSB)
}

unsigned int32 BME280Read24(int8 data)
{
 unsigned int32 value;
 int8 msb, lsb, xlsb;
 
      i2c_start();
      i2c_write(BME280_ADDRESS);
      i2c_write(data);
     
      i2c_start();
      i2c_write(BME280_ADDRESS | 0x01);
     
      // Read register 0xF6 (MSB), 0xF7 (LSB), and 0xF8 (XLSB)
     
      msb = i2c_read();
      lsb = i2c_read();
      xlsb = i2c_read(0); // NACK on last read
      i2c_stop(); //*/
     
      value = make32(0,msb,lsb,xlsb); // (msb<<16)|(lsb<<8)|xlsb ;

    return value;
}


int1 BME280ReadingCalibration(void)
{
 // unsigned int8 const rStatus = BME280ReadByte(0xF3);
  int8 rStatus = BME280ReadByte(0xF3);
  return (rStatus & (1 << 0)) != 0; // return 1 if bus is busy reading 1<<0  is 1 shifted left 0 times
}

void BME280TakeForcedMeasurement()
{   
   
     BME280WriteByte(0xF4,0x6E); //011 011 01 pressure oversampling x 4, temperature oversampling x 4, forced mode
     while (BME280ReadByte(0xF4) & 0x08)  // wait until measurement has been completed, otherwise we would read the values from the last measurement
      delay_us(10);
    }
   

float BME280ReadTemperature(void)
{

 
   signed int32 var1, var2;

    //signed int32 adc_T = BME280Read24(0xFA); //FA THE TEMPERATURE REGISTER
    if (adc_T == 0x800000) // value in case temp measurement was disabled
        return 0;
    adc_T >>= 4;

    var1 = ((((adc_T>>3) - ((signed int32)dig_T1 <<1)))*((signed int32)dig_T2)) >> 11;
             
    var2 = (((((adc_T>>4) - ((signed int32)dig_T1)) * ((adc_T>>4) - ((signed int32)dig_T1))) >> 12) *((signed int32)dig_T3)) >> 14;
   
   t_fine = var1 + var2;

    float T= (t_fine * 5 + 128) >> 8;
    return T/100;
   
}

unsigned int32 BME280_compensate_P_int32()
{

 //signed int32 adc_P = BME280Read24(0xF7); //FA THE TEMPERATURE REGISTER
if (adc_P == 0x800000) // value in case temp measurement was disabled
        return 0;
    adc_P >>= 4;
    signed int32 var1, var2, var3;
    unsigned int32 p;
    //BME280ReadTemperature(); //must be done to get t_fine
  t_fine = t_fine +2000;
var1 = (((signed int32)t_fine)>>1) - (unsigned int32)64000;
//delay_us(100);
 var11_p = (int32)(168278)>>1;
var2 = (((var1>>2) * (var1>>2)) >> 11 ) * ((signed int32)dig_P6);  // dig_p6 is negative
var2 = var2 + ((var1*((signed int32)dig_P5))<<1);   // dig_p5 is negative therefore left shift is OK ? sfhit left is ok
var33_p = ((signed int32)dig_P5)<<1;
var2 = A_SHRT(var2,2)+(((signed int32)dig_P4)<<16);
var3=(signed int32)dig_P2 * var1;
var3 = A_SHRT(var3,1);
var3 = ((dig_P3 * ((A_SHRT(var1,2) *A_SHRT(var1,2)) >> 13 )) >> 3)+ var3;
var1= A_SHRT(var3,18);

 var5_p = var1;
 var1 = (32768+var1)*(signed int32)dig_P1;
 var1 = A_SHRT(var1,15);


if (var1 == 0)
{
return 0; // avoid exception caused by division by zero
}
p = (((unsigned int32)(((signed int32)1048576) - adc_P)- A_SHRT(var2,12)))*3125;
//p = (((unsigned int32)(((signed int32)1048576) - adc_P)-(var2>>12)))*3125;

if (p < 0x80000000)
{
p = (p << 1) / ((unsigned int32)var1);
}
else
{
p = (p / (unsigned int32)var1) * 2;
}
var1 = (((signed int32)dig_P9) * ((signed int32)(((p>>3) * (p>>3))>>13)))>>12;

//var2 = (((signed int32)(p>>2)) * ((signed int32)dig_P8))>>13;
var2 = (((signed int32)(p>>2)) * ((signed int32)dig_P8));
var2 = A_SHRT(var2,13);
//var2 = (((signed int32)(p>>2)) * ((signed int32)dig_P8))>>13;

p = (unsigned int32)((signed int32)p + ((signed int32)(var1 + var2 + dig_P7) >> 4));
return p;
}
   
float Calculate_Pess()
{
   float var1, var2, p;
    if (adc_P == 0x800000) // value in case temp measurement was disabled
        return 0;
    adc_P >>= 4;
   var1 = ((float)t_fine/2.0) - 64000.0;
   var2 = var1 * var1 * ((float)dig_P6) / 32768.0;
   var2 = var2 + var1 * ((float)dig_P5) * 2.0;
   var2 = (var2/4.0)+(((float)dig_P4) * 65536.0);
   var1 = (((float)dig_P3) * var1 * var1 / 524288.0 + ((float)dig_P2) * var1) / 524288.0;
   var1 = (1.0 + var1 / 32768.0)*((float)dig_P1);
   if (var1 == 0.0)
   {
   //return 0; // avoid exception caused by division by zero
   }
   p = 1048576.0 - (float)adc_P;
   p = (p - (var2 / 4096.0)) * 6250.0 / var1;
   var1 = ((float)dig_P9) * p * p / 2147483648.0;
   var2 = p * ((float)dig_P8) / 32768.0;
   p = p + (var1 + var2 + ((float)dig_P7)) / 16.0;
return p/100;
   
}
 

float BME280ReadHumidity(void) {
    //readTemperature(); // must be done first to get
   

    int32 adc_H = BME280Read16(0xFD);// BME280_REGISTER_HUMIDDATA
   
    if (adc_H == 0x8000) // value in case humidity measurement was disabled
        return 0;
    signed int32  v_x1_u32r;

    v_x1_u32r = (t_fine - ((signed int32)76800));

    v_x1_u32r = (((((adc_H << 14) - (((int32)dig_H4) << 20) -
                    (((signed int32)dig_H5) * v_x1_u32r)) + ((signed int32)16384)) >> 15) *
                 (((((((v_x1_u32r * ((int32)dig_H6)) >> 10) *
                      (((v_x1_u32r * ((signed int32)dig_H3)) >> 11) + ((signed int32)32768))) >> 10) +
                    ((signed int32)2097152)) * ((signed int32)dig_H2) + 8192) >> 14));

    v_x1_u32r = (v_x1_u32r - (((((v_x1_u32r >> 15) * (v_x1_u32r >> 15)) >> 7)*((signed int32)dig_H1)) >> 4));
    v_x1_u32r = (v_x1_u32r < 0) ? 0 : v_x1_u32r;
    v_x1_u32r = (v_x1_u32r > 419430400) ? 419430400 : v_x1_u32r;
    float h = (v_x1_u32r>>12);
    return  h / 1024.0;
}

// Read the uncompensated pressure value
//----------------------------------------------






In main.c

Code:

//#include <16f877A.h>
#include <16F887.h>
#fuses HS, NOLVP, NOWDT, NOPROTECT
#use   delay (clock=8000000) //Use built-in function: delay_ms() & delay_us()
#use rs232(baud=38400, xmit=PIN_C6, rcv=PIN_C7)
#include "LCD_TM.c" //use module function
#include "BME280.c"
#include<stdlib.h>
void main(void)
{
int8 a;

float temp, hu;
unsigned int32 press;


 init_BME280();
      BME280Begin();
      delay_ms(200);
     
      printf("\r\ndig_T1: =%LU dig_T2=%Ld dig_T3=%Ld", dig_T1, dig_T2, dig_T3);
      printf("\r\nP1=%LU P2=%Ld  P3=%Ld P4=%Ld P5=%Ld P6=%Ld P7=%Ld P8=%Ld P9=%Ld",dig_P1, dig_P2, dig_P3, dig_P4, dig_P5, dig_P6, dig_P7, dig_P8, dig_P9 );
      printf("\r\nH1=%U H2=%LD H3=%U H4=%Lu H5=%Ld H6=%U", dig_H1, dig_H2, dig_H3, dig_H4, dig_H5, dig_H6);
     
while(true)
   {
     
   
     
      BurstRead();
      delay_ms(100);
     
     temp = BME280ReadTemperature();
     delay_ms(100);
     // press = BME280_compensate_P_int32();
      delay_ms(100);
    hu = BME280ReadHumidity();
    delay_ms(50);
    press = Calculate_Pess();
    delay_ms(50);
      lcd_init();
      lcd_gotoxy(1,1);
      printf(lcd_putc, "%3.1f",hu);   
     
      lcd_gotoxy(8,1);
      printf(lcd_putc, "%3.2f",temp);
     
      lcd_gotoxy(1,2);
      printf(lcd_putc, "%Ld",press);
       printf("adc_H=%Ld",adc_H); 
     
      a = BME280ReadByte(0xF3);
     // BME280WriteByte(0xF5,0x68); //011 (250ms tstandby) 0100 (filter coefficient =4) 0 (i2c)
      BME280WriteByte(0xF4,0x6E);
      lcd_gotoxy(15,1);
      printf(lcd_putc, "%u",a); 
     
       lcd_gotoxy(10,2);
      printf(lcd_putc, "%Lu",adc_P);
     
      // printf("\r\nvar1_p=%Ld var2_p=%Ld var3_p=%Ld var4_p=%Ld var5_p=%Ld ", var1_p, var2_p, var3_p, var4_p, var5_p);
      //printf("\r\nvar6_p=%Ld var7_p=%Ld var8_p=%Ld var9_p=%Ld", var6_p, var7_p, var8_p, var9_p);
     
       
      // printf("\r\nvar11_p_p=%Ld var33_p=%Ld var44_p=%Ld  t_fine=%Ld ", var11_p, var33_p, var44_p, t_fine);
      // printf("\r\nvar444=%Ld var4444=%Ld", var444_p, var4444_p);
      delay_ms(800);
   
    }
}
viki2000



Joined: 08 May 2013
Posts: 233

View user's profile Send private message

PostPosted: Tue Nov 07, 2017 8:35 am     Reply with quote

I have tested the above code for BME280 and in my case works with a small problem.
I need your advices to track down the problem.

In my setup I use PIC16F1829 with internal clock instead of the PIC16f877A.
I sent the data to a small LCD 2x8 using flex_lcd driver.
I force the hardware communication for I2C instead of software.
I am interested only on temperature and humidity.
My BME280 sensor has the address 76 (EC) instead of 77 (EE) – that I have tested with Arduino Uno, when I tested the sensor first time and works fine.
The data shown on LCD is meaningful info compared with Arduino Uno code and setup and it seems that the setup with PIC16F1829 and above code works.
What is my actual problem?
In the main subroutine, in the while(1) loop I must include “BME280Begin();”.
If the “BME280Begin();” is outside of the while(1), before of it, then it reads the sensor data only once at start-up and shows the same value all the time. But that is not normal, it is supposed to do the “BME280Begin();” only once before while(1) loop and not all the time.
Maybe I mixed up or forgot to change an address related with I2C or sensor, I do not know what is it.
Can you help to track down this problem?
Why in my case I have to do the “BME280Begin();” always?
What did I miss to change when I ported to code to PIC16F1829 and sensor address 76 instead of 77?

Here is the code that I have used:
Code:
//main code
//PIC16F1829 with BME280 address 76
#include <16F1829.h>
#use delay(internal=32000000)

#FUSES NOPUT                    //No Power Up Timer
#FUSES NOMCLR                   //Master Clear pin used for I/O
#FUSES NOPROTECT                //Code not protected from reading
#FUSES NOCPD                    //No EE protection
#FUSES NOBROWNOUT               //No brownout reset
#FUSES NOCLKOUT                 //I/O function on OSC2
#FUSES NOIESO                   //Internal External Switch Over mode disabled
#FUSES NOFCMEN                  //Fail-safe clock monitor disabled
#FUSES NOWRT                    //Program memory not write protected
#FUSES NOSTVREN                 //Stack full/underflow will not cause reset
#FUSES BORV19                   //Brownout reset at 1.9V
#FUSES NOLVP                    //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOWDT

//#define BME280_SDA  PIN_B4
//#define BME280_SCL  PIN_B6
#use i2c(master, sda=PIN_B4, scl=PIN_B6, FORCE_HW)

#include <flex_lcd.c>
#include "BME280.c"
#include<stdlib.h>
void main(void)
{
int8 a;

float temp, hu;
unsigned int32 press;

init_BME280();

     
while(true)
   {   
     
      BME280Begin();
      delay_ms(200);
     
      BurstRead();
      delay_ms(100);
     
     temp = BME280ReadTemperature();
     delay_ms(100);
     // press = BME280_compensate_P_int32();
      delay_ms(100);
    hu = BME280ReadHumidity();
    delay_ms(50);
   
      lcd_init();
      lcd_gotoxy(1,1);
      printf(lcd_putc, "%3.1f",hu);
      lcd_putc(" %");
     
     
      lcd_gotoxy(1,2);
      printf(lcd_putc, "%3.2f",temp);
      lcd_putc(" C");
      delay_ms(800);
   
    }
}


Code:
//************************************************
//  BME280 Barometric Pressure Sensor
//
//  - Datasheet:  https://cdn-shop.adafruit.com/datasheets/BST-BME280_DS001-10.pdf
//
//  - Written in CCS PCH C using floating point math
//  - Several integer math versions of this driver exist but the speed improvement is
//    not warranted in typical weather station type applications
//
//  - Based on a paper posted to thebackshed.com by
//    https://learn.adafruit.com/adafruit-bme280-humidity-barometric-pressure-temperature-sensor-breakout/wiring-and-test
//
//
//    Revision - integer algotihm
//     
//    07/24/2017
//
//  Nguyen Trung Truc
//  08/17/12
//************************************************
// place a #use i2c statement in the main program and comment this out if not applicable

#define BME280_ADDRESS 0xEC          // I2C address of BME280 VDD
#define A_SHRT(var2,y) (var2>0)?(var2>>y):(-((-var2)>>y))
#define A_SHLT(x,y) (x>0)?(x<<y):(-((-x)<<y))

#include <math.h>
#include<stdint.h>
//calibration values of BME280
       
       static unsigned int16 dig_T1;
       static signed int16  dig_T2;
       static signed int16  dig_T3;
       static unsigned int16  dig_P1;// = 37621;
       static signed int16  dig_P2;
       static signed int16  dig_P3;
       static signed int16  dig_P4;
       static signed int16  dig_P5;
       static signed int16  dig_P6;
       static signed int16  dig_P7;
       static signed int16  dig_P8;
       static signed int16  dig_P9;
       static unsigned int8  dig_H1;
       static signed int16  dig_H2;
       static unsigned int8  dig_H3;
       static unsigned int16  dig_H4;
       static signed int16  dig_H5;
       static signed int8   dig_H6;
       static signed int32 t_fine;//var1, var2;
       static signed int32 var1_p, var2_p, var3_p, var4_p, var5_p, var6_p, var7_p, var8_p, var9_p, var11_p, var33_p, var44_p, var444_p, var4444_p;
       static unsigned int32 adc_P, adc_T;
       static unsigned int16 adc_H;
       static int8 data[8];
int8 BME280ReadByte(int8 address);
int16 BME280ReadInt(int8 address) ;
int32 BME280Read24(int8 data);
void BME280WriteByte(int8 address, int8 data) ;
int1 BME280ReadingCalibration(void);
void BME280Calibration();
void BME280SetSampling();

void init_BME280()
{
   output_float(PIN_B4);
   output_float(PIN_B6);
}
int1 BME280Begin()
{
   
    // check if sensor, i.e. the chip ID is correct
    if(BME280ReadByte(0xD0) != 0x60)
        return 0;
    // reset the device using soft-reset
    // this makes sure the IIR is off, etc.
    BME280WriteByte(0xE0, 0xB6);

    // wait for chip to wake up.
    delay_ms(300);

    // if chip is still reading calibration, delay
    while ( BME280ReadingCalibration())
          delay_ms(100);

    BME280Calibration(); // read trimming parameters, see DS 4.2.2

    BME280SetSampling(); // use defaults

    return 1;
}
void BME280SetSampling()
{
 
     BME280WriteByte(0xF2,0x03); // oversampling x 4, ctr_hum
     BME280WriteByte(0xF5,0x68); //011 (250ms tstandby) 0100 (filter coefficient =4) 0 (i2c)
     BME280WriteByte(0xF4,0x6E);// 011 011 10 temperature oversampling x 4, pressure oversampling x 4, force mode
    // you must make sure to also set REGISTER_CONTROL after setting the
    // CONTROLHUMID register, otherwise the values won't be applied (see DS 5.4.3)
    // write8(BME280_REGISTER_CONTROLHUMID, _humReg.get());
    // write8(BME280_REGISTER_CONFIG, _configReg.get());
    // write8(BME280_REGISTER_CONTROL, _measReg.get());
}

int8 BME280ReadID()
//----------------------------------------------
{
int8 data;

   i2c_start();
   i2c_write(0xEC); // 0X77 11101110X IS IC ADDRESS, 0X76 IS 1110 110
   i2c_write(0xD0);
   i2c_start();
   i2c_write(0xED);
   data=i2c_read(0);
   i2c_stop();
   delay_us(20);
   return(data);
}
//----------------------------------------------
byte BME280ReadByte(int8 address)
//----------------------------------------------
{
byte data;

   i2c_start();
   i2c_write(BME280_ADDRESS);
   i2c_write(address);
   i2c_start();
   i2c_write(BME280_ADDRESS | 0x01 );
   data=i2c_read(0);
   i2c_stop();
   return(data);
}



//----------------------------------------------
int16 BME280Read16(int8 address)
//----------------------------------------------
{
byte msb, lsb;
unsigned int16 temp;

   i2c_start();
   i2c_write(BME280_ADDRESS);
   i2c_write(address);
   i2c_start();
   i2c_write(BME280_ADDRESS | 0x01 );
   msb = i2c_read();
   lsb = i2c_read(0);
   i2c_stop();
   temp = msb*256 + lsb; //(msb<<8)|lsb;
   return ( temp );
}

/**************************************************************************/
/*!
    @brief  Reads a signed 16 bit value over I2C or SPI
*/
/**************************************************************************/
int16 BME280ReadS16(int8 address)
{
    return ((signed int16)BME280Read16(address));
}

unsigned int16 BME280Read16_LE(int8 address)
{
    unsigned int16 temp;
    temp = BME280Read16(address);
    temp = (temp >> 8) | (temp << 8);
    return (unsigned int16)temp;
}
signed int16 BME280ReadS16_LE(int8 address)
{
    return (signed int16)BME280Read16_LE(address);
}

//----------------------------------------------
void BME280WriteByte(int8 address, int8 data)
//----------------------------------------------
{
   i2c_start();
   i2c_write(BME280_ADDRESS);
   i2c_write(address);
   i2c_write(data);
   i2c_stop();
}

signed int16 BME280ReadDig_H4()
{
   unsigned int16 temp;
   byte msb, lsb;
   msb = BME280ReadByte(0xE4);
   lsb = BME280ReadByte(0xE5);
   temp = ((int16)msb<<4) + (lsb & 0xF);
   return temp;
}

void BME280Calibration()
//----------------------------------------------
{   
  dig_T1 = BME280Read16_LE(0x88);
  dig_T2 = BME280ReadS16_LE(0x8A);
  dig_T3 = BME280ReadS16_LE(0x8C);
  dig_P1 = BME280Read16_LE(0x8E);
  dig_P2 = BME280ReadS16_LE(0x90);
  dig_P3 = BME280ReadS16_LE(0x92);
  dig_P4 = BME280ReadS16_LE(0x94);
  dig_P5 = BME280ReadS16_LE(0x96);
  dig_P6 = BME280ReadS16_LE(0x98);
  dig_P7 = BME280ReadS16_LE(0x9A);
  dig_P8 = BME280ReadS16_LE(0x9C);
  dig_P9 = BME280ReadS16_LE(0x9E);
 
  dig_H1 = BME280ReadByte(0xA1);
  dig_H2 = BME280ReadS16_LE(0xE1);
  dig_H3 = BME280ReadByte(0xE3);
  dig_H4 = BME280ReadDig_H4(); //285
  dig_H5 = (BME280ReadByte(0xE6)<<4)|(BME280ReadByte(0xE5) >>4) ;
  dig_H6 = (signed int8)BME280ReadByte(0xE7);
 
}

//----------------------------------------------


// Read the uncompensated temperature value
//----------------------------------------------

void BurstRead()
{
     // int8 data[8];
      i2c_start();
      i2c_write(BME280_ADDRESS);
      i2c_write(0xF7);
     
      i2c_start();
      i2c_write(BME280_ADDRESS | 0x01);
      data[0] = i2c_read();
      data[1] = i2c_read();
      data[2] = i2c_read();
      data[3] = i2c_read();
      data[4] = i2c_read();
      data[5] = i2c_read();
      data[6] = i2c_read();
      data[7] = i2c_read();   
      i2c_stop();
     //ata[5]=data[5]&0xF0;
      adc_P = make32(0,data[0],data[1],data[2]);
     // adc_T = make32(0,data[3],data[4]);
      adc_T  = make32(0,data[3],data[4],data[5]);
      adc_H = make16(data[6],data[7]);
     
      // Read register 0xF6 (MSB), 0xF7 (LSB), and 0xF8 (XLSB)
}

unsigned int32 BME280Read24(int8 data)
{
 unsigned int32 value;
 int8 msb, lsb, xlsb;
 
      i2c_start();
      i2c_write(BME280_ADDRESS);
      i2c_write(data);
     
      i2c_start();
      i2c_write(BME280_ADDRESS | 0x01);
     
      // Read register 0xF6 (MSB), 0xF7 (LSB), and 0xF8 (XLSB)
     
      msb = i2c_read();
      lsb = i2c_read();
      xlsb = i2c_read(0); // NACK on last read
      i2c_stop(); //*/
     
      value = make32(0,msb,lsb,xlsb); // (msb<<16)|(lsb<<8)|xlsb ;

    return value;
}


int1 BME280ReadingCalibration(void)
{
 // unsigned int8 const rStatus = BME280ReadByte(0xF3);
  int8 rStatus = BME280ReadByte(0xF3);
  return (rStatus & (1 << 0)) != 0; // return 1 if bus is busy reading 1<<0  is 1 shifted left 0 times
}

void BME280TakeForcedMeasurement()
{   
   
     BME280WriteByte(0xF4,0x6E); //011 011 01 pressure oversampling x 4, temperature oversampling x 4, forced mode
     while (BME280ReadByte(0xF4) & 0x08)  // wait until measurement has been completed, otherwise we would read the values from the last measurement
      delay_us(10);
    }
   

float BME280ReadTemperature(void)
{

 
   signed int32 var1, var2;

    //signed int32 adc_T = BME280Read24(0xFA); //FA THE TEMPERATURE REGISTER
    if (adc_T == 0x800000) // value in case temp measurement was disabled
        return 0;
    adc_T >>= 4;

    var1 = ((((adc_T>>3) - ((signed int32)dig_T1 <<1)))*((signed int32)dig_T2)) >> 11;
             
    var2 = (((((adc_T>>4) - ((signed int32)dig_T1)) * ((adc_T>>4) - ((signed int32)dig_T1))) >> 12) *((signed int32)dig_T3)) >> 14;
   
   t_fine = var1 + var2;

    float T= (t_fine * 5 + 128) >> 8;
    return T/100;
   
}

unsigned int32 BME280_compensate_P_int32()
{

 //signed int32 adc_P = BME280Read24(0xF7); //FA THE TEMPERATURE REGISTER
if (adc_P == 0x800000) // value in case temp measurement was disabled
        return 0;
    adc_P >>= 4;
    signed int32 var1, var2, var3;
    unsigned int32 p;
    //BME280ReadTemperature(); //must be done to get t_fine
  t_fine = t_fine +2000;
var1 = (((signed int32)t_fine)>>1) - (unsigned int32)64000;
//delay_us(100);
 var11_p = (int32)(168278)>>1;
var2 = (((var1>>2) * (var1>>2)) >> 11 ) * ((signed int32)dig_P6);  // dig_p6 is negative
var2 = var2 + ((var1*((signed int32)dig_P5))<<1);   // dig_p5 is negative therefore left shift is OK ? sfhit left is ok
var33_p = ((signed int32)dig_P5)<<1;
var2 = A_SHRT(var2,2)+(((signed int32)dig_P4)<<16);
var3=(signed int32)dig_P2 * var1;
var3 = A_SHRT(var3,1);
var3 = ((dig_P3 * ((A_SHRT(var1,2) *A_SHRT(var1,2)) >> 13 )) >> 3)+ var3;
var1= A_SHRT(var3,18);

 var5_p = var1;
 var1 = (32768+var1)*(signed int32)dig_P1;
 var1 = A_SHRT(var1,15);


if (var1 == 0)
{
return 0; // avoid exception caused by division by zero
}
p = (((unsigned int32)(((signed int32)1048576) - adc_P)- A_SHRT(var2,12)))*3125;
//p = (((unsigned int32)(((signed int32)1048576) - adc_P)-(var2>>12)))*3125;

if (p < 0x80000000)
{
p = (p << 1) / ((unsigned int32)var1);
}
else
{
p = (p / (unsigned int32)var1) * 2;
}
var1 = (((signed int32)dig_P9) * ((signed int32)(((p>>3) * (p>>3))>>13)))>>12;

//var2 = (((signed int32)(p>>2)) * ((signed int32)dig_P8))>>13;
var2 = (((signed int32)(p>>2)) * ((signed int32)dig_P8));
var2 = A_SHRT(var2,13);
//var2 = (((signed int32)(p>>2)) * ((signed int32)dig_P8))>>13;

p = (unsigned int32)((signed int32)p + ((signed int32)(var1 + var2 + dig_P7) >> 4));
return p;
}
   
float Calculate_Pess()
{
   float var1, var2, p;
    if (adc_P == 0x800000) // value in case temp measurement was disabled
        return 0;
    adc_P >>= 4;
   var1 = ((float)t_fine/2.0) - 64000.0;
   var2 = var1 * var1 * ((float)dig_P6) / 32768.0;
   var2 = var2 + var1 * ((float)dig_P5) * 2.0;
   var2 = (var2/4.0)+(((float)dig_P4) * 65536.0);
   var1 = (((float)dig_P3) * var1 * var1 / 524288.0 + ((float)dig_P2) * var1) / 524288.0;
   var1 = (1.0 + var1 / 32768.0)*((float)dig_P1);
   if (var1 == 0.0)
   {
   //return 0; // avoid exception caused by division by zero
   }
   p = 1048576.0 - (float)adc_P;
   p = (p - (var2 / 4096.0)) * 6250.0 / var1;
   var1 = ((float)dig_P9) * p * p / 2147483648.0;
   var2 = p * ((float)dig_P8) / 32768.0;
   p = p + (var1 + var2 + ((float)dig_P7)) / 16.0;
return p/100;
   
}
 

float BME280ReadHumidity(void) {
    //readTemperature(); // must be done first to get
   

    int32 adc_H = BME280Read16(0xFD);// BME280_REGISTER_HUMIDDATA
   
    if (adc_H == 0x8000) // value in case humidity measurement was disabled
        return 0;
    signed int32  v_x1_u32r;

    v_x1_u32r = (t_fine - ((signed int32)76800));

    v_x1_u32r = (((((adc_H << 14) - (((int32)dig_H4) << 20) -
                    (((signed int32)dig_H5) * v_x1_u32r)) + ((signed int32)16384)) >> 15) *
                 (((((((v_x1_u32r * ((int32)dig_H6)) >> 10) *
                      (((v_x1_u32r * ((signed int32)dig_H3)) >> 11) + ((signed int32)32768))) >> 10) +
                    ((signed int32)2097152)) * ((signed int32)dig_H2) + 8192) >> 14));

    v_x1_u32r = (v_x1_u32r - (((((v_x1_u32r >> 15) * (v_x1_u32r >> 15)) >> 7)*((signed int32)dig_H1)) >> 4));
    v_x1_u32r = (v_x1_u32r < 0) ? 0 : v_x1_u32r;
    v_x1_u32r = (v_x1_u32r > 419430400) ? 419430400 : v_x1_u32r;
    float h = (v_x1_u32r>>12);
    return  h / 1024.0;
}

// Read the uncompensated pressure value
//----------------------------------------------


Code:
// flex_lcd.c

// These pins are for the Microchip PicDem2-Plus board,
// which is what I used to test the driver.  Change these
// pins to fit your own board.

#define LCD_DB4   PIN_C4
#define LCD_DB5   PIN_C5
#define LCD_DB6   PIN_A4
#define LCD_DB7   PIN_A5

#define LCD_E     PIN_C7
#define LCD_RS    PIN_B7
//#define LCD_RW    PIN_B6

// If you only want a 6-pin interface to your LCD, then
// connect the R/W pin on the LCD to ground, and comment
// out the following line.

//#define USE_LCD_RW   1     

//========================================

#define lcd_type 2        // 0=5x7, 1=5x10, 2=2 lines
#define lcd_line_two 0x40 // LCD RAM address for the 2nd line


int8 const LCD_INIT_STRING[4] =
{
 0x20 | (lcd_type << 2), // Func set: 4-bit, 2 lines, 5x8 dots
 0xc,                    // Display on
 1,                      // Clear display
 6                       // Increment cursor
 };
                             

//-------------------------------------
void lcd_send_nibble(int8 nibble)
{
// Note:  !! converts an integer expression
// to a boolean (1 or 0).
 output_bit(LCD_DB4, !!(nibble & 1));
 output_bit(LCD_DB5, !!(nibble & 2));
 output_bit(LCD_DB6, !!(nibble & 4));   
 output_bit(LCD_DB7, !!(nibble & 8));   

 delay_cycles(1);
 output_high(LCD_E);
 delay_us(2);
 output_low(LCD_E);
}

//-----------------------------------
// This sub-routine is only called by lcd_read_byte().
// It's not a stand-alone routine.  For example, the
// R/W signal is set high by lcd_read_byte() before
// this routine is called.     

#ifdef USE_LCD_RW
int8 lcd_read_nibble(void)
{
int8 retval;
// Create bit variables so that we can easily set
// individual bits in the retval variable.
#bit retval_0 = retval.0
#bit retval_1 = retval.1
#bit retval_2 = retval.2
#bit retval_3 = retval.3

retval = 0;
   
output_high(LCD_E);
delay_cycles(1);

retval_0 = input(LCD_DB4);
retval_1 = input(LCD_DB5);
retval_2 = input(LCD_DB6);
retval_3 = input(LCD_DB7);
 
output_low(LCD_E);
   
return(retval);   
}   
#endif

//---------------------------------------
// Read a byte from the LCD and return it.

#ifdef USE_LCD_RW
int8 lcd_read_byte(void)
{
int8 low;
int8 high;

//output_high(LCD_RW);
delay_cycles(1);

high = lcd_read_nibble();

low = lcd_read_nibble();

return( (high<<4) | low);
}
#endif

//----------------------------------------
// Send a byte to the LCD.
void lcd_send_byte(int8 address, int8 n)
{
output_low(LCD_RS);

#ifdef USE_LCD_RW
while(bit_test(lcd_read_byte(),7)) ;
#else
delay_us(60);
#endif

if(address)
   output_high(LCD_RS);
else
   output_low(LCD_RS);
     
 delay_cycles(1);

#ifdef USE_LCD_RW
//output_low(LCD_RW);
delay_cycles(1);
#endif

output_low(LCD_E);

lcd_send_nibble(n >> 4);
lcd_send_nibble(n & 0xf);
}

//----------------------------
void lcd_init(void)
{
int8 i;

output_low(LCD_RS);

#ifdef USE_LCD_RW
//output_low(LCD_RW);
#endif

output_low(LCD_E);

delay_ms(15);

for(i=0 ;i < 3; i++)
   {
    lcd_send_nibble(0x03);
    delay_ms(5);
   }

lcd_send_nibble(0x02);

for(i=0; i < sizeof(LCD_INIT_STRING); i++)
   {
    lcd_send_byte(0, LCD_INIT_STRING[i]);
   
    // If the R/W signal is not used, then
    // the busy bit can't be polled.  One of
    // the init commands takes longer than
    // the hard-coded delay of 60 us, so in
    // that case, lets just do a 5 ms delay
    // after all four of them.
    #ifndef USE_LCD_RW
    delay_ms(5);
    #endif
   }

}

//----------------------------

void lcd_gotoxy(int8 x, int8 y)
{
int8 address;

if(y != 1)
   address = lcd_line_two;
else
   address=0;

address += x-1;
lcd_send_byte(0, 0x80 | address);
}

//-----------------------------
void lcd_putc(char c)
{
 switch(c)
   {
    case '\f':
      lcd_send_byte(0,1);
      delay_ms(2);
      break;
   
    case '\n':
       lcd_gotoxy(1,2);
       break;
   
    case '\b':
       lcd_send_byte(0,0x10);
       break;
   
    default:
       lcd_send_byte(1,c);
       break;
   }
}

//------------------------------
#ifdef USE_LCD_RW
char lcd_getc(int8 x, int8 y)
{
char value;

lcd_gotoxy(x,y);

// Wait until busy flag is low.
while(bit_test(lcd_read_byte(),7));

output_high(LCD_RS);
value = lcd_read_byte();
output_low(lcd_RS);

return(value);
}
#endif
[/code]
temtronic



Joined: 01 Jul 2010
Posts: 9081
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Tue Nov 07, 2017 8:58 am     Reply with quote

you should run the I2C Scanner program that PCM P posted in the code library. it will find your sensors true address.
Ttelmah



Joined: 11 Mar 2010
Posts: 19195

View user's profile Send private message

PostPosted: Tue Nov 07, 2017 9:04 am     Reply with quote

You need also to understand I2C addresses.....

The address occupies the top 7 bits of the byte sent to the sensor. The eighth bit is the read/write bit (1/0). A device that is at address 0x76, will need to be sent 0x77 to read, and 0x76 to write....
viki2000



Joined: 08 May 2013
Posts: 233

View user's profile Send private message

PostPosted: Tue Nov 07, 2017 9:12 am     Reply with quote

@ temtronic
But I have used the I2C Scanner with Ardunio setup environment and I know the address is 0x76, besides that the code works except repeat begin initialization.

@ Ttelmah
In the library code for BME280 here above, similar as in Arduino library, the address 0x77 is transformed into 0xEE and the address 0x76 is transformed into 0xEC. The initial code is written like that. No where appears 0x77 or 0x76, but the corresponding 0xEE or 0xEC. I see no problem here.
Ttelmah



Joined: 11 Mar 2010
Posts: 19195

View user's profile Send private message

PostPosted: Tue Nov 07, 2017 10:05 am     Reply with quote

The Arduino library is using the 7 bit address. The top seven bits of the address byte. This was the old 'Texas' standard but is used by almost nobody else.
The CCS code uses the 8bit address. 7bit address *2. The code then adds the read/write bit as needed. This is how most manufacturers address their chips.
A device with an Arduino address of 0x77, will need 0xEE for the PIC code, and will physically be at addresses 0xEE and 0xEF.
You have 'waffled' far too much in your post which is why Temtronic and I both thought you were having trouble addressing the chip.

You post could be summarised as:
"Using this library (point to the thread, don't repost the whole library).
Chip works, but requires me to use BME280Begin() every time I want to send a reading. Without this I only get the first reading."

The reason you are having to send 'begin', is that you are programming the chip to 'forced mode', in which it goes back to sleep after a single reading. The Begin code as well as reprogramming all the registers triggers a single conversion.
You can just trigger a single conversion by writing the CTRL_MEAS register. Alternatively change the settings to use 'normal mode'.
viki2000



Joined: 08 May 2013
Posts: 233

View user's profile Send private message

PostPosted: Wed Nov 08, 2017 1:55 am     Reply with quote

I am sorry that I have 'waffled' far too much in my initial post and I created confusion.
I always thought that providing more info is always better than providing less, even if there is the risk that people do not read it because takes too much time.
Probably it would have been far better to summarize it as you did, but we do not all think and speak the same way.
Besides that, because I mentioned that I am able to read the BME280 parameters, that means automatically that I2C works fine and there is no problem with the address. That’s why your explanations with 7bit vs. 8bit make sense also for me because 0x76*2=0xEC and the following for read is 0xEC|0x01=0xED and these 2 addresses 0xEC and 0xED I have used in my code above.
I have posted the entire long code to see where I have done the modifications and maybe someone might say: hey, you forgot to change it there or there, at least this is what I had in mind to that moment. In top of that, for future users, is good to have full working code that is downloadable and applies without modification, just for a quick test without headaches. I thought a another PIC and another address for BME280 will diversify the options for other users, which is a good thing. Besides that many times when a question is asked, the people that are willing to help and answer ask almost always about the code used and in this case there are some places in the given code that must be modified in order to be adapted to the new PIC and new BME280. So I think is not a big deal that I posted the question in the way as I have done it.

Now, regarding your suggestions with “forced mode” and sleep and that I should change to “normal mode” or play with CTRL_MEAS register, they make logical sense to me at the first read, but I have some doubts when I think twice and here is why.
I suppose the initial provided code works fine.
If you look at the main subroutine, the “BME280Begin();” is called only once before the continuous “while(true)” and in that “while(true)” loop the reading of temperature and humidity is called regularly each approx. 1s and is then printed regularly.
It makes no sense to print regularly the temperature and humidity and other parameters, if it is not updated regularly with new data.
If what you say would be true, then it would be true also for initial code and here I have the doubts, because I suppose is working fine, of course not tested yet by me with PIC16F877A and BME280 address 0x77.
I think the “force mode” with sleeping is important, because consumes low current, which is good for portable application (nice explained here http://tinkerman.cat/low-power-weather-station-bme280-moteino/ ). I would like to maintain that low current state with sleeping and “forced trigger”.
But I also think the problem is somewhere else, why does not trigger a new reading. I have to look more into the code. Any other suggestions are appreciated.
Ttelmah



Joined: 11 Mar 2010
Posts: 19195

View user's profile Send private message

PostPosted: Wed Nov 08, 2017 2:13 am     Reply with quote

Big difference. Time.

The chip goes to sleep if it is not read for 250mSec. You delay 800mSec in your loop. The original code does not...

You have to simply trigger a reading. A read does not.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Goto page Previous  1, 2, 3  Next
Page 2 of 3

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group