Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: DS18b20 неправильно показывает температуру
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > MCS51, AVR, PIC, STM8, 8bit
Br.Misha
Здраствуйте!
Вобщем хочу я сделать USB термомерт используя мегу8 и DS18b20. Вобщем написал програмку, а когда запустил то по USB(CDC) начали приходить неверные данные с термометра, сначала грешил на DS18b20 но когда подключил его к другому девайсу то он там работал нормально. Потом я отключил USB (в самом коде) и отправлял даные с датчика на UART, на компе было видно реальную температуру. Дальше я написал программу так, чтобы юсб был включен но даные передавались на ЮАРТ и тут ошибка повториласьsad.gif
Вобщем насколько я понял, то комп постоянно отправляет даные на мегу8 и очень часто вызываеться прерывание по INT0 даже тогда, когда меряеться температура а так как задержки между отправкой и приемом команд к DS маленькие, несколько микросекунд(хотя задержка для измерения температуры датчиком минимум 750мс) то или при отправке комманды долго передается бит и DS перезагружаеться, или когда принимаються то МК невовремя реагирует на комманды и получает неправильные данные. Пробовал отключать глобольно прерывания(cli) перед измерением температуры и включать(sei) после измерения но тогда МК вообще не шлет даные по ЮСБ и не отвечает на комманды с ЮСБ(например когда отправляю "1" то он должен прислать "one", 2 - "two") . Ещё пробовал делать так:
------- отключил прерывания перед отправкой комманд к DS чтобы он измерил температуру.
------- включил после этих комманд потому что далее должна быть задержка 800мс.
------- спустя 800 мс отключал, отправлял комманду чтения температуры, когда он присылал даные опять включал
------- эфект тот же!

Кароче мне нада сделать так,чтобы как то отключать ЮСБ на время измерения температуры ну или ещё что нибутьsmile.gif.

Частота 12Мгц, питание от ЮСБ. Вот клавный файл и библиотека для измерения температуры которую я скачал с инета, немного переделал после чего она работает отлично, правда тока на 1 датчик http://upwap.ru/619341 .

Заранее спасиба!!!!!!!

вот кстате те самые даные с термометра:

+031.1
+125.7
+127.5
+031.3
+023.7
-000.7
+127.1
+021.3
+031.1
-000.7
-000.7
-000.7
-000.7
-000.7
+125.7
-000.7
-000.7
+119.7
+063.7
-000.7
-000.7
+125.6
Андрей Лютько
Во время чтения/записи данных по шине 1-Wire yужно запрещать прерывания на время tREC+tRDV (см. документацию на DS18b20). В течение этого промежутка времени данные спокойно пишутся/читаются с шины. У меня нижеприведенный код вполне успешно работает совместно с прерываниями и проблем нет.

CODE
#include <iom168.h>
//#include <inavr.h>
#include <ina90.h>
#include "OneWire.h"

#define _1W_CLK 8000000
#define _1W_TKSPer10uS _1W_CLK/100000
#define MILLION 1000000
#define tRSTL 48*_1W_TKSPer10uS //480uS
#define tPDH 65*_1W_CLK/MILLION //65uS
#define tRSTH tRSTL-tPDH
#define tSAMPLE 12*_1W_CLK/MILLION
#define tSLOT 12*_1W_TKSPer10uS //120uS
#define tLOW1 0*_1W_CLK/MILLION //3uS
#define t1uS 1*_1W_CLK/MILLION //3uS
#define tLOW0 10*_1W_TKSPer10uS //120uS
#define tREC 7*_1W_CLK/MILLION //7uS

//==================================================================
//Выходы 1Wire
//1Wire port/ SCK ( D INPUT/OUTPUT)
#define OWIREIOOUT DDRC|=(1<<2)
#define OWIREIOIN DDRC&=~(1<<2)
#define OWIREIOH PORTC|=(1<<2)
#define OWIREIOL PORTC&=~(1<<2)
#define OWIRE (PINC&(1<<2))


