BME280 на Atmega8

Добрый день! По урокам на си и atmega8 делаю часы, хочу добавить датчик температуры, давления и влажности BME280, все что нахожу по этой теме уже идет с подключенной библиотекой i2c от автора. У меня уже своя из уроков, на ней работает LCD2004 и RTC1307. Прошу подсказать по адаптации BME 280 в мой проект.

Снизу мой i2c.cpp, на нем уже работаю дисплей и часы.
Функции немного отличаются, и у автора BME280 посложнее.

#ifndef BME280_H_
#define BME280_H_

# define BME280_ADDR 0xEC                   //7-битный адрес на шине I2C 0x76<<1 (Connecting SDO to GND) (1110110<<1)+1/0
//# define BME280_ADDR 0xEE                   //7-битный Адрес на шине I2C 0x77<<1 (Connecting SDO to Vdd) (1110111<<1)+1/0 SDO не оставлять неподключенным!
//111011х0 - запись
//111011х1 - чтение
//Регистры
# define BME280_CHIPID 0x60                 //ID код чипа
# define BME280_ctrl_hum 0xF2               //Адрес регистра ctrl_hum (osrs_h[2:0] = 001  => oversampling x1
# define BME280_status 0xF3                 //Адрес регистра status
# define BME280_ctrl_meas 0xF4              //Адрес регистра ctrl_meas
# define BME280_config 0xF5                 //Адрес регистра config
# define BME280_calib00 0x88                //Начальный адрес регистра калибровочных данных calib00..calib25 (0x88…0xA1) - 26 байт
# define BME280_calib26 0xE1                //Начальный адрес регистра калибровочных данных calib26..calib41 (0xE1…0xF0) - 16 байт




// запись байта в регитр датчика
void bme280_write_reg(uint8_t reg, uint8_t data);

// чтение пакета данных из регистров бме280
// start_reg - стартовый регистр, col - количество считываемых байт
void bme280_read_packet(uint8_t start_reg, uint8_t col);

// инициализация датчика
void bme280_ini(void);

// запуск измерений
//Давление: oversampling x1, Температура: oversampling x1; 01-Forced mode
void bme280_start(void);

/*----Функция вычисления давления, температуры и влажности от датчика BME280----*/
void bme280_clc (void);


// возврат температуры
int bme280_temp(void);

// возврат давления
uint16_t bme280_davl(void);

// возврат влажности
uint16_t bme280_vlazhn(void);


#endif /* BME280_H_ */
#include "main.h"

//Регистры данных для калибровки                                                     (считанные значения с датчика)
unsigned int dig_T1;                        //0x88 / 0x89  dig_T1 [7:0] / [15:8]     (28454)
signed int dig_T2;                          //0x8A / 0x8B  dig_T2 [7:0] / [15:8]     (26444)
signed int dig_T3;                          //0x8C / 0x8D  dig_T3 [7:0] / [15:8]     (50)
unsigned int dig_P1;                        //0x8E / 0x8F  dig_P1 [7:0] / [15:8]     (36283)
signed int dig_P2;                          //0x90 / 0x91  dig_P2 [7:0] / [15:8]     (-10620)
signed int dig_P3;                          //0x92 / 0x93  dig_P3 [7:0] / [15:8]     (3024)
signed int dig_P4;                          //0x94 / 0x95  dig_P4 [7:0] / [15:8]     (7741)
signed int dig_P5;                          //0x96 / 0x97  dig_P5 [7:0] / [15:8]     (-107)
signed int dig_P6;                          //0x98 / 0x99  dig_P6 [7:0] / [15:8]     (-7)
signed int dig_P7;                          //0x9A / 0x9B  dig_P7 [7:0] / [15:8]     (12300)
signed int dig_P8;                          //0x9C / 0x9D  dig_P8 [7:0] / [15:8]     (-12000)
signed int dig_P9;                          //0x9E / 0x9F  dig_P9 [7:0] / [15:8]     (5000)
unsigned char dig_H1;                       //0xA1 dig_H1 [7:0]                      (75)
//
signed int dig_H2;                          //0xE1 / 0xE2 dig_H2 [7:0] / [15:8]      (336)
unsigned char dig_H3;                       //0xE3 dig_H3 [7:0]                      (0)
signed int dig_H4;                          //0xE4 / 0xE5[3:0] dig_H4 [11:4] / [3:0] (387)
signed int dig_H5;                          //0xE5[7:4] / 0xE6 dig_H5 [3:0] / [11:4] (50)
signed char dig_H6;                         //0xE7 dig_H6                            (30)
//
//Массивы для хранения считанных данных из BME280
//unsigned char mass_data_BME[8];             //Массив измеренных параметров hum, temp, press (0xFE...0xF7)
uint8_t mass_tmp_BME[26];             //Временный массив для считывания пакета данных из BME280
volatile int temp=0;                     //Температура в °Сx10
volatile unsigned int davl=0;            //Текущее давление в мм.рт.ст. *10 (ХХХ.Х)
volatile unsigned int vlazhn=0;          //Влажность в %RHx10




