Почистил скетч примера работы с DS18B20 из библы OneWire..

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

WarIock пишет:

Остался вопрос, что будет, если их не запрещать. Но, чувствую, узнать опытным путем будет быстрее.

Если прервёте хоть сколько-нибудь надолго - сломается нахрен. Вы почитайте описание протокола OneWire - там всё построено на микросекунднных таймингах. Сигал должен быть определённой длительности. Будет длинее/короче - приплыли. Запасы там не очень большие. Хотя, может Вы в них и уложитесь. Смотрите сами. Протокол достаточно подробно описан в даташитре на датчик

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

WarIock пишет:

Камрады, такой вопрос... Опрос датчиков тормозит прерывания. Как избавится? Можно это как-то обойти? Если более конкретно, то есть программный диммер, который, используя датчик перехода через 0, повешенный на прерывание, управляет семистором. Как только к этому коду добавляется одна строка ds.write(0x??), появляется еле заметное мерцание, 2 строки - мерцание оч заметно.. и т д, в итоге мигание с частотой опроса. Временно решил проблему отправкой команд датчикам раз в секунду по одной, но мерцание все равно есть. Коллега с телевизором в середине темы испытывал схожие проблемы, скорее всего по той же причине.

Это напоминает мне анекдот: Почему когда я стучу головой об стену, у меня болит голова. Может я заболел. Вы можете опрашивать датчики после преравания. Или у вас прерывания занимают всю работу ЦПУ.

bwn
Offline
Зарегистрирован: 25.08.2014

Не спец в прерываниях, но терзают смутные сомненья, на выше означенном TV сигнале (те же 50Гц) срывало синхронизацию при полном опросе двух датчиков, при разделении опроса по одному все стабилизировалось. Здесь мигает при полной расчлененке опроса одного датчика, может что то с алгоритмом обработки прерывания не так?

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Зачем датчик перехода через 0 вешать на прерывание?
На пик контроллере тау тела цикла хватало обрабатывать этот датчик с лихвой, не думаю, что здесь хуже

WarIock
Offline
Зарегистрирован: 10.01.2017

ЕвгенийП пишет:

но при этом боятся, что их ценнейший код украдут)

Тут другое. Мне за него стыдно. Это как к доктору с грязными труселсями.

 

bwn пишет:

Не спец в прерываниях, но терзают смутные сомненья, на выше означенном TV сигнале (те же 50Гц) срывало синхронизацию при полном опросе двух датчиков, при разделении опроса по одному все стабилизировалось. Здесь мигает при полной расчлененке опроса одного датчика, может что то с алгоритмом обработки прерывания не так?

Да я не скажу, что вот прям мигает. С такой расчлененкой (это ты метко подметил ) иногда может быть скачечек на малых яркостях - чуть позже закроется или откроется, вот и разовое изменение яркости. Мне просто костыли такие напрягают. А алгоритм весь я написал выше.  Сейчас еще отдельно ds.reset() выделил - в нем, оказывается, тоже noInterrupts() - Interrupts(); присутствует, даже трижды. И delayMicroseconds. С тв там проблема тоже не полностью с одним датчиком ушла - частичное подергивание оставалось. 

Так то костыль есть, результат вроде пока не раздражает...  Единственная альтернатива, которую вижу на данный момент - править библиотеку с вероятность рандомно получать  мусор от датчика.  Но это требует изрядно времени на отладку.

На отдельном перрывании, потому, что, если я правильно считаю, переход переменного тока через 0 дважды за период, итого 100гц при частоте переменки в 50. Я ж не тэном управляю, там период можно в неск сек выставлять...

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

WarIock пишет:

На отдельном перрывании, потому, что, если я правильно считаю, переход переменного тока через 0 дважды за период, итого 100гц при частоте переменки в 50. Я ж не тэном управляю, там период можно в неск сек выставлять...

Я как понял. Переход через 0 вызывает перерывание и вы держите это прерывание, пока нужная мощность не выставится. Так что выходит на 100% мощьности идет 100% прерывания и мощности процессора. Но так как полная мощность не всегда нужна , то вы на остатках ресурса ЦП опрашиваете датчики. Диковато-такое решение.  

WarIock
Offline
Зарегистрирован: 10.01.2017

Я готов к конструктивной критике, но другого решения тупо не вижу - чтоб не моргало, резаться должен каждый полупериод. А почему думаешь, что проц то на всю загружен? Ну срабатывает прерывание, пускает таймер... Таймер это таймер, он отдельным потоком работает. millis тоже на таймере висит, все время работает. Я не знаю, тут ссылки на сторонние ресурсы можно, или нет, если что, тапками не пинать. Первое , что дельное попалось http://robotosha.ru/arduino/multitasking-and-interrupts-arduino.html

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Ну к многозадачности я банально подошел с другой стороны. С моей точки зрения надо при прерывании нужно сделать отметку по millis() или micros() и отпустить процессор на другие задачи, периодически отлавливая время отключения.

