stm32 ds18b20

Кто любит RISC в жизни, заходим, не стесняемся.
veso74
Поставщик валерьянки для Кота
Сообщения: 1903
Зарегистрирован: Сб май 05, 2012 20:24:52
Откуда: KN34PC, Болгария
Контактная информация:

Re: stm32 ds18b20

Сообщение veso74 »

Не 0.5% погрешность, а ±0.5°C Accuracy from -10°C to +85°C. А калибровать датчик лично ничего не хочу: покупаю, пишу цифры, и работает.
Последний раз редактировалось veso74 Вт июн 14, 2022 00:16:45, всего редактировалось 1 раз.
Аватара пользователя
Карбофос
Опытный кот
Сообщения: 760
Зарегистрирован: Сб окт 22, 2016 17:33:32
Откуда: кг

Re: stm32 ds18b20

Сообщение Карбофос »

Ваша правда.
Думал одно, напечаталось другое.
Но, от этого, недостатки DS18B20 не менее значимы.
veso74
Поставщик валерьянки для Кота
Сообщения: 1903
Зарегистрирован: Сб май 05, 2012 20:24:52
Откуда: KN34PC, Болгария
Контактная информация:

Re: stm32 ds18b20

Сообщение veso74 »

... недостатки DS18B20 не менее значимы.
Приведите пример, я нахожу только плюсы :).
Кто-то до меня сделал датчик, калибровал, я просто включаю его и пользуюсь ...
Ну относительно, на первое приближение конечно ...
Последний раз редактировалось veso74 Вт июн 14, 2022 00:20:10, всего редактировалось 1 раз.
Аватара пользователя
Карбофос
Опытный кот
Сообщения: 760
Зарегистрирован: Сб окт 22, 2016 17:33:32
Откуда: кг

Re: stm32 ds18b20

Сообщение Карбофос »

Так, я же написал.
Низкая точность.
Очень медленная реакция.
В некоторых применениях, крупный корпус.
Последний раз редактировалось Карбофос Вт июн 14, 2022 00:21:02, всего редактировалось 1 раз.
veso74
Поставщик валерьянки для Кота
Сообщения: 1903
Зарегистрирован: Сб май 05, 2012 20:24:52
Откуда: KN34PC, Болгария
Контактная информация:

Re: stm32 ds18b20

Сообщение veso74 »

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

... Очень медленная реакция.
Странное заявление. Для тепловой времеконстант, которая больше похожа на интегрирование из-за массы.
И почему мы так спешим за измерение температурой? :) рассчитайте беглло времяконстант изменения P * массы нагревателя-нагрузки?
Последний раз редактировалось veso74 Вт июн 14, 2022 01:15:16, всего редактировалось 2 раза.
Аватара пользователя
Карбофос
Опытный кот
Сообщения: 760
Зарегистрирован: Сб окт 22, 2016 17:33:32
Откуда: кг

Re: stm32 ds18b20

Сообщение Карбофос »

Странный вопрос.
Надо знать температуру здесь и сейчас.
Спасибо за внимание.
veso74
Поставщик валерьянки для Кота
Сообщения: 1903
Зарегистрирован: Сб май 05, 2012 20:24:52
Откуда: KN34PC, Болгария
Контактная информация:

Re: stm32 ds18b20

Сообщение veso74 »

Можете измерить в 750 мс для 12 бит. если медленное, может быть, меньше бит.
Ето медленно для датчика вес 3,00 грамма? Нагрев или охлаждение с окружающими металлами не будет быстрее.
Аватара пользователя
Карбофос
Опытный кот
Сообщения: 760
Зарегистрирован: Сб окт 22, 2016 17:33:32
Откуда: кг

Re: stm32 ds18b20

Сообщение Карбофос »

main.c
Спойлер

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

StartAdcConversion(ADC_CHSELR_CHSEL3 | ADC_CHSELR_CHSEL2 | ADC_CHSELR_CHSEL1 | ADC_CHSELR_CHSEL0,
				ADC_SMPR_SMP_2 | ADC_SMPR_SMP_1 | ADC_SMPR_SMP_0);	// tCONV = 18 usec);
ntc.c
Спойлер

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

#include <inttypes.h>
#include "stm32f0xx.h"
#include "main.h"
#include "analog.h"
#include "ntc.h"

volatile
ChData_TypeDef  ChData	[ChDataSize]		__attribute__ ((aligned (sizeof(AdcChData_TypeDef))));
ChData_TypeDef	samRntc	[NUM_ADC_SAMPLES]	__attribute__ ((aligned (sizeof(AdcChData_TypeDef))));
const uint16_t	RA		[NUM_ADC_CHANELS]	__attribute__ ((aligned (sizeof(AdcChData_TypeDef)))) =
	{3297u, 3298u, 3300u, 3300u};

void StartAdcConversion(uint32_t ch, uint8_t stime)
{
	startADC1((void*)ChData, sizeof(ChData) / sizeof(AdcChData_TypeDef), ch, stime);
}

// Sample No
static uint8_t samNo = 0;

void CalcAvrNTC(void)
{
	// Расчёт средних измеренных значений R_NTC
	for(uint8_t ch = 0 ; ch < NUM_ADC_CHANELS; ch++) {
		uint32_t sch = 0;
		const ChData_TypeDef* pch = (const ChData_TypeDef*)ChData;
		for(uint16_t sample = 0; sample < sizeof(ChData) / sizeof(ChData[0]); sample++, pch++) {
			sch += pch->chd[ch];
		}
		sch += (sizeof(ChData) / sizeof(ChData[0])) >> 1;
		sch >>= (ChDataBits - 1);
		uint16_t div = 8191 - sch;
		samRntc[samNo].chd[ch] = ((sch + 1) * RA[ch] + (div >> 1)) / div;
	}
	if(++samNo >= NUM_ADC_SAMPLES) {
		samNo = 0;
	}
}

void CalcAvrTemperature(void)
{
	// Расчёт измеренных значений температуры
	for(uint8_t ch = 0 ; ch < NUM_ADC_CHANELS; ch++) {
		uint32_t sch = 0;
		for(uint8_t sample = 0; sample < NUM_ADC_SAMPLES; sample++) {
			sch += samRntc[sample].chd[ch];
		}
		sch += NUM_ADC_SAMPLES >> 1;
		sch /= NUM_ADC_SAMPLES;
		// температуры в контрольных точках по номерам каналов
		Temper01[ch] = CalcTemperature01((uint16_t)sch);
	}
}

#define TEMPERATURE_START	0		// от 0 гр.С
#define TEMPERATURE_END		1000	// до 100 гр.С
#define TEMPERATURE_STEP	10		// с шагом 0.1 гр.С

// Значения сопротивления NTC терморезистора MF52 10k 5% B25/50=3950K от 0°C до 100°C с шагом 1°C
// Индекс элемента - температура, значение элемента - сопротивление NTC при этой температуре
const uint16_t R_NTC_table[] __attribute__ ((aligned (sizeof(uint16_t)))) = {
/*  0 */	32960, 31308, 29749, 28279, 26891, 25580, 24334, 23158, 22046, 20994,
/* 10 */	20000, 19057, 18164, 17319, 16518, 15760, 15039, 14356, 13708, 13093,
/* 20 */	12510, 11955, 11428, 10927, 10452, 10000,  9569,  9160,  8771,  8400,
/* 30 */	 8048,  7711,  7391,  7086,  6795,  6518,  6253,  6001,  5760,  5531,
/* 40 */	 5312,  5102,  4902,  4711,  4528,  4354,  4187,  4027,  3874,  3728,
/* 50 */	 3588,  3454,  3326,  3204,  3086,  2974,  2866,  2762,  2663,  2567,
/* 60 */	 2476,  2388,  2304,  2224,  2146,  2072,  2001,  1932,  1867,  1804,
/* 70 */	 1743,  1685,  1629,  1575,  1523,  1473,  1425,  1379,  1334,  1291,
/* 80 */	 1250,  1210,  1172,  1135,  1099,  1065,  1032,  1000,   969,   940,
/* 90 */	  911,   883,   857,   831,   806,   782,   759,   737,   715,   695,
/*100 */	  674
};

int16_t CalcTemperature01(uint16_t rntc)
{
	uint8_t l = 0;
	uint8_t r = (sizeof(R_NTC_table) / sizeof(R_NTC_table[0])) - 1;

	// Проверка выхода за пределы и граничных значений
	if(rntc <= R_NTC_table[r]) {
		return TEMPERATURE_END;
	} else if(rntc >= R_NTC_table[l]) {
		return TEMPERATURE_START;
	}

	// Двоичный поиск по таблице
	while((r - l) > 1) {
		uint8_t m = (l + r) >> 1;
		if(rntc > R_NTC_table[m]) {
			r = m;
		} else if(rntc < R_NTC_table[m]) {
			l = m;
		} else {	// наткнулись
			l = r = m;
			break;
		}
	}

	int16_t result;
	if(rntc >= R_NTC_table[l]) {	// наткнулись или ошибка в таблице
		result = TEMPERATURE_START + TEMPERATURE_STEP * l;
	} else {
		uint16_t vd = R_NTC_table[l] - R_NTC_table[r];
		result = TEMPERATURE_START + r * TEMPERATURE_STEP;
		if(vd) {
			// Линейная интерполяция
			result -= ((TEMPERATURE_STEP * (rntc - R_NTC_table[r]) + (vd >> 1)) / vd);
		}
	}
	return result;
}
analog.c
Спойлер

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

#include "stm32f0xx.h"
#include "analog.h"

volatile uint8_t bConversionComplete;

// DMA1 Channel 1 interrupt handler
#ifdef __cplusplus
extern "C"
#endif
void DMA1_Channel1_IRQHandler(void)
{
	// A Transfer Complete or Transfer Error flag
	if(READ_BIT(DMA1->ISR, DMA_ISR_TCIF1 | DMA_ISR_TEIF1) != RESET) {
		// ADC stop
		stopADC1();
		if(READ_BIT(DMA1->ISR, DMA_ISR_TCIF1) != RESET)
			bConversionComplete = SET;
		// Disable DMA1 Channel1
		CLEAR_BIT(DMA1_Channel1->CCR, DMA_CCR_EN);
		// Channel1 clear interrupt flags
		SET_BIT(DMA1->IFCR, DMA_IFCR_CGIF1 | DMA_IFCR_CTCIF1 | DMA_IFCR_CHTIF1 | DMA_IFCR_CTEIF1);
	}
}

// ADC start
void startADC1(void* pData, uint16_t num, uint32_t ch, uint8_t stime)
{
	// ADC stop
	stopADC1();
	// Sampling time selection, Fadc = 14 MHz
	//	SMP		Sampling		tCONV,
	//			time,cycles		usec
	//	000		1,5				1,00
	//	001		7,5				1,43
	//	010		13,5			1,86
	//	011		28,5			2,93
	//	100		41,5			3,86
	//	101		55,5			4,86
	//	110		71,5			6,00
	//	111		239,5			18,00
	MODIFY_REG(ADC1->SMPR, ADC_SMPR_SMP, stime);
	// ADC channel selection
	MODIFY_REG(ADC1->CHSELR, ADC_CHSELR_CHSEL, ch);
	// Analog watchdog disabled, ADC group regular sequencer discontinuous mode disabled,
	// DR register is preserved with the old data when an overrun is detected,
	// Hardware trigger detection disabled, Right alignment, Data resolution 12 bits,
	// Scan sequence direction Upward, DMA one shot mode selected,
	// ADC low power auto power enabled, Wait conversion mode on,
	// Continuous conversion mode enabled, DMA enabled
	MODIFY_REG(ADC1->CFGR1, ADC_CFGR1_AWD1EN | ADC_CFGR1_DISCEN |
		ADC_CFGR1_OVRMOD | ADC_CFGR1_EXTEN | ADC_CFGR1_ALIGN | ADC_CFGR1_RES | ADC_CFGR1_SCANDIR | ADC_CFGR1_DMACFG,
		ADC_CFGR1_AUTOFF | ADC_CFGR1_WAIT |ADC_CFGR1_CONT | ADC_CFGR1_DMAEN);

	// DMA
	// wait DMA1 Channel1 Transfer Complete flag
	if(READ_BIT(DMA1_Channel1->CCR, DMA_CCR_EN) != RESET) {
		// wait for Transfer Complete or Transfer Error flag
		while(READ_BIT(DMA1->ISR, DMA_ISR_TCIF1 | DMA_ISR_TEIF1) == RESET);
		// Disable DMA1 Channel1
		CLEAR_BIT(DMA1_Channel1->CCR, DMA_CCR_EN);
	}
	// ADC DMA map to DMA1 Chanel1
	CLEAR_BIT(SYSCFG->CFGR1, SYSCFG_CFGR1_ADC_DMA_RMP);
	// Configure the peripheral address register
	WRITE_REG(DMA1_Channel1->CPAR, (uint32_t)&(ADC1->DR));
	// Configure the memory address
	WRITE_REG(DMA1_Channel1->CMAR, (uint32_t)pData);
	// Configure the number of DMA tranfer to be performs on channel
	MODIFY_REG(DMA1_Channel1->CNDTR, 0xffffu, num);
	// Channel priority level 01 Medium, Peripheral & Memory size 01 16-bits,
	// Memory increment mode 1 enabled, Data transfer direction 0 Read from peripheral
	// Circular mode disabled, Transfer complete interrupt enabled
	MODIFY_REG(DMA1_Channel1->CCR, DMA_CCR_MEM2MEM | DMA_CCR_PL | DMA_CCR_MSIZE | DMA_CCR_PSIZE |
		DMA_CCR_PINC | DMA_CCR_CIRC | DMA_CCR_DIR | DMA_CCR_TEIE | DMA_CCR_HTIE | DMA_CCR_EN,
		DMA_CCR_PL_0 | DMA_CCR_MSIZE_0 | DMA_CCR_PSIZE_0 | DMA_CCR_MINC | DMA_CCR_TCIE);

	// ADC group regular conversion start
	SET_BIT(ADC1->CR, ADC_CR_ADSTART);
	// Enable DMA1 Channel1
	SET_BIT(DMA1_Channel1->CCR, DMA_CCR_EN);
	// Conversion complete flag
	bConversionComplete = RESET;

	// DMA1 Channel1 (ADC) interrupt enable
	NVIC_EnableIRQ(DMA1_Channel1_IRQn);
	NVIC_SetPriority(DMA1_Channel1_IRQn, 3);
}

uint16_t scmADC1(uint32_t ch, uint8_t stime)
{
	// ADC stop
	stopADC1();
	// Sampling time selection, Fadc = 14 MHz
	//	SMP		Sampling		tCONV,
	//			time,cycles		usec
	//	000		1,5				1,00
	//	001		7,5				1,43
	//	010		13,5			1,86
	//	011		28,5			2,93
	//	100		41,5			3,86
	//	101		55,5			4,86
	//	110		71,5			6,00
	//	111		239,5			18,00
	MODIFY_REG(ADC1->SMPR, ADC_SMPR_SMP, stime);
	// Analog watchdog disabled, ADC group regular sequencer discontinuous mode disabled,
	// Wait conversion mode off, Continuous conversion mode disabled,
	// DR register is preserved with the old data when an overrun is detected,
	// Hardware trigger detection disabled, Right alignment, Data resolution 12 bits,
	// Scan sequence direction Upward, DMA one shot mode selected, DMA disabled
	// ADC low power auto power enabled
	MODIFY_REG(ADC1->CFGR1, ADC_CFGR1_AWD1EN | ADC_CFGR1_DISCEN | ADC_CFGR1_WAIT |
		ADC_CFGR1_CONT | ADC_CFGR1_OVRMOD | ADC_CFGR1_EXTEN | ADC_CFGR1_ALIGN | ADC_CFGR1_RES |
		ADC_CFGR1_SCANDIR | ADC_CFGR1_DMACFG | ADC_CFGR1_DMAEN,
		ADC_CFGR1_AUTOFF);
	// ADC channel selection
	MODIFY_REG(ADC1->CHSELR, ADC_CHSELR_CHSEL, ch);
	// ADC group regular conversion start
	SET_BIT(ADC1->CR, ADC_CR_ADSTART);
	// ADC group regular end of unitary conversion flag
	while(READ_BIT(ADC1->ISR, ADC_ISR_EOC) == RESET);
	// ADC data register
	return READ_BIT(ADC1->DR, 0xffffu);
}

// ADC stop
void stopADC1(void)
{
	// ADC group regular conversion stop
	if(READ_BIT(ADC1->CR, ADC_CR_ADSTART) != RESET) {
		SET_BIT(ADC1->CR, ADC_CR_ADSTP);
		// wait for ADC group regular conversion stop
		while(READ_BIT(ADC1->CR, ADC_CR_ADSTP) != RESET);
	}
}

// ADC calibration
void calADC1(void)
{
	// ADC disable
	if(READ_BIT(ADC1->CR, ADC_CR_ADEN) != RESET) {
		// ADC stop
		stopADC1();
		// ADC disable
		SET_BIT(ADC1->CR, ADC_CR_ADDIS);
		// wait for ADC1 disable
		while(READ_BIT(ADC1->CR, ADC_CR_ADEN) != RESET);
	}

	// ADC DMA transfer disable
	CLEAR_BIT(ADC1->CFGR1, ADC_CFGR1_DMAEN | ADC_CFGR1_DMACFG);
	// ADC calibration
	SET_BIT(ADC1->CR, ADC_CR_ADCAL);
	// Wait until ADCAL=0
	while(READ_BIT(ADC1->CR, ADC_CR_ADCAL) != RESET);

	// ADC Enable
	// Clear the ADRDY bit
	if(READ_BIT(ADC1->ISR, ADC_ISR_ADRDY) != RESET)
		SET_BIT(ADC1->ISR, ADC_ISR_ADRDY);
	// ADC enable
	SET_BIT(ADC1->CR, ADC_CR_ADEN);
	// wait for ADC ready flag
	while(READ_BIT(ADC1->ISR, ADC_ISR_ADRDY) == RESET);
}

// ADC initialization
void initADC1(void)
{
	// HSI14 clock request from ADC disable
	SET_BIT(RCC->CR2, RCC_CR2_HSI14DIS);
	// Internal High Speed 14MHz clock enable
	SET_BIT(RCC->CR2, RCC_CR2_HSI14ON);
	// wait for Internal High Speed 14MHz clock ready
	while(READ_BIT(RCC->CR2, RCC_CR2_HSI14RDY) == RESET);
	// Internal High Speed 14MHz clock enable
	CLEAR_BIT(RCC->CR2, RCC_CR2_HSI14DIS);
	// ADCCLK (Asynchronous clock mode), generated at product level (refer to RCC section)
	CLEAR_BIT(ADC1->CFGR2, RCC_CFGR2_PREDIV);
	// ADC1 clock enable
	SET_BIT(RCC->APB2ENR, RCC_APB2ENR_ADCEN);
	// ADC calibration
	calADC1();
	// Conversion complete flag
	bConversionComplete = RESET;
}
4 канала ADC * 18 usec/канал * 128 измерений = 9.216 msec
veso74
Поставщик валерьянки для Кота
Сообщения: 1903
Зарегистрирован: Сб май 05, 2012 20:24:52
Откуда: KN34PC, Болгария
Контактная информация:

Re: stm32 ds18b20

Сообщение veso74 »

MF52 Time Constant of ≤7 seconds in still air
Если хтите измерить в MHz, ничего не изменит.

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

Available tolerances: ±1%, ±2%, ±3% and ±5%
и беспокоит таблица, какие изменения будут происходить без отдельный выбор датчика.
Напр. настаиваю на 43.0 градусах, сколько изменится при случайным датчиком из пакета с датчиками.
Последний раз редактировалось veso74 Вт июн 14, 2022 01:14:24, всего редактировалось 3 раза.
Аватара пользователя
Карбофос
Опытный кот
Сообщения: 760
Зарегистрирован: Сб окт 22, 2016 17:33:32
Откуда: кг

Re: stm32 ds18b20

Сообщение Карбофос »

Это-же фильтр, среднее берётся.
И, откуда ты эти 7 секунд взял? Придумал?
Или, в сферическом вакууме?
Последний раз редактировалось Карбофос Вт июн 14, 2022 00:58:08, всего редактировалось 1 раз.
veso74
Поставщик валерьянки для Кота
Сообщения: 1903
Зарегистрирован: Сб май 05, 2012 20:24:52
Откуда: KN34PC, Болгария
Контактная информация:

Re: stm32 ds18b20

Сообщение veso74 »

из пдф-а MF52
Аватара пользователя
Карбофос
Опытный кот
Сообщения: 760
Зарегистрирован: Сб окт 22, 2016 17:33:32
Откуда: кг

Re: stm32 ds18b20

Сообщение Карбофос »

В static air? ))
А для DS18B20 в static air какая константа?

Всё, досвидос.
Последний раз редактировалось Карбофос Вт июн 14, 2022 01:00:14, всего редактировалось 1 раз.
veso74
Поставщик валерьянки для Кота
Сообщения: 1903
Зарегистрирован: Сб май 05, 2012 20:24:52
Откуда: KN34PC, Болгария
Контактная информация:

Re: stm32 ds18b20

Сообщение veso74 »

В воздухе, в покое, без обдува.
---
Более - весит больше в граммах. Тепловая времяконстанта, интегратор. Вот почему и писание "датчик - медленный" не имеет смысла для датчика температуры, потому что скорость физическое изменение температуры массы больше, чем максимуме (750 мс) для одного измерения.
kolobok0
Грызет канифоль
Сообщения: 296
Зарегистрирован: Ср дек 30, 2009 09:55:39

info ds18x

Сообщение kolobok0 »

к сведению...

разрешение:
ds1821 = 0,01
для всего остального = 0,0625

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