// запись байта в регитр датчика
void bme280_write_reg(uint8_t reg, uint8_t data) {
	i2c_start();
	i2c_send_addr(BME280_ADDR); // отправка адреса на шине
	i2c_send_byte(reg);// отправка адреса регистра для записи
	i2c_send_byte(data); // отправка данных в регистр
	i2c_stop();
}

// чтение пакета данных из регистров бме280
// start_reg - стартовый регистр, col - количество считываемых байт
void bme280_read_packet(uint8_t start_reg, uint8_t col) {
	  uint8_t n=0;
	  i2c_start();
	  i2c_send_addr(BME280_ADDR); // отправка адреса на шине
	  i2c_send_byte(start_reg); // отправка адреса стартового регистра
	  i2c_start(); // снова старт т.к. будем читать
	  i2c_send_addr(BME280_ADDR+1); // отправка адреса на шине+1 т.к. для чтения
	  while (n<(col-1))
	  {
		  i2c_read_byte(&mass_tmp_BME[n], 1);
		  n++;                                         
	  }
	  i2c_read_byte(&mass_tmp_BME[n], 0);
	  i2c_stop();
}

// инициализация датчика
void bme280_ini(void) {
	bme280_read_packet(BME280_calib00, 26); //Считывание калибровочных данных calib00..calib25 (0x88…0xA1) - 26 байт
	//Преобразование считанных данных calib00..calib25 в калибровочные коэффициенты
	dig_T1=mass_tmp_BME[0];
	dig_T1=dig_T1 | (mass_tmp_BME[1]<<8);
	dig_T2=mass_tmp_BME[2];
	dig_T2=dig_T2 | (mass_tmp_BME[3]<<8);
	dig_T3=mass_tmp_BME[4];
	dig_T3=dig_T3 | (mass_tmp_BME[5]<<8);
	dig_P1=mass_tmp_BME[6];
	dig_P1=dig_P1 | (mass_tmp_BME[7]<<8);
	dig_P2=mass_tmp_BME[8];
	dig_P2=dig_P2 | (mass_tmp_BME[9]<<8);
	dig_P3=mass_tmp_BME[10];
	dig_P3=dig_P3 | (mass_tmp_BME[11]<<8);
	dig_P4=mass_tmp_BME[12];
	dig_P4=dig_P4 | (mass_tmp_BME[13]<<8);
	dig_P5=mass_tmp_BME[14];
	dig_P5=dig_P5 | (mass_tmp_BME[15]<<8);
	dig_P6=mass_tmp_BME[16];
	dig_P6=dig_P6| (mass_tmp_BME[17]<<8) ;
	dig_P7=mass_tmp_BME[18];
	dig_P7=dig_P7 | (mass_tmp_BME[19]<<8);
	dig_P8=mass_tmp_BME[20];
	dig_P8=dig_P8 | (mass_tmp_BME[21]<<8);
	dig_P9=mass_tmp_BME[22];
	dig_P9=dig_P9 | (mass_tmp_BME[23]<<8);
	dig_H1=mass_tmp_BME[25];
	bme280_read_packet(BME280_calib26, 16);//Считывание калибровочных данных calib26..calib41 (0xE1…0xF0) - 16 байт
	//Преобразование считанных данных calib26..calib41 в калибровочные коэффициенты
	dig_H2=mass_tmp_BME[0];
	dig_H2=dig_H2 | (mass_tmp_BME[1]<<8);
	dig_H3=mass_tmp_BME[2];
	dig_H4=mass_tmp_BME[3];
	dig_H4=(dig_H4<<4) | (mass_tmp_BME[4] & 0b00001111);  //0xE4 / 0xE5[3:0] dig_H4 [11:4] / [3:0]
	dig_H5=mass_tmp_BME[4]&0b11110000;
	dig_H5=(dig_H5>>4) | (mass_tmp_BME[5]<<4);  //0xE5[7:4] / 0xE6 dig_H5 [3:0] / [11:4]
	dig_H6=mass_tmp_BME[6];
	bme280_write_reg(BME280_config, 0b00000000);  //000-tstandby=0,5мс, 000-Filter off, 0-SPI interface выключен
	bme280_write_reg(BME280_ctrl_hum, 0b00000001); //Влажность: oversampling x1
	bme280_write_reg(BME280_ctrl_meas, 0b00100101); //Давление: oversampling x1, Температура: oversampling x1; 01-Forced mode, 00-Sleep mode
}