WarIock
Offline
Зарегистрирован: 10.01.2017

Судя по сообщениям на амперике, идея управлять триаком у тебя крутится. Реализуй. С лампочкой, через тело программы. Потом расскажешь. А я тебе и так скажу: получишь рандомный стробоскоп. Потому, что если цикл не совпадет с таймером даже на 1 мкс - такт будет пропущен. В итоге лампа вовремя или не загорится, или не погаснет. В итоге скачки яркости. Причем таймер значение должен уметь менять, иначе яркость будет фиксированной. Подогнать "цикличность цикла" можно только через delay, но разрешение оного никак не соответствует задачам. Да и смысл мероприятия теряется. ИМХО.

А для управления каим либо нагревателем вполне себе вариант. Если считаешь возможным помеху в сеть гнать.

Трабл то не в том, что прерывание проц дергает, а в том, что onewire дергает даже прерывания. 

bwn
Offline
Зарегистрирован: 25.08.2014

Я делал с этой библиотекой, но не освещение, а нагрев четырьмя прожекторами, соответственно о мигании что то сложно сказать, не присматривался.
Если мощность не очень большая, может есть смысл перейти на MOSFET и ШИМ?

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

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

/*
  #1 Серва1 упр. выв -> 12    (servo1_pin)
               +5В -> +5В
               GND -> GND
  #2 резистор  нижний выв   -> GND
             средний выв  -> A0    (R1_pin)
             верхний выв  -> +5
*/
//#1
const int servo1_pin = 12;
uint16_t servo1_value = 544 ; // величина на серве 544-2400 мкс.
uint8_t servo1;//

//#2
const int R1_pin = A0;// нога резистора

void setup() {
  //#1
  pinMode      (servo1_pin, OUTPUT);
  digitalWrite (servo1_pin, servo1 = 0);
  //#2
}
void loop() {
  //#1 20 миллисекунд обслуживание сервы 1 и 2
  static uint32_t past_1 = 0 ;
  if  (servo1 && (micros() - past_1 >= servo1_value))
    digitalWrite (servo1_pin, servo1 = 0);
  if (micros() - past_1 >= 20000) { // если прошло 20000 микросек //  это автозапуск импульса
    past_1 = micros() ;                                           // вставьте эти команды в прерывание
    digitalWrite (servo1_pin, servo1 = 1);                        // и будет вам формирование нужного импульса 
  }                                                               // при освобождении процессора
  //#2
  static uint32_t past_2 = 0 ;
  if (millis() - past_2 >= 200) { // если прошло 200000 микросек
    past_2 = millis() ;
    servo1_value = map (analogRead(R1_pin), 0, 1023, 544, 2400);
  }
}

 

WarIock
Offline
Зарегистрирован: 10.01.2017

bwn, а сторки типа 

    attachInterrupt(0, detect_up, LOW);  // настроить срабатывание прерывания interrupt0 на pin 2 на низкий уровень
    StartTimer1(halfcycle, 40); //время для одного разряда ШИМ
    StopTimer1(); //остановить таймер

в твоей ссылке тебя не смущают? Точно тоже, что у меня, только без левой библиотеки. Детектор 0 на прерывании запускает таймер отсчета.  Судя по схожим названиям и коментариям, даже исходный код у нас из одинакового источника.

qwone, просто сделай, ок? Я не знаю как еще объяснить тебе, что работать это не будет. С рисунками почитай. http://avrproject.ru/publ/poleznaja_informacija/setevoj_dimmer_220v_na_mikrokontrollere/4-1-0-140

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

WarIock, вам нужно из прерываний detectUp/Down вызывать специальную функцию, которая будет при каждом вызове  контролировать текущий ход опроса датчиков, и отдавать новые команды по мере необходимости и возможности. Таким образом всё всегда будет  крутится  в прерываниях,  и никто никому мешать не будет. Но функция должна запускать команды  строго порционно,  с расчётом что бы точно успеть отработать "порцию" до наступления следующего прерывания.  Это довольно сложная задача, не для начинающих.

WarIock
Offline
Зарегистрирован: 10.01.2017

Друзья, пошу прощения, не знал, что тут принято на Вы, на форумах это редкость, исправлюсь.

Если я верно понял мысль, то Вы предлагаете связать этапы опроса датчиков с тактами прерывания. 

Так то это вроде не сложно, но тут какая канитель... такт перывания  200 мкс. А в onewire тот же reset 