//==================================================================
//1wire atmega DRIVERS
//
//-------------------------------------------------------------------------
//This procedure calculates the cumulative Dallas Semiconductor 1ЦWire CRC of all bytes passed to it. The result
//accumulates in the global variable CRC.
unsigned char CRC8(unsigned char inData, unsigned char seed)
{//from AVR318
unsigned char bitsLeft;
unsigned char temp;

for (bitsLeft = 8; bitsLeft > 0; bitsLeft--)
{
temp = ((seed ^ inData) & 0x01);
if (temp == 0)
{
seed >>= 1;
}
else
{
seed ^= 0x18;
seed >>= 1;
seed |= 0x80;
}
inData >>= 1;
}
return seed;
}
//-------------------------------------------------------------------------
//Сброс устройств на шине 1W и чтение Presence Pulse
// Возврат 0- ничего нет
// 1- Есть устройство
// 2- Линия в КЗ
char Reset1W(void)
{
OWIREIOOUT;
__disable_interrupt();
OWIREIOL;
__delay_cycles(tRSTL);
OWIREIOH;
OWIREIOIN;
__delay_cycles(tPDH);
if(!OWIRE)
{ __enable_interrupt();
__delay_cycles(tRSTL);
if(OWIRE)
{ return 1;//Presence pulse
}//if(OWIRE)
else
return 2;//Short circuit
}
__enable_interrupt();
__delay_cycles(tRSTL);
return 0;//Nothing
}
//-------------------------------------------------------------------------
//Проверка наличия 1W устройства
char Check1W(void)
{
if(Reset1W()==1)
{ __delay_cycles(tRSTL);
if(Reset1W()==1)
return 1;
}
return 0;
}
//-------------------------------------------------------------------------
//Передача данных по шине 1Wire
void Write1W(char d)
{ char i;
OWIREIOOUT;
for(i=0;i<8;i++)
{ __disable_interrupt();
OWIREIOL;
__delay_cycles(tLOW1);
if(d&1)
{ OWIREIOH;
__delay_cycles(tSLOT);
}
else
{ __delay_cycles(tLOW0);
OWIREIOH;
}
__enable_interrupt();
__delay_cycles(tREC);
d=d>>1;
}
OWIREIOIN;
}
//-------------------------------------------------------------------------
//Прием данных по шине 1WIRE
char Read1W(void)
{ char i,d=0;
for(i=0;i<8;i++)
{ OWIREIOOUT;
d=d>>1;
__disable_interrupt();
OWIREIOL;
__delay_cycles(t1uS);
OWIREIOH;
OWIREIOIN;
__delay_cycles(tSAMPLE);
if(OWIRE)
d|=0x80;
__enable_interrupt();
__delay_cycles(tSLOT);//tRELEASE 30uS
}
return d;
}

//---------------------------------------------------------------------------
void StartT(char BusNo)//запуск измерения температуры по одной из шин
{ Reset1W();
Write1W(SKIPROM);
Write1W(CONVERTT);
}

//---------------------------------------------------------------------------
float GetT18B20(char *x)//Считывание температуры с датчиков DS18B20,DS1822
{ char i,crc=0;
int j;
char *p;
if(Reset1W()!=1)
return -100;//Нет такого датчика
p=x;
// Write1W(SKIPROM);
Write1W(MATCHROM);
for(i=0;i<8;i++)
{ //OutChar(*p);
Write1W(*p++);//Передача 8 байт адреса
}
Write1W(READSCRATCHPAD);
p=x;
for(i=0;i<8;i++)
{ *p=Read1W();
crc=CRC8(*p,crc);
//OutChar(*p);
*p++;
}
if(Read1W()!=crc)
return -101;//CRC error
p=x;
j=p[1]<<8;
j|=p[0];
return (float)j/16.0;
}

//---------------------------------------------------------------------------
float GetT18S20(char *x)//Считывание температуры с датчика DS18S20
{ char i,crc=0;
int j;
char *p=x;
if(Reset1W()!=1)
return -100;//Нет такого датчика
Write1W(SKIPROM);
// for(i=0;i<8;i++)
// Write1W(*p++);//Передача 8 байт адреса
Write1W(READSCRATCHPAD);
p=x;
for(i=0;i<8;i++)
{ *p=Read1W();
crc=CRC8(*p,crc);
*p++;
}
if(Read1W()!=crc)
return -101;//CRC error
p=x;
j=p[0];
return (float)j/2.0;
}