// запуск измерений
//Давление: oversampling x1, Температура: oversampling x1; 01-Forced mode

void bme280_start(void) {
	bme280_write_reg(BME280_ctrl_meas, 0b00100101); 
}


/*----Функция вычисления давления, температуры и влажности от датчика BME280----*/
void bme280_clc (void) { 
	unsigned long adc_P=0;
	unsigned long adc_T=0;
	unsigned int adc_H=0;
	float t_fine=0;                           //Переменная точной температуры компенсационных вычислений
	float var1=0;                             //Переменная 1 промежуточных компенсационных вычислений
	float var2=0;                             //Переменная 2 промежуточных компенсационных вычислений
	float p=0;
//Считывание пакета данных с BME280 (0xF7-0xFE) в массив mass_tmp_BME[] (7ms)
	bme280_read_packet(0xF7, 8);                     //Считывание измеренных данных (0xFE…0xF7) - 8 байт
//Обработка
	adc_P=mass_tmp_BME[0];
	adc_P=adc_P << 12;
	adc_H=mass_tmp_BME[1]; 
	adc_H=(adc_H<<4) | (mass_tmp_BME[2]>>4);
	adc_P=adc_P | adc_H;
	adc_H=0;
	adc_T=mass_tmp_BME[3];
	adc_T=adc_T  << 12;
	adc_H=mass_tmp_BME[4];
	adc_H=(adc_H<<4) | (mass_tmp_BME[5]>>4);
	adc_T=adc_T | adc_H;
	adc_H=0;
	adc_H=mass_tmp_BME[6];
	adc_H=adc_H<<8;
	adc_H=adc_H | mass_tmp_BME[7];
//
//Вычисление компенсированного значения температуры
	var1 = ((((float)adc_T)/16384.0) - (((float)dig_T1)/1024.0)) * ((float)dig_T2);
//  var1 = ( ((adc_T/8) - (dig_T1*2)) * dig_T2 ) /2048;
	var2 = (((float)adc_T)/131072.0-(((float)dig_T1)/8192.0)) * (((float)adc_T)/131072.0-(((float)dig_T1)/8192.0)) * ((float)dig_T3);
	t_fine = (var1 + var2);
	temp = (int)(((var1 + var2) / 512.0)+0.5);     //Температура в °Сх10 с округлением
//Вычисление компенсированного значения давления
	var1 = (t_fine/2.0) - 64000.0;
	var2 = var1 * var1 * ((float)dig_P6) / 32768.0;
	var2 = var2 + var1 * ((float)dig_P5) * 2.0;
	var2 = (var2/4.0)+(((float)dig_P4) * 65536.0);
	var1 = (((float)dig_P3) * var1 * var1 / 524288.0 + ((float)dig_P2) * var1) / 524288.0;
	var1 = (1.0 + var1 / 32768.0)*((float)dig_P1);
	if (var1 == 0.0) davl=0;                
		else 
		{
			p = 1048576.0 - (float)adc_P;
			p = (p - (var2 / 4096.0)) * 6250.0 / var1;
			var1 = ((float)dig_P9) * p * p / 2147483648.0;
			var2 = p * ((float)dig_P8) / 32768.0;
			p = p + (var1 + var2 + ((float)dig_P7)) / 16.0;  //Давление в Pa
			davl=(unsigned int)((p*0.0750063755419211)+0.5); //Текущее давление в мм.рт.ст.*10 с округлением ( 1 hPa= 100 Pa = 0,75006 мм.рт.ст.)
			if (davl>9999) davl=9999;              //Ограничение в 999.9 мм.рт.ст.(выше 1265 мм по формуле отрицательное давление)
                                           //Пределы BME280 300...1100 hPa => 225...825 мм.рт.ст)
		}
//Вычисление компенсированного значения влажности
	p = (t_fine - 76800.0);
	p=(adc_H-(((float)dig_H4)*64.0+((float)dig_H5)/16384.0*p))*(((float)dig_H2)/65536.0*(1.0+((float)dig_H6)/67108864.0*p*(1.0+((float)dig_H3)/67108864.0*p)));
	p = p * (1.0 - ((float)dig_H1) * p / 524288.0);
	if (p > 100.0) vlazhn=1000;       //Влажность 100.0%
		else 
		{
			if (p < 0.0) vlazhn=0;
				else vlazhn=(unsigned int)(p*10+0.5);
		 }
}

