Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: DS18B20 + WinAVR
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > AVR
Labinskiy Nikolay
DQ подтянут 4к7 на +5 вольт. Датчик один, питание полное(на датчик тоже идет +5В)
Код
#include <avr/io.h>
#include <avr/eeprom.h>
#include <inttypes.h>
#include <stdio.h>
#include <string.h>

#define F_CPU 1000000UL  // 1 MHz
#include <util/delay.h>


void delay_us(uint16_t t)
{
  int i;
  if (t > 10)
    for (i=0;i<t/10;i++)
      _delay_us(10);
  else
    _delay_us(t);
}

void delay_ms(uint16_t t)
{
  int i;
  if (t > 10)
    for (i=0;i<t/10;i++)
      _delay_ms(10);
  else
    _delay_ms(t);
}

int ds_reset()
{
  int r=0;
  PORTA &= ~(1<<4);
  DDRA |= (1<<4);        // DQ = 0;
  delay_us(500);        // 480us minimum
  DDRA &= ~(1<<4);        // DQ in
  delay_us(80);            // waits 15-60us and then
  r = (PINA & (1<<4));    //   capture the presence pulse (60-240us)
  delay_us(400);        
  return !r;
}

все время возвращает 0. В чем может быть проблема?
Если в датчике то как его можно быстро и просто проверить?
xemul
Цитата(Labinskiy Nikolay @ Jul 22 2006, 11:20) *
DQ подтянут 4к7 на +5 вольт. Датчик один, питание полное(на датчик тоже идет +5В)
Код
#include <avr/io.h>
#include <avr/eeprom.h>
#include <inttypes.h>
#include <stdio.h>
#include <string.h>

#define F_CPU 1000000UL  // 1 MHz
#include <util/delay.h>


void delay_us(uint16_t t)
{
  int i;
  if (t > 10)
    for (i=0;i<t/10;i++)
      _delay_us(10);
  else
    _delay_us(t);
}

void delay_ms(uint16_t t)
{
  int i;
  if (t > 10)
    for (i=0;i<t/10;i++)
      _delay_ms(10);
  else
    _delay_ms(t);
}

int ds_reset()
{
  int r=0;
  PORTA &= ~(1<<4);
  DDRA |= (1<<4);        // DQ = 0;
  delay_us(500);        // 480us minimum
  DDRA &= ~(1<<4);        // DQ in

  delay_us(80);            // waits 15-60us and then

  r = (PINA & (1<<4));    //   capture the presence pulse (60-240us)
  delay_us(400);        
  return !r;
}

все время возвращает 0. В чем может быть проблема?
Если в датчике то как его можно быстро и просто проверить?

Проблема в 80 мкс задержке. В даташитах на ванварь черным по английски сказано:
Presence Detect Sample Time tMSP min=60us, max=75us
со сноской: Note 1: System requirement.

В функции delay_us не учитываются задержки на вызов и возврат из функции. Это делает ее совершенно бессмысленной для задержек менее 10 мкс и относительно разумной для задержек менее 30-40 мкс при F_CPU 1000000UL.
Labinskiy Nikolay
Цитата(xemul @ Jul 22 2006, 12:24) *
Проблема в 80 мкс задержке. В даташитах на ванварь черным по английски сказано:
Presence Detect Sample Time tMSP min=60us, max=75us
со сноской: Note 1: System requirement.

В функции delay_us не учитываются задержки на вызов и возврат из функции. Это делает ее совершенно бессмысленной для задержек менее 10 мкс и относительно разумной для задержек менее 30-40 мкс при F_CPU 1000000UL.


Нажмите для просмотра прикрепленного файла

Как тогда корректно делать задержки?
beer_warrior
Цитата
Как тогда корректно делать задержки?