Код же с http://upwap.ru/619341 абсолютно не имеет никаких критических секций и правильно работать в системе с прерываниями без модификации не будет.
_Pasha
Цитата(Br.Misha @ Nov 5 2009, 18:02) *
Ещё пробовал делать так:
------- отключил прерывания перед отправкой комманд к DS чтобы он измерил температуру.
------- включил после этих комманд потому что далее должна быть задержка 800мс.
------- спустя 800 мс отключал, отправлял комманду чтения температуры, когда он присылал даные опять включал
------- эфект тот же!

Надо это все проделать на "молекулярном уровне" - перед приемом/передачей каждого битика отключать прерывания, затем сразу же включать. Получится прозрачно.
Br.Misha
вобщем сделал на "молекулярном уровне":

CODE
#include "therm_ds18b20.h"
#include "ascii_conv.h"
#include <avr/interrupt.h>

volatile char THERM_DQ = 0;
/*
void therm_delay(uint16_t delay)
{
while(delay--) asm volatile("nop");
}
*/

uint8_t therm_reset()
{
uint8_t i;
//Pull line low and wait for 480uS
cli();
ds_cbi(THERM_PORT,THERM_DQ);
ds_sbi(THERM_DDR,THERM_DQ);
sei();
_delay_us(480);
cli();
//Release line and wait for 60uS
ds_cbi(THERM_DDR,THERM_DQ);
sei();
_delay_us(60);
//Store line value and wait until the completion of 480uS period
cli();
i=(THERM_PIN & (1<<THERM_DQ));
sei();
_delay_us(420);
//Return the value read from the presence pulse (0=OK, 1=WRONG)
return i;
}

void therm_write_bit(uint8_t bit)
{
//Pull line low for 1uS
cli();
ds_cbi(THERM_PORT,THERM_DQ);
ds_sbi(THERM_DDR,THERM_DQ);
_delay_us(1);
//If we want to write 1, release the line (if not will keep low)
if(bit) ds_cbi(THERM_DDR,THERM_DQ);
//Wait for 60uS and release the line
sei();
_delay_us(60);
ds_cbi(THERM_DDR,THERM_DQ);
}

uint8_t therm_read_bit(void)
{
uint8_t bit=0;
cli();
//Pull line low for 1uS
ds_cbi(THERM_PORT,THERM_DQ);
ds_sbi(THERM_DDR,THERM_DQ);
_delay_us(1);
//Release line and wait for 14uS
ds_cbi(THERM_DDR,THERM_DQ);
_delay_us(14);
//Read line value
if(THERM_PIN&(1<<THERM_DQ)) bit=1;
//Wait for 45uS to end and return read value
_delay_us(45);
sei();
return bit;
}

uint8_t therm_read_byte(void)
{
uint8_t i=8, n=0;
cli();
while(i--)
{
//Shift one position right and store read value
n>>=1;
n|=(therm_read_bit()<<7);
}
sei();
return n;
}

void therm_write_byte(uint8_t byte)
{
uint8_t i=8;
cli();
while(i--)
{
//Write actual bit and shift one position right to make the next bit ready
therm_write_bit(byte&1);
byte>>=1;
}
sei();
}

void therm_read_temperature(char *buffer, volatile char PIN_DS)
{
THERM_DQ = PIN_DS;
// Buffer length must be at least 12bytes long! ["+XXX.XXXX C"]
uint8_t temperature[2];
// uint16_t temper_16bit;
int8_t digit;
uint16_t decimal;
//Reset, skip ROM and start temperature conversion
therm_reset();
therm_write_byte(THERM_CMD_SKIPROM);
therm_write_byte(THERM_CMD_CONVERTTEMP);
//Wait until conversion is complete
//while(!therm_read_bit());
_delay_ms(750);
//Reset, skip ROM and send command to read Scratchpad
therm_reset();
therm_write_byte(THERM_CMD_SKIPROM);
therm_write_byte(THERM_CMD_RSCRATCHPAD);
//Read Scratchpad (only 2 first bytes)
temperature[0]=therm_read_byte();
temperature[1]=therm_read_byte();
therm_reset();
//Store temperature integer digits and decimal digits
digit=temperature[0]>>4;
digit|=(temperature[1]&0x07)<<4;
//Store decimal digits
decimal=temperature[0]&0xf;
decimal*=5;
if (temperature[1]>0xFB)
{
digit = 127-digit;
buffer[0] = '-';
} else buffer[0] = '+';



buffer[1] = to_ascii(digit/100);
buffer[2] = to_ascii((digit%100)/10);
buffer[3] = to_ascii(digit%10);
buffer[4] = '.';
buffer[5] = to_ascii((decimal%100)/10);

}


