BMP280, датчик давления и температуры

Дисплеи, датчики и прочие функциональные узлы, управляемые МК.
Аватара пользователя
AndTer
Поставщик валерьянки для Кота
Сообщения: 2406
Зарегистрирован: Ср фев 23, 2011 12:12:31

Re: BMP280, датчик давления и температуры

Сообщение AndTer »

[uquote="DESIER",url="/forum/viewtopic.php?p=3515525#p3515525"]А для эксперимента пока нет возможности вынести датчик на улицу.[/uquote]
А что морозильника нет? Или просто куска льда в пакете чтобы приложить к датчику? )
Глупый не задает вопросы. Глупый и так все знает.
Аватара пользователя
passer_by
Открыл глаза
Сообщения: 42
Зарегистрирован: Сб янв 05, 2013 21:03:05

Re: BMP280, датчик давления и температуры

Сообщение passer_by »

Получается, что ни кто не пробовал датчик BME280 при отрицательных температурах? Печалька :(
Если птичка уже в одном прыжке от тебя, всё-таки побереги свой нос, может она за оконным стеклом???
Аватара пользователя
DESIER
Открыл глаза
Сообщения: 47
Зарегистрирован: Пн апр 28, 2014 22:22:33
Откуда: Калуга

Re: BMP280, датчик давления и температуры

Сообщение DESIER »

[uquote="AndTer",url="/forum/viewtopic.php?p=3515571#p3515571"]А что морозильника нет? Или просто куска льда в пакете чтобы приложить к датчику? )[/uquote]
Морозильника нет. Я дома электроникой не занимаюсь, у меня мастерская отдельная для этого, либо на работе, к тому же датчик уже стоит в устройстве и закрыт в корпусе.
Я, конечно, могу вести себя нормально. Но чёрт возьми - это ведь так скучно.
Аватара пользователя
passer_by
Открыл глаза
Сообщения: 42
Зарегистрирован: Сб янв 05, 2013 21:03:05

Re: BMP280, датчик давления и температуры

Сообщение passer_by »

Ну вроде победил проблему :) Поменял формат переменной BME280_S32_t t_fine с 32 на 64 и все поехало. Получается на положительные значения int32 хватало, а при отрицательных уходил в нирвану. В общем прихлебывая валерьянку, курим даташит. :))
Если птичка уже в одном прыжке от тебя, всё-таки побереги свой нос, может она за оконным стеклом???
Аватара пользователя
dadigor
Вымогатель припоя
Сообщения: 593
Зарегистрирован: Пт дек 26, 2014 20:33:38
Откуда: Самая большая деревня. (По мнению Габриэля Гарсиа Маркеса)

Re: BMP280, датчик давления и температуры

Сообщение dadigor »

Не очень понятно. t_fine вроде бы используется в конце вычислений:
t_fine = var1 + var2;
T = (t_fine * 5 +128) >> 8;
return T;
var1, var2 и T имеют тип BME_280_S32_t и они не переполняются, так как Вы их не меняли.
Неужели var1 и var2 близки к максимуму и их сумма переполняется? Или может быть засада в том, что переполнение происходит во время умножения на 5 и возможно достаточно написать по-другому последнее выражение:
T = (int32_t)((((int64_t)t_fine) * 5) >> 8 ) ;
Ну или что-то в этом роде... Впрочем, похоже что это тоже самое, что сделали Вы, только другим способом. Жаль, что я сейчас не могу вытащить датчик на мороз, надо бы погонять в отладчике пошагово и понаблюдать за вычислениями.
О технике чего спорить-то, давайте попробуем.
tea1975
Родился
Сообщения: 2
Зарегистрирован: Вс янв 20, 2019 16:15:21

Re: BMP280, датчик давления и температуры

Сообщение tea1975 »

Самое интересное, что с ошибкой отрицательных температур библиотеки bosh судя по поиску в инете мало кто столкнулся, люди похоже в основном используют в помещениях. Я блин аж второй датчик на Али купил и упёрся в те же грабли. Как уходит Т в минус, то на входе 400 и выше градусов.
passer_by не могли бы вы выложить свой кусок кода, где приведение к 64 битам делаете.
tea1975
Родился
Сообщения: 2
Зарегистрирован: Вс янв 20, 2019 16:15:21

