Winavr работа с двумя датчиками DS18b20

Автор: | 04.11.2016

Пример работы с двумя датчиками DS18B20

 

Есть два алгоритма работы с несколькими датчиками; 1. использование алгоритма SEARCH_ROM, 2. предварительное считывание ROM кодов датчиков, и обращение к каждому по отдельности. Использование первого алгоритма приемлемо когда, требования к стабильности работы устройства минимальны, потому как данный алгоритм довольно сложный. Я ниже буду описывать свой пример реализации второго варианта.

Сначала считываем ROM коды датчиков, для этого используем функцию:

//Функция чтения ROM кода датчика
unsigned char read_rom_code()
{
if(w1_find()==1)//если есть устройство на шине
{
w1_sendcmd(0x33);
for(unsigned char i = 0; i < 8; i++)//в цикле смотрим что на шине и сохраняем значение
{
rom_code[0][i] = w1_receive_byte();
}
}
return 0;
}

 

ROM код записывается в двухмерный массив (rom_code[8][8]), далее выводим код куда либо, на LCD дисплей или в UART и сохраняем. Как выводить я писать не буду это вы уже сами делайте на свой вкус.

Допустим вы считали все коды, и теперь необходимо создать массив где они будут хранится. Выглядеть он будет примерно вот так:

unsigned char romsensor[2][8] =
{
{0x28,0x67,0x22,0x32,0x7,0x0,0x0,0x16},
{0x28,0x9A,0x83,0x33,0x7,0x0,0x0,0x5F}
};

 

Теперь чтобы обратится к нужному нам датчику необходимо реализовать вот этот алгоритм:

алгоритм

 

 

 

 

 

 

 

 

Описание команд можно посмотреть в datashet на датчик.

Пример кода:

//функция преобразует полученные с датчика 18b20 данные в температуру
int temp_18b20(unsigned char number)
{
unsigned char data[2];
int temp = 0;
if(w1_find()==1)//если есть устройство на шине
{
w1_sendcmd(0xcc);//пропустить ROM код, мы знаем, что у нас одно устройство или передаем всем
w1_sendcmd(0x44);//преобразовать температуру
_delay_ms(750);//преобразование в 12 битном режиме занимает 750ms
w1_find();//снова посылаем Presence и Reset
write_rom_code(number);
w1_sendcmd(0xbe);//передать байты ведущему(у 18b20 в первых двух содержится температура)
data[0] = w1_receive_byte();//читаем два байта с температурой
data[1] = w1_receive_byte();
//загоняем в двух байтную переменную
temp = data[1];
temp = temp<<8;
temp |= data[0];

}
//возвращаем температуру
return temp;
}

 

Функция передачи ROM кода датчика:

void write_rom_code(unsigned char sensnumb)
{
w1_sendcmd(0x55);
for(unsigned char i = 0; i <= 7; i++)
{
w1_send_byte(romsensor[sensnumb][i]);
}
}

 


Проект с использованием двух датчиков:

Библиотека 1WIRE.h

//определяем порт и бит к которому подключено устройство 1-wire

#define W1_PORT PORTB
#define W1_DDR DDRB
#define W1_PIN PINB
#define W1_BIT 7


//функция определяет есть ли устройство на шине
unsigned char w1_find()
{
unsigned char device;
W1_DDR |= 1<<W1_BIT;//логический "0"
_delay_us(480);//ждем минимум 480мкс
W1_DDR &= ~(1<<W1_BIT);//отпускаем шину
_delay_us(65);//ждем минимум 60мкс и смотрим что на шине
if((W1_PIN & (1<<W1_BIT)) ==0x00)
device = 1;
else
device = 0;
_delay_us(420);//ждем оставшееся время до 480мкс
return device;
}



//функция посылает команду на устройство 1-wire
void w1_sendcmd(unsigned char cmd)
{
for(unsigned char i = 0; i < 8; i++)//в цикле посылаем побитно
{
if((cmd & (1<<i)) == 1<<i)//если бит=1 посылаем 1
{
W1_DDR |= 1<<W1_BIT;
_delay_us(2);
W1_DDR &= ~(1<<W1_BIT);
_delay_us(65);
}
else//иначе посылаем 0
{
W1_DDR |= 1<<W1_BIT;
_delay_us(65);
W1_DDR &= ~(1<<W1_BIT);
_delay_us(5);
}
}
}


//функция передает один байт в устройства 1-wire
void w1_send_byte(unsigned char byte)
{
for(unsigned char i = 0; i < 8; i++)//в цикле посылаем побитно
{
if((byte & (1<<i)) == 1<<i)//если бит=1 посылаем 1
{
W1_DDR |= 1<<W1_BIT;
_delay_us(2);
W1_DDR &= ~(1<<W1_BIT);
_delay_us(65);
}
else//иначе посылаем 0
{
W1_DDR |= 1<<W1_BIT;
_delay_us(65);
W1_DDR &= ~(1<<W1_BIT);
_delay_us(5);
}
}
}


//функция читает один байт с устройства 1-wire
unsigned char w1_receive_byte()
{
unsigned char data=0;
for(unsigned char i = 0; i < 8; i++)//в цикле смотрим что на шине и сохраняем значение
{
W1_DDR |= 1<<W1_BIT;
_delay_us(2);
W1_DDR &= ~(1<<W1_BIT) ;
_delay_us(7);
if((W1_PIN & (1<<W1_BIT)) == 0x00)
data &= ~(1<<i);
else
data |= 1<<i;
_delay_us(50);//задержка до окончания тайм-слота
}
return data;
}