юсб опять не отвечает на комманды sad.gif но компом распознаеться.
Андрей, а вы пробовали вашу либу совместно с драйвером obdev?
Br.Misha
Мужики, ну помогите, мож тут ещё че не так? Я уже и кварц на 16МГц ставил а оно всеравно не работаетsad.gif
Андрей Лютько
C OBDEV не использовал.
В файле usbdrvasm есть строка - "max allowable interrupt latency: 34 cycles -> max 25 cycles interrupt disable". Судя по всему, максимально допустимое время с запрешёнными прерываниями - 25 тактов.
На мой взгляд, совместить OBDEV и 1-Wire очень тяжело. Разноси эти задачи по двум микроконтроллерам smile.gif
xemul
Цитата(Br.Misha @ Nov 5 2009, 22:06) *
мож тут ещё че не так?

Попробуйте нарисовать ванварный мастер как конечный автомат на прерываниях - внешнему по спаду и от (8-битного) таймера. Естесно, без delayxxx().
(хинт: у мастера 3 операции - сброс, чтение и запись, операции состоят соответственно из 3, 3 и 2 фаз. Всё это легко помещается в 1 байт и отрабатывается computational goto)
С 12 МГц клоком можно позволить себе не зависать в прерывании по спаду даже на 6 или 9 мкс (при чтении с шины), а отрабатывать их (6 и 9 мкс) таймером.
Когда всё с ванварью получится, добавьте obdev usb.
Заведите программный таймер на интервал, меньший интервала опроса по usb, как признак разрешения обмена по ванвари, и перезапускайте его по окончании обмена по usb.
Заведите программный таймер на интервал, равный или больший времени преобразования DS1820, и перезапускайте его по запуску преобразования.
Цитата
Я уже и кварц на 16МГц ставил а оно всеравно не работаетsad.gif

И не должно. Читайте доки от obdev.
_Pasha
Цитата(Br.Misha @ Nov 5 2009, 19:56) *
вобщем сделал на "молекулярном уровне":

Ничего Вы не сделали, либо совсем ничего не поняли. Зачем Вы наглухо запрещаете прерывания, в функциях therm_read_byte() и therm_write_byte() ??? Так Вы совсем надолго отключаете УСБ.
Br.Misha
фух блин...... переделал код но опять не работает...... вот что я написал:

CODE
#include <avr/io.h>
#include "therm_ds18b20.h"
#include "ascii_conv.h"

volatile char THERM_DQ = 0;
/*
void therm_delay(uint16_t delay)
{
while(delay--) asm volatile("nop");
}
*/

uint8_t therm_reset()
{
uint8_t i;
//Pull line low and wait for 480uS
ds_cbi(THERM_PORT,THERM_DQ);
ds_sbi(THERM_DDR,THERM_DQ);
//_delay_us(480);
TCNT1 = 0;
while(TCNT1<(480*12));
//Release line and wait for 60uS
ds_cbi(THERM_DDR,THERM_DQ);
//_delay_us(60);
TCNT1 = 0;
while(TCNT1<(60*12));
//Store line value and wait until the completion of 480uS period
i=(THERM_PIN & (1<<THERM_DQ));
//_delay_us(420);
TCNT1 = 0;
while(TCNT1<(420*12));
//Return the value read from the presence pulse (0=OK, 1=WRONG)
return i;
}

