Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- Raspberry Pi picoで気温、湿度、気圧センサーのBME280をI2Cで使う
- exsampleのbme280_spi.cを参考にI2C版を作ってみました
- 以下にRaspberry Pi 4上でビルドする方法を説明します。
- (~/pico/pico-sdkにpico-sdkが入ってると仮定してます。
- 違う場所にpico-sdkを入れた人は適宜読み替えてください)
- 1.プロジェクトを置きたい場所にプロジェクトのディレクトリを作る
- mkdir test_bme280_i2c_usb01
- cd test_bme280_i2c_usb01
- 2.ソースの作成
- 一番下にtest_bme280_i2c_usb01.cのプログラムソースを記載してます
- 3.CMakeLists.txtの作成
- vi CMakeLists.txt
- 下記の内容で作成
- cmake_minimum_required(VERSION 3.12)
- # Pull in PICO SDK (must be before project)
- include(~/pico/pico-sdk/external/pico_sdk_import.cmake)
- project(test_bme280_i2c_usb01_project)
- set(CMAKE_C_STANDARD 11)
- set(CMAKE_CXX_STANDARD 17)
- # Initialize the SDK
- pico_sdk_init()
- add_executable(test_bme280_i2c_usb01 test_bme280_i2c_usb01.c)
- target_link_libraries(test_bme280_i2c_usb01 pico_stdlib hardware_i2c)
- pico_enable_stdio_usb(test_bme280_i2c_usb01 1)
- pico_enable_stdio_uart(test_bme280_i2c_usb01 0)
- pico_add_extra_outputs(test_bme280_i2c_usb01)
- 上記のようにI2Cを使う場合はtarget_link_librariesでhardware_i2cを指定する必要があります
- 4.buildディレクトリの作成し、カレントディレクトリをbuildに移動
- mkdir build
- cd build
- 5.ビルドの実行
- export PICO_SDK_PATH=~/pico/pico-sdk
- cmake ..
- make
- cmake ..の..の部分は親のディレクトリを指してます
- つまり、今いるbuildディレクトリの上にCMakeLists.txtがあることを指定してます
- ビルドが終わるとbuildディレクトリ内に
- test_bme280_i2c_usb01.bin test_bme280_i2c_usb01.dis test_bme280_i2c_usb01.elf test_bme280_i2c_usb01.elf.map test_bme280_i2c_usb01.hex test_bme280_i2c_usb01.uf2
- ができます
- picoへの書き込みに使うのはtest_bme280_i2c_usb01.uf2です
- 6.picoへの書き込み
- picoのbootselボタンを押しながらpicoをRaspberry Pi 4のUSB2ポートに差します
- すると他にUSBストレージを何も差してなければ新たに/dev/sda1ができます
- 他にUSBストレージが差してある場合は/dev/sdb1、/dev/sdc1、/dev/sdd1など
- すでにあるストレージデバイスの次の番号のストレージデバイスが/devに追加されます
- Raspberry Pi 4が自動マウントした場合
- そこにビルドで出来上がったtest_bme280_i2c_usb01.uf2をコピーして
- syncを1回実行してからsudo umountでマウントを解除します
- 自動マウントしない場合は
- 新しくできたデバイスが/dev/sda1の場合は下記のようになります
- sudo mount -t vfat /dev/sda1 /mnt
- sudo cp test_bme280_i2c_usb01.uf2 /mnt
- sync
- sudo umount /mnt
- 7.USBシリアルに接続する
- test_bme280_i2c_usb01はUSBシリアルを使うようにプログラムされているので
- test_bme280_i2c_usb01.uf2をpicoへコピーしてマウントを解除したあとにpicoが再起動して
- /dev/ttyACM0ができます
- minicomで/dev/ttyACM0に接続します
- minicomがない場合は
- sudo apt install minicom
- でインストールしてください
- minicom -D /dev/ttyACM0 -b 115200
- minicomの終了方法はCTRL+aを押した後にzを押すとメニューが出ます
- メニューが出たらxを押して「はい」を選択すると終了します
- 以下、test_bme280_i2c_usb01.cのソースになります
- このソースではBME280のI2Cアドレスは0x76にしてあります。
- BME280のI2Cアドレスが違う場合は変更してください
- I2CはpicoのI2C0を使ってます(SDAがGPIO4(6番ピン)、SCLがGPIO5(7番ピン))
- #include <stdio.h>
- #include "pico/stdlib.h"
- #include "hardware/i2c.h"
- #include "pico/binary_info.h"
- #define BME280_DEVICE_ADDRESS 0x76
- #define I2C_PORT i2c0
- #define MODE_SLEEP 0b00
- #define MODE_FORCED 0b01
- #define MODE_NORMAL 0b11
- void i2c_write_byte_non_regster(int addr, uint8_t val);
- void i2c_write_byte(int addr, uint8_t reg, uint8_t val);
- void i2c_write_half_word_little(int addr, uint8_t reg, uint16_t val);
- void i2c_write_half_word_big(int addr, uint8_t reg, uint16_t val);
- uint8_t i2c_read_byte(int addr, uint8_t reg);
- uint16_t i2c_read_half_word_little(int addr, uint8_t reg);
- uint16_t i2c_read_half_word_big(int addr, uint8_t reg);
- void i2c_read_buf(int addr, uint8_t reg, uint8_t *buf, int16_t len);
- int32_t bme280_read_raw_pressure();
- int32_t bme280_read_raw_temperature();
- int32_t bme280_read_raw_humidity();
- bool bme280_isMeasuring(void);
- void bme280_setMode(uint8_t mode);
- void bme280_setStandbyTime(uint8_t timeSetting);
- void bme280_setFilter(uint8_t filterSetting);
- int32_t t_fine;
- uint16_t dig_T1;
- int16_t dig_T2, dig_T3;
- uint16_t dig_P1;
- int16_t dig_P2, dig_P3, dig_P4, dig_P5, dig_P6, dig_P7, dig_P8, dig_P9;
- uint8_t dig_H1, dig_H3;
- int8_t dig_H6;
- int16_t dig_H2, dig_H4, dig_H5;
- int32_t compensate_temp(int32_t adc_T) {
- int32_t var1, var2, T;
- var1 = ((((adc_T >> 3) - ((int32_t) dig_T1 << 1))) * ((int32_t) dig_T2)) >> 11;
- var2 = (((((adc_T >> 4) - ((int32_t) dig_T1)) * ((adc_T >> 4) - ((int32_t) dig_T1))) >> 12) * ((int32_t) dig_T3))
- >> 14;
- t_fine = var1 + var2;
- T = (t_fine * 5 + 128) >> 8;
- return T;
- }
- uint32_t compensate_pressure(int32_t adc_P) {
- int32_t var1, var2;
- uint32_t p;
- var1 = (((int32_t) t_fine) >> 1) - (int32_t) 64000;
- var2 = (((var1 >> 2) * (var1 >> 2)) >> 11) * ((int32_t) dig_P6);
- var2 = var2 + ((var1 * ((int32_t) dig_P5)) << 1);
- var2 = (var2 >> 2) + (((int32_t) dig_P4) << 16);
- var1 = (((dig_P3 * (((var1 >> 2) * (var1 >> 2)) >> 13)) >> 3) + ((((int32_t) dig_P2) * var1) >> 1)) >> 18;
- var1 = ((((32768 + var1)) * ((int32_t) dig_P1)) >> 15);
- if (var1 == 0)
- return 0;
- p = (((uint32_t) (((int32_t) 1048576) - adc_P) - (var2 >> 12))) * 3125;
- if (p < 0x80000000)
- p = (p << 1) / ((uint32_t) var1);
- else
- p = (p / (uint32_t) var1) * 2;
- var1 = (((int32_t) dig_P9) * ((int32_t) (((p >> 3) * (p >> 3)) >> 13))) >> 12;
- var2 = (((int32_t) (p >> 2)) * ((int32_t) dig_P8)) >> 13;
- p = (uint32_t) ((int32_t) p + ((var1 + var2 + dig_P7) >> 4));
- return p;
- }
- uint32_t compensate_humidity(int32_t adc_H) {
- int32_t v_x1_u32r;
- v_x1_u32r = (t_fine - ((int32_t) 76800));
- v_x1_u32r = (((((adc_H << 14) - (((int32_t) dig_H4) << 20) - (((int32_t) dig_H5) * v_x1_u32r)) +
- ((int32_t) 16384)) >> 15) * (((((((v_x1_u32r * ((int32_t) dig_H6)) >> 10) * (((v_x1_u32r *
- ((int32_t) dig_H3)) >> 11) + ((int32_t) 32768))) >> 10) + ((int32_t) 2097152)) *
- ((int32_t) dig_H2) + 8192) >> 14));
- v_x1_u32r = (v_x1_u32r - (((((v_x1_u32r >> 15) * (v_x1_u32r >> 15)) >> 7) * ((int32_t) 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);
- return (uint32_t) (v_x1_u32r >> 12);
- }
- /* This function reads the manufacturing assigned compensation parameters from the device */
- void read_compensation_parameters() {
- uint8_t buffer[26];
- i2c_read_buf(BME280_DEVICE_ADDRESS, (uint8_t)0x88, buffer, 24);
- dig_T1 = buffer[0] | (buffer[1] << 8);
- dig_T2 = buffer[2] | (buffer[3] << 8);
- dig_T3 = buffer[4] | (buffer[5] << 8);
- dig_P1 = buffer[6] | (buffer[7] << 8);
- dig_P2 = buffer[8] | (buffer[9] << 8);
- dig_P3 = buffer[10] | (buffer[11] << 8);
- dig_P4 = buffer[12] | (buffer[13] << 8);
- dig_P5 = buffer[14] | (buffer[15] << 8);
- dig_P6 = buffer[16] | (buffer[17] << 8);
- dig_P7 = buffer[18] | (buffer[19] << 8);
- dig_P8 = buffer[20] | (buffer[21] << 8);
- dig_P9 = buffer[22] | (buffer[23] << 8);
- dig_H1 = i2c_read_byte(BME280_DEVICE_ADDRESS, (uint8_t)0xA1);
- i2c_read_buf(BME280_DEVICE_ADDRESS, (uint8_t)0xE1, buffer, 7);
- dig_H2 = buffer[0] | ((int16_t)buffer[1] << 8);
- dig_H3 = (int8_t) buffer[2];
- dig_H4 = (int16_t)buffer[3] << 4 | (buffer[4] & 0xf);
- dig_H5 = ((buffer[4] >> 4) & 0x0f) | ((int16_t)buffer[5] << 4);
- dig_H6 = (int8_t) buffer[6];
- }
- static void bme280_read_raw(int32_t *humidity, int32_t *pressure, int32_t *temperature) {
- uint8_t buffer[8];
- i2c_read_buf(BME280_DEVICE_ADDRESS, (uint8_t)0xF7, buffer, 8);
- *pressure = ((uint32_t) buffer[0] << 12) | ((uint32_t) buffer[1] << 4) | ((uint32_t)buffer[2] >> 4);
- *temperature = ((uint32_t) buffer[3] << 12) | ((uint32_t) buffer[4] << 4) | ((uint32_t)buffer[5] >> 4);
- *humidity = ((uint32_t) buffer[6] << 8) | ((uint32_t)buffer[7]);
- }
- int32_t bme280_read_raw_pressure() {
- uint8_t buffer[3];
- int32_t pressure;
- i2c_read_buf(BME280_DEVICE_ADDRESS, (uint8_t)0xF7, buffer, 3);
- pressure = ((uint32_t) buffer[0] << 12) | ((uint32_t) buffer[1] << 4) | ((uint32_t)buffer[2] >> 4);
- return pressure;
- }
- int32_t bme280_read_raw_temperature() {
- uint8_t buffer[3];
- int32_t temperature;
- i2c_read_buf(BME280_DEVICE_ADDRESS, (uint8_t)0xFA, buffer, 3);
- temperature = ((uint32_t) buffer[0] << 12) | ((uint32_t) buffer[1] << 4) | ((uint32_t)buffer[2] >> 4);
- return temperature;
- }
- int32_t bme280_read_raw_humidity() {
- uint8_t buffer[3];
- int32_t humidity;
- i2c_read_buf(BME280_DEVICE_ADDRESS, (uint8_t)0xFD, buffer, 2);
- humidity = ((uint32_t) buffer[0] << 8) | ((uint32_t)buffer[1]);
- return humidity;
- }
- int main() {
- stdio_init_all();
- printf("Hello, bme280! Reading raw data from registers via I2C...\n");
- // This example will use SPI0 at 0.5MHz.
- i2c_init(I2C_PORT, 400 * 1000); // I2C clock 400kHz
- gpio_set_function(4, GPIO_FUNC_I2C);
- gpio_set_function(5, GPIO_FUNC_I2C);
- gpio_pull_up(4);
- gpio_pull_up(5);
- // Make the I2C pins available to picotool
- bi_decl( bi_2pins_with_func(4, 5, GPIO_FUNC_I2C));
- // BME280 Reset
- i2c_write_byte(BME280_DEVICE_ADDRESS, (uint8_t)0xE0, (uint8_t)0xB6);
- sleep_ms(100);
- // See if SPI is working - interrograte the device for its I2C ID number, should be 0x60
- uint8_t id;
- id = i2c_read_byte(BME280_DEVICE_ADDRESS, (uint8_t)0xD0);
- printf("Chip ID is 0x%x\n", id);
- read_compensation_parameters();
- i2c_write_byte(BME280_DEVICE_ADDRESS, (uint8_t)0xF2, (uint8_t)0x1); // Humidity oversampling register - going for x1
- i2c_write_byte(BME280_DEVICE_ADDRESS, (uint8_t)0xF4, (uint8_t)0x27);// Set rest of oversampling modes and run mode to normal
- bme280_setStandbyTime(0);
- bme280_setFilter(0);
- bme280_setMode(MODE_SLEEP);
- int32_t humidity, pressure, temperature;
- while (1) {
- bme280_setMode(MODE_FORCED);
- while (!bme280_isMeasuring()) sleep_ms(1); // Wait before the start of measurement
- while ( bme280_isMeasuring()) sleep_ms(1); // Wait during a measurement
- bme280_read_raw(&humidity, &pressure, &temperature);
- // These are the raw numbers from the chip, so we need to run through the
- // compensations to get human understandable numbers
- pressure = compensate_pressure(pressure);
- temperature = compensate_temp(temperature);
- humidity = compensate_humidity(humidity);
- printf("Humidity : %.2f%%\r\n", humidity / 1024.0);
- printf("Pressure : %.2fhPa\r\n", pressure / 100.0);
- printf("Temp : %.2fC\r\n", temperature / 100.0);
- printf("\n");
- sleep_ms(5000);
- }
- return 0;
- }
- void i2c_write_byte_non_register(int addr, uint8_t val) {
- i2c_write_blocking(I2C_PORT, addr, &val, 1, false);
- }
- void i2c_write_byte(int addr, uint8_t reg, uint8_t val) {
- uint8_t buf[2];
- buf[0] = reg;
- buf[1] = val;
- i2c_write_blocking(I2C_PORT, addr, buf, 2, false);
- }
- void i2c_write_half_word_little(int addr, uint8_t reg, uint16_t val) {
- uint8_t buf[3];
- buf[0] = reg;
- buf[1] = (uint8_t)(val & 0x00ff);
- buf[2] = (uint8_t)((val >> 8) & 0x00ff);
- i2c_write_blocking(I2C_PORT, addr, buf, 3, false);
- }
- void i2c_write_half_word_big(int addr, uint8_t reg, uint16_t val) {
- uint8_t buf[3];
- buf[0] = reg;
- buf[1] = (uint8_t)((val >> 8) & 0x00ff);
- buf[2] = (uint8_t)(val & 0x00ff);
- i2c_write_blocking(I2C_PORT, addr, buf, 3, false);
- }
- uint8_t i2c_read_byte(int addr, uint8_t reg) {
- uint8_t buf;
- i2c_write_blocking(I2C_PORT, addr, ®, 1, true);
- i2c_read_blocking(I2C_PORT, addr, &buf, 1, false); // False - finished with bus
- return buf;
- }
- uint16_t i2c_read_half_word_little(int addr, uint8_t reg) {
- uint8_t buf[2];
- uint16_t ret;
- i2c_write_blocking(I2C_PORT, addr, ®, 1, true);
- i2c_read_blocking(I2C_PORT, addr, buf, 2, false); // False - finished with bus
- ret = (uint16_t)(((uint16_t)buf[1] << 8) | (uint16_t)buf[0]);
- return ret;
- }
- uint16_t i2c_read_half_word_big(int addr, uint8_t reg) {
- uint8_t buf[2];
- uint16_t ret;
- i2c_write_blocking(I2C_PORT, addr, ®, 1, true);
- i2c_read_blocking(I2C_PORT, addr, buf, 2, false); // False - finished with bus
- ret = (uint16_t)(((uint16_t)buf[0] << 8) | (uint16_t)buf[1]);
- return ret;
- }
- void i2c_read_buf(int addr, uint8_t reg, uint8_t *buf, int16_t len) {
- i2c_write_blocking(I2C_PORT, addr, ®, 1, true);
- i2c_read_blocking(I2C_PORT, addr, buf, len, false); // False - finished with bus
- }
- bool bme280_isMeasuring(void) {
- uint8_t stat = i2c_read_byte(BME280_DEVICE_ADDRESS, (uint8_t)0xF3);
- return(stat & (1<<3));
- }
- void bme280_setMode(uint8_t mode) {
- if(mode > 0b11) mode = 0;
- uint8_t controlData = i2c_read_byte(BME280_DEVICE_ADDRESS, (uint8_t)0xF4);
- controlData &= ~( (1<<1) | (1<<0) ); //Clear the mode[1:0] bits
- controlData |= mode;
- i2c_write_byte(BME280_DEVICE_ADDRESS, (uint8_t)0xF4, controlData);
- }
- // 0, 0.5ms
- // 1, 62.5ms
- // 2, 125ms
- // 3, 250ms
- // 4, 500ms
- // 5, 1000ms
- // 6, 10ms
- // 7, 20ms
- void bme280_setStandbyTime(uint8_t timeSetting) {
- if(timeSetting > 0b111) timeSetting = 0;
- uint8_t controlData = i2c_read_byte(BME280_DEVICE_ADDRESS, (uint8_t)0xF5);
- controlData &= ~( (1<<7) | (1<<6) | (1<<5) ); //Clear the 7/6/5 bits
- controlData |= (timeSetting << 5); //Align with bits 7/6/5
- i2c_write_byte(BME280_DEVICE_ADDRESS, (uint8_t)0xF5, controlData);
- }
- // 0, filter off
- // 1, coefficients = 2
- // 2, coefficients = 4
- // 3, coefficients = 8
- // 4, coefficients = 16
- void bme280_setFilter(uint8_t filterSetting) {
- if(filterSetting > 0b111) filterSetting = 0;
- uint8_t controlData = i2c_read_byte(BME280_DEVICE_ADDRESS, (uint8_t)0xF5);
- controlData &= ~( (1<<4) | (1<<3) | (1<<2) ); //Clear the 4/3/2 bits
- controlData |= (filterSetting << 2); //Align with bits 4/3/2
- i2c_write_byte(BME280_DEVICE_ADDRESS, (uint8_t)0xF5, controlData);
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement