Кто любит RISC в жизни, заходим, не стесняемся.
Ответить

Re: stm32 ds18b20

Вт июн 14, 2022 00:13:15

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

Re: stm32 ds18b20

Вт июн 14, 2022 00:15:44

Ваша правда.
Думал одно, напечаталось другое.
Но, от этого, недостатки DS18B20 не менее значимы.

Re: stm32 ds18b20

Вт июн 14, 2022 00:17:08

... недостатки DS18B20 не менее значимы.

Приведите пример, я нахожу только плюсы :).
Кто-то до меня сделал датчик, калибровал, я просто включаю его и пользуюсь ...
Ну относительно, на первое приближение конечно ...
Последний раз редактировалось veso74 Вт июн 14, 2022 00:20:10, всего редактировалось 1 раз.

Re: stm32 ds18b20

Вт июн 14, 2022 00:19:48

Так, я же написал.
Низкая точность.
Очень медленная реакция.
В некоторых применениях, крупный корпус.
Последний раз редактировалось Карбофос Вт июн 14, 2022 00:21:02, всего редактировалось 1 раз.

Re: stm32 ds18b20

Вт июн 14, 2022 00:20:26

Код:
... Очень медленная реакция.

Странное заявление. Для тепловой времеконстант, которая больше похожа на интегрирование из-за массы.
И почему мы так спешим за измерение температурой? :) рассчитайте беглло времяконстант изменения P * массы нагревателя-нагрузки?
Последний раз редактировалось veso74 Вт июн 14, 2022 01:15:16, всего редактировалось 2 раз(а).

Re: stm32 ds18b20

Вт июн 14, 2022 00:23:12

Странный вопрос.
Надо знать температуру здесь и сейчас.
Спасибо за внимание.

Re: stm32 ds18b20

Вт июн 14, 2022 00:25:32

Можете измерить в 750 мс для 12 бит. если медленное, может быть, меньше бит.
Ето медленно для датчика вес 3,00 грамма? Нагрев или охлаждение с окружающими металлами не будет быстрее.

Re: stm32 ds18b20

Вт июн 14, 2022 00:32:02

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

Re: stm32 ds18b20

Вт июн 14, 2022 00:53:10

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 раз(а).

Re: stm32 ds18b20

Вт июн 14, 2022 00:55:36

Это-же фильтр, среднее берётся.
И, откуда ты эти 7 секунд взял? Придумал?
Или, в сферическом вакууме?
Последний раз редактировалось Карбофос Вт июн 14, 2022 00:58:08, всего редактировалось 1 раз.

Re: stm32 ds18b20

Вт июн 14, 2022 00:57:49

из пдф-а MF52

Re: stm32 ds18b20

Вт июн 14, 2022 00:58:50

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

Всё, досвидос.
Последний раз редактировалось Карбофос Вт июн 14, 2022 01:00:14, всего редактировалось 1 раз.

Re: stm32 ds18b20

Вт июн 14, 2022 01:00:10

В воздухе, в покое, без обдува.
---
Более - весит больше в граммах. Тепловая времяконстанта, интегратор. Вот почему и писание "датчик - медленный" не имеет смысла для датчика температуры, потому что скорость физическое изменение температуры массы больше, чем максимуме (750 мс) для одного измерения.

info ds18x

Вт июн 14, 2022 01:20:51

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

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

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

----------
ну и скажу крамолу....
разогрев датчика = около ДЕСЯТЫХ градуса...

Re: stm32 ds18b20

Вт июн 14, 2022 01:33:02

Да, самонагрев не высокий. При 3 сек подготовки/3 сек снятия данных зимой (около 11-13 градусов), при вкл. первые минуты увеличивается примерно с 0,2-0,3 оC. 5V, 4,7 kOm.

Re: stm32 ds18b20

Вт июн 14, 2022 16:42:07

Спойлер
int16_t curr_temp;extern uint8_t ow_Answ[9];

Хорошо у меня есть переменная int tt=int16_t curr_temp;А вторая переменная это массив?и почему экстерн.?И как всё это вывести на lcd7

Потому что в сообщении выше я сказал, что массив используется другим файлом исходника (ds18b20.c), который в него СЧИТЫВАЕТ Scratch Pad из датчика. Была у меня такая потребность в процессе разработки. Потом файл перетёк в этот проект. Просто потому что работает и позволяет делать интересные вещи асинхронно.

Так покажите полную картину вывода на экран LCD?.А то кусочек секса не интересно.

На какой 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 - Вот сайт, с которого я взял картинку.

Re: stm32 ds18b20

Чт июн 16, 2022 19:50:12

Вообщем как то так вышло правда взял проект на 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);
    
    }
}

[spoiler]
[spoiler]
Код:
#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 датчика .Хотелось бы влажность измерять.

Re: stm32 ds18b20

Пт июн 17, 2022 07:09:15

У Вас код для 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"
Если нужен другой вариант окончания строки - нужно соответственно изменить фукнцию, либо копировать результат из переменной в другое место.

Re: stm32 ds18b20

Пт июн 17, 2022 07:21:06

Я заменил на uint16_t эту переменную.Спасибо за информацию я ценю людей которые больше меня знают.Наверное главное научится думать анализировать и эксперементировать.Я правда так машину разбил.Не умел ездить.Если боишься не садись.Наверное так и здесь.Сначала теория потом практика.А насчёт библиотеки.Да есть варианты.В stm32 i2c я вообще без функций обошёлся голые регистры и заработало.Но 1-wire сложнее на порядок.

Re: stm32 ds18b20

Пт июн 17, 2022 07:48:37

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