Перейти к содержанию
    

Atmega328P и DS18B20 в фоновом режиме

Всем привет,

 

имеется атмега328п, хочется к ней прикрутить несколько, от одного до четырех, датчиков температуры DS18B20 по 1-wire. Незадачка в том, что эта атмега должна в реальном времени выполнять кучу другой работы, которую нельзя прерывать 100мкс-750мс ожиданиями протокола 1-wire.

 

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

 

Возникает идея, что этот протокол может быть реализован на прерываниях таймера и int0 (я могу повесить 1-wire на эту ножку) и практически не занимать время процессора, но программировать это может быть довольно не тривиально.

 

Скажите, пожалуйста, может кто-то уже такое запрограммировал, и такие исходники существуют в сети? Если да, тыкните, пожалуйста, пальцем где скачать. Если нет, может я в чем-то ошибаюсь и это не так просто, как мне кажется?

 

Знаю, что есть еще решение - поставить на плату тиньку или еще одну ардуину, которая будет 100% занята опросами этой температуры, но очень не хотелось бы это делать.

 

Спасибо

 

ИИВ

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вариантов реализации 1-Wire довольно много - выбирай любой. И ждать там совсем незачем, принцип простой: раз в секунду (например) прочитали температуру, потом сразу же отправили команду на преобразование. К следующей секунде преобразование как раз будет готово.

А вообще, прерывания там желательно запрещать только на время приема/отправки одного бита.

Изменено пользователем birden

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

100 мкс - 750 мкс ждать никогда не нужно с запрещенными прерываниями. запрет прерываний требуется на 15-60 мкс максимум, так что сколько-нибудь заметного влияния на фоновые процессы обмен 1-wire не должен оказать

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Возникает идея, что этот протокол может быть реализован на прерываниях таймера и int0 (я могу повесить 1-wire на эту ножку) и практически не занимать время процессора, но программировать это может быть довольно не тривиально.

Да, такая реализация вполне возможна. Я не представляю: зачем Вам int0 ? Я без него обошелся, одним таймером... Надавно встретилась в инете статья про использование в целях работы по 1-wire USART (если есть свободный). Работает USART фактически как таймер (скорость передачи настраивается так, что время передачи байта - нужное для реализации протокола 1-wire), но, ещё и импульсы на Tx формирует...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

100 мкс - 750 мкс ждать никогда не нужно с запрещенными прерываниями. запрет прерываний требуется на 15-60 мкс максимум, так что сколько-нибудь заметного влияния на фоновые процессы обмен 1-wire не должен оказать

на сколько понимаю, 5-10мкс (или все-таки 60 мкс?) мне надо ждать для передачи одного бита, а передавать надо где-то 16 байт, то есть на момент коммуникации мне надо выделить 1-2 милисекунду. Вот их-то я и не готов выделить, так как в реальном времени у меня с 6 портов идут конвертации с АЦП и на результаты мне надо реагировать незамедлительно.

 

Термодатчики хочу вкрячить на силовые модули, чтобы мониторить нагрев мосфетов во время работы...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Надавно встретилась в инете статья про использование в целях работы по 1-wire USART (если есть свободный). Работает USART фактически как таймер (скорость передачи настраивается так, что время передачи байта - нужное для реализации протокола 1-wire), но, ещё и импульсы на Tx формирует...

 

Изумительно хорошо работает. При этом можно точно определить, когда датчик готов выдать результат на гора. Обычно он делает это быстрее , чем 750мс

 

 

раз в секунду (например) прочитали температуру

 

Это перебор , если конечно датчик чем-то не нагревать в течении секунды

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

или все-таки 60 мкс?

 

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

 

Можно поделить работу с датчиками на элементарные операции, каждая из которых будет не длиннее 60 мкс. Ведь между тайм-слотами задержка не ограничивается. Я делал что-то подобное, но делил на байты, Вам же нужно поделить на биты:

 

//----------------------------------------------------------------------------

//DSS-90
//Модуль обслуживания термометра DS18B20

//Цифровой датчик температуры DS18B20 подключен по 1-проводному
//интерфейсу, который реализован программно.
//Для подключения датчика используется порт OWP.
//Порт должен быть  настроен на ввод,
//внутренний подтягивающий резистор должен быть отключен,
//используется внешний подтягивающий резистор 4.7 кОм.
//Во время измерения обеспечивается сильноточная
//подтяжка линии данных (порт переключается на вывод ВЫСОКОГО уровня),
//поэтому возможно использование термометра с паразитным питанием.
//Должны быть определены следующие макросы:
//#define OWP (1 << Pxn)
//#define Port_OWP_OUT (DDRx |= OWP)
//#define Port_OWP_IN (DDRx &= ~OWP)
//#define Pin_OWP   (PINx & OWP)
//Датчик DS18B20 должен быть запрограммирован в 12-разрядный режим
//(биты R0, R1 в регистре конфигурации равны единице,
//это заводская установка).

