Sari la conținut
ELFORUM - Forumul electronistilor

BME280 mikroc


tudorel1999

Postări Recomandate

Salut! Incerc sa programez un PIC16f1516 sa lucreze cu un BME280 ca sa citeasca presiunea, temperatura si umiditatea. Am gasit o librarie pe internet ( https://simple-circuit.com/bme280-pic-mcu-nokia-lcd-mikroc/ ) pe care am modificat-o in functie de datasheet-ul de la bosch, compileaza fara erori, insa cand initializez citirea, adica functia BME280_begin(...) nu-mi da return nici 1, nici 0, nici nimic, deci ceva nu merge acolo.

asta e librarie BME280.h 

 

#ifdef __cplusplus
extern "C" {
#endif

#include <stdint.h>

#if !defined BME280_I2C1  &&  !defined BME280_I2C2
#define  BME280_I2C1
#endif

#if defined BME280_I2C1  &&  defined BME280_I2C2
#undef  BME280_I2C2
#endif

#ifdef  BME280_I2C1
#define BME280_Start    I2C1_Start
#define BME280_Write    I2C1_Wr
#define BME280_Read     I2C1_Rd
#define BME280_Stop     I2C1_Stop
#define BME280_Is_Idle  I2C1_Is_Idle
#define BME280_Repeated_Start    I2C1_Repeated_Start
#endif

#ifdef  BME280_I2C2
#define BME280_Start    I2C2_Start
#define BME280_Write    I2C2_Wr
#define BME280_Read     I2C2_Rd
#define BME280_Stop     I2C2_Stop
#define BME280_Is_Idle  I2C1_Is_Idle
#define BME280_Repeated_Start    I2C1_Repeated_Start
#endif

#ifndef BME280_I2C_ADDRESS
  #define BME280_I2C_ADDRESS    0x76
#endif

#define BME280_CHIP_ID          0x60    //valoarea din el pentru a putea verifica daca se initializeaza senzorul

#define BME280_REG_DIG_T1     0x88
#define BME280_REG_DIG_T2     0x8A
#define BME280_REG_DIG_T3     0x8C

#define BME280_REG_DIG_P1     0x8E
#define BME280_REG_DIG_P2     0x90
#define BME280_REG_DIG_P3     0x92
#define BME280_REG_DIG_P4     0x94
#define BME280_REG_DIG_P5     0x96
#define BME280_REG_DIG_P6     0x98
#define BME280_REG_DIG_P7     0x9A
#define BME280_REG_DIG_P8     0x9C
#define BME280_REG_DIG_P9     0x9E

#define BME280_REG_DIG_H1     0xA1
#define BME280_REG_DIG_H2     0xE1
#define BME280_REG_DIG_H3     0xE3
#define BME280_REG_DIG_H4     0xE4
#define BME280_REG_DIG_H5     0xE5
#define BME280_REG_DIG_H6     0xE7

#define BME280_REG_CHIPID     0xD0
#define BME280_REG_SOFTRESET  0xE0

#define BME280_REG_CTRLHUM    0xF2
#define BME280_REG_STATUS     0xF3
#define BME280_REG_CONTROL    0xF4
#define BME280_REG_CONFIG     0xF5
#define BME280_REG_PRESS_MSB  0xF7
#define BME280_REG_PRESS_LSB  0xF8
#define BME280_REG_PRESS_XLSB 0xF9
#define BME280_REG_TEMP_MSB   0xFA
#define BME280_REG_TEMP_LSB   0xFB
#define BME280_REG_TEMP_XLSB  0xFC
#define BME280_REG_HUM_MSB    0xFD
#define BME280_REG_HUM_LSB    0xFE

int32_t adc_T, adc_P, adc_H, t_fine;

typedef enum
{
  MODE_SLEEP  = 0x00,  // sleep mode
  MODE_FORCED = 0x01,  // forced mode
  MODE_NORMAL = 0x03   // normal mode
} bme280_mode;

typedef enum
{
  SAMPLING_SKIPPED = 0x00,  //skipped, output set to 0x80000 (0x8000)
  SAMPLING_X1      = 0x01,  // oversampling x1
  SAMPLING_X2      = 0x02,  // oversampling x2
  SAMPLING_X4      = 0x03,  // oversampling x4
  SAMPLING_X8      = 0x04,  // oversampling x8
  SAMPLING_X16     = 0x05   // oversampling x16
} bme280_sampling;

typedef enum
{
  FILTER_OFF = 0x00,  // filter off
  FILTER_2   = 0x01,  // filter coefficient = 2
  FILTER_4   = 0x02,  // filter coefficient = 4
  FILTER_8   = 0x03,  // filter coefficient = 8
  FILTER_16  = 0x04   // filter coefficient = 16
} bme280_filter;

// standby in normal mode
typedef enum
{
  STANDBY_0_5   =  0x00,  // standby time = 0.5 ms
  STANDBY_62_5  =  0x01,  // standby time = 62.5 ms
  STANDBY_125   =  0x02,  // standby time = 125 ms
  STANDBY_250   =  0x03,  // standby time = 250 ms
  STANDBY_500   =  0x04,  // standby time = 500 ms
  STANDBY_1000  =  0x05,  // standby time = 1000 ms
  STANDBY_10    =  0x06,  // standby time = 10 ms
  STANDBY_20    =  0x07   // standby time = 20 ms
} standby_time;

struct
{
  uint16_t dig_T1;
  int16_t  dig_T2;
  int16_t  dig_T3;
  
  uint16_t dig_P1;
  int16_t  dig_P2;
  int16_t  dig_P3;
  int16_t  dig_P4;
  int16_t  dig_P5;
  int16_t  dig_P6;
  int16_t  dig_P7;
  int16_t  dig_P8;
  int16_t  dig_P9;

  uint8_t  dig_H1;
  int16_t  dig_H2;
  uint8_t  dig_H3;
  int16_t  dig_H4;
  int16_t  dig_H5;
  int8_t   dig_H6;
} BME280_calib;

// writes 1 byte '_data' to register 'reg_addr'
void BME280_Write8(uint8_t reg_addr, uint8_t _data)
{
  BME280_Start();
  BME280_Write(BME280_I2C_ADDRESS);
  BME280_Write(reg_addr);
  BME280_Write(_data);
  BME280_Stop();
}

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

  BME280_Start();
  BME280_Write(BME280_I2C_ADDRESS + 1);  //adresa slave-ului+read
  ret = BME280_Read(0);                  //citim datele(fara semnal de confirmare a primirii)
  BME280_Stop();                         //i2c stop

  return ret;
}

// reads 16 bits from register 'reg_addr'
uint16_t BME280_Read16(uint8_t reg_addr)
{
  union      //tipuri de date diferite in aceeasi locatie de memorie: uint8_t si uint16_t
  {
    uint8_t  b[2];
    uint16_t w;
  } ret;

  BME280_Start();
  BME280_Write(BME280_I2C_ADDRESS + 1);
  ret.b[0] = BME280_Read(1);
  ret.b[1] = BME280_Read(0);
  BME280_Stop();

  return(ret.w);
}

// BME280 sensor configuration function
void BME280_Configure(bme280_mode mode, bme280_sampling T_sampling, bme280_sampling H_sampling,
                      bme280_sampling P_sampling, bme280_filter filter, standby_time standby)
{
  uint8_t _ctrl_hum, _ctrl_meas, _config;

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

  BME280_Write8(BME280_REG_CTRLHUM, _ctrl_hum);
  BME280_Write8(BME280_REG_CONFIG,  _config);
  BME280_Write8(BME280_REG_CONTROL, _ctrl_meas);
}

// initializes the BME280 sensor, returns 1 if OK and 0 if error
uint8_t BME280_begin(bme280_mode mode, 
                  bme280_sampling T_sampling,
                  bme280_sampling H_sampling,
                  bme280_sampling P_sampling,
                  bme280_filter filter,
                  standby_time  standby)
{
  if(BME280_Read8(BME280_REG_CHIPID) != BME280_CHIP_ID)
    return 0;
  // reset the BME280 with soft reset
  BME280_Write8(BME280_REG_SOFTRESET, 0xB6);
  delay_ms(100);

  // if NVM data are being copied to image registers, wait 100 ms
  while( (BME280_Read8(BME280_REG_STATUS) & 0x01) == 0x01 )
    delay_ms(100);

  BME280_calib.dig_T1 = BME280_Read16(BME280_REG_DIG_T1) | BME280_Read16(BME280_REG_DIG_T1+1)<<8;
  BME280_calib.dig_T2 = BME280_Read16(BME280_REG_DIG_T2) | BME280_Read16(BME280_REG_DIG_T2+1)<<8;
  BME280_calib.dig_T3 = BME280_Read16(BME280_REG_DIG_T3) | BME280_Read16(BME280_REG_DIG_T3+1)<<8;

  BME280_calib.dig_P1 = BME280_Read16(BME280_REG_DIG_P1) | BME280_Read16(BME280_REG_DIG_P1+1)<<8;
  BME280_calib.dig_P2 = BME280_Read16(BME280_REG_DIG_P2) | BME280_Read16(BME280_REG_DIG_P2+1)<<8;
  BME280_calib.dig_P3 = BME280_Read16(BME280_REG_DIG_P3) | BME280_Read16(BME280_REG_DIG_P3+1)<<8;
  BME280_calib.dig_P4 = BME280_Read16(BME280_REG_DIG_P4) | BME280_Read16(BME280_REG_DIG_P4+1)<<8;
  BME280_calib.dig_P5 = BME280_Read16(BME280_REG_DIG_P5) | BME280_Read16(BME280_REG_DIG_P5+1)<<8;
  BME280_calib.dig_P6 = BME280_Read16(BME280_REG_DIG_P6) | BME280_Read16(BME280_REG_DIG_P6+1)<<8;
  BME280_calib.dig_P7 = BME280_Read16(BME280_REG_DIG_P7) | BME280_Read16(BME280_REG_DIG_P7+1)<<8;
  BME280_calib.dig_P8 = BME280_Read16(BME280_REG_DIG_P8) | BME280_Read16(BME280_REG_DIG_P8+1)<<8;
  BME280_calib.dig_P9 = BME280_Read16(BME280_REG_DIG_P9) | BME280_Read16(BME280_REG_DIG_P9+1)<<8;

  BME280_calib.dig_H1 = BME280_Read8(BME280_REG_DIG_H1);
  BME280_calib.dig_H2 = BME280_Read16(BME280_REG_DIG_H2) | BME280_Read16(BME280_REG_DIG_H2+1)<<8;
  BME280_calib.dig_H3 = BME280_Read16(BME280_REG_DIG_H3);
  BME280_calib.dig_H4 = BME280_Read16(BME280_REG_DIG_H4) | (BME280_Read16(BME280_REG_DIG_H4+1) & 0b00000111)<<4;
  BME280_calib.dig_H5 = (BME280_Read16(BME280_REG_DIG_H5) & 0b11110000) | BME280_Read16(BME280_REG_DIG_H5+1)<<4;
  BME280_calib.dig_H6 = BME280_Read8(BME280_REG_DIG_H6);

  BME280_Configure(mode, T_sampling, H_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 BME280_ForcedMeasurement()
{
  uint8_t ctrl_meas_reg = BME280_Read8(BME280_REG_CONTROL);

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

  // set sensor to forced mode
  BME280_Write8(BME280_REG_CONTROL, ctrl_meas_reg | 1);
  // wait for conversion complete
  while (BME280_Read8(BME280_REG_STATUS) & 0x08)
    delay_ms(1);

  return 1;
}

// read (updates) adc_P, adc_T and adc_H from BME280 sensor
/*void BME280_Update()
{
  union
  {
    uint8_t  b[4];
    uint32_t dw;
  } ret;
  ret.b[3] = 0x00;

  BME280_Start();
  BME280_Write(BME280_I2C_ADDRESS);
  BME280_Write(BME280_REG_PRESS_MSB);
  BME280_Repeated_Start();
  BME280_Write(BME280_I2C_ADDRESS | 1);
  ret.b[2] = BME280_Read(1);
  ret.b[1] = BME280_Read(1);
  ret.b[0] = BME280_Read(1);

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

  ret.b[2] = BME280_Read(1);
  ret.b[1] = BME280_Read(1);
  ret.b[0] = BME280_Read(1);

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

  ret.b[2] = 0x00;
  ret.b[1] = BME280_Read(1);
  ret.b[0] = BME280_Read(0);
  BME280_Stop();

  adc_H = ret.dw & 0xFFFF;
}*/

// Reads temperature from BME280 sensor.
// Temperature is stored in hundredths 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 BME280_readTemperature(int32_t *temp)
{
  int32_t var1, var2;

/*BME280_Update();*/

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

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

  t_fine = var1 + var2;

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

  return 1;
}

// Reads humidity from BME280 sensor.
// Humidity is stored in relative humidity percent in 1024 steps
// (output value of "47445" represents 47445/1024 = 46.333 %RH).
// Humidity value is saved to *humi, returns 1 if OK and 0 if error.
uint8_t BME280_readHumidity(uint32_t *humi)
{
  int32_t v_x1_u32r;
  uint32_t H;

  v_x1_u32r = (t_fine - ((int32_t)76800));

  v_x1_u32r = (((((adc_H * 16384) - (((int32_t)BME280_calib.dig_H4) * 1048576) - (((int32_t)BME280_calib.dig_H5) * v_x1_u32r)) +
      ((int32_t)16384)) / 32768) * (((((((v_x1_u32r * ((int32_t)BME280_calib.dig_H6)) / 1024) * (((v_x1_u32r *
      ((int32_t)BME280_calib.dig_H3)) / 2048) + ((int32_t)32768))) / 1024) + ((int32_t)2097152)) *
      ((int32_t)BME280_calib.dig_H2) + 8192) / 16384));

  v_x1_u32r = (v_x1_u32r - (((((v_x1_u32r / 32768) * (v_x1_u32r / 32768)) / 128) * ((int32_t)BME280_calib.dig_H1)) / 16));
  v_x1_u32r = (v_x1_u32r < 0 ? 0 : v_x1_u32r);
  v_x1_u32r = (v_x1_u32r > 419430400 ? 419430400 : v_x1_u32r);

  H = (uint32_t)(v_x1_u32r / 4096);
  *humi = H;

  return 1;
}

// Reads pressure from BME280 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.
uint8_t BME280_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)BME280_calib.dig_P6);

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

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

  var1 =((((32768 + var1)) * ((int32_t)BME280_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)BME280_calib.dig_P9) * ((int32_t)(((p/8) * (p/8)) / 8192))) / 4096;
  var2 = (((int32_t)(p/4)) * ((int32_t)BME280_calib.dig_P8)) / 8192;

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

  *pres = p;

  return 1;
}

