Страница 1 из 3
d18b20 и мерцание
Добавлено: Пн окт 24, 2011 03:54:16
pierro
Доброго времени суток все "котам"
Прошу помочи у старожилом и профессионалов. Это моя 3-я разработка на микроконтроллере. Делаю термостат на attiny2313 с возможностью регулирования температур (также будет использоваться для инкубатора). Все сделал, программу написал, все работает. Только одна проблема осталась. Мерцание индикатора при считывание температуры с d18b20. Вроде проблема старая, как свет, много форумом перечитал, все перепробовал, но проблема осталась.
Били решения но
1. они били на atmega8
2. либо использовалса кварц
У меня
1. attiny2313
2. кварца нету
3. Переписана функция считывания температура, так как та что шла с CodeVision уж больно много места занимала (не хватало памяти для остальной программами)
4. Пробовал не отключать прерывания в функции my_ds18b20_temperature - но температура недосчитываться (как би и не должна)
Существующий ли решения этой проблемы (жк индикатор не подходит)?
Код программами
- term.zip
- Программа
- (2.72 КБ) 162 скачивания
Вот схема
Это фото уже почти готового устройства
Спасибо всем!
Re: d18b20 и мерцание
Добавлено: Пн окт 24, 2011 07:25:24
Мастер Ломастер
перечитайте форум еще раз - решение всегда одно, независимо от типа МК, кварца, схемы и т.п.: нельзя запрещать прерывания на время всей работы с датчиком температуры, достаточно запрещать их только на время чтения/записи одно бита - это гарантирует исключение мерцания при динамической индикации (при условии, что сама динамическая индикация сделана без ошибок).
Re: d18b20 и мерцание
Добавлено: Пн окт 24, 2011 08:21:57
ploop
Заводится счетчик на интервал 1-2 секунды. В прерывании его сначала считываем температуру с датчика, потом даём команду на преобразование. Это выполняется довольно быстро, мерцания не будет заметно, а при следующем входе в прерывание считается готовая температура. Слишком часто опрос тоже делать не стоит.
Re: d18b20 и мерцание
Добавлено: Пн окт 24, 2011 10:03:42
Аlex
ploop, не советуйте ерунды. Работать с датчиком в прерывании глупо. Так-же как и глупо вешать обработчик любыми другими способами. Вы ещё посоветуйте индикацию вынести в основной цикл с использованием всяких там delay_ms.
pierro, придерживайтесь совету Ломастера. Он дал совет по единственно правильному решению подобной проблемы. Если уж не терпится ждать весь тайм слот с запрещёнными прерываниями, можно их запретить только на основную часть тайм-слота (в самом начале), но это при условии того, что прерывание, которое может вызваться во время остальной части, не затянется на большое время.
Re: d18b20 и мерцание
Добавлено: Пн окт 24, 2011 10:12:41
ploop
Работать с датчиком в прерывании глупо.
Обоснуйте?
Зависит от задачи. Во время обмена данными всё равно прерывания запрещены, а я предложил делать внутри перрывания только обмен (не ожидание). При том не чаще раза в секунду.
Второй вариант - флаговый автомат, когда в прерывании выставляем флаг, обмен делаем в основном цикле. Но опять же, как говорил, на время обмена прерывания запрещены, так что ничего не выигрываем и не теряем.
Разве что обсчет CRC обычным (не табличным) методом лучше не делать в прерывании.
Re: d18b20 и мерцание
Добавлено: Пн окт 24, 2011 11:08:46
Аlex
Обоснуйте?
Что кнокретно ? Что вешать прерывание - глупо ? Дак тут и обоснований не нужно. На то он и обработчик прерываний, что-бы обработать быстренько событие и бегом оттуда, сломя голову...
Зависит от задачи.
Естественно. И в конкретной задаче, как раз, вешать его глупо. Т.к. , пологаю, дин. индикация происходит в прерывании по таймеру. По этому и нельзя запрещать прерывания на длительное время. И премещать работу с датчиком в ОП, обосновывая это тем, что прерывания и так запрещены - не выход. Это тоже-самое, только "вид сбоку"... Необходимо давать возможность обработаться событию вовремя, по этому единственный выход - запрет прерываний на то время, которое критично к изменению. Это время и есть 1 тайм-слот. Между тайм-слотами время неограничено.
Re: d18b20 и мерцание
Добавлено: Пн окт 24, 2011 11:21:48
ploop
Это время и есть 1 тайм-слот
Всё верно.
Длительность полного обмена (8 байт + 1 CRC) всегда будет меньше 10мс, если это время критично для дин. индикации - тогда да, я не прав.
Re: d18b20 и мерцание
Добавлено: Пн окт 24, 2011 11:25:20
Аlex
10 мс это наверное многовато будет. Предположим 3 индикатора, 30 мс полупериод на один индикатор. Получается период 60 мс = 16.6 Гц на индикатор.