// возврат температуры
int bme280_temp(void){
	return temp;
}


// возврат давления
uint16_t bme280_davl(void){
	return davl;
}


// возврат влажности
uint16_t bme280_vlazhn(void){
	return vlazhn;
}

#include "twi.h"

void I2C_Init (void)
{
	TWBR=0x48;//скорость передачи (при 8 мгц получается 100 кгц, что и необходимо для общения с ds1307) // 0x48 при 16 MHz // 0x20 8 Mhz (было)
}


void I2C_StartCondition(void)
{
	TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN);
	while (!(TWCR & (1<<TWINT)));//подождем пока установится TWIN
}

void I2C_StopCondition(void)
{
	TWCR = (1<<TWINT)|(1<<TWSTO)|(1<<TWEN);
}

void I2C_SendByte(unsigned char c)
{
	TWDR = c;//запишем байт в регистр данных
	TWCR = (1<<TWINT)|(1<<TWEN);//включим передачу байта
	while (!(TWCR & (1<<TWINT)));//подождем пока установится TWIN
}

void I2C_SendByteByADDR(unsigned char c,unsigned char addr)
{
	I2C_StartCondition(); // Отправим условие START
	I2C_SendByte(addr); // Отправим в шину адрес устройства + бит чтения-записи
	I2C_SendByte(c);// Отправим байт данных
	I2C_StopCondition();// Отправим условие STOP
}

unsigned char I2C_ReadByte(void)
{
	TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWEA);
	while (!(TWCR & (1<<TWINT)));//ожидание установки бита TWIN
	return TWDR;//читаем регистр данных
}

unsigned char I2C_ReadLastByte(void)
{
	TWCR = (1<<TWINT)|(1<<TWEN);
	while (!(TWCR & (1<<TWINT)));//ожидание установки бита TWIN
	return TWDR;//читаем регистр данных
}

что именно подсказать?

По первому взгляду могу только подсказать, что ваш код не очень красивый и читать его трудно, а потому маловероятно, что кто-то захочет в нем копатся.

Например, каждый раз, когда вы начинаете называть переменные dig_P1, dig_P2, dig_P3 и так далее - это признак кривого кода и неумения пользоваться массивами.
Еще в вашем коде масса так называемых “магических чисел” - то есть жестко заданных цифровых значений без всякого объяснения, что это такое и почему. Да и вообще с логикой и с комментариями в этом коде все очень плохо.

Цель-то какая? Написать свою библиотеку или просто встроить датчик в проект? Если второе - почему не взять готовую библиотеку, зачем изобректать велосипед?

Первый и второй блок кода это h и cpp автора библиотеки датчика, но она связана с его библиотекой i2c, мне нужно адаптировать его код BME280 под мою библиотеку i2c так как на ней уже отлажено все остальное. Ну буду ковыряться…

В библиотеке для BME280 есть только две зависимые от железа подпрограммы writeRegister и readRegister. Если у тебя какой то особенный менеджер i2c достаточно эти подпрограммы адаптировать под него. Но это ужас ужасный использовать свою i2c реализацию вместо стандартной.

У Adafruit примерно (если не точно) так же. Я сам сдувал у них расчёт - от массива там особого выигрыша нет.

Не лучше ли
while(col--)

Тут либо его,либо свой код переписывать. Вообще библиотека на то и существует,чтобы был универсальный инструмент. Что в TWI и и2с можно сделать не так как у всех? Вроде взаимодействие простое, сложно учудить нестандартно.
4 функции отправка и приём байта/пакета байт.

В первом случае сравнивается n со значением col-1, а во втором декремент col до нуля.
В данном случае начальное значение n=0, поэтому записи будут схожи. Но, наверное, нужно так:

while (--col)

1 лайк

Это уже детали) Да,наверно,цикл 1 раз отработает при нуле. Я о том, что незачем лишние сущности плодить.

Ну, не все так однозначно. В условии цикла “сущности по рубали”, а внутри цикла что?

И как сделать эквивалент этой записи только с col?
“Городить вычисления” и плодить сущности? ))

Вместо n подставить col)) в массив пишем от старшего к младшему) ну либо вместо n поставить “размер массива минус col”.
Я всегда стремлюсь в подобных местах делать инкремент и сравнивать с нулём,это быстрее чем сравнивать с числом.

Вот видишь, в одном месте упростил, в другом месте “начудил” )))

"Да не ссы,я сто раз так делал":grin: