Страница 1 из 1

Время выполнения функций библиотеки OneWire (для управления термодатчиками DS18B20).

Добавлено: 11 дек 2016, 18:59
Эдуард
Функции библиотеки Ардуино для работы с интерфейсом 1-Wire достаточно сложные и явно требуют для выполнения значительного времени. К тому же функции работают с последовательным интерфейсом, а значит, в цикле повторяются многочисленные операции с передачей и приемом битов, что вносит еще больше неопределенности по поводу времени выполнения.

Если программа Ардуино строится по традиционному принципу – последовательное выполнение программных блоков, то время выполнений операций с шиной 1-Wire не имеет большого значения. Одна, две, десять миллисекунд. Какая разница, если все происходит в цикле, например, 1 сек.

В случае с параллельным выполнением задач программы часто необходимо знать время выполнения таких сложных и критичных ко времени функций.

При разработке Ардуино контроллера элемента Пельтье я вынужден был реализовывать параллельное выполнение нескольких задач с разными временными циклами.
Остро встали вопросы:
    Сколько времени выделять на управление датчиками температуры DS18B20?
    Как организовывать обмен данными по 1-Wire шине?

Пришлось определить время выполнения функций класса OneWire. Я сделал это двумя способами:
    Посчитал теоретически, исходя из временных требований к операциям на шине 1-Wire.
    Измерил специальной программой. Я писал о ней в этой теме.

Для измерения времени выполнения функций библиотеки OneWire я подкорректировал программу, добавил библиотеку и объявление класса OneWire.

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

// определение времени выполнения функций OneWire

#include <OneWire.h>

OneWire sensD (16);  // датчик подключен к выводу 16 (A2)
unsigned int  timerValue; // значение таймера
byte bufData[9];  // буфер данных
 
void setup() {
  Serial.begin(9600);  // инициализируем порт
  // установки таймера 1
  TCCR1A = 0;
  TCCR1B = 0; 
}

void loop() {
  noInterrupts(); // запрет прерываний
  TCNT1H = 0; // сброс таймера
  TCNT1L = 0;
  TCCR1B = 1; // разрешение работы таймера

  // ---------- исследуемый программный блок ---------

   // sensD.reset();  // сброс шины
   // sensD.write(0xCC, 1); // пропуск ROM
   // sensD.write(0x44, 1); // инициализация измерения

  // sensD.reset();  // сброс шины
  // sensD.write(0xCC, 1); // пропуск ROM 
  // sensD.write(0xBE, 1); // команда чтения памяти датчика 
  // sensD.read_bytes(bufData, 9);  // чтение памяти датчика, 9 байтов
  // bufData[0]= sensDs.read();  // чтение памяти датчика, 9 байтов

  // if ( OneWire::crc8(bufData, 8) == bufData[8] ) { bufData[8]=0; }  // проверка CRC
  // else bufData[8]=1;
     
  // -------------------------------------------------

  TCCR1B = 0; // остановка таймера
  timerValue = (unsigned int)TCNT1L | ((unsigned int)TCNT1H << 8); // чтение таймера
  interrupts(); // разрешение прерываний
     
  // вывод на компьютер
  Serial.print( (float)(timerValue - 2) * 0.0625);
  Serial.println(" mks");
  delay(500);
}

По очереди открывал от комментариев функции и получал время выполнения. Результаты я свел в таблицу.

Функция Назначение Расчетное время Измеренное время
reset() Инициализация обмена 960 мкс 966 мкс
write() Запись байта 480 - 960 мкс 548 мкс
read() Чтение байта 480 - 960 мкс 522 мкс
read_bytes() Чтение блока байтов (9байтов) 4320 - 8640 мкс 4700 мкс
crc8 Вычисление контрольной суммы - 7,3 мкс

Получается, что последовательность самой простой инициализации измерения датчика DS18B20 требует 2063 мкс.

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

sensD.reset();  // сброс
sensD.write(0xCC, 1); // пропуск ROM
sensD.write(0x44, 1); // инициализация измерения


А на чтение температуры из датчика DS18B20 и проверку контрольной суммы требуется 6,8 мс.

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

