Меню сайта
Администрация
579-010-666
Или воспользуйтесь формой обратной связи.
Разделы
Автолюбителям [13]
Таймер NE555 [11]
Конструктор схем [11]
Измерительная аппаратура [5]
Осциллографы [2]
На микрухах [10]
Роботы [0]
Световые эффекты [1]
Термостат [0]
Обучение PIC с нуля [17]
Чат
500
Наш опрос
Оцените мой сайт

Результат опроса Результаты Все опросы нашего сайта Архив опросов

Всего голосовало: 148
Статистика



Онлайн всего: 1
Гостей: 1
Пользователей: 0
Главная » Статьи » Обучение PIC с нуля

16 One-wire на примере DS18b20

Задача: Измерение температуры с помощью датчика DS18b20

Исходный материал: PIC16f628a, DS18b20, MAX232 level converter, devboard, proteus.

В данной статье рассмотрен пример работы в случае присутствия на линии одного датчика DS18b20, также здесь приводится текст стандартных функций для работы с протоколом 1-wire.



Наша цель — получить температуры с минимальными телодвижениями, поэтому читаем даташит и обращаем внимание лишь на существенные моменты. Первый из которых — организация питания. В данном случае я не испытывал проблем с подачей питания, поэтому будем использовать стандартную схему питания:

Линия данных должна быть обязательна подтянута к питанию через резистор (в даташите рекомендуют 4.7 кОм). Курим даташит дальше — смотрим на организацию памяти:

Всего 9 байт памяти:
младший байт значения температуры
старший байт значения температуры
триггер срабатывания по максимуму
триггер срабатывания по минимуму
конфигурационный регистр
внутренние нужды
внутренние нужды
внутренние нужды
CRC

Из это кучи нас интересуют 0, 1 и 4 байт (и то 4 постольку поскольку).

4 байт — конфигурационный регистр:

В нем мы можем перезаписывать только 6 и 5 биты отвечающие за разрешение измерений. По дефолту датчик измеряет с 12 битным разрешением, что соответствует точности 0.0625 градуса. Возможны также следующие варианты:
9 бит — 0.5 градуса
10 бит — 0.25 градуса
11 бит — 0.125 градуса

Ниже представлена таблица значений битов и значений получаемого разрешения:

Рекомендую также обратить внимание на время преобразования температуры (такое время придется ждать, после подачи команды конвертации) если вы не хотите ловить левые косяки.

Посмотрим, что собой представляет непосредственно значение температуры в первых двух байтах:

В младшем байте 4 младших бита отвечают за дробную часть, целое значение берется из старших бит младшего и трех младших бит старшего байта. Биты S отвечают за знак значения (Обратите внимание, что для конвертации отрицательных значений температуры, нужно применять другие правила конвертации двоичного кода в десятичный) — если биты S = 1 — температура отрицательна, ну и соответственно наоборот.

Рассмотрим базовые процедуры для работы с one-wire, любая система команд по протоколу начинается с инициализации:

Для успешной процедуры, микроконтроллер должен провалить линию минимум на 480 мкс, затем отпустить и посмотреть провалит ли ее вслед за ним наш датчик, если провал есть — все нормально датчик присутствует. Напишем под это дело свою функцию, не забывая что в данном случае мы оперируем лишь состояниями порта (вход/выход) а не значениями.

предварительно объявим такое дело:

#define STATE TRISB4
#define PIN RB4


static bit INIT(void){
static bit b;
STATE = 1;
STATE = 0; //Проваливаем линию
__delay_us(500); //Ждем 500 мкс
STATE = 1; //Переключаемся на вход
__delay_us(65); //Ждем 65 мкс
b = PIN; //Смотрим чего там на линии
__delay_us(450); //Дожидаемся до положенного временного интервала
return b; //Возвращаем 0 или 1
}


Функция возвращает 0 если устройство присутствует на шине и 1 если устройства не обнаружено. Дальше нам надо сварганить функцию для записи в микросхему:

Чтобы передать устройству 0, нужно опустить линию минимум на 60 мкс, для передачи 0 — проваливаем шину минимум на 1 мкс, а затем отпускаем и выдерживаем нужное время. Учитываем то, что биты должны передаваться младшим вперед:

void TX(unsigned char cmd){

unsigned char temp = 0;
unsigned char i = 0;
temp = cmd;
for (i=0;i<8;i++) {
if (temp&0x01) {
STATE = 0; //передаем 1
__delay_us(5);
STATE = 1;
__delay_us(70);
} else { //передаем 0
STATE = 0;
__delay_us(70);
STATE = 1;
__delay_us(5);
}
temp >>= 1;
}
}