Прерыванием.
Еще частота низковата 1МГц - 1(2)мкс на команду, 5-7 команд на процедуру, тут дай бог на асме уложиться.
virtuality
Вставлю свою лепту - у меня, да и судя по постам у других людей на форуме была проблема с датчиком из-за того, что контроллер работал на внутреннем RC-генераторе на частоте 1 МГц, а программа была настроена на 8 МГц. Зажгите светодиод на 1 секунду, и проверьте, соответствует ли...
aesok
Цитата(Labinskiy Nikolay @ Jul 22 2006, 11:20) *
Код
#include <avr/io.h>

void delay_us(uint16_t t)

  int i;
  if (t > 10)
    for (i=0;i<t/10;i++)
      _delay_us(10);
  else
    _delay_us(t);
}

}


В этой функции 2 ошибки:
1. Вы используете деление в цикле: "for (i=0;i<t/10;i++)", на эту операцию требуеться примернр 200 циклов (AVR200: Multiply and Divide Routines). Следовательно вы получаете дополнительную задежку в 200us к каждым 10.

2. _delay_us(t); -так нельзя. Используйте '_delay_us' (и '_delay_мs') только с константами, или вы получите дополнительную задежку на несколько операций с плавуещей точкой:

Код
    \note When using _delay_us() and _delay_ms(), the expressions
    passed as arguments to these functions shall be compile-time
    constants, otherwise the floating-point calculations to setup the
    loops will be done at run-time, thereby drastically increasing
    both the resulting code size, as well as the time required to
    setup the loops.


В вашем случае вы можете применять '_delay_us' для задежек до 768us. Читайте описание '_delay_us'.

Анатолий.
xemul
Цитата(Labinskiy Nikolay @ Jul 22 2006, 13:43) *
Цитата(xemul @ Jul 22 2006, 12:24) *

Проблема в 80 мкс задержке. В даташитах на ванварь черным по английски сказано:
Presence Detect Sample Time tMSP min=60us, max=75us
со сноской: Note 1: System requirement.

В функции delay_us не учитываются задержки на вызов и возврат из функции. Это делает ее совершенно бессмысленной для задержек менее 10 мкс и относительно разумной для задержек менее 30-40 мкс при F_CPU 1000000UL.


Нажмите для просмотра прикрепленного файла

Как тогда корректно делать задержки?

Извините, не посмотрел, что для датчиков температуры ворота по Presence Pulse гораздо шире, чем для iButton. Тем не менее, если программу написать под стандартные тайминги для iButton, она будет работать и с остальными ванварными девайсами.
Посмотрите AN126.pdf
Я делал задержки более 70 мкс кратными этим самым 70 мкс (т.е., н-р, сброс = 7*70) и отрабатывал их по 70-мкс таймерному прерыванию. Мелкие задержки при Fclk=1MHz приходилось делать nop'ами, goto $+1 (синтаксис PIC'ов) и циклами ожидания.
Labinskiy Nikolay
Цитата(virtuality @ Jul 22 2006, 13:11) *
Вставлю свою лепту - у меня, да и судя по постам у других людей на форуме была проблема с датчиком из-за того, что контроллер работал на внутреннем RC-генераторе на частоте 1 МГц, а программа была настроена на 8 МГц. Зажгите светодиод на 1 секунду, и проверьте, соответствует ли...

все ок

aesok, xemul, спасибо.
xemul
Цитата(Labinskiy Nikolay @ Jul 22 2006, 15:04) *
все ок

И это здОровоsmile.gif.
Кста, длительность Presence Pulse и время выборки все-таки одинаковы для всех ванварных девайсов
для стандартной скорости обмена:
Presence Detect High Time 15-60 us
Presence Detect Low Time 60-240 us
Presence Detect Sample Time 60-75 us
Labinskiy Nikolay
вот что получилось:
Код
#include <avr/io.h>
#include <avr/eeprom.h>
#include <inttypes.h>
#include <stdio.h>
#include <string.h>

#define F_CPU 1000000UL  // 1 MHz
#include <util/delay.h>