uint8_t OneWire::reset(void)
{
	IO_REG_TYPE mask = bitmask;
	volatile IO_REG_TYPE *reg IO_REG_ASM = baseReg;
	uint8_t r;
	uint8_t retries = 125;

	noInterrupts();
	DIRECT_MODE_INPUT(reg, mask);
	interrupts();
	// wait until the wire is high... just in case
	do {
		if (--retries == 0) return 0;
		delayMicroseconds(2);
	} while ( !DIRECT_READ(reg, mask));

	noInterrupts();
	DIRECT_WRITE_LOW(reg, mask);
	DIRECT_MODE_OUTPUT(reg, mask);	// drive output low
	interrupts();
	delayMicroseconds(480);
	noInterrupts();
	DIRECT_MODE_INPUT(reg, mask);	// allow it to float
	delayMicroseconds(70);
	r = !DIRECT_READ(reg, mask);
	interrupts();
	delayMicroseconds(410);
	return r;
}

Имеет 3 delayMicroseconds между noInterrupts().  Тут, похоже, не попасть будет.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Эти делэи некритичны, а функцию можно разорвать на части и выполнять по частям. Я же Вам советовал прочитать описание протокола OneWire - почитайте.

WarIock
Offline
Зарегистрирован: 10.01.2017

Прошу прощения, я таки не очень понимаю... Т е Вы предлагаете отказаться от onewire, а тот же reset вынести в отдельную функцию или, точнее, несколько функций, делеи между которыми будут завязаны на такты прерывания. Так?

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

WarIock, если у Вас пошла такая пьянка, Вам нужно просто выбросить эту библиотеку написать всё ручками на  прерываниях от таймера, так чтобы не было никаких задержек вовсе.

Вы поймите, протоколу не мешают как таковые прерывания. Он их запрещает только для того, чтобы соблюсти правильные тайминги. Так это делается и без задержек с запрешёнными прерываниями.

Определяете список состояний в которых может находиться Ваш протокол (на бумажку выписываете). Вместо задержки, заводите таймер на нужное количество микросекунд, а сами занимаетесь своими делами. По прерыванию таймера выполняете действие (в зависимости от текущего состояния), меняете состояние и, если нужна ещё задержка, опять заводите таймер на нужное количество микросекунд. При таком подходе у Вас вообще не будет задержек. Вы получите неблокирующую версию библиотеки для работы с датчиком.

Serg1
Offline
Зарегистрирован: 04.12.2015

Dimax, подскажите, чтоб сделать опрос датчиков не каждую секунду а раз в 8 секунд , где нужно это изменить?

WDTCSR=(1<<WDIE)| (1<<WDP2)|(1<<WDP1); // разрешение прерывания + выдержка 1 секунда

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

Serg1, вот так: WDTCSR=(1<<WDIE)| (1<<WDP3)|(1<<WDP0);

YuraSh
Offline
Зарегистрирован: 18.01.2013

Что я делаю не так? Из этой темы взят пример.

ds.write(0xBE); // Read Scratchpad (чтение регистров)
temp =  ds.read() | (ds.read() << 8); //прочитаны 2 байта
temp_kot = temp / 16.0;

Переменные Double.

Резолюция 12 бит

Все работает четко. Захотелось выводить температуру с десятыми. Выдает с шагом 0,5. Сделал так...

Pyotr пишет:

(t*10)>>4   =  (t*10)/16 - получаем целое число равное температуре в десятых градуса, сотые отбрасываются: число 214 соответствует температуре 21,4 *С

выдает с шагом 5 (760, 765,770) а хотелось бы (760, 761, 762....)

bwn
Offline
Зарегистрирован: 25.08.2014

temp_kot = (float)temp / 16.0; Вроде так.

YuraSh
Offline
Зарегистрирован: 18.01.2013

Разобрался. Недочитал и схитрож...ил.

Написано ведь снять ВСЕ ремарки:

// снять все ремарки если нужно поменять разрешение
//  ds.reset(); // сброс шины
//  ds.select(addr); //выставить адрес
//  ds.write(0x4E); // разрешение записать конфиг
//  ds.write(0x7F); // Th контроль температуры макс 128грд
//  ds.write(0xFF); //Tl контроль температуры мин -128грд
//  ds.write(0x60); // 0x60 12-бит разрешение, 0x00 -9бит разрешение

А я решил, что будет достаточно для всех датчиков скопом

ds.reset(); // сброс шины
ds.write(0x60); // 0x60 12-бит разрешение, 0x00 -9бит разрешение

Вот оно и в дефолтном 9-бит режиме и работало.

Sanyaba
Sanyaba аватар
Offline
Зарегистрирован: 27.07.2015

подскажите пожалуйста как использовать код из 47 коммента 

http://arduino.ru/forum/programmirovanie/pochistil-sketch-primera-raboty-s-ds18b20-iz-bibly-oneware#comment-174443

