Появилась задачка мерить температуру на нескольких датчиках. В качестве управляющего МК дана ATmega48, в качестве датчика решил использовать DS18S20, поскольку работа через 1-wire показалась очень удобной штукой. Проштудировал переведённую статью про интерфейс 1-wire и вперёд.
Вооружившись осциллографом стал пытаться что-нибудь отиравить и принять. Отправка РЕСЕТ и приём ПРЕСЕНС прошли замечательно, отправка команды SEARCH ROM тоже, а вот попытка получить ответ на последнюю команду как-то не прошла... Точнее так, судя по осциллографу датчик мне отвечает, а вот если пытаться посмотреть на экране монитора через Watch, то он говорит, что одни нули...
Вот тут я добрался до самого неприятного момента и пока малопонятного для меня. Дело в том, что я себе не очень хорошо представляю, что есть пресловутая оптимизация в АВРСтудии. Да, я знаю, что она выкидывает ненужный по её мнению код, куда она ессно отправляет функции, которые ничего не получают и не возвращают, переменные, которые по ЕЁ мнению не несут смысловой нагрузки и что её вроде как можно отучить от этого через написание магического слова volatile перед объявлением переменных. Всё, более точно я про неё ничего не знаю, а в настройках проекта помимо этого, можно выбрать аж 4 режима этой оптимизации... Так вот, дабы она не компостировала мне мозги, я её всегда вырубал и не испытывал никаких угрызений совести, а тут вот проблема - на шине 1-wire необходимо строго выдерживать временные интервалы, естественно я сразу желаю использовать функции "_delay_us/ms" (просто другого я не знаю способа), но тут как обычно всё обламывается, т.к. они без оптимизации не работают... Что делать дальше - хз... Можно конечно использовать таймер, но почему-то не очень хочется=), хотя если это единственный выход как обойти проблема - куда деваеться... Просто проект будет дальше разрастаться, а как-то мучатся в нём с этой оптимизацией не хочется=/
Вот этот простой код, с которым у меня ничего пока не вышло сегодня.
Заранее спасибо за ответы
CODE
#include <avr/io.h>
#include <avr/sfr_defs.h>
#include <avr/interrupt.h>
#define F_CPU 20000000UL
#include <util/delay.h>
#define READ_ROM 0x33
void init_ports(void)
{
DDRB = (1<<DD0);
PORTB = (1<<PB0);
PORTD = (1<<PD6) | (0<<PD5) | (0<<PD4) | (0<<PD3) | (0<<PD2);
DDRD = (1<<DDD6) | (1<<DDD5) | (1<<DDD4) | (1<<DDD3) | (1<<DDD2);
asm("nop");
return;
}
volatile void write1()
{
DDRB = (1<<DDB0);
PORTB &= ~(1<<PB0);
_delay_us(2);
PORTB = (1<<PB0);
_delay_us(28);
DDRB = (0<<DDB0);
_delay_us(10);
}
volatile void write0()
{
DDRB = (1<<DDB0);
PORTB &= ~(1<<PB0);
_delay_us(30);
DDRB = (0<<DDB0);
_delay_us(10);
}
void main ()
{
volatile char help_byte = 0xFF;
volatile char help_byte_2 = 0;
init_ports();
//---отсылка импульса RESET-----
PORTB &= ~(1<<PB0);
_delay_us(500);
//---приём импульса PRESENSE-----
DDRB = (0<<DDB0);
_delay_us(61);
help_byte = PIN0;
help_byte_2 = help_byte;
_delay_us(500);
//---отправка команды чтения адреса устройства-----
volatile char command = READ_ROM;
for (int i=0;i<8;i++)
{
if((command & 1) == 1)
write1();
else
write0();
command = command >> 1;
}
_delay_ms(1);
//---попытка получить от устройства его серийник---
volatile char serial_number[8] =
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
volatile char help_byte_3 = 0x00;
for (int i=0;i<8;i++)
{
for (int k=0;k<8;k++)
{
serial_number[i] = serial_number[i]<<1;
DDRB = (1<<DDB0);
PORTB &= ~(1<<PB0);
_delay_us(5);
DDRB = (0<<DDB0);
_delay_us(8);
help_byte_3 = PINB0;
serial_number[i] = serial_number[i] + (help_byte_3<<k);
_delay_us(45);
_delay_us(10);
}
}
}
#include <avr/sfr_defs.h>
#include <avr/interrupt.h>
#define F_CPU 20000000UL
#include <util/delay.h>
#define READ_ROM 0x33
void init_ports(void)
{
DDRB = (1<<DD0);
PORTB = (1<<PB0);
PORTD = (1<<PD6) | (0<<PD5) | (0<<PD4) | (0<<PD3) | (0<<PD2);
DDRD = (1<<DDD6) | (1<<DDD5) | (1<<DDD4) | (1<<DDD3) | (1<<DDD2);
asm("nop");
return;
}
volatile void write1()
{
DDRB = (1<<DDB0);
PORTB &= ~(1<<PB0);
_delay_us(2);
PORTB = (1<<PB0);
_delay_us(28);
DDRB = (0<<DDB0);
_delay_us(10);
}
volatile void write0()
{
DDRB = (1<<DDB0);
PORTB &= ~(1<<PB0);
_delay_us(30);
DDRB = (0<<DDB0);
_delay_us(10);
}
void main ()
{
volatile char help_byte = 0xFF;
volatile char help_byte_2 = 0;
init_ports();
//---отсылка импульса RESET-----
PORTB &= ~(1<<PB0);
_delay_us(500);
//---приём импульса PRESENSE-----
DDRB = (0<<DDB0);
_delay_us(61);
help_byte = PIN0;
help_byte_2 = help_byte;
_delay_us(500);
//---отправка команды чтения адреса устройства-----
volatile char command = READ_ROM;
for (int i=0;i<8;i++)
{
if((command & 1) == 1)
write1();
else
write0();
command = command >> 1;
}
_delay_ms(1);
//---попытка получить от устройства его серийник---
volatile char serial_number[8] =
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
volatile char help_byte_3 = 0x00;
for (int i=0;i<8;i++)
{
for (int k=0;k<8;k++)
{
serial_number[i] = serial_number[i]<<1;
DDRB = (1<<DDB0);
PORTB &= ~(1<<PB0);
_delay_us(5);
DDRB = (0<<DDB0);
_delay_us(8);
help_byte_3 = PINB0;
serial_number[i] = serial_number[i] + (help_byte_3<<k);
_delay_us(45);
_delay_us(10);
}
}
}