void therm_write_bit(uint8_t bit)
{
//Pull line low for 1uS
ds_cbi(THERM_PORT,THERM_DQ);
ds_sbi(THERM_DDR,THERM_DQ);
//_delay_us(1);
TCNT1 = 0;
while(TCNT1<12);
//If we want to write 1, release the line (if not will keep low)
if(bit) ds_cbi(THERM_DDR,THERM_DQ);
//Wait for 60uS and release the line
//_delay_us(60);
TCNT1 = 0;
while(TCNT1<(60*12));
ds_cbi(THERM_DDR,THERM_DQ);
}

uint8_t therm_read_bit(void)
{
uint8_t bit=0;
//Pull line low for 1uS
ds_cbi(THERM_PORT,THERM_DQ);
ds_sbi(THERM_DDR,THERM_DQ);
//_delay_us(1);
TCNT1 = 0;
while(TCNT1<12);
//Release line and wait for 14uS
ds_cbi(THERM_DDR,THERM_DQ);
//_delay_us(14);
TCNT1 = 0;
while(TCNT1<(14*12));
//Read line value
if(THERM_PIN&(1<<THERM_DQ)) bit=1;
//Wait for 45uS to end and return read value
//_delay_us(45);
TCNT1 = 0;
while(TCNT1<(45*12));
return bit;
}

uint8_t therm_read_byte(void)
{
uint8_t i=8, n=0;
while(i--)
{
//Shift one position right and store read value
n>>=1;
n|=(therm_read_bit()<<7);
}
return n;
}

void therm_write_byte(uint8_t byte)
{
uint8_t i=8;
while(i--)
{
//Write actual bit and shift one position right to make the next bit ready
therm_write_bit(byte&1);
byte>>=1;
}
}

void therm_read_temperature(char *buffer, volatile char PIN_DS)
{
THERM_DQ = PIN_DS;
// Buffer length must be at least 12bytes long! ["+XXX.XXXX C"]
uint8_t temperature[2];
// uint16_t temper_16bit;
int8_t digit;
uint16_t decimal;
//Reset, skip ROM and start temperature conversion
therm_reset();
therm_write_byte(THERM_CMD_SKIPROM);
therm_write_byte(THERM_CMD_CONVERTTEMP);
//Wait until conversion is complete
//while(!therm_read_bit());
//_delay_ms(750);
for (volatile char gggg=0;gggg<151;gggg++)
{
TCNT1 = 0;
while(TCNT1<(5000*12));
}
//Reset, skip ROM and send command to read Scratchpad
therm_reset();
therm_write_byte(THERM_CMD_SKIPROM);
therm_write_byte(THERM_CMD_RSCRATCHPAD);
//Read Scratchpad (only 2 first bytes)
temperature[0]=therm_read_byte();
temperature[1]=therm_read_byte();
therm_reset();
//Store temperature integer digits and decimal digits
digit=temperature[0]>>4;
digit|=(temperature[1]&0x07)<<4;
//Store decimal digits
decimal=temperature[0]&0xf;
decimal*=5;
if (temperature[1]>0xFB) digit = 127-digit;

buffer[0] = to_ascii(digit/100);
buffer[1] = to_ascii((digit%100)/10);
buffer[2] = to_ascii(digit%10);
buffer[3] = '.';
buffer[4] = to_ascii((decimal%100)/10);

}


Обьясняю что наделал:
Частота 12000000 Гц получаеться что timer1 с пределителем на 1 будет делать 12 тиков каждую микросекунду.
Теперь чтобы сделать задержку в 1 микросекунду нада написать: TCNT1 = 0;while(TCNT1<(1*12)); тоесть теперь спустя 12 тиков(1мкс) програма будет выполняться дальше а так как таймер1 будет тикать постоянно, даже когда выполняеться прерывание INT0 то задержка будет более точной чем писать просто через _delay_us. А чтобы сделать иную задержку нада заменить 1 на нужное кол-во микросекунд(тока не больше 5400).
Тут как и раньше с выключеным ЮСБ работает а с включеным нет.
xemul
Цитата(Br.Misha @ Nov 6 2009, 04:02) *
Обьясняю что наделал:

Некоторый объём бесполезной работы?
Цитата
даже когда выполняеться прерывание INT0 то задержка будет более точной чем писать просто через _delay_us.

Вы не поняли причину проблемы и потому не с тем боретесь. С точки зрения контроллера между
//_delay_us(480);
и
TCNT1 = 0;
while(TCNT1<(480*12));
абсолютно никакой разницы нет - его на 480 мкс завесили в тупом цикле, и он не в состоянии отвлечься на другие задачи (н-р, на обработку обмена по usb, приоритет которой разумно сделать выше приоритета обмена по ванвари).
Я предлагал построить автомат не на задержках, а на интервалах, когда, обрабатывая (в прерывании) текущее состояние автомата и зная/предполагая его следующее состояние и время возникновения этого состояния, Вы можете задать это время таймером, выйти из обработки текущего прерывания, сделать что-нить полезное и по прерыванию от таймера вернуться к обработке следующего состояния автомата.
Цитата
Тут как и раньше с выключеным ЮСБ работает а с включеным нет.

Угу.
Br.Misha
но почему когда выполняеться _delay_us он не может переключиться на обмен данными по usb? а еси например появляеться прерывание INT0 которое вызывает комп по USB?
xemul
Цитата(Br.Misha @ Nov 6 2009, 12:03) *
но почему когда выполняеться _delay_us он не может переключиться на обмен данными по usb? а еси например появляеться прерывание INT0 которое вызывает комп по USB?

Может, но тогда может нарушаться обмен по ванвари - собственно, этим Вы и начали топик. 480 мкс - самый длинный, но и самый некритичный по допуску интервал в этом обмене.
Я уже сказал, что, имхо, обмен по usb должен иметь приоритет перед обменом по ванвари. Т.к. запросами с компа контроллер управлять не может (почти), то остаётся только подстроить обмен по ванвари под паузы между обменом по usb, н-р, с помощью программного таймера, но это второй шаг в решении.
Не как решение задачи, а костыль - можно, коль Вы читаете из 1820 полностью скрэчпэд, просто проверять CRC прочитанного.
_Pasha
Раз Вы таки не поняли, показываю. Измените эти две функции.
CODE

void therm_write_bit(uint8_t bit)
{
cli();
if(bit)
{
ds_cbi(THERM_PORT,THERM_DQ);
_delay_us(4);
ds_sbi(THERM_PORT,THERM_DQ);
sei();
_delay_us(60);
}
else
{
ds_cbi(THERM_PORT,THERM_DQ);
sei();
_delay_us(60);
ds_sbi(THERM_PORT,THERM_DQ);
}
}

uint8_t therm_read_bit(void)
{
uint8_t bit=0;

cli();
ds_cbi(THERM_PORT,THERM_DQ);
_delay_us(4);
ds_sbi(THERM_DDR,THERM_DQ);
_delay_us(8);
if(THERM_PIN&(1<<THERM_DQ)) bit=1;
sei();
_delay_us(45);
return bit;
}
Rst7
Господа, о чем вы? Понятное дело, что единственный способ работать с 1W софтово - это вклеить 1W в драйвер USB. Между битиками в USB ловить битики в 1W. Иначе - никак. Другое дело - если есть свободный UART, вопрос с 1W решается легко и небрежно:

CODE

static UREG OWByte(UREG b )
{
UREG i=8;
UBRR0=10; //115200
do
{
UREG d=0x00;
if (b&1) d=0xFF;
__disable_interrupt();
UDR0=d;
UCSR0A=(1<<TXC0);
__enable_interrupt();
while(!UCSR0A_TXC0);
b>>=1;
if (UDR0>0xFE) b|=128;
}
while(--i);
return b&255;
}

static UREG OWReset(void)
{
UREG c;
UCSR0B=(1<<RXEN0)|(1<<TXEN0);
UBRR0=129; //9600
while(UCSR0A_RXC0) UDR0; //Зачистка буферов
__disable_interrupt();
UDR0=0xF0;
UCSR0A=(1<<TXC0);
__enable_interrupt();
while(!UCSR0A_TXC0);
c=UDR0;
if (c!=0xF0) return 1;
return 0;
}

