Добрый день! По урокам на си и 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;//читаем регистр данных
}