Пример работы с двумя датчиками DS18B20
Есть два алгоритма работы с несколькими датчиками; 1. использование алгоритма SEARCH_ROM, 2. предварительное считывание ROM кодов датчиков, и обращение к каждому по отдельности. Использование первого алгоритма приемлемо когда, требования к стабильности работы устройства минимальны, потому как данный алгоритм довольно сложный. Я ниже буду описывать свой пример реализации второго варианта.
Сначала считываем ROM коды датчиков, для этого используем функцию:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
//Функция чтения 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 и сохраняем. Как выводить я писать не буду это вы уже сами делайте на свой вкус.
Допустим вы считали все коды, и теперь необходимо создать массив где они будут хранится. Выглядеть он будет примерно вот так:
1 2 3 4 5 |
unsigned char romsensor[2][8] = { {0x28,0x67,0x22,0x32,0x7,0x0,0x0,0x16}, {0x28,0x9A,0x83,0x33,0x7,0x0,0x0,0x5F} }; |
Теперь чтобы обратится к нужному нам датчику необходимо реализовать вот этот алгоритм:
Описание команд можно посмотреть в datashet на датчик.
Пример кода:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
//функция преобразует полученные с датчика 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 кода датчика:
1 2 3 4 5 6 7 8 |
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 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 |
//определяем порт и бит к которому подключено устройство 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
#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 кода.