Re: BMP280, датчик давления и температуры

Сообщение tea1975 »

[uquote="dadigor",url="/forum/viewtopic.php?p=3527645#p3527645"]Не очень понятно. t_fine вроде бы используется в конце вычислений:
достаточно написать по-другому последнее выражение:
T = (int32_t)((((int64_t)t_fine) * 5) >> 8 ) ;
Ну или что-то в этом роде... Впрочем, похоже что это тоже самое, что сделали Вы, только другим способом. Жаль, что я сейчас не могу вытащить датчик на мороз, надо бы погонять в отладчике пошагово и понаблюдать за вычислениями.[/uquote]

Попробовал. Не взлетело.. Всё также при минусах температура за 400 выходит.
Где-то на гитхабе попадалась библиотека для этого датчика полностью на 64 бита заточенная
Аватара пользователя
DESIER
Открыл глаза
Сообщения: 47
Зарегистрирован: Пн апр 28, 2014 22:22:33
Откуда: Калуга

Re: BMP280, датчик давления и температуры

Сообщение DESIER »

Наконец то я нашел время и проверил работу при отрицательных температурах. У меня все нормально работает. Проблем не было.
Вот прилагаю вырезку из своего кода. В функции PreesAndTemp я просто проверяю температуру больше она или меньше ноля и убираю или добавляю соответственно знак минуса и пихаю все это на дисплей.
Расчет температуры и давления взят из datasheet, данные библиотеки не изменялись, они оригинальные.
Спойлер

Код: Выделить всё

uint8_t BMP280_Status;
uint32_t Pressure_pascale; // Значение давления в паскалях
uint32_t Pressure_mmHg; // Значение давления в мм.рт.с
int32_t Temperature_BMP280; // Значение температуры в градусах цельсия
unsigned char ptd[6];
int32_t t_fine;
uint16_t dig_T1;
int16_t dig_T2;
int16_t dig_T3;
uint16_t dig_P1;
int16_t dig_P2;
int16_t dig_P3;
int16_t dig_P4;
int16_t dig_P5;
int16_t dig_P6;
int16_t dig_P7;
int16_t dig_P8;
int16_t dig_P9;

int32_t bmp280_compensate_T(int32_t adc_T) // расчет температуры
{
	int32_t var1;
	int32_t var2;
	int32_t temperature = 0;
	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;
	temperature = (t_fine * 5 + 128) >> 8;
	return temperature;
}

uint32_t bmp280_compensate_P(int32_t adc_P) // расчет давления
{
	int32_t var1;
	int32_t var2;
	uint32_t pressure = 0;
	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);
	pressure = (((uint32_t) (((int32_t) 1048576) - adc_P) - (var2 >> 12))) * 3125;
	if (var1 != 0)
	{
		if (pressure < 0x80000000) pressure = (pressure << 1) / ((uint32_t) var1);
		else pressure = (pressure / (uint32_t) var1) * 2;

		var1 = (((int32_t) dig_P9) * ((int32_t) (((pressure >> 3) * (pressure >> 3)) >> 13))) >> 12;
		var2 = (((int32_t) (pressure >> 2)) * ((int32_t) dig_P8)) >> 13;
		pressure = (uint32_t) ((int32_t) pressure + ((var1 + var2 + dig_P7) >> 4));
	}
	else pressure = 0;
	return pressure;
}

uint8_t BMP280_Update() //
{
	while (BMP280_Status != NOT_BUSY) { _delay_us(10); }
	while (!TWI_Read(TWI_Adress, &adr_data, 1, ptd, 6, &BMP280_Status));
	do { _delay_us(10); if (BMP280_Status == TWI_SLA_W_NACK || BMP280_Status == TWI_DATA_NACK || BMP280_Status == TWI_SLA_R_NACK) return 0; }
	while (BMP280_Status != NOT_BUSY);
        // обязательно сначала рассчитываем температуру, а потом давление.
	Temperature_BMP280 = bmp280_compensate_T(((int32_t)ptd[3]<<12) | ((int32_t)ptd[4]<<4) | ((int32_t)ptd[5]>>4));
	Pressure_pascale = bmp280_compensate_P((((int32_t)ptd[0]<<12) | ((int32_t)ptd[1]<<4) | (int32_t)ptd[2]>>4));
	Pressure_mmHg = Pressure_pascale/133.3224;
	return 1;
}

void PreesAndTemp()
{
	uint16_t t = 0;
	uint8_t i = 0;
	if (BMP280_Update())
	{
		i = 10;
		i += LCD_AddSimbol(FONT1,ARIAL,(Pressure_mmHg/100)%10,4,i);
		i += LCD_AddSimbol(FONT1,ARIAL,(Pressure_mmHg/10)%10,4,i);
		i += LCD_AddSimbol(FONT1,ARIAL,Pressure_mmHg%10,4,i);
		i += LCD_AddString(" мм рт.ст.",FONT1,ARIAL,LEFT,4,i);
		i += 10;
		if (Temperature_BMP280 < 0) { t = -Temperature_BMP280; i += LCD_AddSimbol(FONT1, ARIAL, '-', 4, i); }
		else t = Temperature_BMP280;
		if (t >= 1000) i += LCD_AddSimbol(FONT1,ARIAL,(t/1000)%10,4,i);
		i += LCD_AddSimbol(FONT1,ARIAL,(t/100)%10,4,i);
		i += LCD_AddSimbol(FONT1,ARIAL,'.',4,i);
		i += LCD_AddSimbol(FONT1,ARIAL,(t/10)%10,4,i);
		i += LCD_AddSimbol(FONT1,ARIAL,t%10,4,i);
		i += LCD_AddString("°C",FONT1,ARIAL,LEFT,4,i);
	}
	else
	{
		i = 0;
		switch(BMP280_Status)
		{
			case TWI_SLA_W_NACK: LCD_AddString("ОШИБКА! BMP280 не отвечает", FONT1, ARIAL, CENTR, 4, i); break;
			case TWI_SLA_R_NACK: LCD_AddString("ОШИБКА! BMP280 не отвечает", FONT1, ARIAL, CENTR, 4, i); break;
			case TWI_DATA_NACK: LCD_AddString("BMP280 ошибка передачи данных", FONT1, ARIAL, CENTR, 4, i); break;
		}
	}
}
Я, конечно, могу вести себя нормально. Но чёрт возьми - это ведь так скучно.
Аватара пользователя
passer_by
Открыл глаза
Сообщения: 42
Зарегистрирован: Сб янв 05, 2013 21:03:05

Re: BMP280, датчик давления и температуры

Сообщение passer_by »

[uquote="tea1975",url="/forum/viewtopic.php?p=3553322#p3553322"]passer_by не могли бы вы выложить свой кусок кода, где приведение к 64 битам делаете.[/uquote]
Вот код:

Код: Выделить всё

int64_t temper_int;   //глобальная переменная
.........
...........
float BME280_ReadTemperature(void)
{

  float temper_float = 0.0f;
	uint32_t temper_raw;
	int32_t val1, val2;
	BME280_ReadReg_BE_U24(BME280_REGISTER_TEMPDATA,&temper_raw);
	temper_raw >>= 4;
	val1 = ((((temper_raw>>3) - ((int32_t)CalibData.dig_T1 <<1))) *
		((int32_t)CalibData.dig_T2)) >> 11;
	val2 = (((((temper_raw>>4) - ((int32_t)CalibData.dig_T1)) *
		((temper_raw>>4) - ((int32_t)CalibData.dig_T1))) >> 12) *
		((int32_t)CalibData.dig_T3)) >> 14;
	temper_int = val1 + val2;
	temper_int = ((temper_int * 5 + 128) >> 8);
	temper_float = temper_int/100;
	
  if (temper_float >100) // если значение температуры перевалило в отрицательные значения
  {
    temper_float = 409.6-temper_float;
    temper_float = -temper_float;
  }	
	
  return temper_float;
}
Обратите внимание. Переменная int64_t temper_int это BME280_S32_t t_fine по даташиту, используется и в расчете давления и влажности.

to DESIER
Раз работает код как у DS18B20 это говорит о том что формат значения температуры на выходе у датчиков одинаков.
К стате, как я понял Ваш код, Вы делаете ровно то же самое, только вместо двух строчек кода довольно громоздкая структура.
Если птичка уже в одном прыжке от тебя, всё-таки побереги свой нос, может она за оконным стеклом???
Аватара пользователя
DESIER
Открыл глаза
Сообщения: 47
Зарегистрирован: Пн апр 28, 2014 22:22:33
Откуда: Калуга