// end of driver code.

 

asta e main-ul, am incercat sa aprind doua LED-uri (daca am initializat transmisia I2c sau nu) pe port C, in proteus, pentru feedback, dar nu obtin nimic:

 

// define BME280 device I2C address: 0x76 or 0x77 (0x77 is library default address)
#define BME280_I2C_ADDRESS  0x76    //adresa I2C de write a slavelului

#include <BME280.h>

// main function
void main()
{
  OSCCON = 0b01101010;   // set internal oscillator to 1MHz
  ANSELB = 0;
  ANSELC = 0;
  TRISC = 0b00001100;
  PORTC.RC0=0;
  PORTC.RC1=0;
  I2C1_Init(100000);  // initialize I2C communication with clock frequency of 100 kHz
  delay_ms(100);
  while(1)
  {        if(BME280_begin(MODE_NORMAL, SAMPLING_X1, SAMPLING_X1, SAMPLING_X1, FILTER_OFF, STANDBY_1000) == 1)
             {                           PORTC.RC1=1;
                                         }
             else PORTC.RC0=1;
          }
  }

 

Editat de tudorel1999
Link spre comentariu
  • Răspunsuri 15
  • Creat
  • Ultimul Răspuns

Top autori în acest subiect

  • tudorel1999

    7

  • Liviu M

    3

  • Mircea

    3

  • Bandi Szasz

    3

