И еще раз здравствуйте, уважаемые коты.
Так сказать, в продолжении вот этой темы.
Есть МК, подключенный к COM-порту. Есть кучка датчиков DS18B20, подключенных к МК. По запросу от компьютера надо выдать значение температуры того или иного датчика.
Протокол использует такой формат пакетов: известный всем заголовок (4 байта) - длина пакета (1 байт) - данные. Пока МК не ответит на предыдущий пакет, следующий не посылается. Предусмотрен таймаут ожидания, во избежание "затыков" из-за потерь пакетов.
Пишу в cvavr. Основной цикл:Флаг is_recive выставляется по корректному принятию пакета, в функции do_cmd собирается и высылается ответ. Значения измеряются постоянно, заносятся в буфер thermo_values, откуда их по надобности читает функция do_cmd. В прерывании USART по принятию байта я переписываю его в буфер и перезапускаю таймер таймаута. По прерыванию таймера таймаута (100 мс) происходит проверка целостности пакета: в случае успеха выставляется флаг is_recive, в случае неудачи высылается уведомление о "битости" пакета.
Для общения с датчиками использую библиотеку 1-wire из cvavr.
Но работает сей монстр не вполне стабильно - термометры могут хаотически "отваливаться" или показывать "магические" значения, типа 85 градусов. Как выяснилось в предыдущей теме, проблема все же не в железе, а в коде. Возможно, дело в слишком долгом выполнении кода между cli и sei, когда теряется какой-нибудь байт пакета, или в каком-нибудь месте работы с шиной 1-wire - у меня, если честно, уже кончились предположения.
Простите за длинный пост и заранее спасибо за помощь!
Так сказать, в продолжении вот этой темы.
Есть МК, подключенный к COM-порту. Есть кучка датчиков DS18B20, подключенных к МК. По запросу от компьютера надо выдать значение температуры того или иного датчика.
Протокол использует такой формат пакетов: известный всем заголовок (4 байта) - длина пакета (1 байт) - данные. Пока МК не ответит на предыдущий пакет, следующий не посылается. Предусмотрен таймаут ожидания, во избежание "затыков" из-за потерь пакетов.
Пишу в cvavr. Основной цикл:
Код: Выделить всё
while (1)
{
// Старт измерения!
#asm("cli")
measure_start_all();
#asm("sei")
// Ждем, пока померяется (~800мс)
i = 0;
while (i++ < 800)
{
delay_ms(1);
if (is_recive)
do_cmd();
}
// читаем, чего намеряли
for (i = 0; i < thermo_count; i++)
{
#asm("cli")
thermo_values[i] = read_temperature(i);
#asm("sei")
}
}Для общения с датчиками использую библиотеку 1-wire из cvavr.
Код: Выделить всё
// Служебная процедура инициализации линии 1wire
unsigned char wire_init(void)
{
if (w1_init() == 0)
{
return 0;
}
w1_write(0xCC);
return 1;
}
// Служебная процедура выбора канала мультиплексора
unsigned char set_thermo(unsigned char index)
{
unsigned char i = 8;
unsigned char state = index;
while (i > 0)
{
IN_DATA_PIN = (state >> (i - 1)) & 1;
IN_CLOCK_PIN = 0;
delay_us(5);
IN_CLOCK_PIN = 1;
delay_us(5);
--i;
}
IN_STROBE_PIN = 1;
delay_us(10);
IN_STROBE_PIN = 0;
IN_DATA_PIN = 0;
IN_CLOCK_PIN = 0;
delay_ms(1);
return wire_init();
}
void measure_start_all(void)
{
unsigned char i;
for (i = 0; i < thermo_count; i++)
{
if (set_thermo(i) == 0)
{
set_bit_longint(&thermo_states,i,0); // термометр не отвечает
continue;
}
set_bit_longint(&thermo_states,i,1); // термометр в порядке
w1_write(0x44); // Команда начала измерения
w1_init();
}
}
int read_temperature(unsigned char index)
{
unsigned char i;
unsigned char *p;
if (set_thermo(index) == 0)
{
set_bit_longint(&thermo_states,index,0);
return thermo_values[index];
}
i = 0;
p = (char*)&__ds18b20_mem;
w1_write(0xBE);
do
*(p++) = w1_read();
while (++i < 9);
w1_init();
if (!w1_dow_crc8(&__ds18b20_mem,9) == 0)
{
set_bit_longint(&thermo_states,index,0);
return thermo_values[index];
}
return (*((int*)&__ds18b20_mem.temp_lsb));
}Простите за длинный пост и заранее спасибо за помощь!