Re: BMP280, датчик давления и температуры

Сообщение DESIER »

[uquote="passer_by",url="/forum/viewtopic.php?p=3564108#p3564108"]

Код: Выделить всё

int64_t temper_int;   //глобальная переменная
.........
...........
float BME280_ReadTemperature(void)
{

  float temper_float = 0.0f;
	uint32_t temper_raw;
	int32_t val1, val2;
	BME280_ReadReg_BE_U24(BME280_REGISTER_TEMPDATA,&temper_raw);
	temper_raw >>= 4;
	val1 = ((((temper_raw>>3) - ((int32_t)CalibData.dig_T1 <<1))) *
		((int32_t)CalibData.dig_T2)) >> 11;
	val2 = (((((temper_raw>>4) - ((int32_t)CalibData.dig_T1)) *
		((temper_raw>>4) - ((int32_t)CalibData.dig_T1))) >> 12) *
		((int32_t)CalibData.dig_T3)) >> 14;
	temper_int = val1 + val2;
	temper_int = ((temper_int * 5 + 128) >> 8);
	temper_float = temper_int/100;
	
  if (temper_float >100) // если значение температуры перевалило в отрицательные значения
  {
    temper_float = 409.6-temper_float;
    temper_float = -temper_float;
  }	
	
  return temper_float;
}
to DESIER
Раз работает код как у DS18B20 это говорит о том что формат значения температуры на выходе у датчиков одинаков.
К стате, как я понял Ваш код, Вы делаете ровно то же самое, только вместо двух строчек кода довольно громоздкая структура.[/uquote]

Да у меня абсолютно тоже самое. В datasheet на датчик есть 2 варианта кода, код для расчетов с применением переменных с плавающей запятой и вариант для расчетов с целочисленными переменными.
Для 8-bit микроконтроллера расчеты с плавающей запятой занимают больше процессорного времени. Поэтому ваш вариант мне не подходит так как у меня простой 8-bit микроконтроллер. А вот если бы я использовал какой нибудь ARM, конечно же я использовал бы вариант как у вас.

Вот мой код для расчета температуры (из datasheet), я не вижу тут огромной структуры, наоборот, у меня даже меньше получается:

Код: Выделить всё

int32_t bmp280_compensate_T(int32_t adc_T)
{
	int32_t var1;
	int32_t var2;
	int32_t temperature = 0;
	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;
	temperature = (t_fine * 5 + 128) >> 8;
	return temperature;
}
Я, конечно, могу вести себя нормально. Но чёрт возьми - это ведь так скучно.
MOHCTEP
Опытный кот
Сообщения: 768
Зарегистрирован: Вс янв 19, 2014 00:55:09

Re: BMP280, датчик давления и температуры

Сообщение MOHCTEP »

Здоровья читателю.
Столкнулся с такой же проблемой с выводом отрицательных или около-нулевых температур. Вот лог:

Код: Выделить всё

temperature = 1.32 C
raw_temperature = 0x0006F840 := 456768

temperature = 1.27 C
raw_temperature = 0x0006F7A0 := 456608

temperature = 1.19 C
raw_temperature = 0x0006F6A0 := 456352

temperature = 1.02 C
raw_temperature = 0x0006F490 := 455824

temperature = 86 C
raw_temperature = 0x0006F280 := 455296

temperature = 85 C
raw_temperature = 0x0006F260 := 455264

temperature = 91 C
raw_temperature = 0x0006F320 := 455456

temperature = 88 C
raw_temperature = 0x0006F2D0 := 455376

temperature = 63 C
raw_temperature = 0x0006EFA0 := 454560

temperature = 58 C
raw_temperature = 0x0006EF20 := 454432

temperature = 65 C
raw_temperature = 0x0006EFE0 := 454624

temperature = 68 C
raw_temperature = 0x0006F040 := 454720