----------------
ну и скажу крамолу....
разогрев датчика = около ДЕСЯТЫХ градуса...
veso74
Поставщик валерьянки для Кота
Сообщения: 1903
Зарегистрирован: Сб май 05, 2012 20:24:52
Откуда: KN34PC, Болгария
Контактная информация:

Re: stm32 ds18b20

Сообщение veso74 »

Да, самонагрев не высокий. При 3 сек подготовки/3 сек снятия данных зимой (около 11-13 градусов), при вкл. первые минуты увеличивается примерно с 0,2-0,3 оC. 5V, 4,7 kOm.
Аватара пользователя
AlanDrakes
Прорезались зубы
Сообщения: 236
Зарегистрирован: Пн июл 04, 2016 16:51:22
Откуда: Россия, Омск

Re: stm32 ds18b20

Сообщение AlanDrakes »

[uquote="ivan dimir",url="/forum/viewtopic.php?p=4244936#p4244936"]
Спойлер
int16_t curr_temp;extern uint8_t ow_Answ[9];
Хорошо у меня есть переменная int tt=int16_t curr_temp;А вторая переменная это массив?и почему экстерн.?И как всё это вывести на lcd7[/uquote]
Потому что в сообщении выше я сказал, что массив используется другим файлом исходника (ds18b20.c), который в него СЧИТЫВАЕТ Scratch Pad из датчика. Была у меня такая потребность в процессе разработки. Потом файл перетёк в этот проект. Просто потому что работает и позволяет делать интересные вещи асинхронно.

[uquote="ivan dimir",url="/forum/viewtopic.php?p=4245001#p4245001"]Так покажите полную картину вывода на экран LCD?.А то кусочек секса не интересно.[/uquote]
На какой LCD? На графический? Давайте лучше возьму пример для платы с экраном e-ink, на котором у меня метео-прогноз дёргается из интернетов.

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

	snprintf(txt,  sizeof(txt),  "%d.%d°", curr_temp/10, curr_temp % 10); // Форматируем строку из примера выше. Число 77 станет "7.7°"
	get_text_bounds((G_FONT_t *)&Tahoma16, txt, &x, &y, &l1, &h); // Вычисляем габариты строки (сколько она займёт места на экране). Значения размеров будут помещены в переменные l1 и h
	write_string((G_FONT_t *)&Tahoma16, txt,  &l1, &cy, framebuffer); // Вызываем функцию отрисовки полученой выше строки в экранный буфер framebuffer.
// И где-то сильно позже будет вызвана функция отправки данных на дисплей.

	// Процесс вывода из буфера на экран.
	epd_init();
	// ESP_LOGI("Renderer", "EPD Power ON");
	epd_poweron();
	// ESP_LOGI("Renderer", "EPD CLS");
	epd_clear();
	// ESP_LOGI("Renderer", "EPD Draw");
	epd_draw_grayscale_image(epd_full_screen(), framebuffer);
	// ESP_LOGI("Renderer", "EPD Power OFF");
	epd_poweroff_all();
Как работает ВАШ дисплей - я не знаю, и предлагаю разобраться с выводом в него уже самостоятельно.

Вы уже БУКВАЛЬНО просите за вас доделать проект.
Всё разжёвано и разложено по полочкам. (Фу, я это представил >_<), осталось только собрать код воедино.

1. Каким угодно способом отправляете датчику команду 0xCC, 0x44 (Skip ROM + Convert Temp)
2. Ждёте, пока датчик не сконвертирует температуру, либо время от времени читаете одиночный тайм-слот. Если датчик подтягивает его в состояние "0" - всё ещё происходит преобразование температуры. Если перестал - датчик готов к чтению данных.
3. Читаете температуру. В моём случае, она оказывается в массиве ow_Answ[] со всеми остальными данными из Scratch Pad'а. (Я проверял CRC)
Изображение
4. Собираем два байта в кучу (uint8_t | uint8_t) -> (int16_t). По вкусу: Выделяем целое, приводим дробное... изголяемся как хотим, в общем.
5. Выводим куда угодно.

Опять же, в случае с моим кодом, я выводил на управляемую светодиодную ленту, потому участок кода выглядит подобным образом:
Спойлер

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

const uint8_t Digits[13] = {0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x40,0x00,0x08};
 // ^- Вот это - сами цифры.

 // v- Вот это - как расположены сегменты геометрически.
// g-f-e-d-c-b-a [5]
// h [2] -g-f-e-d-c-b-a [5]
// g-f-e-d-c-b-a [5]
// deg [4]

 // v- Вот это их представление в виде битов.
// 0 -> 0 1 1 1 1 1 1
// 1 -> 0 0 0 0 1 1 0
// 2 -> 1 0 1 1 0 1 1
// 3 -> 1 0 0 1 1 1 1
// 4 -> 1 1 0 0 1 1 0
// 5 -> 1 1 0 1 1 0 1
// 6 -> 1 1 1 1 1 0 1
// 7 -> 0 0 0 0 1 1 1
// 8 -> 1 1 1 1 1 1 1
// 9 -> 1 1 0 1 1 1 1
// - -> 1 0 0 0 0 0 0
//   -> 0 0 0 0 0 0 0
// _ -> 0 0 0 1 0 0 0

void LED_Push(int16_t value) {
	uint8_t v;
	// -550 .. +1250 (degrees * 10 with fixed decimal point)
	if (value < 0) {
		// Blue if neg
		CurrentColor[0] = 0;
		CurrentColor[1] = 0;
		CurrentColor[2] = 0xFF;
		is_minus = 1;
		if (value > -100) {
			// -x.x
			is_dot = 1;
			value = -value;
			v = value / 10;
			Led_DigitAt(v, 1);
			Led_DigitAt((value % 10), 2);
		} else {
			is_dot = 0;
			value = -value;
			value = value / 10;
			v = value / 10;
			Led_DigitAt(v, 1);
			Led_DigitAt((value % 10), 2);
			// -xx
		};
	} else {
		is_minus = 0;
		// no minus
		
		// 0..40 -> Yellow
		if ((value >= 0) && (value < 400)) {
			CurrentColor[0] = 0xFF;
			CurrentColor[1] = 0xFF;
			CurrentColor[2] = 0;
		} else if ((value >= 400) && (value < 900)) {
		// 40..90 -> Green
			CurrentColor[0] = 0;
			CurrentColor[1] = 0xFF;
			CurrentColor[2] = 0;
		} else {
		// > 90 -> Red
			CurrentColor[0] = 0xFF;
			CurrentColor[1] = 0;
			CurrentColor[2] = 0;
		};
		
		if (value < 100) {
			is_dot = 1;
			// _x.x
			Led_DigitAt(11, 0);
			v = value % 10;
			value = value / 10;
			Led_DigitAt(v, 2);
			v = value % 10;
			value = value / 10;
			Led_DigitAt(v, 1);
		} else if (value < 1000) {
			is_dot = 1;
			v = value % 10;
			value = value / 10;
			Led_DigitAt(v, 2);
			v = value % 10;
			value = value / 10;
			Led_DigitAt(v, 1);
			Led_DigitAt(value, 0);
			// xx.x
		} else {
			is_dot = 0;
			value = value / 10;
			v = value % 10;
			value = value / 10;
			Led_DigitAt(v, 2);
			v = value % 10;
			value = value / 10;
			Led_DigitAt(v, 1);
			Led_DigitAt(value, 0);
			// xxx
		};
	};
	
	if (is_dot) {
		pixels[75*3 + 0] = CurrentColor[0] & Current_BL;
		pixels[75*3 + 1] = CurrentColor[1] & Current_BL;
		pixels[75*3 + 2] = CurrentColor[2] & Current_BL;
		pixels[74*3 + 0] = CurrentColor[0] & Current_BL;
		pixels[74*3 + 1] = CurrentColor[1] & Current_BL;
		pixels[74*3 + 2] = CurrentColor[2] & Current_BL;
	} else {
		pixels[75*3 + 0] = 0x00;
		pixels[75*3 + 1] = 0x00;
		pixels[75*3 + 2] = 0x00;
		pixels[74*3 + 0] = 0x00;
		pixels[74*3 + 1] = 0x00;
		pixels[74*3 + 2] = 0x00;
	};
	if (is_minus) {
		Led_DigitAt(11, 0);
	};
	// degree sign
	pixels[0] = CurrentColor[0] & Current_BL;
	pixels[1] = CurrentColor[1] & Current_BL;
	pixels[2] = CurrentColor[2] & Current_BL;
	pixels[3] = CurrentColor[0] & Current_BL;
	pixels[4] = CurrentColor[1] & Current_BL;
	pixels[5] = CurrentColor[2] & Current_BL;
	pixels[6] = CurrentColor[0] & Current_BL;
	pixels[7] = CurrentColor[1] & Current_BL;
	pixels[8] = CurrentColor[2] & Current_BL;
	pixels[9] = (CurrentColor[0] & Current_BL) / 2;
	pixels[10] = (CurrentColor[1] & Current_BL) / 2;
	pixels[11] = (CurrentColor[2] & Current_BL) / 2;
}

void Led_DigitAt(uint8_t Digit, uint8_t Pos) {
	uint16_t shift = 0;
	int i;
	uint8_t v;
	switch (Pos) {
		case 0: {
			shift = 76;
			break;
		};
		case 1: {
			shift = 39;
			break;
		};
		case 2: {
			shift = 4;
			break;
		};
	};
	for (i=0; i<7; i++) {
		if (Digits[Digit] & (0x01 << i)) {
			for (v=0; v<5; v++) {
				pixels[shift*3 + i*15 + v*3 + 0] = Current_BL & CurrentColor[0];
				pixels[shift*3 + i*15 + v*3 + 1] = Current_BL & CurrentColor[1];
				pixels[shift*3 + i*15 + v*3 + 2] = Current_BL & CurrentColor[2];
			};
		} else {
			for (v=0; v<5; v++) {
				pixels[shift*3 + i*15 + v*3 + 0] = 0x00;
				pixels[shift*3 + i*15 + v*3 + 1] = 0x00;
				pixels[shift*3 + i*15 + v*3 + 2] = 0x00;
			};
		};
	};
}

void Led_Push_Px(int Number) {
	uint8_t i;
	uint8_t clr = 0, j;
	// F_CPU = 8MHz = 62.5nS/tick
	uint8_t H = PORTB | 1;
	uint8_t L = PORTB & ~(1);
	for (j=0;j<3;j++){
		if (j==1) {clr = pixels[Number*3];};
		if (j==0) {clr = pixels[Number*3+1];};
		if (j==2) {clr = pixels[Number*3+2];};
		i = 0x80;
		while(i) {
			if (clr & i) {
				PORTB = H;			// 62uS
				asm volatile("nop");		// ~125nS
				asm volatile("nop");		// ~295nS
				asm volatile("nop");		// ~355nS
				asm volatile("nop");		// ~420nS
				asm volatile("nop");		// 485nS
				asm volatile("nop");		// 550nS
				asm volatile("nop");		// 615nS
				asm volatile("nop");		// 670nS
				PORTB = L;
			} else {
				PORTB = H;		// 0nS
				asm("nop");		// 62nS
				asm("nop");		// 125nS
				asm("nop");		// 185nS
				PORTB = L;		// +250nS -> 400uS
				asm("nop");		// 465nS
				asm("nop");		// 520nS
				asm("nop");		// 580nS
				asm volatile("nop");	// 650nS
			};
			i = i >> 1;
		};
	};
}
https://chipenable.ru/index.php/program ... 18b20.html - Вот сайт, с которого я взял картинку.
ivan dimir
Мучитель микросхем
Сообщения: 440
Зарегистрирован: Вс дек 29, 2019 08:05:21

Re: stm32 ds18b20

Сообщение ivan dimir »

Вообщем как то так вышло правда взял проект на Stm32 и посмотрел .Ну в протеусе получилось
Спойлер

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

/*
 * 1-wire(mega32a).c
 *
 * Created: 13.03.2018 5:40:10
 * Author : User
 */ 
#define F_CPU 8000000UL
#include <avr/io.h>
#include <util/delay.h>
#include <avr/wdt.h>
#include <avr/interrupt.h>
#include <stdio.h>

#include "DS18B20.h"


//#include "adc.h"
#include "lcd.h"
	unsigned int temper;

	unsigned int temper_tt;
	unsigned char S;
	char bufer0[60];
 
void inits_ports(void)
{
	
	
	DDRB=0xFF;
	PORTB=0x00;
	DDRC|=(1<<2);
	PORTC|=(0<<2);
	DDRA=0x00;
	PORTA=0x00;
   DDRD=0xFF;
	PORTD=0x00;
	
}


int main(void)
{
	
	//unsigned int tt=0;
	
	inits_ports();
	//init_ADC();
	lcd_init(LCD_DISP_ON);
	lcd_clrscr();
   
    while (1) 
    {
		
		temper_tt=dt_check();
		
	  
	 
		if (ds18b20_GetSign(temper_tt))
		{
	      
			
			
			temper_tt=~temper_tt+1;
			S='-';
		
			
		} 
		else
		{
			
			S=' ';
			
	      
	      
			
		}
		temper=converttemp(temper_tt);
		  lcd_gotoxy(0,1);
	      sprintf(bufer0,"t=%c%2d *C\n\r",S,temper);
		  
		
		lcd_puts(bufer0);
	  
    }
}

Спойлер
Спойлер

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

#include "DS18B20.h"
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <stdlib.h>
#define NOID 0xCC //Пропустить идентификацию
#define T_CONVERT  0x44 //Код измерения температуры
#define READ_DATA 0xBE //Передача байтов ведущему



#define PORTTEMP PORTD
#define DDRTEMP DDRD
#define PINTEMP PIND
#define BITTEMP 1

//функция определения датчика на шине
char dt_testdevice(void) //dt - digital termomether | определим, есть ли устройство на шине
{
	//char stektemp=SREG;// сохраним значение стека
	cli(); //запрещаем прерывание
	char dt;
	DDRTEMP |= 1<<BITTEMP; //притягиваем шину
	_delay_us(485); //задержка как минимум на 480 микросекунд
	DDRTEMP &= ~(1<<BITTEMP); //отпускаем шину
	_delay_us(65); //задержка как максимум на 60 микросекунд
	if ((PINTEMP & (1<<BITTEMP))==0)//проверяем, ответит ли устройство
	{
		dt=1;//устройство есть
	} 
	else dt=0;//устройства нет
	//SREG = stektemp;// вернем значение стека
	_delay_us(420); //задержка как минимум на 480 микросекунд, но хватит и 420, тк это с учетом времени прошедших команд
	return dt; //вернем результат
}


//функция записи бита на устройство
void dt_sendbit(char bt)
{
	//char stektemp=SREG;// сохраним значение стека
	cli(); //запрещаем прерывание
	DDRTEMP |= 1<<BITTEMP; //притягиваем шину
	_delay_us(2); //задержка как минимум на 2 микросекунды
	if(bt)
		DDRTEMP &= ~(1<<BITTEMP); //отпускаем шину
	_delay_us(65); //задержка как минимум на 60 микросекунд
	DDRTEMP &= ~(1<<BITTEMP); //отпускаем шину
	//SREG = stektemp;// вернем значение стека
}
//функция записи байта на устройство
void dt_sendbyte(unsigned char bt)
{
	char i;		
	for(i=0;i<8;i++)//посылаем отдельно каждый бит на устройство
	{
		if((bt & (1<<i)) == 1<<i)//посылаем 1
			dt_sendbit(1);
		else //посылаем 0
			dt_sendbit(0);
	}	
}

//функция чтения бита с устройства
char dt_readbit(void)
{
	//char stektemp=SREG;// сохраним значение стека
	cli(); //запрещаем прерывание
	char bt; //переменная хранения бита
	DDRTEMP |= 1<<BITTEMP; //притягиваем шину
	_delay_us(2); //задержка как минимум на 2 микросекунды
	DDRTEMP &= ~(1<<BITTEMP); //отпускаем шину
	_delay_us(13);
	bt = (PINTEMP & (1<<BITTEMP))>>BITTEMP; //читаем бит
	_delay_us(45);
//	SREG = stektemp;// вернем значение стека
	return bt; //вернем результат
}

//функция чтения байта с устройства
unsigned char dt_readbyte(void)
{
	char c=0;
	char i;
	for(i=0;i<8;i++)
		c|=dt_readbit()<<i; //читаем бит
	return c;
}