void StartMeasureTemp(void)
{
if (!OWReset()) return;
OWByte(0xCC); //Skip ROM
OWByte(0x44); //Convert Temperature
}

REG16 ExtractMeasureTemp_one(void)
{
if (!OWReset()) return -273*16;
OWByte(0xCC); //Skip ROM
OWByte(0xBE); //Read scratchpad
REG16 v=OWByte(0xFF);
v|=OWByte(0xFF)<<8;
return v;
}


Только нужно заточить значения для UBRR под 12МГц (в приведенном исходнике - под 20). И подключить термометр - между ножками TXD и RXD процессора резистор 2.2к, вывод DQ термометра подключается к RXD. Питание не паразитное.
Br.Misha
_Pasha, я понял и делал так уже, юсб не отвечал потому что прерывания отключаються на больше чем 25 тактов.

Rst7, извиняюсь но я не совсем понял что вы написали. в моем девайсе чтоит датчик не с паразитным питанием и подтянут 2к2, но причем тут юарт и зачем соеденять Rx и Tx?
Rst7
Цитата
но я не совсем понял что вы написали.


Разъясняю. Если есть свободный UART (это написано в посте выше), то можно работать с 1W используя UART (код приведен, как подключить - написано), при этом прерывания запрещены минимальное время (на 4 такта).
xemul
Цитата(Br.Misha @ Nov 6 2009, 16:36) *
Rst7, извиняюсь но я не совсем понял что вы написали. в моем девайсе чтоит датчик не с паразитным питанием и подтянут 2к2, но причем тут юарт и зачем соеденять Rx и Tx?

Using a UART to Implement a 1-Wire Bus Master
У производителя много аппнотов по ванвари. Имеет смысл ознакомиться.
Br.Misha
Блин..... у меня почему то так и не получилось реализовать 1wire на UART'e
Rst7, а у вас есть рабочая либа для работы с DS18B20 через UART?
Rst7
Цитата
Rst7, а у вас есть рабочая либа для работы с DS18B20 через UART?


О_о

А что по Вашему я в пост под тег codebox положил?
Br.Misha
гы....странно. какой та код маленький......
Br.Misha
такс.... переделал я вашу либу, вот что получилось:
CODE
static unsigned char OWByte(unsigned char b )
{
unsigned char i=8;
//UBRR0=10; //115200
UBRRH = 0;
UBRRL = 12;
UCSRA |= (1<<U2X);

do
{
unsigned char d=0x00;
if (b&1) d=0xFF;
cli();
UDR=d;
UCSRA=(1<<TXC);
sei();
//while(!UCSRA_TXC);
while(!(UCSRA&(1<<TXC)));
b>>=1;
if (UDR>0xFE) b|=128;
}
while(--i);
return b&255;
}

static unsigned char OWReset(void)
{
unsigned char c;
UCSRB=(1<<RXEN)|(1<<TXEN);
//UBRR0=129; //9600
UBRRH = 0;
UBRRL = 77;
UCSRA &= ~(1<<U2X);

//while(UCSRA_RXC) UDR; //Зачистка буферов
while(UCSRA&(1<<RXC)) UDR; //Зачистка буферов
cli();
UDR=0xF0;
UCSRA=(1<<TXC);
sei();
//while(!UCSRA_TXC);
while(!(UCSRA&(1<<TXC)));
c=UDR;
if (c!=0xF0) return 1;
return 0;
}

void StartMeasureTemp(void)
{
if (!OWReset()) return;
OWByte(0xCC); //Skip ROM
OWByte(0x44); //Convert Temperature
}

int ExtractMeasureTemp_one(void)
{
if (!OWReset()) return -273*16;
OWByte(0xCC); //Skip ROM
OWByte(0xBE); //Read scratchpad
int v=OWByte(0xFF);
v|=OWByte(0xFF)<<8;
return v;
}


насколько я понял, вы писали в IAR, я переделал на ВинАВР но не понял что означает строка while(UCSRA_RXC) UDR;, для чего тут UDR?
Андрей Лютько
Цитата(Br.Misha @ Nov 7 2009, 17:43) *
но не понял что означает строка while(UCSRA_RXC) UDR;, для чего тут UDR?