temperature = 3.64 C
raw_temperature = 0x00071500 := 464128
Датчик ВМР280 под снегом в пакете. :) Код с даташита, проверял 100500 раз, сверял с выкладками в этой теме, пробовал шаман-бубен здешний с удваиванием типа t_fine - ничего не помогает...
Вот по "raw_temperature" в логе (это 20-битный компот значений соответствующих регистров ВМР280), не понятно, когда температура становится отрицательной/нулевой?
Братцы, если кому удалось цивилизовано решить эту проблему, поделитесь волшебством пожалуйста.
Аватара пользователя
DESIER
Открыл глаза
Сообщения: 47
Зарегистрирован: Пн апр 28, 2014 22:22:33
Откуда: Калуга

Re: BMP280, датчик давления и температуры

Сообщение DESIER »

[uquote="MOHCTEP",url="/forum/viewtopic.php?p=3583888#p3583888"]Братцы, если кому удалось цивилизовано решить эту проблему, поделитесь волшебством пожалуйста.[/uquote]
Покажите ваш код, тогда подумаем. А так можно гадать долго. Я думаю что проблема в типах данных, возможно вы где то вместо int используете unsigned int в коде расчета.
Я, конечно, могу вести себя нормально. Но чёрт возьми - это ведь так скучно.
MOHCTEP
Опытный кот
Сообщения: 768
Зарегистрирован: Вс янв 19, 2014 00:55:09

Re: BMP280, датчик давления и температуры

Сообщение MOHCTEP »

DESIER, возможно "глаз замылился" и я просто не вижу ошибку.
Спойлер

Код: Выделить всё

//signed long t_fine;
int32_t t_fine;
//int64_t t_fine;
int32_t _bmp280_temp;
uint32_t _bmp280_pres;
//структура калибров
static union _bmp280_cal_union {
	uint8_t bytes[BMP280_CAL_DATA_SIZE];
	struct {
		uint16_t dig_t1;
		int16_t  dig_t2;
		int16_t  dig_t3;
		uint16_t dig_p1;
		int16_t  dig_p2;
		int16_t  dig_p3;
		int16_t  dig_p4;
		int16_t  dig_p5;
		int16_t  dig_p6;
		int16_t  dig_p7;
		int16_t  dig_p8;
		int16_t  dig_p9;
	};
} bmp280_cal;
//...

//измерение
void bmp280_measure(void){
	uint8_t data[BMP280_RAWDATA_BYTES];
	int32_t temp_raw, pres_raw;
	// чтение raw ADC данных из регистров I2C
	readmem(BMP280_PRES_REG, data, BMP280_RAWDATA_BYTES);
        // форматирую загрузки в 20-битные числа
	pres_raw = bmp280_20bit_reg(data[0], data[1], data[2]);
	temp_raw = bmp280_20bit_reg(data[3], data[4], data[5]);

	//Тест вариантов измерений. Остановился на 32-битном
	//64 bits formula:: Flash - 4900 bytes, RAM - 444 Bytes
	//_bmp280_temp = compensate_T_int32(temp_raw);
	//_bmp280_pres = compensate_P_int64(pres_raw);
	
	//floating point formula:: Flash - 4700 bytes, RAM - 438 Bytes
	//_bmp280_temp = compensate_T_double(temp_raw);
	//_bmp280_pres = compensate_P_double(pres_raw);
	
	//32 bits formula:: Flash - 3768 bytes, RAM - 438 Bytes
	_bmp280_temp = compensate_T_int32(temp_raw);
	_bmp280_pres = compensate_P_int32(pres_raw);
}
//Собственно алхимия из даташита

// Returns temperature in DegC, resolution is 0.01 DegC. Output value of “5123” equals 51.23 DegC.
int32_t compensate_T_int32(int32_t adc_T){
	int32_t var1, var2, T;
	var1 = ((((adc_T >> 3) - ((int32_t)bmp280_cal.dig_t1 << 1))) * ((int32_t)bmp280_cal.dig_t2)) >> 11;
	var2 = (((((adc_T >> 4) - ((int32_t)bmp280_cal.dig_t1)) * ((adc_T >> 4) - ((int32_t)bmp280_cal.dig_t1))) >> 12) *
	((int32_t)bmp280_cal.dig_t3)) >> 14;
	t_fine = var1 + var2;
	T = (t_fine * 5 + 128) >> 8;
	return T;
}
//Дебаг этого мохера
//
void debugSendTP(void){
	uart_puts("temperature = ");
	//bin2dec(_bmp280_temp);
	num2dec(_bmp280_temp, 2);
	uart_puts(" C\r");
	uart_puts("pressure = ");
	//bin2dec(_bmp280_pres);
	num2dec(_bmp280_pres, 0);
	uart_puts(" Pa,  ");
	//bin2dec(Pa2mmHg(_bmp280_pres));
	num2dec(Pa2mmHg(_bmp280_pres), 2);
	uart_puts(" mmHg\r");
	debugRAWData();
}
Аватара пользователя
DESIER
Открыл глаза
Сообщения: 47
Зарегистрирован: Пн апр 28, 2014 22:22:33
Откуда: Калуга