Top autori în acest subiect

Salutare,

In primul rand o rugaminte - cand postezi cod, foloseste tag-urile code (< si >).

Referitor la problema ta, tinand cont ca adresa de citire e adresa de scriere + 1

uint8_t BME280_Read8(uint8_t reg_addr)
{
  uint8_t ret;

  BME280_Start();
  BME280_Write(BME280_I2C_ADDRESS + 1);  //adresa slave-ului+read

as zice ca adreasa pe care trebuie s-o folosesti e 0x76 << 1, adica 0xEC. Bitul cel mai putin semnificativ (pentru care ai facut loc prin deplasarea la stanga) e bitul de operatie - 0 pentru scriere, 1 pentru citire.

 

Link spre comentariu

Salut, 

  Nu prea am timp acum sa parcurg tot codul tau dar daca te ajuta uite aici libraria mea care e testata de mult timp.

 

bme280.h

#include <stdint.h>

#define BME280_Start    Soft_I2C_Start
#define BME280_Write    Soft_I2C_Write
#define BME280_Read     Soft_I2C_Read
#define BME280_Stop     Soft_I2C_Stop

#ifndef BME280_I2C_ADDRESS
  #define BME280_I2C_ADDRESS  0xEE
#endif

#define BME280_CHIP_ID        0x60

#define BME280_REG_DIG_T1     0x88
#define BME280_REG_DIG_T2     0x8A
#define BME280_REG_DIG_T3     0x8C

#define BME280_REG_DIG_P1     0x8E
#define BME280_REG_DIG_P2     0x90
#define BME280_REG_DIG_P3     0x92
#define BME280_REG_DIG_P4     0x94
#define BME280_REG_DIG_P5     0x96
#define BME280_REG_DIG_P6     0x98
#define BME280_REG_DIG_P7     0x9A
#define BME280_REG_DIG_P8     0x9C
#define BME280_REG_DIG_P9     0x9E

#define BME280_REG_DIG_H1     0xA1
#define BME280_REG_DIG_H2     0xE1
#define BME280_REG_DIG_H3     0xE3
#define BME280_REG_DIG_H4     0xE4
#define BME280_REG_DIG_H5     0xE5
#define BME280_REG_DIG_H6     0xE7

#define BME280_REG_CHIPID     0xD0
#define BME280_REG_SOFTRESET  0xE0

#define BME280_REG_CTRLHUM    0xF2
#define BME280_REG_STATUS     0xF3
#define BME280_REG_CONTROL    0xF4
#define BME280_REG_CONFIG     0xF5
#define BME280_REG_PRESS_MSB  0xF7

int32_t adc_T, adc_P, adc_H, t_fine;

// BME280 sensor modes, register ctrl_meas mode[1:0]
typedef enum
{
  MODE_SLEEP  = 0x00,  // sleep mode
  MODE_FORCED = 0x01,  // forced mode
  MODE_NORMAL = 0x03   // normal mode
} bme280_mode;

// oversampling setting. osrs_h[2:0], osrs_t[2:0], osrs_p[2:0]
typedef enum
{
  SAMPLING_SKIPPED = 0x00,  //skipped, output set to 0x80000 (0x8000 for humidity)
  SAMPLING_X1      = 0x01,  // oversampling x1
  SAMPLING_X2      = 0x02,  // oversampling x2
  SAMPLING_X4      = 0x03,  // oversampling x4
  SAMPLING_X8      = 0x04,  // oversampling x8
  SAMPLING_X16     = 0x05   // oversampling x16
} bme280_sampling;

// filter setting filter[2:0]
typedef enum
{
  FILTER_OFF = 0x00,  // filter off
  FILTER_2   = 0x01,  // filter coefficient = 2
  FILTER_4   = 0x02,  // filter coefficient = 4
  FILTER_8   = 0x03,  // filter coefficient = 8
  FILTER_16  = 0x04   // filter coefficient = 16
} bme280_filter;

// standby (inactive) time in ms (used in normal mode), t_sb[2:0]
typedef enum
{
  STANDBY_0_5   =  0x00,  // standby time = 0.5 ms
  STANDBY_62_5  =  0x01,  // standby time = 62.5 ms
  STANDBY_125   =  0x02,  // standby time = 125 ms
  STANDBY_250   =  0x03,  // standby time = 250 ms
  STANDBY_500   =  0x04,  // standby time = 500 ms
  STANDBY_1000  =  0x05,  // standby time = 1000 ms
  STANDBY_10    =  0x06,  // standby time = 10 ms
  STANDBY_20    =  0x07   // standby time = 20 ms
} standby_time;

struct
{
  uint16_t dig_T1;
  int16_t  dig_T2;
  int16_t  dig_T3;
  uint16_t dig_P1;
  int16_t  dig_P2;
  int16_t  dig_P3;
  int16_t  dig_P4;
  int16_t  dig_P5;
  int16_t  dig_P6;
  int16_t  dig_P7;
  int16_t  dig_P8;
  int16_t  dig_P9;

  uint8_t  dig_H1;
  int16_t  dig_H2;
  uint8_t  dig_H3;
  int16_t  dig_H4;
  int16_t  dig_H5;
  int8_t   dig_H6;
} BME280_calib;

// writes 1 byte '_data' to register 'reg_addr'
void BME280_Write8(uint8_t reg_addr, uint8_t _data)
{
  BME280_Start();
  BME280_Write(BME280_I2C_ADDRESS);
  BME280_Write(reg_addr);
  BME280_Write(_data);
  BME280_Stop();
}

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

  BME280_Start();
  BME280_Write(BME280_I2C_ADDRESS);
  BME280_Write(reg_addr);
  BME280_Start();
  BME280_Write(BME280_I2C_ADDRESS | 1);
  ret = BME280_Read(0);
  BME280_Stop();

  return ret;
}

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

  BME280_Start();
  BME280_Write(BME280_I2C_ADDRESS);
  BME280_Write(reg_addr);
  BME280_Start();
  BME280_Write(BME280_I2C_ADDRESS | 1);
  ret.b[0] = BME280_Read(1);
  ret.b[1] = BME280_Read(0);
  BME280_Stop();

  return(ret.w);
}

// BME280 sensor configuration function
void BME280_Configure(bme280_mode mode, bme280_sampling T_sampling, bme280_sampling H_sampling,
                      bme280_sampling P_sampling, bme280_filter filter, standby_time standby)
{
  uint8_t _ctrl_hum, _ctrl_meas, _config;

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

  BME280_Write8(BME280_REG_CTRLHUM, _ctrl_hum);
  BME280_Write8(BME280_REG_CONFIG,  _config);
  BME280_Write8(BME280_REG_CONTROL, _ctrl_meas);
}

// initializes the BME280 sensor, returns 1 if OK and 0 if error
uint8_t BME280_begin(bme280_mode mode,
                  bme280_sampling T_sampling,
                  bme280_sampling H_sampling,
                  bme280_sampling P_sampling,
                  bme280_filter filter,
                  standby_time  standby)
{
  if(BME280_Read8(BME280_REG_CHIPID) != BME280_CHIP_ID)
    return 0;

  // reset the BME280 with soft reset
  BME280_Write8(BME280_REG_SOFTRESET, 0xB6);
  delay_ms(100);

  // if NVM data are being copied to image registers, wait 100 ms
  while( (BME280_Read8(BME280_REG_STATUS) & 0x01) == 0x01 )
    delay_ms(100);

  BME280_calib.dig_T1 = BME280_Read16(BME280_REG_DIG_T1);
  BME280_calib.dig_T2 = BME280_Read16(BME280_REG_DIG_T2);
  BME280_calib.dig_T3 = BME280_Read16(BME280_REG_DIG_T3);

  BME280_calib.dig_P1 = BME280_Read16(BME280_REG_DIG_P1);
  BME280_calib.dig_P2 = BME280_Read16(BME280_REG_DIG_P2);
  BME280_calib.dig_P3 = BME280_Read16(BME280_REG_DIG_P3);
  BME280_calib.dig_P4 = BME280_Read16(BME280_REG_DIG_P4);
  BME280_calib.dig_P5 = BME280_Read16(BME280_REG_DIG_P5);
  BME280_calib.dig_P6 = BME280_Read16(BME280_REG_DIG_P6);
  BME280_calib.dig_P7 = BME280_Read16(BME280_REG_DIG_P7);
  BME280_calib.dig_P8 = BME280_Read16(BME280_REG_DIG_P8);
  BME280_calib.dig_P9 = BME280_Read16(BME280_REG_DIG_P9);

  BME280_calib.dig_H1 = BME280_Read8(BME280_REG_DIG_H1);
  BME280_calib.dig_H2 = BME280_Read16(BME280_REG_DIG_H2);
  BME280_calib.dig_H3 = BME280_Read8(BME280_REG_DIG_H3);
  BME280_calib.dig_H4 = ((uint16_t)BME280_Read8(BME280_REG_DIG_H4) << 4) | (BME280_Read8(BME280_REG_DIG_H4 + 1) & 0x0F);
  if (BME280_calib.dig_H4 & 0x0800)    // if BME280_calib.dig_H4 < 0
      BME280_calib.dig_H4 |= 0xF000;
  BME280_calib.dig_H5 = ((uint16_t)BME280_Read8(BME280_REG_DIG_H5 + 1) << 4) | (BME280_Read8(BME280_REG_DIG_H5) >> 4);
  if (BME280_calib.dig_H5 & 0x0800)    // if BME280_calib.dig_H5 < 0
      BME280_calib.dig_H5 |= 0xF000;
  BME280_calib.dig_H6 = BME280_Read8(BME280_REG_DIG_H6);

  BME280_Configure(mode, T_sampling, H_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 BME280_ForcedMeasurement()
{
  uint8_t ctrl_meas_reg = BME280_Read8(BME280_REG_CONTROL);

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

  // set sensor to forced mode
  BME280_Write8(BME280_REG_CONTROL, ctrl_meas_reg | 1);
  // wait for conversion complete
  while (BME280_Read8(BME280_REG_STATUS) & 0x08)
    delay_ms(1);

  return 1;
}

// read (updates) adc_P, adc_T and adc_H from BME280 sensor
void BME280_Update()
{
  union
  {
    uint8_t  b[4];
    uint32_t dw;
  } ret;
  ret.b[3] = 0x00;

  BME280_Start();
  BME280_Write(BME280_I2C_ADDRESS);
  BME280_Write(BME280_REG_PRESS_MSB);
  BME280_Start();
  BME280_Write(BME280_I2C_ADDRESS | 1);
  ret.b[2] = BME280_Read(1);
  ret.b[1] = BME280_Read(1);
  ret.b[0] = BME280_Read(1);

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

  ret.b[2] = BME280_Read(1);
  ret.b[1] = BME280_Read(1);
  ret.b[0] = BME280_Read(1);

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

  ret.b[2] = 0x00;
  ret.b[1] = BME280_Read(1);
  ret.b[0] = BME280_Read(0);
  BME280_Stop();

  adc_H = ret.dw & 0xFFFF;
}

// Reads temperature from BME280 sensor.
// Temperature is stored in hundredths 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 BME280_readTemperature(int32_t *temp)
{
  int32_t var1, var2;

  BME280_Update();

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

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

  t_fine = var1 + var2;

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

  return 1;
}

// Reads humidity from BME280 sensor.
// Humidity is stored in relative humidity percent in 1024 steps
// (output value of "47445" represents 47445/1024 = 46.333 %RH).
// Humidity value is saved to *humi, returns 1 if OK and 0 if error.
uint8_t BME280_readHumidity(uint32_t *humi)
{
  int32_t v_x1_u32r;
  uint32_t H;

  v_x1_u32r = (t_fine - ((int32_t)76800));

  v_x1_u32r = (((((adc_H * 16384) - (((int32_t)BME280_calib.dig_H4) * 1048576) - (((int32_t)BME280_calib.dig_H5) * v_x1_u32r)) +
      ((int32_t)16384)) / 32768) * (((((((v_x1_u32r * ((int32_t)BME280_calib.dig_H6)) / 1024) * (((v_x1_u32r *
      ((int32_t)BME280_calib.dig_H3)) / 2048) + ((int32_t)32768))) / 1024) + ((int32_t)2097152)) *
      ((int32_t)BME280_calib.dig_H2) + 8192) / 16384));

  v_x1_u32r = (v_x1_u32r - (((((v_x1_u32r / 32768) * (v_x1_u32r / 32768)) / 128) * ((int32_t)BME280_calib.dig_H1)) / 16));
  v_x1_u32r = (v_x1_u32r < 0 ? 0 : v_x1_u32r);
  v_x1_u32r = (v_x1_u32r > 419430400 ? 419430400 : v_x1_u32r);

  H = (uint32_t)(v_x1_u32r / 4096);
  *humi = H;

  return 1;
}

// Reads pressure from BME280 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.
uint8_t BME280_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)BME280_calib.dig_P6);

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

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

  var1 =((((32768 + var1)) * ((int32_t)BME280_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)BME280_calib.dig_P9) * ((int32_t)(((p/8) * (p/8)) / 8192))) / 4096;
  var2 = (((int32_t)(p/4)) * ((int32_t)BME280_calib.dig_P8)) / 8192;

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

  *pres = p;

  return 1;
}