//***Функция считывания температуры c Далласов*****
void dallRead(unsigned long interval){
  static unsigned long prevTime = 0;
  if (millis() - prevTime > interval) { //Проверка заданного интервала
  static boolean flagDall = 0; //Признак операции
  prevTime = millis();
  flagDall =! flagDall; //Инверсия признака
  if (flagDall) {
    ds.reset();
    ds.write(0xCC); //Обращение ко всем датчикам
    ds.write(0x44); //Команда на конвертацию
    flagDallRead = 1; //Время возврата в секундах
  }
  else {
    byte i;
     int temp;
    for (i = 0; i < 3; i++){ //Перебор количества датчиков
     ds.reset();
     ds.select(addr[i]);
     ds.write(0xBE); //Считывание значения с датчика
     temp = (ds.read() | ds.read()<<8); //Принимаем два байта температуры
     Temp[i] = (float)temp / 16.0; 
     flagDallRead = 2; //Время возврата в секундах
     }
   }
  }
}
//--------------------------------------------------

Вызов из loop - dallRead(flagDallRead*1000);

bwn
Offline
Зарегистрирован: 25.08.2014

Объявляете глобально массив адресов датчиков: byte addr[3][8] = {{.......},{......},{.....}}; Массив температур: float Temp[3]; и переменную времени обработки: byte flagDallRead;
Вставляете функцию в скетч и вызываете через: dallRead(flagDallRead*1000) значения температуры будут в массиве Temp[]. Количество датчиков изменяется размерами массивов адресов и температур и значением for в функции. Время повторного измерения выставляется в 23 строке. Если нужны более точные, чем секундные,  интервалы - flagDallRead объявляем как unsigned long и выставляем задержки в миллисекудах, соответственно при вызове на 1000 не перемножать.

Sanyaba
Sanyaba аватар
Offline
Зарегистрирован: 27.07.2015

2 часа промаялся, так и не запустил код, ошбки invalid use of void expression...

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Давайте полную ошибку и текущую версию кода. Чего так-то гадать?

Sanyaba
Sanyaba аватар
Offline
Зарегистрирован: 27.07.2015
#include <TM74HC595Display.h>
#include <TimerOne.h>

int SCLK = 7;
int RCLK = 6;
int DIO = 5;

TM74HC595Display disp(SCLK, RCLK, DIO); // 4-bit led tube module

#include <OneWire.h>
OneWire ds(10); // 10 pin
byte addr[8] = {0X28, 0XFF, 0XFD, 0X50, 0XA1, 0X16, 0X05, 0XFE}; // 28FFFD50A11605FE
float Temp[3];
byte flagDallRead;

void setup() {
 
  Timer1.initialize(1500); // set a timer of length 1500
  Timer1.attachInterrupt(timerIsr); // attach the service routine here

  ds.reset(); // сброс шины
  //  ds.select(addr2); //выставить адрес
  //  ds.write(0x4E); // разрешение записать конфиг
  //  ds.write(0x7F); // Th контроль температуры макс 128грд
  //  ds.write(0xFF); //Tl контроль температуры мин -128грд
  ds.write(0x3F); // точность 0,5гр = 1F; 0,25гр = 3F; 0,125гр = 5F; 0,0625гр = 7F
  
}

void loop() {  
  
  disp.dispFloat(dallRead(flagDallRead*1000), 2);  //send led tube counter 0-9999 hide zero
  delay(100);
  //disp.clear();
}


void timerIsr() {
  disp.timerIsr();
}

void dallRead(unsigned long interval){
  static unsigned long prevTime = 0;
  if (millis() - prevTime > interval) { //Проверка заданного интервала
    static boolean flagDall = 0; //Признак операции
    prevTime = millis();
    flagDall =! flagDall; //Инверсия признака
    if (flagDall) {
      ds.reset();
      ds.write(0xCC); //Обращение ко всем датчикам
      ds.write(0x44); //Команда на конвертацию
      flagDallRead = 1; //Время возврата в секундах
    } else {
      byte i;
      int temp;
      for (i = 0; i < 3; i++){ //Перебор количества датчиков
        ds.reset();
        ds.select(addr[i]);
        ds.write(0xBE); //Считывание значения с датчика
        temp = (ds.read() | ds.read()<<8); //Принимаем два байта температуры
        Temp[i] = (float)temp / 16.0; 
        flagDallRead = 2; //Время возврата в секундах
      }
    }
  }
}
при компиляции:
void select(const uint8_t rom[8]);
 ^
exit status 1
invalid use of void expression
ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Блин, ну писал же, давайте полное сообщение об ошибке. Там ведь и номер строки был, а теперь мне его самому искать. Сейчас поищу, но впредь, имейте совесть. Сейчас посмотрю.