sensD.reset();  // сброс
sensD.write(0xCC, POWER_MODE); // пропуск ROM 
sensD.write(0xBE, POWER_MODE); // команда чтения памяти датчика 
sensD.read_bytes(bufData, 9);  // чтение памяти датчика, 9 байтов
if ( OneWire::crc8(bufData, 8) == bufData[8] ) {  // проверка CRC

Re: Время выполнения функций библиотеки OneWire (для управления термодатчиками DS18B20).

Добавлено: 11 дек 2017, 22:30
dok
Приветствую, Эдуард. Большое спасибо за уроки. Классно ! У меня вопрос по датчикам DS18B20. Наваял я по Вашим урокам "нечто" с тремя датчиками. По дилетантски. Хочу родителям в деревню в баню термометр сделать. Парилка, моечная и предбанник по очереди. Хотелось, чтобы перед выводом температуры в парной , сначала выводилось слово "ПАР", например. Но к сожалению, чужеродный код не вставляется , а если компилируется, то не работает. Второй вариант: зажигать 3 отдельных светодиода напротив надписей "Парилка", "Моечная" , "Предбанник" Как пишут у Вас на форумах: Всю голову сломал. Помогите, пожалуйста.

// термометр, 3 датчикa DS18B20
#include <MsTimer2.h>
#include <Led4Digits.h>
#include <OneWire.h>

#define POWER_MODE 0 // режим питания, 0 - внешнее, 1 - паразитное

// тип индикатора 1; выводы разрядов 5,4,3,2; выводы сегментов 6,7,8,9,10,11,12,13
Led4Digits disp(1, 5,4,3,2, 6,7,8,9,10,11,12,13);

OneWire sensDs (14); // датчик подключен к выводу 14
OneWire sensDs2 (15); // датчик подключен к выводу 15
OneWire sensDs3 (16); // датчик подключен к выводу 16

byte bufData[9]; // буфер данных
byte bufData2[9]; // буфер данных 2
byte bufData3[9]; // буфер данных 3
float temperature; // измеренная температура
float temperature2; // измеренная температура 2
float temperature3; // измеренная температура 3

void setup() {
MsTimer2::set(2, timerInterrupt); // задаем период прерывания по таймеру 2 мс
MsTimer2::start(); // разрешаем прерывание по таймеру
Serial.begin(9600); // инициализируем порт, скорость 9600
}

void loop() {
sensDs.reset(); // сброс шины
sensDs.write(0xCC, POWER_MODE); // пропуск ROM
sensDs.write(0x44, POWER_MODE); // инициализация измерения
delay(900); // пауза 0,9 сек
sensDs.reset(); // сброс шины
sensDs.write(0xCC, POWER_MODE); // пропуск ROM
sensDs.write(0xBE, POWER_MODE); // команда чтения памяти датчика
sensDs.read_bytes(bufData, 9); // чтение памяти датчика, 9 байтов


if ( OneWire::crc8(bufData, 8) == bufData[8] ) { // проверка CRC
// данные правильные
temperature= (float)((int)bufData[0] | (((int)bufData[1]) << 8)) * 0.0625 + 0.03125;


// вывод измеренной температуры на индикаторы
if (temperature >= 0){


// температура положительная
disp.print((int)(temperature * 10.), 4, 1);
}
else {
// температура отрицательная
disp.print((int)(temperature * -1 * 10.), 3, 0);
disp.digit[3]= 0x40; } // отображается минус
disp.digit[1] |= 0x80; // зажечь точку второго разряда

// передача температуры на компьютер
Serial.print(" Температура 1 ");
Serial.println(temperature);
}
else {
// ошибка CRC, отображается ----
disp.digit[0]= 0x40;
disp.digit[1]= 0x40;
disp.digit[2]= 0x40;
disp.digit[3]= 0x40; }

//disp.digit[1]= B0000000; вывод на индикаторы слова "ПАР" (парилка)
//disp.digit[1]= B1110011;
//disp.digit[2]= B1110111;
//disp.digit[3]= B0110111;


//disp.tetradToSegCod(1,0);
delay(1000);
sensDs2.reset(); // сброс шины
sensDs2.write(0xCC, POWER_MODE); // пропуск ROM
sensDs2.write(0x44, POWER_MODE); // инициализация измерения
delay(900); // пауза 0,9 сек
sensDs2.reset(); // сброс шины
sensDs2.write(0xCC, POWER_MODE); // пропуск ROM
sensDs2.write(0xBE, POWER_MODE); // команда чтения памяти датчика
sensDs2.read_bytes(bufData2, 9); // чтение памяти датчика, 9 байтов

if ( OneWire::crc8(bufData2, 8) == bufData2[8] ) { // проверка CRC
// данные правильные
temperature2= (float)((int)bufData2[0] | (((int)bufData2[1]) << 8)) * 0.0625 + 0.03125;
// delay(1000);
// вывод измеренной температуры на индикаторы
if (temperature2 >= 0) {
// температура положительная
disp.print((int)(temperature2 * 10.), 4, 1);
}
else {
// температура отрицательная
disp.print((int)(temperature2 * -1 * 10.), 3, 0);
disp.digit[3]= 0x40; // отображается минус
}
disp.digit[1] |= 0x80; // зажечь точку второго разряда

// передача температуры на компьютер
Serial.print(" Температура 2 ");
Serial.println(temperature2);
}
else {
// ошибка CRC, отображается ----
disp.digit[0]= 0x40;
disp.digit[1]= 0x40;
disp.digit[2]= 0x40;
disp.digit[3]= 0x40; }
// else {
//disp.regen();
delay(1000);
{
sensDs3.reset(); // сброс шины
sensDs3.write(0xCC, POWER_MODE); // пропуск ROM
sensDs3.write(0x44, POWER_MODE); // инициализация измерения
delay(900); // пауза 0,9 сек
sensDs3.reset(); // сброс шины
sensDs3.write(0xCC, POWER_MODE); // пропуск ROM
sensDs3.write(0xBE, POWER_MODE); // команда чтения памяти датчика
sensDs3.read_bytes(bufData3, 9); // чтение памяти датчика, 9 байтов

if ( OneWire::crc8(bufData3, 8) == bufData3[8] ) { // проверка CRC
// данные правильные
temperature3= (float)((int)bufData3[0] | (((int)bufData3[1]) << 8)) * 0.0625 + 0.03125;
// delay(1000);
// вывод измеренной температуры на индикаторы
if (temperature3 >= 0) {
// температура положительная
disp.print((int)(temperature3 * 10.), 4, 1);
}
else {
// температура отрицательная
disp.print((int)(temperature3 * -1 * 10.), 3, 0);
disp.digit[3]= 0x40; // отображается минус
}
disp.digit[1] |= 0x80; // зажечь точку второго разряда

// передача температуры на компьютер
Serial.print(" Температура 3 ");
Serial.println(temperature3);
}
else {
// ошибка CRC, отображается ----
disp.digit[0]= 0x40;
disp.digit[1]= 0x40;
disp.digit[2]= 0x40;
disp.digit[3]= 0x40;
}
}
}
//-------------------------------------- обработчик прерывания 2 мс
void timerInterrupt() {
disp.regen(); // регенерация индикатора
}

Re: Время выполнения функций библиотеки OneWire (для управления термодатчиками DS18B20).

Добавлено: 12 дек 2017, 21:23
Эдуард
Здравствуйте!
Создайте новую тему в разделе "Проекты Ардуино" с названием, например, "Термометр для бани". Коротко опишите задачу. Напишите куда, что подключено к плате Ардуино. Если можете, приведите схему. Я помогу написать программу.

Re: Время выполнения функций библиотеки OneWire (для управления термодатчиками DS18B20).

Добавлено: 12 дек 2017, 21:23
Эдуард
Здравствуйте!
Создайте новую тему в разделе "Проекты Ардуино" с названием, например, "Термометр для бани". Коротко опишите задачу. Напишите куда, что подключено к плате Ардуино. Если можете, приведите схему. Я помогу написать программу.

Re: Время выполнения функций библиотеки OneWire (для управления термодатчиками DS18B20).

Добавлено: 12 дек 2017, 22:22
dok
Хорошо, Понял. Спасибо.
Скачал недавно программку по генерации кодов на 7-ми сегментный индикатор. http://www.getchip.net/posts/080-konver ... ndikatora/
Поигрался. Поэкспериментировал. Сделал следующую последовательность вывода: положительная температура первого датчика индицируется с тремя горизонтальными полосками в старшем разряде. disp.digit[3] = 0x49; Отрицательная -- как обычно, с минусом в старшем разряде. температура второго датчика -- с двумя горизонтальными полосками. disp.digit[3] = 0x48; температура третьего датчика с одной полоской -- горит сегмент "D" disp.digit[3] = 0x08 . Пока на этом всё. Спасибо, что ответили.