void delay_ms(uint16_t t)
{
  uint8_t i;
  if (t > 10)
    for (i=0;i<t/10;i++)
      _delay_ms(10);
  else
    _delay_ms(t);
}

int ds_reset()
{
  uint8_t r=0;
  PORTA &= ~(1<<4);
  DDRA |= (1<<4);        // DQ = 0;
  _delay_us(480);
  DDRA &= ~(1<<4);        // DQ pull up
  _delay_us(70);
  r = (PINA & (1<<4));    // Capture the presence pulse
  _delay_us(410);        
  return !r;
}

void ds_write_bit(uint8_t b)
{
  if (b)
    {
        PORTA &= ~(1<<4);
      DDRA |= (1<<4);        // DQ = 0;
        _delay_us(6);
        DDRA &= ~(1<<4);        // DQ pull up
        _delay_us(64);    
    }
  else
    {
      PORTA &= ~(1<<4);
      DDRA |= (1<<4);        // DQ = 0;
      _delay_us(60);
      DDRA &= ~(1<<4);        // DQ pull up
      _delay_us(10);
    };
}

uint8_t ds_read_bit()
{
  uint8_t r=0;
  PORTA &= ~(1<<4);
  DDRA |= (1<<4);        // DQ = 0;
  _delay_us(6);
  DDRA &= ~(1<<4);        // DQ pull up
  _delay_us(9);
  r = (PINA & (1<<4));
  _delay_us(55);
  if (r)
    return 1;
  else
    return 0;
}

void ds_write_byte(uint8_t data)
{
  uint8_t loop;
  // Loop to write each bit in the byte, LS-bit first
  for (loop = 0; loop < 8; loop++)
    {
      ds_write_bit(data & 0x01);
      // shift the data byte for the next bit
      data >>= 1;
    }
}

uint8_t ds_read_byte()
{
  uint8_t loop, result=0;
  for (loop = 0; loop < 8; loop++)
    {
      // shift the result to get it ready for the next bit
      result >>= 1;
      // if result is one, then set MS bit
      if (ds_read_bit())
        result |= 0x80;
    }
  return result;
}

int16_t ds_read_temperature()
{
  int16_t r = -1;
  int i;
  uint8_t buf[9]={0};

  if (ds_reset())
    {
      ds_write_byte(0xCC);    //Skip ROM command
      ds_write_byte(0x44);    //Convert T command
      delay_ms(1000);        // lame :)
      ds_write_byte(0xBE);    //Read Scratchpad
      for (i=0; i < 10; i++)
        buf[i] = ds_read_byte();
      r = (buf[0] | (buf[1] << 8)) >> 4;

    };
  return r;
}

но инициализация все равно не проходит...
может что-то с датчиком?
xemul
Цитата(Labinskiy Nikolay @ Jul 22 2006, 15:55) *
вот что получилось:
[skipped]
но инициализация все равно не проходит...
может что-то с датчиком?

Вряд ли.
На сайте господина protoss'а лежат его сорцы для борьбы с ванварью:
1Wire.C
1Wire.Asm
за что ему большое спасибо.
Я на AVR только переползаю и пока не владею особенностями генерации кода компиляторами для этой архитектуры. Тем не менее, общие соображения:
1) посмотрите ассемблерный текст и вручную посчитайте время выполнения/выполните профилирование по ванварным функциям.
2) если в программе используются прерывания, на время выполнения коротких задержек и связанных с ними манипуляций со входами/выходами их придется запрещать.

И для упрощения жизни компилятору и контроллеру я бы сделал так:
Код
void delay_ms(uint16_t t)
{
   uint8_t i;
   if (t > 10)
      for (i=t/10;i;i--)
         _delay_ms(10);
      else
         _delay_ms(t);
}


