SPL: читаем данные с датчика BMP280

     Краткое описание: Для работы с этим примером необходимы плата расширения 1 и Индикатор (t°C). Подключаем индикационную плату Индикатор (t°C) к плате CodeIN через плату расширения 1 рисунок 1. 

     Задача: Требуется написать с использованием библиотеки StdPeriph код. Программа должна производить настойку аппаратного i2c, и аппаратного SPI. Используя стандартные функции библиотеки StdPeriph для работы с i2c прочитать содержимое регистров с калибровочными коэффициентами, произвести настройку датчика, преобразовать полученные данные в высоту над уровнем моря в метрах и вывести на индикационную плату с помощью интерфейса SPI. 

Рисунок 1

#include "stm32f30x.h"
#include "stm32f30x_gpio.h"
#include "stm32f30x_rcc.h"
#include "stm32f30x_i2c.h"
#include "stm32f30x_spi.h"
#include "stm32f30x_tim.h"
#include "math.h"
#include "stm32f30x_syscfg.h"

#define ADR_BMP280_W 0xEC //Адрес устройства BMP280 с битом записи
#define ADR_BMP280_R 0xED //Адрес устройства BMP280 с битом чтения

#define OWN_ADR 0x15 //Собственный адрес устройства i2c1
#define TIMING_I2C1 100000 //Частота тактового сигнала i2c1

#define PRESCALER_TIM2 720 //Пределитель чистоты для таймера 2
#define PERIOD_TIM2 1000 //Период таймера 10 миллисекунд (1 единица значения равна 0,01 миллисекунде (10 микросекунд))

GPIO_InitTypeDef gpio; //Объявляем переменную gpio типа GPIO_InitTypeDef
I2C_InitTypeDef i2c; //Объявляем переменную i2c типа I2C_InitTypeDef
SPI_InitTypeDef spi; //Объявляем переменную spi типа SPI_InitTypeDef
TIM_TimeBaseInitTypeDef timer; //Объявляем переменную timer типа TIM_TimeBaseInitTypeDef

short read_byte(char ADR_DEVICE_W, char ADR_DEVICE_R, char ADR_REGISTER); //Функция чтения байта по i2c
short read_word(char ADR_DEVICE_W, char ADR_DEVICE_R, char ADR_REGISTER); //Функция чтения слова по i2c
short read_word_sign(char ADR_DEVICE_W, char ADR_DEVICE_R, char ADR_REGISTER); //Функция чтения слова с учетом знака по i2c
long read_long(char ADR_DEVICE_W, char ADR_DEVICE_R, char ADR_REGISTER); //Функция чтения 3 байт по i2c
void write_byte(char ADR_DEVICE_W, char ADR_REGISTER, char SETTINGS); //Функция записи байта по i2c

//BMP280 адрес по умолчанию
#define BMP280_I2CADDR 0x77

//BMP280 основные управляющие регистры и регистры данных
#define BMP280_CONTROL 0xF4
#define BMP280_CONFIG 0xF5
#define BMP280_PRESSURE 0xF7
#define BMP280_TEMP 0xFA
//BMP280 регистры с калибровочными значениями
#define BMP280_DIG_T1 0x88
#define BMP280_DIG_T2 0x8A
#define BMP280_DIG_T3 0x8C
#define BMP280_DIG_P1 0x8E
#define BMP280_DIG_P2 0x90
#define BMP280_DIG_P3 0x92
#define BMP280_DIG_P4 0x94
#define BMP280_DIG_P5 0x96
#define BMP280_DIG_P6 0x98
#define BMP280_DIG_P7 0x9A
#define BMP280_DIG_P8 0x9C
#define BMP280_DIG_P9 0x9E

//Настройки выборки
#define BMP280_OVERS_T1 0x20
#define BMP280_OVERS_T2 0x40
#define BMP280_OVERS_T4 0x60
#define BMP280_OVERS_T8 0x80
#define BMP280_OVERS_T16 0xA0

#define BMP280_OVERS_P1 0x04
#define BMP280_OVERS_P2 0x08
#define BMP280_OVERS_P4 0x0C
#define BMP280_OVERS_P8 0x10
#define BMP280_OVERS_P16 0x14

//Настройки питания
//#define BMP280_SLEEP_MODE 0x00
//#define BMP280_FORCED_MODE 0x01
#define BMP280_NORMAL_MODE 0x03