Sanyaba
Sanyaba аватар
Offline
Зарегистрирован: 27.07.2015
sketch_feb28a:32: error: invalid use of void expression
disp.dispFloat(dallRead(flagDallRead*1000), 2);  //send led tube counter 0-9999 hide zero
ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Про эту ошибку всё понятно, у Вас функция dallRead описана в 42 строке как не возвращающая никакого значения.

А в 32 строке Вы пытаетесь возвращённое ею значение передать функции dispFloat.

Вы уж определитесь. Если она что-то должна возвращать, так опишите её соответсвующим типом и пусть возвращает. А если она ничего не возвращает (как сейчас), так что именно Вы собрались передавать dispFloat?

Но там есть ещё оибка. В 58 строке Вы передаёте функции select один байт, а она ждёт массива из 8 байтов.

bwn
Offline
Зарегистрирован: 25.08.2014

Sanyaba, ведь написал же, что за что отвечает. Функция сделана на несколько датчиков, у Вас один. Соответственно адресный массив стал одномерным, зачем его крутить в форе? Для температуры массив стал не нужен.

Убираете for, в 58 строке ds.select(addr); , 61 строка Temp = ....., 13-я float Temp; и передавайте значение из Temp, температура там хранится, она глобальная.

Sanyaba
Sanyaba аватар
Offline
Зарегистрирован: 27.07.2015

Парни, я новичек в этом всем и для меня очень сложно, на практике применяю куски кода которые есть в сети и свои наработки, но бывают ситуации как сейчас что не могу разобраться и ВАМ за это огромное человеческое спасибо!

добавлено позже: Спасибо заработало.

 

WarIock
Offline
Зарегистрирован: 10.01.2017

Жуто извиняюсь за дикий оффтоп, но беда - не отписаться никак от уведомлениях на почту о новых коментариях в этой теме. Писать в другую тему просто опасаюсь, чтобы спамом не завалило. При переходе по ссылке из письма "Отключить уведомления" пишет "отключено", но реально не отключает. В профиле в "Следить" значится эта тема, но там можно только перейти сюда, кнопки удалить нет. В "изменить" в "уведомления по e-mail " стоит "не уведомлять"...  Даже где удалиться найти не могу...

bwn
Offline
Зарегистрирован: 25.08.2014

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

Serg1
Offline
Зарегистрирован: 04.12.2015

Dimax, здравствуйте. 

Успешно использую ваш метод с датчиками DS18.

Возможно ли его применить для датчикиков DHT22?

И как?

ProstoAlex
Offline
Зарегистрирован: 21.01.2015

Димах и всем в этой теме - спасбио большое за классный код!

очень долго мучался и неработой сериал порта при считывании датчиков.

Этот код все решил!

 

Sanyaba
Sanyaba аватар
Offline
Зарегистрирован: 27.07.2015

Выложу код того что получилось для одного датчика DS18b20, может кому пригодится ;)

#include <OneWire.h>
OneWire ds(10); // 10 pin к которому подключен датчик DS18b20
byte addr[8] = {0X28,0XFF,0X05,0XCB,0X50,0X16,0X04,0X6B};// ROM = 28 FF 5 CB 50 16 4 6B
float Temp; // Переменная в которой будет храниться полученная температура
byte flagDallRead;


void setup() {
  ds.reset(); // сброс шины
  //  ds.select(addr2); //выставить адрес
  //  ds.write(0x4E); // разрешение записать конфиг
  //  ds.write(0x7F); // Th контроль температуры макс 128грд
  //  ds.write(0xFF); //Tl контроль температуры мин -128грд
  ds.write(0x7F); // точность 0,5гр = 1F; 0,25гр = 3F; 0,125гр = 5F; 0,0625гр = 7F;
  
}

void loop() {  
  dallRead(flagDallRead*100);
  // Далее к коде выводим данные из переменной Temp

}

void dallRead(unsigned long interval){
  static unsigned long prevTime = 0;
  if (millis() - prevTime > interval) { //Проверка заданного интервала
    static boolean flagDall = 0; //Признак операции
    prevTime = millis();
    flagDall =! flagDall; //Инверсия признака
    if (flagDall) {
      ds.reset();
      ds.write(0xCC); //Обращение ко всем датчикам
      ds.write(0x44); //Команда на конвертацию
      flagDallRead = 1; //Время возврата в секундах
    } else {
      byte i;
      int temp;
      ds.reset();
      ds.select(addr);
      ds.write(0xBE); //Считывание значения с датчика
      temp = (ds.read() | ds.read()<<8); //Принимаем два байта температуры
      Temp = (float)temp / 16.0; 
      flagDallRead = 2; //Время возврата в секундах
    }
  }
}

Я запитывал по 2-м проводам вот так.

*конденсатор желательно с низким ESR

bwn
Offline
Зарегистрирован: 25.08.2014

Sanyaba пишет:

Выложу код того что получилось для одного датчика DS18b20, может кому пригодится ;)

В 19 строке ошибка, должно быть ......*1000.

Sanyaba
Sanyaba аватар
Offline
Зарегистрирован: 27.07.2015

да хоть 1 хоть 10000 поставь, это интервал опроса.. смотри 24 строку

bwn
Offline
Зарегистрирован: 25.08.2014

Sanyaba пишет:

да хоть 1 хоть 10000 поставь, это интервал опроса.. смотри 24 строку

Ну спасибо, отец родной, открыл истину. Я то когда эту функцию писал, весь извелся, какую мне цифирку там поставить. А ты вона как быстро.
Прежде, чем  разъяснять, сам разберись как работает.

Факт, что работает корректно при любых значениях, не значит, что ты понимаешь как это происходит.

Sanyaba
Sanyaba аватар
Offline
Зарегистрирован: 27.07.2015

Спасибо за функцию.

smile-777
Offline
Зарегистрирован: 26.05.2017

А может человеку просто стыдно показать свой говнокод? ))) Не в обиду никому, я по себе сужу ))

ProstoAlex
Offline
Зарегистрирован: 21.01.2015

коллеги, а скажите:

в схемах с подключением через диод-конденсатор указывают кондер 1...10 мкФ.

я правильно понимаю, что кашу маслом не испортишь, и можно постаивть хоть 100 - хуже не будет?

или я о чем-то не догадываюсь?

 

и еще - имеет смысл для 5 датчиков при очень плохой линии (экран+ 2 жилы, длина 20 м., несколько "лучей", причем сходящихся в разных точках) повесить керамические кондеры или они уже включены внутрь?

 

спасибо!

Katroha
Offline
Зарегистрирован: 28.02.2017

Здавствуйте, помогите плиз наченающему ученику в ардуино.

Использовал скетч с 4 сообщения для щитывания 3 датчиков DS18B20 и вывод их на LCd, пока все работает но не могу избавиться от лишнего символа, на фото посредине, точнее не пойму от куда он береться. спс.

ХЗ как код сгорнуть...

 

 

#include <OneWire.h>
OneWire  ds(5);   //пин для датчиков
byte addr1[8]={0x28,0xFF,0xC8,0x8A,0xC2,0x15,0x01,0xC7};  //двигатель
byte addr2[8]={0x28,0xFF,0x66,0x18,0xC2,0x15,0x02,0x52};  //салон
byte addr3[8]={0x28, 0xFF, 0xAA, 0xDB, 0xA2, 0x16, 0x04, 0xCD};  //
volatile int temp1,temp2,temp3;

#include "RTClib.h"
RTC_DS1307 RTC;

#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x3f, 16, 2);
#if defined(ARDUINO) && ARDUINO >= 100
#define printByte(args)  write(args);
#else
#define printByte(args)  print(args,BYTE);
#endif
int analog = A0;                     //пульт руль
int Gabarit = 2;                      //вход lsd
int LedLsd = 6;                       //выход lsd
int inPin = 3;                       //газ
int analogInput = A6;                //вход для вольтметра
float vin = 0;                       // ВХОДНОЕ ЕАПРЯЖЕНИЕ

                                     //Символ градуса
byte grad[8] = {
  0b01100,
  0b10010,
  0b10010,
  0b01100,
  0b00000,
  0b00000,
  0b00000,
  0b00000
};


void setup(void) {
Serial.begin(9600);

WDTCSR=(1<<WDCE)|(1<<WDE); //установить биты WDCE WDE (что б разрешить запись в другие биты
WDTCSR=(1<<WDIE)| (1<<WDP2)|(1<<WDP1); // разрешение прерывания + выдержка 1 секунда
// снять все ремарки если нужно поменять разрешение
//  ds.reset(); // сброс шины
//  ds.select(addr2); //выставить адрес
//  ds.write(0x4E); // разрешение записать конфиг
//  ds.write(0x7F); // Th контроль температуры макс 128грд
//  ds.write(0xFF); //Tl контроль температуры мин -128грд
//  ds.write(0x60); // 0x60 12-бит разрешение, 0x00 -9бит разрешение


    pinMode(8, INPUT);     
     pinMode(9, INPUT); 
     pinMode(10, INPUT);  
     pinMode(11, INPUT);  
     pinMode(12, INPUT);  
   pinMode(analogInput, INPUT);     //пин А6 как вход
     pinMode(LedLsd, OUTPUT);         //пин 6 как выход для LSD
     pinMode(Gabarit, INPUT);         //пин 2 как вход от габаритов для LSD
     
  lcd.init();                       // Инициализация lcd 
   lcd.backlight();                 // Включаем подсветку
  
   lcd.createChar(0, grad);           //Символ градуса
   lcd.setCursor(4, 0);               //курсор
   lcd.print("Hello :)");     //надпись при включении
   lcd.setCursor(3, 1);               //курсор
   lcd.print("Good day.");     //надпись при включении
   delay(1500);                       //задержка
   lcd.clear();                       //очистить екран

              if (! RTC.isrunning()) 
  {
                   // строка ниже используется для настройки даты и времени часов
                 RTC.adjust(DateTime(__DATE__, __TIME__));
  }


}

void loop() {
 
  Serial.print("Temp1= ");
Serial.print(temp1/16.0);
Serial.print("   ");
Serial.print("Temp2= ");
Serial.println(temp2/16.0);
                                                //часы

 DateTime now = RTC.now();
  DateTime future (now.unixtime() + 7 * 86400L + 30);
  lcd.setCursor(11, 0);
  lcd.print(future.hour(), DEC);
  lcd.print(':');
  lcd.print(future.minute(), DEC);

                                               //газ
 
  
 if (digitalRead(inPin))
  {                                            
  lcd.setCursor(5, 0);
  lcd.print("GAZ");
  }
  
 else
  {  
  lcd.setCursor(5, 0);
  lcd.print(" - ");
 } 

  lcd.setCursor(0, 0);        //темп улица
  lcd.print("");
  lcd.print(temp3/16);
  lcd.printByte(0);

 
  lcd.setCursor(0, 1);        //темп салон
  lcd.print("");
  lcd.print(temp1/16);
  lcd.printByte(0);

   
  lcd.setCursor(5, 1);           //темп двигатель
  lcd.print("");
  lcd.println(temp2/16);
  lcd.printByte(0);

                                                         //вольтметр

                                                       
    vin = float(analogRead(analogInput))/18.3;    //подстроичное число для показа вольтметра
  lcd.setCursor(11, 1);
  lcd.print("");
  lcd.print(vin, 1);
  lcd.print("V");


   analog=analogRead(14);                  //считываем сигнал с пина АЦП 
                  
     if(analog>750&&analog<820)              // k1 - up
     {   
     
       pinMode(8, OUTPUT);  
       digitalWrite(8,LOW); 
       delay(50);
       pinMode(8, INPUT); 
       delay(150); 
        }      
          
      if(analog>300&&analog<400)           //k2 - right
       {  
      
       pinMode(9, OUTPUT); 
       digitalWrite(9,LOW); 
       delay(50);
       pinMode(9, INPUT); 
       delay(70);

        }

     if(analog>200&&analog<290)            //k3  down
     { 
    
       pinMode(10, OUTPUT);  
       digitalWrite(10,LOW);
       delay(50); 
       pinMode(10, INPUT);
       delay(70);
      
     } 
   
    
      if(analog>100&&analog<190)      //k4     vol+
     { 
                                     // для енкодера
       pinMode(11, OUTPUT);
       pinMode(12, OUTPUT); 
       digitalWrite(11, HIGH);
       delay(25);
       digitalWrite(12, HIGH);
       delay(25);
       digitalWrite(11,LOW);    
       delay(25);
       digitalWrite(12,LOW);  
       delay(25);
       pinMode(11, INPUT);
       pinMode(12, INPUT); 

     } 
                  
    if(analog>=0&&analog<80)         //k5  vol-
     { 
                                     // для енкодера

       pinMode(12, OUTPUT);
       pinMode(11, OUTPUT); 
       digitalWrite(12, HIGH);
       delay(25);
       digitalWrite(11, HIGH);
       delay(25);
       digitalWrite(12,LOW);    
       delay(25);
       digitalWrite(11,LOW);  
       delay(25);
       pinMode(12, INPUT);  
       pinMode(11, INPUT);  

     } 

}
 
ISR (WDT_vect){ //вектор прерывания WD
static boolean n=0; // флаг работы: запрос температуры или её чтение
n=!n;
if (n) {ds.reset();  // сброс шины
        ds.write(0xCC);//обращение ко всем датчикам
        ds.write(0x44);// начать преобразование (без паразитного питания)  
       }
else   {ds.reset();
        ds.select(addr1);    
        ds.write(0xBE); // Read Scratchpad (чтение регистров)  
        temp1 =  ds.read() | (ds.read()<<8); //прочитаны 2 байта       
        // получение с 2-го датчика
        ds.reset();
        ds.select(addr2);    
        ds.write(0xBE); // Read Scratchpad (чтение регистров)  
        temp2 =  ds.read() | (ds.read()<<8); //прочитаны 2 байта 

          ds.reset();
        ds.select(addr3);    
        ds.write(0xBE); // Read Scratchpad (чтение регистров)  
        temp3 =  ds.read() | (ds.read()<<8); //прочитаны 2 байта
       }
}
 
 
  
 

 