//Дискретность измерения температуры составляет 0.1°C.
//Из датчика считываются только 2 байта, CRC не проверяется.

//Для инициализации модуля один раз в начале программы должна
//вызываться функция DS18B20_Init(). Функция DS18B20_Exe() должна
//вызываться в основном цикле, она осуществляет запуск преобразования,
//формирует в фоновом режиме временную задержку и производит считывание
//температуры во внутреннюю переменную Temp.

//Поскольку обмен по однопроводной шине довольно медленный (чтение или
//запись одного байта занимает порядка 0.5 мс), целиком выполнять
//чтение температуры и запуск преобразования за один вызов DS18B20_Exe()
//нельзя. Это может нарушить выполнение других задач. Поэтому процесс
//обмена с термометром разбит на элементарные операции, каждая из
//которых включает в себя обмен не более чем одним байтом.

//Значение температуры в любой момент может быть считано с помощью функции
//DS18B20_GetT(). Значение представлено в виде 16-разрядного целого числа
//со знаком и представляет собой температуру в десятых долях градуса.
//До того, как закончится первое преобразование температуры, возвращается
//значение T_NORDY. В случае отсутствия ответа термометра возвращается
//код ошибки T_ERROR.

//----------------------------------------------------------------------------

#include "Main.h"
#include "DS18B20.h"

//------------------------------ Константы: ----------------------------------

#define TCONV 800	  //время преобразования температуры, мс

//----------------------------- Переменные: ----------------------------------

static int Temp;	   //текущая температура
static char TState;	//состояние процесса измерения

//-------------------------- Прототипы функций: ------------------------------

bool TReset(void);	 //формирование импульса сброса
char TByte(char dat);  //запись/чтение байта
bool TBit(bool B);	 //запись/чтение бита

//--------------------- Инициализация термометра: ----------------------------

void DS18B20_Init(void)
{
 Temp = T_NORDY;	  //результат измерения не готов
 TState = 0;		  //начало процесса
}

//----------------------- Измерение температуры: -----------------------------

void DS18B20_Exe(bool t)
{
 static int TTimer = 0;			  //таймер термометра
 static int T;					   //код температуры
 if(t)
 {
if(TTimer)						//если интервал таймера не истек,
{
  TTimer--;					   //ожидание (и декремент таймера)
}
else							  //иначе выполнение шага
{
  switch(TState)
  {
  case 0: if(TReset())			//команда RESET
			TState++;			 //если выполнена успешно, следующий шаг
			  else TState = 0xFF; //если ошибка, переход на задержку
		  break;
  case 1: TByte(0xCC);			//команда SKIP ROM
		  TState++;			   //следующий шаг
		  break;			   
  case 2: TByte(0x44);			//команда START CONVERSION
		  TTimer = ms2sys(TCONV); //загрузка задержки преобразования
		  TState++;			   //следующий шаг
		  break;
  case 3: if(TReset())			//команда RESET
			TState++;			 //если выполнена успешно, следующий шаг
			  else TState = 0xFF; //если ошибка, переход на задержку
		  break;
  case 4: TByte(0xCC);			//команда SKIP ROM
		  TState++;			   //следующий шаг
		  break;
  case 5: TByte(0xBE);			//команда READ SCRATCHPAD
		  TState++;			   //следующий шаг
		  break;
  case 6: T = TByte(0xFF);		//чтение TL
		  TState++;			   //следующий шаг
		  break;
  case 7: T |= TByte(0xFF) << 8;  //чтение TH
		  TState++;			   //следующий шаг
		  break;
  case 8: Temp = 10 * T / 16;	 //вычисление температуры
		  TState = 0;			 //переход на первый шаг
		  break;
  default: TTimer = ms2sys(TCONV); //загрузка задержки
		  Temp = T_ERROR;		 //код ошибки
		  TState = 0;			 //переход на первый шаг
  }
}
 }
}

//--------------------- Генерация импульса сброса: ---------------------------

bool TReset(void)
{
 char si;
 Port_OWP_0;
 Port_OWP_OUT;				//OWP <- 0
 Delay_us(500);			   //delay 500 uS
 si = __save_interrupt();
 __disable_interrupt();	   //запрещение прерываний
 Port_OWP_IN;				 //OWP <- 1
 Delay_us(14);				//delay 14 uS
 if(Pin_OWP)				  //если OWP = 0, то ошибка
 {
Delay_us(52);			  //delay 52 uS
if(!Pin_OWP)			   //если OWP = 1, то ошибка
{
  __restore_interrupt(si); //восстанавление прерываний
  Delay_us(250);		   //delay 250 uS
  if(Pin_OWP)			  //если OWP = 0, то ошибка
  {
	return(1);			 //если ошибок нет, термометр присутствует
  }
}
 }
 __restore_interrupt(si);	 //восстанавление прерываний в случае ошибки
 return(0);
}

//-------------- Запись/чтение байта по однопроводной шине: ------------------

char TByte(char dat)
{
 char res;
 for(char i = 0; i < 8; i++)
 {
res = res >> 1;
if(TBit(dat & 1)) res |= 0x80;
 else res &= ~0x80;
dat = dat >> 1;
 }
 return(res);
}

//--------------- Запись/чтение бита по однопроводной шине: ------------------

bool TBit(bool B)
{
 char si;
 si = __save_interrupt();
 __disable_interrupt();	   //запрещение прерываний
 Port_OWP_0;
 Port_OWP_OUT;				//OWP <- 0
 Delay_us(2);				 //delay 2 uS
 if(B) Port_OWP_IN;		   //bit = 1, OWP <- 1
 Delay_us(13);				//delay 13 uS
 bool owp = Pin_OWP;		  //чтение порта
 Delay_us(45);				//delay 45 uS
 Port_OWP_1;				  //force pullup
 Port_OWP_OUT;
 __restore_interrupt(si);	 //восстанавление прерываний
 Delay_us(2);				 //delay 2 uS
 return(owp);
}

//------------------------- Чтение температуры: ------------------------------

int DS18B20_GetT(void)
{
 return(Temp);
}

//----------------------------------------------------------------------------

Изменено пользователем IgorKossak
[codebox]

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

на сколько понимаю, 5-10мкс (или все-таки 60 мкс?)

можно глянуть тут исходники, они на ассемблере, зато сама программа в реальном времени сканирует

клавиатурную матрицу 4х4, с помощью динамической индикации работает со светодиодной матрицей 4х4х2 двухцветные диоды,

читает таблетку 1-wire,

сама прикидывается подчинееным 1-wire устройством,

все одновременно без паразитных подмаргиваний индикации при работе 1-wire интерфейсов.

http://electronix.ru/forum/index.php?showt...st&p=672770

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

 

Можно поделить работу с датчиками на элементарные операции, каждая из которых будет не длиннее 60 мкс. Ведь между тайм-слотами задержка не ограничивается. Я делал что-то подобное, но делил на байты, Вам же нужно поделить на биты:

 

Огромное Вам спасибо, Леонид Иванович,

 

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

 

Надеюсь, что в 45мкс задержку смогу положить несколько других важных операций, длительность которых мне полностью известна. Опрашивать по-видимому надо будет 5 датчиков, буду разбираться хватит ли у меня свободных ног для этого...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Изумительно хорошо работает.

Для проектов, где есть свободный UART у Maxim из AN214 можно позаимствовать идею использования UART для реализации 1-wire Bus Master

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Для проектов, где есть свободный UART у Maxim из AN214 можно позаимствовать идею использования UART для реализации 1-wire Bus Master

У MAXIM чего только нет. Так например для Ds18x20 отдельный application, но я делал по ATMEL - хорошо расписан USART для 1- wire / И даже где-то встречал русский перевод какого-то из этих applications.

Applications.rar

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

По одному проводу 4 датчика часто читать нельзя, перегреваются они, да и не получится физически, на каждый уйдет примерно 1 сек.

Я бы поставил отдельно тиньку и загрузил бы ее этой работой, после этого через UART уже командовать ней.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

По одному проводу 4 датчика часто читать нельзя, перегреваются они, да и не получится физически, на каждый уйдет примерно 1 сек.
не на каждый уйдет 1 сек, а на все сразу. думаю, пару десятков датчиков за 1 секунду можно успеть опросить :)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

не на каждый уйдет 1 сек, а на все сразу. думаю, пару десятков датчиков за 1 секунду можно успеть опросить :)

ага, я уже 5 прикрутил, без основного софта на основе one-wire.cpp и все в секунду укладывается, но вот в параллель-то конечно надо все аккуратно расписать...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

ага, я уже 5 прикрутил, без основного софта на основе one-wire.cpp и все в секунду укладывается, но вот в параллель-то конечно надо все аккуратно расписать...

 

Почему параллель? До начала чтения данных с датчиков , Вы работаете со всеми сразу игнорируя ID микросхем, а вот чтение для каждого своё.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

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

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...