или так
Код
void delay_ms(uint16_t t)
{
   uint8_t i;
   if (t >= 256)
   {
      for (i=t/256;i;i--)
         _delay_ms(256);
      t &= 255;
   }
   _delay_ms(t);
}
Labinskiy Nikolay
Спасибо за ссылки, ну а delay_ms у меня только и осталась чтобы сделать одну большую задержку на ~1 секунду, ну а где нужно поточнее использовал _delay_us(const)...
З.Ы. прерывания не используются...
WHALE
Вручную считать задержки-нафига? cranky.gif Тот самый случай,когда симулятор-то,что доктор прописал
xemul
Цитата(WHALE @ Jul 22 2006, 21:17) *
Вручную считать задержки-нафига? cranky.gif Тот самый случай,когда симулятор-то,что доктор прописал

Если там пять команд, то почему бы и нет? Заодно можно подивиться разумности компилятора. Или наоборотsmile.gif.
Labinskiy Nikolay
Ничего не понимаю...
PORTA.4(нумерация с нуля) Mega16(внутренний 1 МГц) подключон через 4к7 к +5 и от туда же (прямо от порта перед резистором) подключон DQ DS18B20, еще две ножки датчика подключены на +5 и землю (непаразитное питание).. Ошибок в схеме вроде нету, но вот на этом коде оч странные напряжения на выходе порта (меряю между землей и ножкой порта)

Код
int ow_reset()
{
  uint8_t r=0;
  PORTA &= ~(1<<4); // +4.95В
  DDRA |= (1<<4);        // DQ = 0;
r = (PORTA & (1<<4));    //+4.28В        как такое может быть???
  _delay_us(480);
  DDRA &= ~(1<<4);        // DQ pull up
  _delay_us(70);
  r = (PORTA & (1<<4));    // Capture the presence pulse
  _delay_us(410);        
  return r;                        // +4.95В
}

как такое возможно?
virtuality
Николай, советую проверить работоспособность датчика на готовом примере в CodeVision. Если и там у вас ничего работать не будет - значит проблема железе.
Labinskiy Nikolay
Ну вот, купил специально второй датчик для проверок в CodeVision

Код
#include <mega16.h>
// 1 Wire Bus functions
#asm
   .equ __w1_port=0x1B;PORTA
   .equ __w1_bit=4
#endasm
#include <1wire.h>
#include <ds18b20.h>
#include <stdio.h>
void main(void)
{
// USART initialization
UCSRA=0x00;
UCSRB=0x08;
UCSRC=0x86;
UBRRH=0x00;
UBRRL=0x0C;

// 1 Wire Bus initialization
w1_init();
if (ds18b20_init(NULL,0,0,DS18B20_12BIT_RES))
  {
     while (1)
      {
      /* measure and display the temperature(s) */
          printf("t=%+.3f\xf8C\n\r",
          ds18b20_temperature(NULL));
      };
  }
else
  printf("error!");

while (1);
}

выдает ошибку на обоих датчиках...

от куда беруться такие напряжения (4.28В, см. выше)? Какие есть идеи?
Просто схема подключения элементарная, ну где там можно ошибиться....
virtuality
Может у вас ошибка не в съеме информации с датчика, а в передаче ее? Я так понял вы через UART передаете?
Labinskiy Nikolay
Да, через УАРТ, но там ошибок нету, я через гиперткрминал посылаю команды контроллеру на которые он успешно отвечает мигая светодиодами и т.д., и одна из этих команд - опрос датчика...
Дебагил по шагам через JTAG ICE и мерял напряжения на ножках...
До сих пор не пойму почему там не появляется на выходе 0...
Balun
Код
/* Multipoint thermometer with LCD display
   using the Maxim DS18B20
   1 Wire bus temperature sensors

   CodeVisionAVR C Compiler
   (C) 2000-2005 HP InfoTech S.R.L.
   www.hpinfotech.ro

   Chip: ATmega8515
   Memory Model: SMALL
   Data Stack Size: 128 bytes
  
   THE ATmega8515 CLOCK FREQUENCY MUST BE 3.6864 MHz

   The DS18B20 sensors are connected to
   bit 6 of PORTA of the ATmega8515 as follows:

   [DS18B20]     [STK500 PORTA HEADER]
    1 GND         -   9  GND
    2 DQ          -   7  PA6
    3 VDD         -  10 +5V

   All the temperature sensors must be connected
   in parallel
  
   AN 4.7k PULLUP RESISTOR MUST BE CONNECTED
   BETWEEN DQ (PA6) AND +5V !
*/
#asm
    .equ __w1_port=0x1b
    .equ __w1_bit=6