//Функция чтения ROM кода датчика
unsigned char read_rom_code()
{
if(w1_find()==1)//если есть устройство на шине
{
w1_sendcmd(0x33);
for(unsigned char i = 0; i < 8; i++)//в цикле смотрим что на шине и сохраняем значение
{
rom_code[0][i] = w1_receive_byte();
}
}
return 0;
}

//Функция передачи ROM кода датчика
void write_rom_code(unsigned char sensnumb)
{
w1_sendcmd(0x55);
for(unsigned char i = 0; i <= 7; i++)
{
w1_send_byte(romsensor[sensnumb][i]);
}
}


//функция преобразует полученные с датчика 18b20 данные в температуру
int temp_18b20(unsigned char number)
{
unsigned char data[2];
int temp = 0;
if(w1_find()==1)//если есть устройство на шине
{
w1_sendcmd(0xcc);//пропустить ROM код, мы знаем, что у нас одно устройство или передаем всем
w1_sendcmd(0x44);//преобразовать температуру
_delay_ms(750);//преобразование в 12 битном режиме занимает 750ms
w1_find();//снова посылаем Presence и Reset
write_rom_code(number);
w1_sendcmd(0xbe);//передать байты ведущему(у 18b20 в первых двух содержится температура)
data[0] = w1_receive_byte();//читаем два байта с температурой
data[1] = w1_receive_byte();
//загоняем в двух байтную переменную
temp = data[1];
temp = temp<<8;
temp |= data[0];

}
//возвращаем температуру
return temp;
}

 

Файл arrays.h

unsigned char rom_code[8][8];//Область памяти (9 байт) для хранения ROM-кода датчиков



unsigned char romsensor[2][8] =
{
{0x28,0x67,0x22,0x32,0x7,0x0,0x0,0x16},
{0x28,0x9A,0x83,0x33,0x7,0x0,0x0,0x5F}
};




const unsigned char ds18b20_rom1[8] PROGMEM ={0x28,0x30,0xC5,0xB8,0x00,0x00,0x00,0x8E};
const unsigned char ds18b20_rom2[8] PROGMEM ={0x28,0x31,0xC5,0xB8,0x00,0x00,0x00,0xB9};

 

Файл main.h

#define F_CPU 4000000UL  // 4 MHz
#include <avr\io.h>
#include <util\delay.h>
#include <stdio.h>
#include <stdint.h>
#include <avr/pgmspace.h>
#include "arrays.h"
#include "1wire\1WIRE.h"
#include <avr/interrupt.h>
#include "LCD.h"
#include <avr/wdt.h>



#define COOLER            PB6
#define LCDLED            PD3
#define PORTLCDLED        PORTD
#define PORTCOOLER        PORTB
#define DDRCOOLER         DDRB
#define DDRLCDLED        DDRD
#define BIT(bit)       (1<<(bit))



unsigned int tmp,drob,drob_tmp,celie,counter;
char buffer[20];
int temperature;

int main (void){

DDRLCDLED|=(1<<LCDLED);
DDRCOOLER|=(1<<COOLER);
PORTLCDLED |= BIT(LCDLED);

WDTCR=(1<<WDCE) | (1<<WDE) ;
WDTCR=(0<<WDCE) | (1<<WDE) | (1<<WDP2) | (1<<WDP1) | (1<<WDP0);

LCDinit();



while(1){
LCDclear();
temperature = temp_18b20(0);
tmp = (unsigned int) temperature;
if (temperature<0)tmp = ( ~tmp ) + 0x0001; // если число отрицательное перевести его в норм.вид
celie = tmp >> 4;              // целая часть числа
drob_tmp  = tmp & 0x000F;          // дробная часть числа с точностью 1/16 градуса
drob  = (unsigned int) ((drob_tmp * 10) / 16); // преобразование дробной части в формате "1/16 градуса" в десятичный формат с точностью 0,1 градуса
if (temperature>=0)//Если темп. плюсовая или 0
{
sprintf(buffer,"MOTOR=%u.%u",celie,drob);//Если темп. плюсовая или 0, то покажем эту строку
}
else
{
sprintf(buffer,"MOTOR=-%u.%u",celie,drob);//Если темп. минусовая, то покажем эту строку
}
LCDstring(buffer,0,0);
temperature = temp_18b20(1);
tmp = (unsigned int) temperature;
if (temperature<0)tmp = ( ~tmp ) + 0x0001; // если число отрицательное перевести его в норм.вид
celie = tmp >> 4;              // целая часть числа
drob_tmp  = tmp & 0x000F;          // дробная часть числа с точностью 1/16 градуса
drob  = (unsigned int) ((drob_tmp * 10) / 16); // преобразование дробной части в формате "1/16 градуса" в десятичный формат с точностью 0,1 градуса
//*****************************************************************************
if(celie >= 92 && drob >= 0){
PORTCOOLER|=BIT(COOLER);
}
 if(celie <= 87 && drob <= 9){
PORTCOOLER&=~BIT(COOLER);
}
 //****************************************************************************
if (temperature>=0)//Если темп. плюсовая или 0
{
sprintf(buffer,"RADIATOR=%u.%u",celie,drob);//Если темп. плюсовая или 0, то покажем эту строку
}
else
{
sprintf(buffer,"RADIATOR=-%u.%u",celie,drob);//Если темп. минусовая, то покажем эту строку
}
LCDstring(buffer,0,1);
wdt_reset();
_delay_ms(800);
}
}

 

Полный архив с проектом скачать.

Winavr работа с двумя датчиками DS18b20: 1 комментарий

  1. kostya

    Спасибо. По Вашей статье разобрался со считыванием ROM кода.

Добавить комментарий