Re: BMP280, датчик давления и температуры

Сообщение DESIER »

[uquote="MOHCTEP",url="/forum/viewtopic.php?p=3583925#p3583925"]DESIER, возможно "глаз замылился" и я просто не вижу ошибку.[/uquote]
А вот что вот это за функция? num2dec(_bmp280_temp, 2);
Она выводит переменную _bmp280_temp в знаковом типе?
Что то мне кажется дело в ней. Если осуществлять вывод информации в беззнаковом типе, будет вот такая байда.
Я, конечно, могу вести себя нормально. Но чёрт возьми - это ведь так скучно.
MOHCTEP
Опытный кот
Сообщения: 768
Зарегистрирован: Вс янв 19, 2014 00:55:09

Re: BMP280, датчик давления и температуры

Сообщение MOHCTEP »

DESIER писал(а):Что то мне кажется дело в ней.
Вот - да. Я на нее тоже грешу. Она самописная, а так как я не умею толком преобразовывать, вполне вероятна проблема в ней.

Код: Выделить всё

void num2dec(long arg, int fractionDigits){
	unsigned long dec = 1;
	int i = 0, index = 0,max = 0;
	char arr[16];
	memset(arr, 0, 16);
	while(dec < arg){
		dec *= 10;
		max ++;
	}
	if(max)	dec /= 10;
	if(fractionDigits && max > fractionDigits) max -= fractionDigits; 
	while(dec){
		i = 0;
		if(index == max && fractionDigits) arr[index ++ ] = 0x2E; //	Symbol - "."
		while(dec <= arg){
			arg -= dec;
			i++;
		}
		arr[index++] = i + 48;
		dec /= 10;
	}
	uart_puts(arr);
}
Аватара пользователя
DESIER
Открыл глаза
Сообщения: 47
Зарегистрирован: Пн апр 28, 2014 22:22:33
Откуда: Калуга

Re: BMP280, датчик давления и температуры

Сообщение DESIER »

MOHCTEP, я так понял это ардуино?! А в нем разве нельзя просто взять и отправить число в uart без вот таких танцев с бубнами?
Я с ардуино не работал и отладку я делаю через JTAG. Не могу понять для чего эта функция? Опишите в кратце что она делает.
Я, конечно, могу вести себя нормально. Но чёрт возьми - это ведь так скучно.
MOHCTEP
Опытный кот
Сообщения: 768
Зарегистрирован: Вс янв 19, 2014 00:55:09

Re: BMP280, датчик давления и температуры

Сообщение MOHCTEP »

DESIER Не-не, чур меня. :) Ни разу ардуино не доводилось видеть. Это Мега 8 + ВМР280 + USB-UART для отладки, а и + макетка.:)
DESIER писал(а):Не могу понять для чего эта функция? Опишите в кратце что она делает.
Задумывалась для преобразования любого числа (до 32 бит) в читабельный вид, с фиксированной точкой и отправки его в UART. Если есть какие-то стандартные вещи в си, для этого, не сильно отжирающие ресурсы и память, подскажите пожалуйста.
Аватара пользователя
DESIER
Открыл глаза
Сообщения: 47
Зарегистрирован: Пн апр 28, 2014 22:22:33
Откуда: Калуга

Re: BMP280, датчик давления и температуры

Сообщение DESIER »

Ну вот например если отправлять побайтно.
допустим переменная t несет значение температуры в виде -567 на пример, это будет температура -5,67 гр.С
и какая либо функция uart(char) принимающая в качестве аргумента байт, записывая его на шину.

Код: Выделить всё