// end of driver code.

 

i2c.h  ( eu am folosit soft I2C in loc de hardware din motive de proiectare PCB. Sa schimbi pinii la care ai legat senzorul.

sbit Soft_I2C_Scl           at RA0_bit;
sbit Soft_I2C_Sda           at RA1_bit;
sbit Soft_I2C_Scl_Direction at TRISA0_bit;
sbit Soft_I2C_Sda_Direction at TRISA1_bit;

void I2C_Init() {
  Soft_I2C_Init();
}

void I2C_Enable() {
  SSP1CON1.SSPEN = 1;
}

void I2C_Disable() {
  SSP1CON1.SSPEN = 0;
}

 

In main ar trebuii sa ai ceva de genu acesta (daca ceva nu e ok atunci pinul RC1 va clipii continu, daca sta stins inseamna ca totul e ok):

#define BME280_I2C_ADDRESS  0xEC

#include "i2c.h"
#include "bme280.h"

void BME280_Init() {
  Soft_I2C_Init();
  if(BME280_begin(MODE_FORCED, SAMPLING_X1, SAMPLING_X1, SAMPLING_X1, FILTER_OFF, STANDBY_0_5) == 0) {
     while(1) {
         PORTC.RC1 = 1;
         delay_ms(50);
         PORTC.RC1 = 0;
         delay_ms(150);
     }
  }
}


void readData() {
  unsigned long pressure, humidity;
  signed long temperature;
  BME280_ForcedMeasurement();
  Delay_ms(1000);
  BME280_readTemperature(&temperature);  // read temperature
  BME280_readHumidity(&humidity);        // read humidity
  BME280_readPressure(&pressure);        // read pressure
  
  // variabilele pressure,humidity,temperature contin acum datele citite de la sensor

}


void main() {
  OSCCON = 0b01101010;   // set internal oscillator to 1MHz
  ANSELB = 0;
  ANSELC = 0;
  TRISC = 0b00001100;
  PORTC.RC0=0;
  PORTC.RC1=0;
  
  BME280_Init();

  while(1) {
    readData();
    Delay_ms(2500);
  }
}

 

 

 

Daca apar erori ne mai uitam ca am luat bucatelele dintr-un proiect mult mai pare si posibil sa imi fi scapat ceva.

Editat de Bandi Szasz
Link spre comentariu
Acum 2 ore, Liviu M a spus:

Salutare,

In primul rand o rugaminte - cand postezi cod, foloseste tag-urile code (< si >).

Referitor la problema ta, tinand cont ca adresa de citire e adresa de scriere + 1

uint8_t BME280_Read8(uint8_t reg_addr)
{
  uint8_t ret;

  BME280_Start();
  BME280_Write(BME280_I2C_ADDRESS + 1);  //adresa slave-ului+read

as zice ca adreasa pe care trebuie s-o folosesti e 0x76 << 1, adica 0xEC. Bitul cel mai putin semnificativ (pentru care ai facut loc prin deplasarea la stanga) e bitul de operatie - 0 pentru scriere, 1 pentru citire.

 

Am inteles, voi incerca cu 0xEC, acum am vazut si eu pe internet ca unii producatori ofera doua adrese I2C pe 8 biti in mod incorect care encodeaza cele doua adrese de scriere si citere, iar daca ofera doar o singura adresa pe 7 bitit( adica daca adresa este intre 0x08 si 0x77, cum e de altfel si in cazul meu va trebui sa-l schimb eu). Va multumesc!

Editat de tudorel1999
Link spre comentariu
Acum 2 ore, Bandi Szasz a spus:
  BME280_calib.dig_T1 = BME280_Read16(BME280_REG_DIG_T1);
  BME280_calib.dig_T2 = BME280_Read16(BME280_REG_DIG_T2);
  BME280_calib.dig_T3 = BME280_Read16(BME280_REG_DIG_T3);

  BME280_calib.dig_P1 = BME280_Read16(BME280_REG_DIG_P1);
  BME280_calib.dig_P2 = BME280_Read16(BME280_REG_DIG_P2);
  BME280_calib.dig_P3 = BME280_Read16(BME280_REG_DIG_P3);
  BME280_calib.dig_P4 = BME280_Read16(BME280_REG_DIG_P4);
  BME280_calib.dig_P5 = BME280_Read16(BME280_REG_DIG_P5);
  BME280_calib.dig_P6 = BME280_Read16(BME280_REG_DIG_P6);
  BME280_calib.dig_P7 = BME280_Read16(BME280_REG_DIG_P7);
  BME280_calib.dig_P8 = BME280_Read16(BME280_REG_DIG_P8);
  BME280_calib.dig_P9 = BME280_Read16(BME280_REG_DIG_P9);

  BME280_calib.dig_H1 = BME280_Read8(BME280_REG_DIG_H1);
  BME280_calib.dig_H2 = BME280_Read16(BME280_REG_DIG_H2);
  BME280_calib.dig_H3 = BME280_Read8(BME280_REG_DIG_H3);
  BME280_calib.dig_H4 = ((uint16_t)BME280_Read8(BME280_REG_DIG_H4) << 4) | (BME280_Read8(BME280_REG_DIG_H4 + 1) & 0x0F);
  if (BME280_calib.dig_H4 & 0x0800)    // if BME280_calib.dig_H4 < 0
      BME280_calib.dig_H4 |= 0xF000;
  BME280_calib.dig_H5 = ((uint16_t)BME280_Read8(BME280_REG_DIG_H5 + 1) << 4) | (BME280_Read8(BME280_REG_DIG_H5) >> 4);
  if (BME280_calib.dig_H5 & 0x0800)    // if BME280_calib.dig_H5 < 0
      BME280_calib.dig_H5 |= 0xF000;
  BME280_calib.dig_H6 = BME280_Read8(BME280_REG_DIG_H6);

Codul dvs. functioneaza, pot comanda un LED cu functia BME208_begin(), insa mai am o intrebare. In datasheet scrie ca word-urile de trimming sunt pe 16 biti, impartite la cate doua adrese pe 8 biti, complementare. Cum functioneaza trimming-ul aici? Eu vad doar ca se citeste de la cate o adresa de 16 biti folosind functia BME280_READ16, adica din ce am inteles eu din cod, la BME280_calib.dig_T1, in loc sa combin bitii 7:0 din adresa 0x88 si bitii 15:8 din adresa 0x89, imi citeste toti bitii din adresa 0x88 si-i pune in BME280_calib.dig_T1.

Editat de tudorel1999
Link spre comentariu
Acum 1 oră, Mircea a spus:

Exemplul este pentru PIC32, dar se poate porta simplu pentru un PIC pe 8b. 

Nu-mi prea merge, am incercat sa-l adaptez pentru 8 biti dar la simularea din Proteus imi da erori la alocarea de memorie; in mikroC imi compileaza fara erori.

[PIC16 CORE] PC=0x0044. Indirection address (0x810E) for INDF0 register is outside writable data memory - no write occurs. [U2] (cateva mii de de astea)

[PIC16 CORE] PC=0x017D. Stack overflow executing CALL instruction. [U2]


 

Link spre comentariu

Dupa parerea mea, daca biblioteca oferita de Bandi face ce-ti trebuie, nu e cazul sa te chinui cu altele. E varianta cea mai la indemana, ai si suport in caz ca nu merge cum te astepti.

Daca insisti sa testezi si alte biblioteci, la cea pe care ai incercat-o in primul post folosesti adresa gresita. 0x76 (sau 0x77, in functie de cum e legat pinul SDO *) ) e adresa "pura". La asta trebuie adaugat bitul de operatie (scriere/citire), adica shiftul pe care l-am facut eu in postul anetrior. 0x76 << 1 = 0xEC, 0x77 << 1 = 0xEE. Daca zici ca functioneaza bibliteca de la Bandi, atunci adresa e 0xEE.

Referitor la nedumerirea pe care o ai la codul lui Bandi, cea cu lungimea datelor citite din senzor, citeste o documentatie de C/C++ referitoare la uniuni, dupa care arunci inca o privire prin cod dupa variabilele ret.

  union
  {
    uint8_t  b[2];
    uint16_t w;
  } ret;

 

*) Pagina 32 din foaia de catalog:

Quote

The 7-bit device address is 111011x. The 6 MSB bits are fixed. The last bit is changeable by SDO value and can be changed during operation. Connecting SDO to GND results in slave address 1110110 (0x76); connection it to VDDIO results in slave address 1110111 (0x77),

 

Editat de Liviu M
Link spre comentariu

Sa nu scapam din vedere ca colegul testeaza in Proteus. Ceva imi spune ca programul nu prea se incurca cu adresa I2C. Nu folosesc Proteus, deci poate gresesc. 

 

Pentru testul real, cu piese adevarate, e clar ca adresa e importanta.

Link spre comentariu

Mie

20 hours ago, tudorel1999 said:

nu-mi da return nici 1, nici 0, nici nimic,

imi seamana a program blocat in BME280_begin(...). Acu' daca Proteus stie sa se blocheze intr-o functie sau nu habar n-am, da' o comunicatie i2c cu adresa gresita se blocheaza destul de usor.

Link spre comentariu
18 hours ago, tudorel1999 said:

Codul dvs. functioneaza, pot comanda un LED cu functia BME208_begin(), insa mai am o intrebare. In datasheet scrie ca word-urile de trimming sunt pe 16 biti, impartite la cate doua adrese pe 8 biti, complementare. Cum functioneaza trimming-ul aici? Eu vad doar ca se citeste de la cate o adresa de 16 biti folosind functia BME280_READ16, adica din ce am inteles eu din cod, la BME280_calib.dig_T1, in loc sa combin bitii 7:0 din adresa 0x88 si bitii 15:8 din adresa 0x89, imi citeste toti bitii din adresa 0x88 si-i pune in BME280_calib.dig_T1.

 