Re: d18b20 и мерцание
Добавлено: Пн окт 24, 2011 11:29:42
Леонид Иванович
Аlex писал(а):Работать с датчиком в прерывании глупо.
Как раз "interrupt-driven 1-wire master" - самая правильная реализация. Все задержки отсчитываются таймером, все действия с шиной производятся в прерываниях. Тратится минимальное количество вычислительных ресурсов. Но такая реализация сложнее. Ну и прерывание должно быть высокоприоритетным, ведь формируются малые интервалы времени.
Но даже реализация без прерываний тратит не так много ресурсов. Вот такой код позволяет даже вынести динамическую индикацию из прерывания и вставить в основной цикл. Мерцания незаметны. Ну, почти
Код: Выделить всё
//----------------------------------------------------------------------------
//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);
}
//----------------------------------------------------------------------------
Re: d18b20 и мерцание
Добавлено: Пн окт 24, 2011 11:30:54
Satyr
Как то вы усложняете.
Вижу незапользованный UART.
Можно на нем и таймере 1-wire интерфейс практически нахаляву в смысле вычислительных ресурсов сделать и некритичный к обработке прочих прерываний.
Re: d18b20 и мерцание
Добавлено: Пн окт 24, 2011 11:36:10
ploop
Кстати да, что-то мы про UART забыли.
Если что - вот докУмент

Re: d18b20 и мерцание
Добавлено: Пн окт 24, 2011 11:40:20
Леонид Иванович
UART хорош, если только 1 порт 1-Wire нужен. А чаще датчиков несколько.
Re: d18b20 и мерцание
Добавлено: Пн окт 24, 2011 11:40:39
ploop
Аlex писал(а):10 мс это наверное многовато будет. Предположим 3 индикатора, 30 мс полупериод на один индикатор. Получается период 60 мс = 16.6 Гц на индикатор.

Зачем? Затык на 10мс будет раз в 1-2 секунды, в остальном, пока датчики считают, всё будет крутиться как положено. И я сомневаюсь, если этот затык будет виден.
Просто данный вариант проще в реализации.
Re: d18b20 и мерцание
Добавлено: Пн окт 24, 2011 11:41:04
Аlex
Да, кстати, с датчиком можно по усарту работать. Я пробовал, работает

Re: d18b20 и мерцание
Добавлено: Пн окт 24, 2011 11:42:18
ploop
Ничегонеработает писал(а):UART хорош, если только 1 порт 1-Wire нужен. А чаще датчиков несколько.
А какая разница? Передаём адрес нужного и работаем с ним.
Re: d18b20 и мерцание
Добавлено: Пн окт 24, 2011 11:42:50
Аlex
И я сомневаюсь, если этот затык будет виден.
Очень хорошо будет виден, даже не сомневайтесь.
Re: d18b20 и мерцание
Добавлено: Пн окт 24, 2011 11:49:02
Леонид Иванович
ploop писал(а):Зачем? Затык на 10мс будет раз в 1-2 секунды...И я сомневаюсь, если этот затык будет виден.
Хорошо виден. Раз в секунду будет подмигивать.
Аlex писал(а):Да, кстати, с датчиком можно по усарту работать. Я пробовал, работает

И я пробовал. На PC. Исходник на Delphi тут:
http://digit-el.com/files/open/ds18x20/ds18x20.html
ploop писал(а):А какая разница? Передаём адрес нужного и работаем с ним.
Еще чего. Связываться с адресацией - это такие проблемы на свою голову. Их же как-то прописывать при инсталляции системы нужно. А датчик заменил - и всё. Другое дело, если для каждого датчика - свой порт.
Re: d18b20 и мерцание
Добавлено: Пн окт 24, 2011 11:49:39
Satyr
Ничегонеработает писал(а):UART хорош, если только 1 порт 1-Wire нужен. А чаще датчиков несколько.
Какая разница то ?
Пакеты все одинакового формата
Re: d18b20 и мерцание
Добавлено: Пн окт 24, 2011 11:50:42
Аlex
Другое дело, если для каждого датчика - свой порт.
А поиск ROM Вам не знаком ?

Re: d18b20 и мерцание
Добавлено: Пн окт 24, 2011 11:51:10
Satyr
Аlex писал(а):Да, кстати, с датчиком можно по усарту работать. Я пробовал, работает

Не то что работает, а и коду кроха, и на софтовые тайминги не заложено.