#endasm

/* Use an 2x16 alphanumeric LCD connected
   to PORTC as follows:

  [LCD]   [STK500 PORTC HEADER]
   1 GND- 9  GND
   2 +5V- 10 VCC  
   3 VLC- LCD contrast control voltage 0..1V
   4 RS - 1  PC0
   5 RD - 2  PC1
   6 EN - 3  PC2
  11 D4 - 5  PC4
  12 D5 - 6  PC5
  13 D6 - 7  PC6
  14 D7 - 8  PC7
*/

#asm
    .equ __lcd_port=0x15
#endasm

#include <lcd.h> // LCD driver routines
#include <ds18b20.h>
#include <delay.h>
#include <stdio.h>

char lcd_buffer[33];

/* maximum number of DS18B20 connected to the 1 Wire bus */
#define MAX_DEVICES 8

/* DS18B20 devices ROM code storage area */
unsigned char rom_code[MAX_DEVICES][9];

main()
{
unsigned char i,j,devices;

lcd_init(16);
lcd_putsf("CodeVisionAVR\n1 Wire Bus Demo");
delay_ms(2000);
lcd_clear();

/* detect how many DS18B20 devices
   are connected to the 1 Wire bus */
devices=w1_search(0xf0,rom_code);
sprintf(lcd_buffer,"%u DS18B20\nDevice detected",devices);
lcd_puts(lcd_buffer);
delay_ms(2000);

/* display the ROM codes for each device */
if (devices)
   {
   for (i=0;i<devices;i++)
       {
       sprintf(lcd_buffer,"Device #%u ROM\nCode is:",i+1);
       lcd_clear();
       lcd_puts(lcd_buffer);
       delay_ms(2000);
       lcd_clear();
       for (j=0;j<8;j++)
           {
           sprintf(lcd_buffer,"%02X ",rom_code[i][j]);
           lcd_puts(lcd_buffer);
           if (j==3) lcd_gotoxy(0,1);
           };
       delay_ms(5000);
       };
   }
else
while (1); /* stop here if no devices were found */

/* configure each DS18B20 device for 12 bit temperature
   measurement resolution */
for (i=0;i<devices;)
    if (!ds18b20_init(&rom_code[i++][0],20,30,DS18B20_12BIT_RES))
       {
       sprintf(lcd_buffer,"Init error for\ndevice #%u",i);
       lcd_clear();
       lcd_puts(lcd_buffer);
       while (1); /* stop here if init error */
       };

/* measure and display the temperature(s) */      
while (1)
      {
      j=1;
      for (i=0;i<devices;i++)
          {
          sprintf(lcd_buffer,"t%u=%+.3f\xdfC",j++,ds18b20_temperature(&rom_code[i][0]));
          lcd_clear();
          lcd_puts(lcd_buffer);
          delay_ms(500);
          };
      };
}


У меня вот этот пример из кодевижена работает.

Посмотрите на эту строчку
(!ds18b20_init(&rom_code[i++][0],20,30,DS18B20_12BIT_RES))
Вроду нада поискать датччики и определмить их адрес, ну уж потом
делать инит
Labinskiy Nikolay
Цитата
Вроду нада поискать датччики и определмить их адрес, ну уж потом
делать инит

Это если на 1wire шине их несколько, если же датчик один, его поиск (чтение заводского ROM кода) не обязателен.

Но я все равно проверю, спасибо.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2024 Invision Power Services, Inc.