De obicei prin I2C,SPI si alte multe protocoale de comunicare se pot efectua citiri / scrieri consecutive. Asta inseamna ca se trimite doar adresa de start (0x88) dupa care se pot citii n biti, BME280 prima data o sa returneze primii 8 biti din 0x88 dupa care la urmatoarea cerere de citire fara adresa stie sa faca increment la urmatoarea adresa (0x89) si returneaza urmatorii 8 biti. Si mai pe scurt cand vrei sa citsti / scrii adrese consecutive trebuie sa trimiti doar adresa de start si dupa poti citii cate biti vrei pentru ca trecerea la urmatoarea adresa se va face automat, functia aia de READ16 exact asta face si anume trimite adresa de start 0x88 si citest 16 biti care de fapt o sa fie primii 8 din 0x88 si urmatorii 8 din 0x89 din cauza incrementului automat.

Editat de Bandi Szasz
Link spre comentariu
Acum 50 minute, Bandi Szasz a spus:

De obicei prin I2C,SPI si alte multe protocoale de comunicare se pot efectua citiri / scrieri consecutive. Asta inseamna ca se trimite doar adresa de start (0x88) dupa care se pot citii n biti, BME280 prima data o sa returneze primii 8 biti din 0x88 dupa care la urmatoarea cerere de citire fara adresa stie sa faca increment la urmatoarea adresa (0x89) si returneaza urmatorii 8 biti. Si mai pe scurt cand vrei sa citsti / scrii adrese consecutive trebuie sa trimiti doar adresa de start si dupa poti citii cate biti vrei pentru ca trecerea la urmatoarea adresa se va face automat, functia aia de READ16 exact asta face si anume trimite adresa de start 0x88 si citest 16 biti care de fapt o sa fie primii 8 din 0x88 si urmatorii 8 din 0x89 din cauza incrementului automat.