#define BMP280_TSB_0_5 0x00
#define BMP280_TSB_62_5 0x20
#define BMP280_TSB_125 0x40
#define BMP280_TSB_250 0x60
#define BMP280_TSB_500 0x80
#define BMP280_TSB_1000 0xA0
#define BMP280_TSB_2000 0xC0
#define BMP280_TSB_4000 0xE0

#define BMP280_FILTER_OFF 0x00
#define BMP280_FILTER_COEFFICIENT2 0x04
#define BMP280_FILTER_COEFFICIENT4 0x08
#define BMP280_FILTER_COEFFICIENT8 0x0C
#define BMP280_FILTER_COEFFICIENT16 0x10

//Регистр включения/отключения spi
#define BMP280_SPI_OFF 0x00
#define BMP280_SPI_ON 0x01

//Настройки датчика
#define BMP280_CONTROL_SET 0xB7 //(BMP280_OVERS_T16 | BMP280_OVERS_P16 | BMP280_NORMAL_MODE)
#define BMP280_CONFIG_SET 0x10 //(BMP280_TSB_0_5 | BMP280_FILTER_COEFFICIENT16 | BMP280_SPI_OFF)

//Значения для работы с индикатором
#define Zero 63 //Соответствует цифре <0> на индикаторе
#define One 6 //Соответствует цифре <1> на индикаторе
#define Two 91 //Соответствует цифре <2> на индикаторе
#define Three 79 //Соответствует цифре <3> на индикаторе
#define Four 102 //Соответствует цифре <4> на индикаторе
#define Five 109 //Соответствует цифре <5> на индикаторе
#define Six 125 //Соответствует цифре <6> на индикаторе
#define Seven 7 //Соответствует цифре <7> на индикаторе
#define Eight 127 //Соответствует цифре <8> на индикаторе
#define Nine 111 //Соответствует цифре <9> на индикаторе
#define Point 128 //Соответствует точке на индикаторе

//Значения для работы с индикационными светодиодами
#define Led_ALL_Good 1 //Соответствует зеленому цвету
#define Led_Warning 2 //Соответствует красному цвету

//Калибровочные коэффициенты
unsigned short dig_T1;
short dig_T2;
short dig_T3;
unsigned short dig_P1;
short dig_P2;
short dig_P3;
short dig_P4;
short dig_P5;
short dig_P6;
short dig_P7;
short dig_P8;
short dig_P9;

char LSB; //Переменная для работы с приемом данных по i2c
char MSB; //Переменная для работы с приемом данных по i2c

//Переменные для работы с датчиком BMP280

long adc_t;
long adc_p;

double var1;
double var2;
double t_fine;
double T;
double p;
double P;
double temp;
double altitude;

int Indikator_1 = Zero; //Присваиваем переменной индикатора 1 значение 0
int Indikator_2 = Zero; //Присваиваем переменной индикатора 2 значение 0
int Indikator_3 = Zero; //Присваиваем переменной индикатора 3 значение 0

int Led_conf = Led_ALL_Good; //Присваиваем переменной светодиода значение соответствующее зеленному цвету

int k = 0; //Переменная для условной операции изменения значения индикатора 1
int m = 0; //Переменная для условной операции изменения значения индикатора 2
int n = 0; //Переменная для условной операции изменения значения индикатора 3