uint16_t t = temperatureBMP280;
if (t < 0) { t = -t; uart('-'); }
if (t >= 1000) uart(((t/1000)%10)+48);
uart(((t/100)%10)+48);
uart('.');
uart(((t/10)%10)+48);
uart((t%10)+48);
uart('°');
uart('C');
Может я что то и нагородил, но я вывожу на LCD дисплей по шине I2C именно таким методом. У меня вместо uart другая рисующая символ на дисплее функция выводит изображение в соответствии с кодировкой ASCII.
Или вот так:

Код: Выделить всё

void DesSend(int32_t n)
{
	uint16_t temp = 0;
	if (n < 0) { temp = -n; UDR = 45; }
        else temp = n;
	if (t >= 1000) UDR = ((temp/1000)%10)+48;
	UDR = ((temp/100)%10)+48;
	UDR = 46;
	UDR = ((temp/10)%10)+48;
	UDR = (temp%10)+48;
	UDR = 176;
	ADR = 67;
}
Я, конечно, могу вести себя нормально. Но чёрт возьми - это ведь так скучно.
MOHCTEP
Опытный кот
Сообщения: 768
Зарегистрирован: Вс янв 19, 2014 00:55:09

Re: BMP280, датчик давления и температуры

Сообщение MOHCTEP »

Я чуть откомментировал
Спойлер

Код: Выделить всё

/*bcd
@arg - знаковое число 
@fractionDigits - количество "дробных, десятичных разрядов", если = 0, точку не рисуем
*/
void num2dec(long arg, int fractionDigits){
	unsigned long dec = 1;//десятичный делитель: 1,10, 100...
	int i = 0, index = 0, max = 0;
	char arr[16];//выходной массив с символами цифр и точки
	memset(arr, 0, 16);
	//выясним максимально возможный делитель для исходного числа - arg и заодно посчитаем разряды(количество цифр) - max
	while(dec < arg){
		dec *= 10;
		max ++;
	}
	//если arg!=0, уменьшим dec в 10 раз(подготовим вычитаемое, для старшего десятичного разряда arg)
	if(max)	dec /= 10;
	//если нужна точка(fractionDigits!=0) и количество цифр позволяет ее поставить, переделаем max в указатель места точки в массиве
	if(fractionDigits && max > fractionDigits) max -= fractionDigits; 
	//начинаем посимвольный вывод числа в массив
	while(dec){//пока делитель ненулевой
		i = 0;//сброс счетчика цифры
		//если индекс ячейки массива == месту точки, сунем в эту ячейку точку, а индекс пусть кажет на седующую ячейку
		if(index == max && fractionDigits) arr[index ++ ] = 0x2E; //	Symbol - "."
		//По сути это i = arg / dec, но вроде поменьше места занимает
		while(dec <= arg){
			arg -= dec;
			i++;
		}
		
		arr[index++] = i + 48;	//кладем в массив код символа найденой цифры
		dec /= 10;	//следующая цифра
	}
	uart_puts(arr);//вывод результата
}
По сути, вся верхняя возня придумана, чтоб не выводить левые нули при любой десятичной разрядности аргумента. Иначе говоря у вас код выведет температуру нормально, а давление в паскалях уже - проблема. По вашему коду есть вопросы.
1). "if (t < 0) { t = -t; uart('-'); }". Как это условие у вас срабатывает, если t - без знаковая(uint16_t)?
2) Покажите, ради хвоста, паяльника и прочих мимоз, как у вас выглядит эта самая "-567" в 16-ричном виде! Очень прошу. И главное куда этот долбаный минус засунулся в 32-битном результате даташитовских манипуляций? У вас все просто "if (n < 0)" = кайф! :) У меня, почему-то, эта самая "n" всегда больше нуля.
Аватара пользователя
ПростоНуб
Собутыльник Кота
Сообщения: 2723
Зарегистрирован: Пт сен 07, 2018 20:20:02
Откуда: деревня в Тульской губернии

Re: BMP280, датчик давления и температуры

Сообщение ПростоНуб »

Не проще ли было воспользоваться если не sprintf(), то хотя бы itoa() или utoa()?
А если уж очень захотелось конвертировать из двоичку в десятичку самостоятельно, то лучше воспользоваться более быстрым алгоритмом, без деления. Например, тем же Double dabble.
Ответить

Вернуться в «Периферия»