Теперь по чтению:

Для успешного чтения микроконтроллер сначала должен опустить шину хотя бы на секунду, а дальше переключиться обратно на вход и смотреть чего там происходит. Чтобы снять корректное значение нужно выждать по крайней мере 15 мкс от начала (чтобы не попасть на значение во время перезарядки емкостей).

unsigned char RX() {

unsigned char d = 0;
unsigned char i = 0;
for (i=0;i<8;i++){
STATE = 0; //прижимаем линию
__delay_us(6);
STATE = 1;
__delay_us(10); //дожидаемся больше чем 15 мкс
d>>=1; //освобождаем место под новый бит
if (PIN == 1) d |= 0x80; //если 1 то записываем 1
__delay_us(60); //ждем до положенного времени
}
return d;
}



Этих трех функций достаточно для работы с протоколом 1-wire. Для того чтобы снять показания температуры нам нужно выполнить ряд команд (для случая одного датчика на шине):
инициализация
0xCC — пропускаем идентификацию
0х44 — запуск конвертации температуры
ждем необходимое время(750 мс для 12 битного разрешения)
повторная инициализация
0xCC — пропускаем идентификацию
0хBE — читаем регистры

Я создал для выполнения данной последовательности отдельную процедуру, включающую в себя конвертацию двоичного значения температуры в десятичное.

void get_temp() {
static bit init;

unsigned char temp1;
unsigned char temp2;
init = INIT();
if (!init) { //успешно инициализировались?
TX(0xCC);
TX(0x44);
__delay_ms(150); //ждем 750 мс
__delay_ms(150);
__delay_ms(150);
__delay_ms(150);
__delay_ms(150); }
init = INIT(); //повторная инициализация
if (!init) {
TX(0xCC);
TX(0xBE); //команда на чтение
temp1 = RX(); //читаем младший байт
temp2 = RX(); //читаем старший байт
}

temp_drob = temp1 & 0b00001111; //Записываем дробную часть в отдельную переменную
temp_drob = ((temp_drob*6)+2)/10; //Переводим в нужное дробное число
temp1 >>= 4;
sign = temp2 & 0x80; //определяем знак температуры
temp2 <<= 4;
temp2 &= 0b01110000;
temp2 |= temp1; //помещаем все в одну переменную

if (sign) { //если минус
temperature = 127-temp2; //глобальная переменная
temp_drob = 10 - temp_drob; //глобальная переменная
} else temperature = temp2;
}



Чтобы проверить работоспособность я собрал схему на макетке и вывел информацию через уарт:

void main() {
unsigned char input = 0;

init_comms();
get_temp();
printf("\ftemperatura -- ");
if (sign) printf("-"); else printf("+");
printf("%d", temperature);
printf(".%d", temp_drob);

while(1){
input = getch();
if (input == 50) {
get_temp();
printf("\r\ntemperatura -- ");
if (sign) printf("-"); else printf("+");
printf("%d", temperature);
printf(".%d", temp_drob);
}
}
}



Вот что получилось:








Источник: http://diymicro.ru/?p=137
Категория: Обучение PIC с нуля | Добавил: аля))) (28.06.2012)
Просмотров: 2505 | Комментарии: 1 | Теги: 1-wire, one-wire, I2C, pic16f628a., DS18b20, PIC микроконтроллеры | Рейтинг: 0.0/0
Всего комментариев: 1
0  
1 Linar   (05.02.2013 10:32) [Материал]
static bit INIT(void){
static bit b;
STATE = 1;
NOP();
STATE = 0; //Проваливаем линию
PIN=0; //###### Чтобы провалить линию нужно записать 0 в порт, а то не всегда инициализация проходила
__delay_us(500); //Ждем 500 мкс
STATE = 1; //Переключаемся на вход
__delay_us(65); //Ждем 65 мкс
b = PIN; //Смотрим чего там на линии
__delay_us(450); //Дожидаемся до положенного временного интервала
return b; //Возвращаем 0 или 1
}

Добавлять комментарии могут только зарегистрированные пользователи.
[ Регистрация | Вход ]
Профиль
Суббота
04.05.2024
17:14

Новости сайта
Добавленно новых материалов:
****************************************
1.06.2012
Просьба...
Уважаемые пользователи!
Выделите пожалуйста 1 минуту вашего времени и кликните пару ссылок от рекламы на Google. Тем самым вы потдержите проект.
Спасибо!
Реклама