void initAll()
{
    RCC_HSICmd(ENABLE); //Включаем тактирование от внутреннего источника
    RCC_SYSCLKConfig(RCC_SYSCLKSource_HSI); //Подаем тактовый сигнал на системную шину

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE); //Тактирование i2c1
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE); //Включаем тактирование SPI1
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); //Тактирование таймера 2
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE); //Включаем тактирование A
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE); //Тактирование порта B

    GPIO_PinAFConfig(GPIOB, GPIO_PinSource8, GPIO_AF_4); //(SCL) Настраиваем ножку для работы в режиме альтернативной функции
    GPIO_PinAFConfig(GPIOB, GPIO_PinSource9, GPIO_AF_4); //(SDA) Настраиваем ножку для работы в режиме альтернативной функции

    //Настройки ножек i2c1
    gpio.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9; //Выбираем нужные пины SCL/SDA
    gpio.GPIO_Mode = GPIO_Mode_AF; //Выбираем режим работы пинов
    gpio.GPIO_Speed = GPIO_Speed_50MHz; //Выбираем максимальную скорость
    gpio.GPIO_OType = GPIO_OType_OD; //Выход с открытым стоком
    gpio.GPIO_PuPd = GPIO_PuPd_UP; //Конфигурируем подтяжку
    GPIO_Init(GPIOB, &gpio); //Инициализируем структуру с настройками

    //Настройки модуля i2c1
    i2c.I2C_Timing = TIMING_I2C1; //Частота тактового сигнала i2c1
    i2c.I2C_Mode = I2C_Mode_I2C; //Режим работы
    i2c.I2C_OwnAddress1 = OWN_ADR; //Собственный адрес устройства
    i2c.I2C_Ack = I2C_Ack_Enable; //Включение/отключения бита подтверждения ACK
    i2c.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit; //Выбор формата адреса: 7 бит / 10 бит.
    I2C_Init(I2C1, &i2c); //Инициализация настроек
    I2C_Cmd(I2C1, ENABLE); //Включение модуля i2c1

    gpio.GPIO_Mode = GPIO_Mode_OUT; //Выбираем режим работы пинов: ВЫХОД
    gpio.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1; //Выбираем пин PB0( <LE> нужен для вывода данных на индикаторы после загрузки посылки в                                                                                                               //микросхему MBI), пин PB1 <nOE> Для включения микросхемы MBI
    GPIO_Init(GPIOB, &gpio); //Инициализируем структуру с настройками

    //Настраиваем пины SPI1 для работы в режиме альтернативной функции
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource5, GPIO_AF_5); //Будет использоваться как SCK
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource6, GPIO_AF_5); //Будет использоваться как SDO
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource7, GPIO_AF_5); //Будет использоваться как SDI

    gpio.GPIO_Mode = GPIO_Mode_AF; //Выбираем режим работы пинов: Альтернативная функция
    gpio.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7; //Выбираем нужные пины
    GPIO_Init(GPIOA, &gpio); //Инициализируем структуру с настройками

    //Заполняем структуру с параметрами SPI модуля
    spi.SPI_Direction = SPI_Direction_1Line_Tx; //Полный дуплекс
    spi.SPI_DataSize = SPI_DataSize_8b; //Передаем по 8 бит
    spi.SPI_CPOL = SPI_CPOL_High; //Полярность и
    spi.SPI_CPHA = SPI_CPHA_2Edge; //Фаза тактового сигнала
    spi.SPI_NSS = SPI_NSS_Soft; //Управлять состоянием сигнала NSS программно
    spi.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_32; //Предделитель SCK
    spi.SPI_FirstBit = SPI_FirstBit_MSB; //Первым отправляется старший бит
    spi.SPI_Mode = SPI_Mode_Master; //Режим - мастер
    SPI_Init(SPI1, &spi); //Настраиваем SPI1
    SPI_Cmd(SPI1, ENABLE); //Включаем модуль SPI1....

    //Поскольку сигнал NSS контролируется программно, установим его в единицу
    //Если сбросить его в ноль, то наш SPI модуль подумает, что
    //у нас мультимастерная топология и его лишили полномочий мастера.
    SPI_NSSInternalSoftwareConfig(SPI1, SPI_NSSInternalSoft_Set);

    TIM_TimeBaseStructInit(&timer); //Инициализация структуры

    timer.TIM_Prescaler = PRESCALER_TIM2; //Выбор пределителя
    timer.TIM_Period = PERIOD_TIM2; //Период досчитав до которого произойдет прерывание
    TIM_TimeBaseInit(TIM2, &timer); //Инициализация выбранных значений

    TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE); //Настраивает таймер на генерирования прерывания по переполнению
    NVIC_EnableIRQ(TIM2_IRQn); //Разрешаем соответствующие прерывания
    TIM_Cmd(TIM2, ENABLE); //Запускаем таймер
}

int main()
{

    initAll(); //Вызов функции инициализации i2c1
    ok_enable_irq(); //Разрешаются прерывания с линии IRQ на контроллере "disable_irq и enable_irq управляeт битом в регистре PRIMASK (запрет/разрешение)"

    //Считываем калибровочные значения
    dig_T1 = read_word(ADR_BMP280_W, ADR_BMP280_R, BMP280_DIG_T1);
    dig_T2 = read_word_sign(ADR_BMP280_W, ADR_BMP280_R, BMP280_DIG_T2);
    dig_T3 = read_word_sign(ADR_BMP280_W, ADR_BMP280_R, BMP280_DIG_T3);
    dig_P1 = read_word(ADR_BMP280_W, ADR_BMP280_R, BMP280_DIG_P1);
    dig_P2 = read_word_sign(ADR_BMP280_W, ADR_BMP280_R, BMP280_DIG_P2);
    dig_P3 = read_word_sign(ADR_BMP280_W, ADR_BMP280_R, BMP280_DIG_P3);
    dig_P4 = read_word_sign(ADR_BMP280_W, ADR_BMP280_R, BMP280_DIG_P4);
    dig_P5 = read_word_sign(ADR_BMP280_W, ADR_BMP280_R, BMP280_DIG_P5);
    dig_P6 = read_word_sign(ADR_BMP280_W, ADR_BMP280_R, BMP280_DIG_P6);
    dig_P7 = read_word_sign(ADR_BMP280_W, ADR_BMP280_R, BMP280_DIG_P7);
    dig_P8 = read_word_sign(ADR_BMP280_W, ADR_BMP280_R, BMP280_DIG_P8);
    dig_P9 = read_word_sign(ADR_BMP280_W, ADR_BMP280_R, BMP280_DIG_P9);

    //Настраиваем работу датчика BMP280
    write_byte(ADR_BMP280_W, BMP280_CONFIG, BMP280_CONFIG_SET);
    write_byte(ADR_BMP280_W, BMP280_CONTROL, BMP280_CONTROL_SET);

    GPIO_ResetBits(GPIOB, GPIO_Pin_1); //Включаем микросхему MBI (для этого подтягиваем ножку PB1 земле)

    while (1) {
    }
}

void TIM2_IRQHandler() //Функция прерывания по переполнению таймера 2
{
    TIM_ClearITPendingBit(TIM2, TIM_IT_Update); //Функция очищает бит прерывания

    //Обрабатываем полученные из датчика значения давления и температуры согласно документации на датчик
    adc_t = read_long(ADR_BMP280_W, ADR_BMP280_R, BMP280_TEMP);
    adc_p = read_long(ADR_BMP280_W, ADR_BMP280_R, BMP280_PRESSURE);

    var1 = (adc_t / 16384.0 - dig_T1 / 1024.0) * dig_T2;
    var2 = ((adc_t / 131072.0 - dig_T1 / 8192.0) * (adc_t / 131072.0 - dig_T1 / 8192.0)) * dig_T3;
    t_fine = (var1 + var2);
    T = round(t_fine / 5120.0);

    var1 = (t_fine / 2.0) - 64000.0;
    var2 = var1 * var1 * dig_P6 / 32768.0;
    var2 = var2 + var1 * dig_P5 * 2.0;
    var2 = (var2 / 4.0) + (dig_P4 * 65536.0);
    var1 = (dig_P3 * var1 * var1 / 524288.0 + dig_P2 * var1) / 524288.0;
    var1 = (1.0 + var1 / 32768.0) * dig_P1;

    p = 1048576.0 - adc_p;
    p = (p - (var2 / 4096.0)) * 6250.0 / var1;
    var1 = dig_P9 * p * p / 2147483648.0;
    var2 = p * dig_P8 / 32768.0;
    P = round(p + (var1 + var2 + dig_P7) / 16.0);

    //Рассчитываем высоту
    temp = P / 101325;
    temp = 1 - pow(temp, 0.19029);
    altitude = round(44330 * temp);

    //Выводим значения высоты на индикатор
    int a = (int)altitude;
    int b = a % 100;
    int n = (a - b) / 100;
    int k = b % 10;
    int m = (b - k) / 10;

    //Условия переключения значений индикатора 1
    if (k == 0) {
        Indikator_1 = Zero;
    }
    if (k == 1) {
        Indikator_1 = One;
    }
    if (k == 2) {
        Indikator_1 = Two;
    }
    if (k == 3) {
        Indikator_1 = Three;
    }
    if (k == 4) {
        Indikator_1 = Four;
    }
    if (k == 5) {
        Indikator_1 = Five;
    }
    if (k == 6) {
        Indikator_1 = Six;
    }
    if (k == 7) {
        Indikator_1 = Seven;
    }
    if (k == 8) {
        Indikator_1 = Eight;
    }
    if (k == 9) {
        Indikator_1 = Nine;
    }

    //Условия переключения значений индикатора 2
    if (m == 0) {
        Indikator_2 = Zero;
    }
    if (m == 1) {
        Indikator_2 = One;
    }
    if (m == 2) {
        Indikator_2 = Two;
    }
    if (m == 3) {
        Indikator_2 = Three;
    }
    if (m == 4) {
        Indikator_2 = Four;
    }
    if (m == 5) {
        Indikator_2 = Five;
    }
    if (m == 6) {
        Indikator_2 = Six;
    }
    if (m == 7) {
        Indikator_2 = Seven;
    }
    if (m == 8) {
        Indikator_2 = Eight;
    }
    if (m == 9) {
        Indikator_2 = Nine;
    }

    //Условия переключения значений индикатора 3
    if (n == 0) {
        Indikator_3 = Zero;
    }
    if (n == 1) {
        Indikator_3 = One;
    }
    if (n == 2) {
        Indikator_3 = Two;
    }
    if (n == 3) {
        Indikator_3 = Three;
    }
    if (n == 4) {
        Indikator_3 = Four;
    }
    if (n == 5) {
        Indikator_3 = Five;
    }
    if (n == 6) {
        Indikator_3 = Six;
    }
    if (n == 7) {
        Indikator_3 = Seven;
    }
    if (n == 8) {
        Indikator_3 = Eight;
    }
    if (n == 9) {
        Indikator_3 = Nine;
    }

    //Условия переключения цветов светодиода
    if (n == 0)
        Led_conf = Led_ALL_Good;
    if (n == 2)
        Led_conf = Led_Warning;

    GPIO_ResetBits(GPIOB, GPIO_Pin_0); //Сбрасываем LE

    SPI_SendData8(SPI1, Led_conf); //Передаем байт управляющий цветами светодиода
    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY) == SET); //Передатчик занят? значит ничего не делаем

    SPI_SendData8(SPI1, Indikator_1); // Передаем байт управляющий первым индикатором
    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY) == SET); //Передатчик занят? значит ничего не делаем

    SPI_SendData8(SPI1, Indikator_2); //Передаем байт управляющий вторым индикатором
    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY) == SET); //Передатчик занят? значит ничего не делаем

    SPI_SendData8(SPI1, Indikator_3); //Передаем байт управляющий третьим индикатором
    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY) == SET); //Передатчик занят? значит ничего не делаем

    GPIO_SetBits(GPIOB, GPIO_Pin_0); //Устанавливаем LE для вывода переданных данных на индикаторы
}

long read_long(char ADR_DEVICE_W, char ADR_DEVICE_R, char ADR_REGISTER)
{

    short MSB = read_byte(ADR_DEVICE_W, ADR_DEVICE_R, ADR_REGISTER); //Считываем байт MSB
    short LSB = read_byte(ADR_DEVICE_W, ADR_DEVICE_R, ADR_REGISTER + 1); //Считываем байт LSB
    short XLSB = read_byte(ADR_DEVICE_W, ADR_DEVICE_R, ADR_REGISTER + 2); //Считываем байт XLSB

    long value = MSB << 16 | LSB << 8 | XLSB; //Записываем полученные данные в переменную value

    value = value >> 4; //Сдвигаем значения на 4 бита в право

    return value; //Возвращаем результат
}

short read_word_sign(char ADR_DEVICE_W, char ADR_DEVICE_R, char ADR_REGISTER)
{

    short var = read_word(ADR_DEVICE_W, ADR_DEVICE_R, ADR_REGISTER); //Вызываем функция чтения слова

    if (var - 1 >= 0x7FFF)
        return -((65535 - var) + 1); //определяем знак
    else
        return var; //Возвращаем результат
}

short read_word(char ADR_DEVICE_W, char ADR_DEVICE_R, char ADR_REGISTER)
{
    short LSB = read_byte(ADR_DEVICE_W, ADR_DEVICE_R, ADR_REGISTER); //Считываем байт LSB
    short MSB = read_byte(ADR_DEVICE_W, ADR_DEVICE_R, ADR_REGISTER + 1); //Считываем байт MSB
    short WORD = (MSB << 8) | LSB; //Записываем полученные данные в переменную WORD
    return WORD; //Возвращаем результат
}

short read_byte(char ADR_DEVICE_W, char ADR_DEVICE_R, char ADR_REGISTER)
{

    while (I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY)) {}; //Ждем пока освободится шина i2c1

    /*Формируем первую посылку с адресом ведомого устройства и битом записи (ADR_BMP280_W = hex 0xEC) выбираем режим работы модуля / генерируем старт записи*/

    I2C_TransferHandling(I2C1, ADR_DEVICE_W, 1, I2C_AutoEnd_Mode, I2C_Generate_Start_Write);

    while (I2C_GetFlagStatus(I2C1, I2C_ISR_TXE) == RESET) {}; //Ждем, установки флага TXE

    I2C_SendData(I2C1, ADR_REGISTER); //Отправляем адрес регистра из которого хотим прочитать данные

    while (I2C_GetFlagStatus(I2C1, I2C_ISR_TXE) == RESET) {}; //Ждем, установки флага TXE

    /*Формируем посылку с адресом ведомого устройства и битом чтения (ADR_BMP280_R = hex 0xED) выбираем режим работы модуля / генерируем старт чтения*/

    I2C_TransferHandling(I2C1, ADR_DEVICE_R, 1, I2C_AutoEnd_Mode, I2C_Generate_Start_Read);

    while (I2C_GetFlagStatus(I2C1, I2C_FLAG_RXNE) == RESET) {}; //Ждем, установки флага RXEN

    short BYTE = I2C_ReceiveData(I2C1); //Запись данных в переменную Data

    while (I2C_GetFlagStatus(I2C1, I2C_FLAG_RXNE) != RESET) {}; //Ждем, установки флага RXEN

    /*!!!!!!!!!!!!!По окончанию работы с I2С вызываем следующие функции!!!!!!!!!!!!!*/

    while (I2C_GetFlagStatus(I2C1, I2C_ISR_STOPF) == RESET); //Ждем установки флага STOPF

    I2C_ClearFlag(I2C1, I2C_ICR_STOPCF); //Очистить флаг STOPF

    return BYTE; //Возвращаем результат
}

void write_byte(char ADR_DEVICE_W, char ADR_REGISTER, char SETTINGS)
{
    while (I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY)) {}; //Ждем пока освободится шина i2c1

    /*Формируем первую посылку с адресом ведомого устройства и битом записи (ADR_BMP280_W = hex 0xEC)/передаем два байта выбираем режим работы модуля / генерируем старт записи*/

    I2C_TransferHandling(I2C1, ADR_DEVICE_W, 2, I2C_AutoEnd_Mode, I2C_Generate_Start_Write);

    while (I2C_GetFlagStatus(I2C1, I2C_ISR_TXE) == RESET) {}; //Ждем, установки флага TXE

    I2C_SendData(I2C1, ADR_REGISTER); //Отправляем адрес регистра в который хотим записать данные

    while (I2C_GetFlagStatus(I2C1, I2C_ISR_TXE) == RESET) {}; //Ждем, установки флага TXE

    I2C_SendData(I2C1, SETTINGS); //Отправляем данные в выбранный регистр

    while (I2C_GetFlagStatus(I2C1, I2C_ISR_TXE) == RESET) {}; //Ждем, установки флага TXE

    while (I2C_GetFlagStatus(I2C1, I2C_ISR_STOPF) == RESET); //Ждем установки флага STOPF

    I2C_ClearFlag(I2C1, I2C_ICR_STOPCF); //Очистить флаг STOPF
}

     Скомпилируйте программу нажав кнопку Build, прошейте микроконтроллер, нажмите RESET. При запуске программы, произойдет чтение и преобразование данных из датчика BMP280 с последующим выводом на индикационную плату. 

     ВНИМАНИЕ: Приведенный листинг кода не является единственной и оптимальной реализацией поставленной задачи. Пример опубликован с демонстрационной целью. Также автор во избежание переписывания чужих статей, пропускает теоретические основы необходимые для понимания примера, связывая это с тем что всю необходимую информацию можно найти в интернете.

Комментариев (0)

Написать комментарий

Имя *
E-mail
Введите комментарий *
Капча
32 + ? = 34