This post shows how to interface Microchip PIC16F877A microcontroller with BMP280 barometric pressure and temperature sensor. Values of the temperature and the pressure are displayed on 16×2 LCD screen connected to the microcontroller.
In this project the BMP280 sensor is used in I2C mode and the compiler used is CCS PIC C.
The BMP280 sensor from Bosch Sensortec is a low cost pressure and temperature sensor with good accuracy. Because pressure changes with altitude we can use it as an altimeter with ±1 meter accuracy (pressure accuracy = ±1 hPa). Some parameters of the sensor are listed below:
Pressure range: 300…1100 hPa (equivalent to +9000…-500m above/below sea level)
Pressure resolution: 0.01 hPa ( < 10 cm)
Temperature range: -40…85 °C
Temperature resolution: 0.01 °C
Interface: I2C and SPI
The BMP280 chip works with maximum voltage of 3.6V (supply voltage range is from 1.71 to 3.6V) which means we’ve to use a 3V3 voltage regulator to supply it from a 5V source.
Also if we’re working with a 5V system (development board, microcontroller …) like the PIC16F877A microcontroller we’ve to use a voltage level shifter (level converter) which converts the 3.3V (comes from the BMP280 chip) into 5V (goes to the PIC16F877A MCU) and vice versa. This level shifter is for the I2C bus lines (clock and data).
Some BMP280 modules come with 3V3 voltage regulator and level shifter like the one provided by Adafruit Industries which is shown below.
A module like this can be used with 3.3V or 5V system without any problem.
In this example I’m going to use a Chinese BMP280 module came with 3.3V regulator and level shifter, this mans connection will be more easier!
BMP280 Driver for CCS C compiler:
To simplify the C code, I wrote a simple driver (library) for the BMP280 sensor. With this driver the interfacing is more easier.
Driver functions:
BMP280_begin(mode, T_sampling, P_sampling, filter, standby): this function initializes the BMP280 sensor with the 5 configurations (mode, T_sampling, P_sampling, filter and standby), returns 1 if OK and 0 if error:
mode is sensor mode which can be: MODE_SLEEP, MODE_FORCED or MODE_NORMAL.
T_sampling is temperature oversampling and P_sampling is pressure oversampling, each one of them can be one of the following list (library default is SAMPLING_X1):
SAMPLING_SKIPPED —> skipped, output set to 0x80000
SAMPLING_X1 —> oversampling x1
SAMPLING_X2 —> oversampling x2
SAMPLING_X4 —> oversampling x4
SAMPLING_X8 —> oversampling x8
SAMPLING_X16 —> oversampling x16
filter sets BMP280 sensor IIR filter configuration, it could be (library default is FILTER_OFF):
FILTER_OFF —> filter off
FILTER_2 —> filter coefficient = 2
FILTER_4 —> filter coefficient = 4
FILTER_8 —> filter coefficient = 8
FILTER_16 —> filter coefficient = 16
standby is BMP280 sensor standby time (library default is STANDBY_0_5):
STANDBY_0_5 —> standby time = 0.5 ms
STANDBY_62_5 —> standby time = 62.5 ms
STANDBY_125 —> standby time = 125 ms
STANDBY_250 —> standby time = 250 ms
STANDBY_500 —> standby time = 500 ms
STANDBY_1000 —> standby time = 1000 ms
STANDBY_2000 —> standby time = 2000 ms
STANDBY_4000 —> standby time = 4000 ms
Examples:
The following line initializes the BMP280 sensor in normal mode, temperature oversampling = X2, pressure oversampling = X16, IIR filter coefficient = 4 and standby time = 125 ms:
BMP280_begin(MODE_NORMAL, SAMPLING_X2, SAMPLING_X16, FILTER_4, STANDBY_125);
and the following line initializes the BMP280 sensor in normal mode, temperature oversampling = X1, pressure oversampling = X1, IIR filter is off and standby time = 0.5 ms where default settings are used:
BMP280_begin(MODE_NORMAL);
BMP280_ForcedMeasurement(): this function is used to start a new measurement conversion, used in forced mode only. Returns 1 if ok and 0 if error (sensor is not in sleep mode).
BMP280_readTemperature(int32_t *temp): reads temperature from BMP280 sensor. Temperature is stored in hundredths °C (output value of “5123” equals 51.23 °C). Temperature value is saved to *temp, returns 1 if OK and 0 if error.
BMP280_readPressure(uint32_t *pres): reads pressure from BMP280 sensor. Pressure is stored in Pa (output value of “96386” equals 96386 Pa = 963.86 hPa). Pressure value is saved to *pres, returns 1 if OK and 0 if error.
BMP280 driver for CCS C compiler download:
Driver source file download link is below, installation of this driver is easy, just add it to project folder or CCS C drivers folder (for example C:\Program Files (x86)\CCS\Drivers). Driver name is: BMP280_Lib.c.
BMP280 CCS C driver
Interfacing PIC16F877A microcontroller with BMP280 sensor:
This is an example that shows how to interface the BMP280 sensor with PIC MCU and shows how to use the device driver.
Hardware Required:
- PIC16F877A microcontroller
- BMP280 sensor module with 3.3V regulator and level shifter —-> BMP280 datasheet
- 1602 LCD screen
- 8 MHz crystal oscillator
- 2 x 22pF ceramic capacitor
- 10k ohm variable resistor (or potentiometer)
- 330 ohm resistor
- 10k ohm resistor
- 5V source
- Breadboard
- Jumper wires
Example circuit schematic diagram is shown below.
Note that the BMP280 module shown in the circuit diagram has a 3.3V regulator and level shifter.
Generally, the BMP280 module has at least 4 pins because it can work in SPI mode or I2C mode. For the I2C mode we need 4 pins: VCC, GND, SCL and SDA where:
GND (ground) is connected to circuit ground (0V)
VCC is the supply pin, it is connected to +5V
SCL is I2C bus serial clock line, connected to PIC16F877A RC3 pin (#18)
SDA is I2C bus serial data line, connected to PIC16F877A RC4 pin (#23).
The 1602 LCD screen is used to display temperature and pressure values where:
RS —> pin RD0
RW —> pin RD1
E —> pin RD2
D4 —> pin RD3
D5 —> pin RD4
D6 —> pin RD5
D7 —> pin RD7
VSS, RW, D0, D1, D2, D3 and K are connected to circuit ground
VEE to the variable resistor (or potentiometer) output
VDD to +5V and A to +5V through 330 ohm resistor.
VEE pin is used to control the contrast of the LCD. A (anode) and K (cathode) are the back light LED pins.
In this project the PIC16F877A microcontroller runs with 8 MHz crystal oscillator.
Interfacing PIC16F877A with BMP280 sensor C code:
The C code below is for CCS C compiler, it was tested with version 5.051.
To be able to compile project C code, a driver for the BMP280 sensor is required, download link is above.
After you download driver file which named BMP280_Lib.c, add it to your project folder!
As any other I2C device, the BMP280 sensor has an I2C slave address which is 0xEC or 0xEE. This address depends on the connection of the SDO pin (used for SPI mode as serial data out or MISO), if the SDO pin is connected (directly or through resistor) to VCC (3.3V) the address will be 0xEE, and if it’s connected to GND the address will be 0xEC.
The default I2C address of the library is defined as 0xEE and my device I2C address is 0xEC.
In the code the definition of the I2C slave address is as shown below:
1 2 | // define device I2C address: 0xEC or 0xEE (0xEE is library default address) #define BMP280_I2C_ADDRESS 0xEC |
The initialization of the BMP280 sensor is done using the function BMP280_begin(MODE_NORMAL) which returns 1 if OK and 0 if error. In the code the initialization of the sensor is as shown below:
1 2 3 4 5 6 7 8 9 | // initialize the BMP280 sensor if(BMP280_begin(MODE_NORMAL) == 0) { // connection error or device address wrong! lcd_gotoxy(1, 1); // go to column 1 row 1 lcd_putc("Connection"); lcd_gotoxy(1, 2); // go to column 1 row 2 lcd_putc("error!"); while(TRUE); // stay here } |
The LCD displays “connection error!” if there was an error with the initialization of the device.
Reading the values of temperature and pressure is done as shown below.
Note that the library returns the temperature in hundredths °C which means we’ve to divide it by 100 and it returns the pressure in Pa, to get the pressure in hPa we’ve to divide it by 100.
1 2 3 4 | // Read temperature (in hundredths C) and pressure (in Pa) // values from BMP280 sensor BMP280_readTemperature(&temperature); // read temperature BMP280_readPressure(&pressure); // read pressure |
Temperature and pressure values are displayed on 16×2 LCD screen.
1 bar = 10000 Pa = 100 hPa. ( 1 hPa = 100 Pa)
Pa: Pascal
hPa: hectoPascal
Full CCS C Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 | /* * Interfacing PIC16F877A microcontroller with BMP280 temperature and pressure sensor. * C Code for CCS C compiler. * Temperature and pressure values are displayed on 16x2 LCD. * This is a free software with NO WARRANTY. * http://simple-circuit.com/ */ // define device I2C address: 0xEC or 0xEE (0xEE is library default address) #define BMP280_I2C_ADDRESS 0xEC // LCD module connections #define LCD_RS_PIN PIN_D0 #define LCD_RW_PIN PIN_D1 #define LCD_ENABLE_PIN PIN_D2 #define LCD_DATA4 PIN_D3 #define LCD_DATA5 PIN_D4 #define LCD_DATA6 PIN_D5 #define LCD_DATA7 PIN_D6 // end LCD module connections #include <16F877A.h> #fuses HS, NOWDT, NOPROTECT, NOLVP #use delay(clock = 8MHz) #use I2C(MASTER, I2C1, FAST = 400000, STREAM = BMP280_STREAM) #include <BMP280_Lib.c> // include BMP280 sensor driver source file #include <lcd.c> // include LCD driver source file signed int32 temperature; unsigned int32 pressure; void main() { delay_ms(1000); // wait 1 second lcd_init(); // initialize LCD module lcd_putc('\f'); // clear the LCD // initialize the BMP280 sensor if(BMP280_begin(MODE_NORMAL) == 0) { // connection error or device address wrong! lcd_gotoxy(1, 1); // go to column 1 row 1 lcd_putc("Connection"); lcd_gotoxy(1, 2); // go to column 1 row 2 lcd_putc("error!"); while(TRUE); // stay here } lcd_gotoxy(1, 1); // go to column 1 row 1 lcd_putc("Temp:"); lcd_gotoxy(1, 2); // go to column 1 row 2 lcd_putc("Pres:"); while(TRUE) { // Read temperature (in hundredths C) and pressure (in Pa) // values from BMP280 sensor BMP280_readTemperature(&temperature); // read temperature BMP280_readPressure(&pressure); // read pressure // print data on the LCD screen // 1: print temperature lcd_gotoxy(6, 1); // go to column 6 row 1 if(temperature < 0) { lcd_putc('-'); temperature = abs(temperature); } else lcd_putc(' '); printf(lcd_putc, "%02Lu.%02Lu%cC", temperature / 100, temperature % 100, 223); // 2: print pressure lcd_gotoxy(7, 2); // go to column 7 row 1 printf(lcd_putc, "%04Lu.%02LuhPa", pressure/100, pressure % 100); delay_ms(2000); // wait 2 seconds } } // end of code. |
Discover more from Simple Circuit
Subscribe to get the latest posts sent to your email.
Hello, what would be the difference in the diagram and in the code, if we connected a display using I2C (GND, VCC, SDA and SCL)
Nobody knows.
Hello, when you write the #use I2C, what does the parameter I2C1 do?
Is it posible to use said library with the PIC18F45K50?
Do you have the Simulation in proteus ?
i copied to this code to mikroc program and i attached bmp280 driver to project folder but this code didn’t work.I wish you could also share the hex file of the code.
Hello , do you maybe have a source code for bmp388 ? Thanks a lot 😀
Right now I have no example for the BMP388 sensor, any example for this device will be posted in this blog.
Hi what compiler are u using for this project? All the I2C function produce an error for me.
I made by (CCS PCWHD) 5.092 x86. Project built good.
do you need to define if the pins on the portc like SCL and SCI/SDA are inputs or outputs with trisc?