Пример работы с двумя датчиками 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); } }
Полный архив с проектом скачать.
Спасибо. По Вашей статье разобрался со считыванием ROM кода.