T.Rook
Offline
Зарегистрирован: 05.03.2016

в 126 строчке "lcd.println(temp2/16)" точно уверены?

Katroha
Offline
Зарегистрирован: 28.02.2017

Да, это было оно, 3 дня искал в чем проблема, спасибо))

see_watson
Offline
Зарегистрирован: 03.11.2016

Давно собрал такой код

#include <OneWire.h> 
OneWire ds(2);
// подключение датчика №2 ds18b20 к 2 контакту


void setup() {
//ds.reset();
//ds.write(0x4E);
//ds.write(0x7F); не работает
// установка скорости обмена Serial port. По умолчанию 9600
Serial.begin(9600); 

}
 
 
void loop() 
{
byte data[2];
ds.reset(); 
ds.write(0xCC);
ds.write(0x44);
delay(1000);
ds.reset();
ds.write(0xCC);
ds.write(0xBE);
for (byte i = 0; i < 9; i++) // можно увеличить точность измерения до 0.0625 *С (от 9 до 12 байт) НИЧЕГО НЕ ИЗМЕНЯЕТ
  { // we need 9 bytes
    data[i] = ds.read ();
  }
float raw =  (data[1] << 8) | data[0];//=======Пересчитываем в температуру
float Temp = raw / 16.0;
Serial.print("TEMP 1: ");
Serial.println(Temp);

}

Но не получется вывести с погрешность 0,0625 . Выводит до 100.

HELP PLZ. Где косячу??

датчик без адреса, так и задуманно

bwn
Offline
Зарегистрирован: 25.08.2014
// снять все ремарки если нужно поменять разрешение
//  ds.reset(); // сброс шины
//  ds.select(addr); //выставить адрес
//  ds.write(0x4E); // разрешение записать конфиг
//  ds.write(0x7F); // Th контроль температуры макс 128грд
//  ds.write(0xFF); //Tl контроль температуры мин -128грд
//  ds.write(0x60); // 0x60 12-бит разрешение, 0x00 -9бит разрешение

Не помню, воспримет ли без адреса. Настройка делается один раз.
Ваша 26 строка разрешение не изменяет, это 8 байт данных от датчика.

Deamon
Offline
Зарегистрирован: 21.09.2017

Чтобы избавиться от задержек, можно ds.read() делать не разом, а в отдельных прерываниях.

Можно даже читать побитово read_bit.

Я вообще дорабатывал эту функцию, вынеся её из класса и удалив внутри задержку в 53мкс перед return.

Такая доработка практически убрала задержки при опросе датчиков.

Deamon
Offline
Зарегистрирован: 21.09.2017

Вот кусок кода побайтной обработки. Тут идёт опрос множества датчиков, расположенных на разных пинах.

Может кому пригодиться.

// обработка данных с датчиков температуры (вызов каждые 2мс)
void getTemp () {
  static OneWire *ds;     // Линия для чтения
  static byte bufData[9]; // буфер данных
  static byte sCnt = 0;   // номер датчика
  static unsigned int tCnt = 0;  // счётчик времени для обработки данных OneWire
 
  switch (tCnt) {

    // инициализируем линию
    case 0: ds = new OneWire(sensor[sCnt].pin); break;

    // инициализация измерения
    case 1: if (!ds->reset()) tCnt = 515; break;
    case 2: ds->skip(); break;
    case 3: ds->write(0x44); break;

    // чтение памяти датчика    
    case 500: if (!ds->reset()) tCnt = 515; break;
    case 501: ds->skip(); break;
    case 502: ds->write(0xBE); break;
    case 505: bufData[0] = ds->read(); break;
    case 506: bufData[1] = ds->read(); break;
    case 507: bufData[2] = ds->read(); break;
    case 508: bufData[3] = ds->read(); break;
    case 509: bufData[4] = ds->read(); break;
    case 510: bufData[5] = ds->read(); break;
    case 511: bufData[6] = ds->read(); break;
    case 512: bufData[7] = ds->read(); break;
    case 513: bufData[8] = ds->read(); break;

    // обработка данных
    case 515:
      if ( OneWire::crc8(bufData, 8) == bufData[8] ) {  // проверка CRC
      sensor[sCnt].temp = (float)((int)bufData[0] | (((int)bufData[1]) << 8)) * 0.0625 + 0.03125;
      sensor[sCnt].tTime = millis();
     }
     break;
    
    // освобождаем память
    case 516: delete ds; bufData[8] = 0; break;

    // переходим к следующему датчику
    case 5000: // 5000 * 2мс = 10сек частота опроса датчиков по порядку    
      tCnt = 0;
      if (++sCnt>=sensCount) sCnt = 0;
      return;
  }
  tCnt++;
}