Va multumesc pentru raspuns!

Link spre comentariu
Acum 12 ore, Bandi Szasz a spus:

De obicei prin I2C,SPI si alte multe protocoale de comunicare se pot efectua citiri / scrieri consecutive. Asta inseamna ca se trimite doar adresa de start (0x88) dupa care se pot citii n biti, BME280 prima data o sa returneze primii 8 biti din 0x88 dupa care la urmatoarea cerere de citire fara adresa stie sa faca increment la urmatoarea adresa (0x89) si returneaza urmatorii 8 biti. Si mai pe scurt cand vrei sa citsti / scrii adrese consecutive trebuie sa trimiti doar adresa de start si dupa poti citii cate biti vrei pentru ca trecerea la urmatoarea adresa se va face automat, functia aia de READ16 exact asta face si anume trimite adresa de start 0x88 si citest 16 biti care de fapt o sa fie primii 8 din 0x88 si urmatorii 8 din 0x89 din cauza incrementului automat.

As mai avea o intrebare, daca nu va suparati. Cum ati afisat datele? Am incercat in Proteus cu un virtual debugger sa afisez temperature, humidity si pressure printr-o interfata UART, am verificat cu I2C debugger si registrii in BME280 arata ok și se citesc și valorile dig_X +MSB/LSB/XLSB (pot vedea asta in  I2C debugger) dar cand incerc sa convertesc variabilele in str ca sa le afisez,cu longToStr() obtin valori gresite, iar cu floatToStr() imi compileaza in mikroC, dar obtin eroare in proteus (Indirection address (0x8F0E) for INDF0 register is outside writable data memory - no write occurs). Asta e main-ul:

unsigned long pressure, humidity;
signed long temperature;
char uart_rd;
char txt[30];
void BME280_Init() {
  Soft_I2C_Init();
  if(BME280_begin(MODE_SLEEP, SAMPLING_X1, SAMPLING_X1, SAMPLING_X1, FILTER_OFF, STANDBY_0_5) == 0) {
   while(1){
   PORTC.RC1=1;
   delay_ms(100);
   PORTC.RC1=0;
   delay_ms(100);
  }
}
}


void readData() {
  BME280_ForcedMeasurement();
  delay_ms(100);
  BME280_readTemperature(&temperature);
  // read temperature  + update adc_T, adc_H, adc_P
  BME280_readHumidity(&humidity);        // read humidity
  BME280_readPressure(&pressure);        // read pressure
  }



void main() {

  OSCCON = 0b01101010;   // set internal oscillator to 4MHz
  ANSELC = 0;
  TRISC=0;
  PORTC=0;
  BME280_Init();
  UART1_init(9600);
  Delay_ms(100);                  // Wait for UART module to stabilize
/*longtostr(humidity,txt);*/
  readData();
  floattostr(humidity,txt);
  UART1_Write_Text(txt);                // Write buffer on UART
  delay_ms(100);
;
  if (UART1_Data_Ready()) {     // If data is received,
     uart_rd = UART1_Read();     // read the received data,
     UART1_Write(uart_rd);       // and send data via UART
    }
  floattostr(temperature,txt);
  uart_write_text(txt);
    delay_ms(100);
  if (UART1_Data_Ready()) {     // If data is received,
     uart_rd = UART1_Read();     // read the received data,
     UART1_Write(uart_rd);       // and send data via UART
    }
  floattostr(pressure,txt);
  uart_write_text(txt);
  delay_ms(100);
  if (UART1_Data_Ready()) {     // If data is received,
     uart_rd = UART1_Read();     // read the received data,
     UART1_Write(uart_rd);       // and send data via UART
    }
}

 

Editat de tudorel1999
Link spre comentariu

Creează un cont sau autentifică-te pentru a adăuga comentariu

Trebuie să fi un membru pentru a putea lăsa un comentariu.

Creează un cont

Înregistrează-te pentru un nou cont în comunitatea nostră. Este simplu!

Înregistrează un nou cont

Autentificare

Ai deja un cont? Autentifică-te aici.

Autentifică-te acum



×
×
  • Creează nouă...

Informații Importante

Am plasat cookie-uri pe dispozitivul tău pentru a îmbunătății navigarea pe acest site. Poți modifica setările cookie, altfel considerăm că ești de acord să continui.Termeni de Utilizare si Ghidări