tudorel1999 Postat Martie 20, 2022 Partajează Postat Martie 20, 2022 (editat) 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 Martie 20, 2022 de tudorel1999 Link spre comentariu
Liviu M Postat Martie 20, 2022 Partajează Postat Martie 20, 2022 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
Bandi Szasz Postat Martie 20, 2022 Partajează Postat Martie 20, 2022 (editat) 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 Martie 20, 2022 de Bandi Szasz Link spre comentariu
tudorel1999 Postat Martie 20, 2022 Autor Partajează Postat Martie 20, 2022 (editat) 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 Martie 20, 2022 de tudorel1999 Link spre comentariu
Mircea Postat Martie 20, 2022 Partajează Postat Martie 20, 2022 Exemplul Mikroelektronika de pe Libstock: https://libstock.mikroe.com/projects/view/1555/weather-click/older-versions Link spre comentariu
tudorel1999 Postat Martie 20, 2022 Autor Partajează Postat Martie 20, 2022 (editat) 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 Martie 20, 2022 de tudorel1999 Link spre comentariu
tudorel1999 Postat Martie 20, 2022 Autor Partajează Postat Martie 20, 2022 1 oră în urmă, Mircea a spus: Exemplul Mikroelektronika de pe Libstock: https://libstock.mikroe.com/projects/view/1555/weather-click/older-versions Multumesc!Am doar mikroC PRO for PIC (simplu), nu am softul necesar pentru a rula exemplele acelea. Link spre comentariu
Mircea Postat Martie 20, 2022 Partajează Postat Martie 20, 2022 Am pus link la versiunea veche, care ruleaza in MikroC pro. Exemplul este pentru PIC32, dar se poate porta simplu pentru un PIC pe 8b. Link spre comentariu
tudorel1999 Postat Martie 20, 2022 Autor Partajează Postat Martie 20, 2022 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
Liviu M Postat Martie 20, 2022 Partajează Postat Martie 20, 2022 (editat) 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 Martie 20, 2022 de Liviu M Link spre comentariu
Mircea Postat Martie 20, 2022 Partajează Postat Martie 20, 2022 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
Liviu M Postat Martie 21, 2022 Partajează Postat Martie 21, 2022 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
Bandi Szasz Postat Martie 21, 2022 Partajează Postat Martie 21, 2022 (editat) 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 Martie 21, 2022 de Bandi Szasz Link spre comentariu
tudorel1999 Postat Martie 21, 2022 Autor Partajează Postat Martie 21, 2022 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
tudorel1999 Postat Martie 21, 2022 Autor Partajează Postat Martie 21, 2022 (editat) 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 Martie 21, 2022 de tudorel1999 Link spre comentariu
Postări Recomandate
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 contAutentificare
Ai deja un cont? Autentifică-te aici.
Autentifică-te acum