//функция преобразования показаний датчика в температуру
int dt_check(void)
{
	unsigned char bt;//переменная для считывания байта
	unsigned int tt=0;
	if(dt_testdevice()==1) //если устройство нашлось
	{
		dt_sendbyte(NOID); //пропустить идентификацию, тк у нас только одно устройство на шине
		dt_sendbyte(T_CONVERT); //измеряем температуру
		_delay_ms(750); //в 12битном режиме преобразования - 750 милисекунд
		dt_testdevice(); //снова используем  те же манипуляции с шиной что и при проверке ее присутствия
		dt_sendbyte(NOID); //пропустить идентификацию, тк у нас только одно устройство на шине
		dt_sendbyte(READ_DATA); //даем команду на чтение данных с устройства
		bt = dt_readbyte(); //читаем младший бит
		tt = dt_readbyte(); //читаем старший бит MS
		tt = (tt<<8)|bt;//сдвигаем старший влево, младший пишем на его место, тем самым получаем общий результат
	}
	return tt;
}
char ds18b20_GetSign(unsigned int dt)
{
  //Проверим 11-й бит
  if (dt&(1<<11)) return 1;
  else return 0;
}
//преобразование температуры в единицы
char converttemp (unsigned int tt)
{
	char t = tt>>4;//сдвиг и отсечение части старшего байта
	return t;
}
Я не знаю как это вышло.Нужно всё проанализировать.Тут больше эксперемент.Спасибо.Попробую 2 3 датчика .Хотелось бы влажность измерять.
Аватара пользователя
AlanDrakes
Прорезались зубы
Сообщения: 236
Зарегистрирован: Пн июл 04, 2016 16:51:22
Откуда: Россия, Омск

Re: stm32 ds18b20

Сообщение AlanDrakes »

У Вас код для AVR в примере.
И всё же, смотрите:
У Вас функция "int dt_check(void)" уже возвращает знаковое число, а вы его пишете в беззнаковую переменную:

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

unsigned int temper_tt;
temper_tt=dt_check();
1. Замените "unsigned int temper_tt;" на "int temper_tt;"
2. Проверяйте знак самой переменной:

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

char ds18b20_GetSign(unsigned int dt)
{
  //Проверим 11-й бит
  if (dt&(1<<11)) return 1;
  else return 0;
}

char ds18b20_GetSign(int dt)
{
  if (dt < 0) return 1;
  else return 0;
}
3. Раз переменная стала знаковой - используйте деление (да, это медленнее, но даёт надёжный результат).

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

//преобразование температуры в единицы
char converttemp (unsigned int tt)
{
   char t = tt>>4;//сдвиг и отсечение части старшего байта
   return t;
}

char converttemp (int tt)
{
   char t = tt / 16;
   return t;
}
И раз уж на то пошло....

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

char text_array[5];
// Работает со значениями -55~127 градусов
// [-55n ] n = NULL-терминатор строки
// [-18n ]
// [ 0n  ]
// [ 22n ]
// [ 127n]
void temp_to_text(int temp, chat *text) {
	int temp_value = temp;
	if (temp_value < 0) {
		text[0] = '-';
		temp_value = -temp_value;
	} else {
		text[0] = ' ';
	}
	// Здесь temp_value всегда имеет положительное значение.
	if (temp_value < 10) {
		// Значения 0..9
		text[1] = '0' + temp_value;
		text[2] = 0;
	} else if (temp_value < 100) {
		// Значения 10..99
		text[1] = '0' + (temp_value / 10);
		text[2] = '0' + (temp_value % 10);
		text[3] = 0;
	} else {
		// Значения 100..127
		text[1] = '1'; // Потому что не больше 127
		temp_value = temp_value % 100;
		text[2] = '0' + (temp_value / 10);
		text[3] = '0' + (temp_value % 10);
		text[4] = 0;
	};
}
Функция заменяет на входе ваш sprintf(bufer0,"t=%c%2d *C\n\r",S,temper);

temp_to_text(-5, text_array); - в результате в объявленной переменной text_array будет содержаться "-5n??". n = нулевой байт (является признаком конца строки), "?" - байт, который не менялся функцией и сохраняет предыдущее значение, либо мусор.
temp_to_text(0, text_array); -> " 0n??"
temp_to_text(-58, text_array); -> "-58n?"
temp_to_text(199, text_array); -> " 199n"
Если нужен другой вариант окончания строки - нужно соответственно изменить фукнцию, либо копировать результат из переменной в другое место.
ivan dimir
Мучитель микросхем
Сообщения: 440
Зарегистрирован: Вс дек 29, 2019 08:05:21

Re: stm32 ds18b20

Сообщение ivan dimir »

Я заменил на uint16_t эту переменную.Спасибо за информацию я ценю людей которые больше меня знают.Наверное главное научится думать анализировать и эксперементировать.Я правда так машину разбил.Не умел ездить.Если боишься не садись.Наверное так и здесь.Сначала теория потом практика.А насчёт библиотеки.Да есть варианты.В stm32 i2c я вообще без функций обошёлся голые регистры и заработало.Но 1-wire сложнее на порядок.
Аватара пользователя
AlanDrakes
Прорезались зубы
Сообщения: 236
Зарегистрирован: Пн июл 04, 2016 16:51:22
Откуда: Россия, Омск

Re: stm32 ds18b20

Сообщение AlanDrakes »

1-wire не сложнее, он требует точных таймингов.
Самое смешное, что я сначала смог разобраться с работой как раз этого протокола, а уже потом заставил работать I2C на ATMega. Были там у меня какие-то странные заморочки.
На STM32 i2c... интересный. На новых чипах он удобнее, а вот на F103 - ну... там он требует больше телодвижений.
Ответить

Вернуться в «ARM»