Если в UDR есть какие-то ранее принятые данные, то читаем их из приемного буфера UDR в "никуда". Соответственно, после того, как этот цикл выполнится, регистр UDR будет чист.
demiurg_spb
Цитата(Br.Misha @ Nov 7 2009, 16:43) *
... но не понял что означает строка while(UCSRA_RXC) UDR;, для чего тут UDR?

Посмотрите эту тему.
Br.Misha
блин, я пару часов назад написал тут сообщение. куда оно пропало?
Rst7
Цитата
куда оно пропало?


Не знаю. Мне уведомление пришло. Если Вам не приходило на почту уведомление об удалении Вашего сообщения модератором, то может сглючил движок форума. Я, например, в тексте сообщения, включенного в уведомление, криминала с точки зрения нарушения правил форума вроде не увидел, так что более вероятен глюк, что более неприятно sad.gif
zltigo
Цитата(Rst7 @ Nov 8 2009, 21:38) *
так что более вероятен глюк, что более неприятно sad.gif

Никаких глюков. Очередная неформатированная портянка с исходником удалена. Несколько предыдущих, кто-то из модераторов редактировал и указывал причину редактирования. Хватит. Уведомление Автору, естественно, отправлено.
Rst7
Цитата
Никаких глюков.


Понятно.

2 Br.Misha:

Посмотрел я на Ваш код, если ничего не напутали с установкой скорости порта, то все должно работать. Пробуйте в реальном железе. Я то Вам кусок из рабочего проекта скопипастил.
Br.Misha
Rst7, всё работает правильно!!! ExtractMeasureTemp_one возвращает правильные значения 16 битного температурного регистра.
Волько вот никак не пойму почему не получаеться конвертировать в нормальную температуру, делал всё как и в библиотеке с первого поста. сделал ф-цию showTemperature:
CODE
void showTemperature(char *ds_buffer)
{
unsigned char ds_temp[2]; // массив для хранения возвращаемой температуры
unsigned char ds_digit; // целое значение
unsigned char ds_decimal; //десятичное значение
unsigned int ds_data = ExtractMeasureTemp_one();// считавыем значение температуры и записываем в переменную
ds_temp[0]=(ds_data>>8);// старший байт
ds_temp[1]=(ds_data<<8);// младший байт
ds_digit=ds_temp[0]>>4;// сюда пишем старшие 4 бита старшего байта
ds_digit|=(ds_temp[1]&0x07)<<4;// сюда пишем младшие 4 бита младшего байта
ds_decimal=ds_temp[0]&0xf;//
ds_decimal*=5; // десятичное значение
if (ds_temp[1]>0xFB) // еси датчик показывает меньше -55С
{
ds_digit = 127-ds_digit; //
ds_buffer[0] = '-'; // ставим минус
} else ds_buffer[0] = '+'; // в противоположном случает - плюс
ds_buffer[1] = to_ascii(ds_digit/100); //
ds_buffer[2] = to_ascii((ds_digit%100)/10); //
ds_buffer[3] = to_ascii(ds_digit%10); //
ds_buffer[4] = '.'; //
ds_buffer[5] = to_ascii((ds_decimal%100)/10);//
}


в бесконечном цикле сначала вызываю StartMeasureTemp и спустя 750мс эту функцию.

проблема в том, что по ЮСБ мне приходит температура 000.0С а еси напишу
ds_temp[1]=(ds_data>>8);// старший байт
ds_temp[0]=(ds_data<<8);// младший байт
тогда приходит +016.0С.
в чем тут может быть проблема? я же все вроде правильно сделал.

Кстате, забыл написать.
Когда я просто отсылаю с МК на комп значение возвращаемое ExtractMeasureTemp_one() то при смене температуры меняеться значение этой переменной, показывая реальную температуру но с ф-цией showTemperature приходит постоянно одинаковое значениеsad.gif я даже представить не могу в чем косяк.
microsin
Один умный человек как-то скрестил V-USB с протоколом 1-Wire. См. AVR-USB-MEGA16: измеряем и контролируем температуру.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.