Опрос датчика температуры по 1-wire контроллером AVR на Си с avr-libc

Недавно мне по работе нужно было реализовать на AVR опрос датчика температуры Dallas DS18B20 для управления частотным приводом насоса системы охлаждения. В интернете нашел много статей как всё это сделать на ассемблере, но по некоторым обстоятельствам мне нужно было на Си.

В начале добавим заголовочные файлы:

 

#include <avr/io.h>
#include <util/crc16.h>
#include <util/delay.h>
#include <avr/interrupt.h>

 

После этого я обычно объявляю макросы для работы с отдельными выводами портов ввода/вывода. На моей схеме датчик был подкулючен через согласующий транзистор к разным выводам. У меня получился такой код:

 

#define RX() bit_is_set(PINC,0)
#define TX1() PORTC &= ~_BV(1) //выходной сигнал инвертирован
#define TX0() PORTC |= _BV(1)

 

Из datasheet на датчики температуры фирмы Dallas ясно, что все команды общения с датчиком посылаются после инициализация. Она нужна для того чтобы датчик понял, что ему сейчас будет послана команда. И написал такую функцию:

 

/*Сброс и ожидание начала presence pulse*/
uint8_t oneWireInit() {
	cli();
	TX0();
	_delay_us(500);
	TX1();
	_delay_us(60);
	sei();
	return RX() ; //если на выводе 1 - ошибка
}

 

Далее напишем фунцию отправки массива данных. т.к. вся работа с датчиком происходит в пределах одного пространтва имен я объявил глобальный массив:

 

uint8_t frame[9] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

 

как разделяемые данные для разных функций. И так функция отправки(как аргумент функция получает байт который необходимо отправить):

 

/* Передача 1 байта. Передача осуществляется
 * младшим битом вперед
 */
void oneWireTans(uint8_t data) {
	cli();
	for (uint8_t i = 0; i<8;i++) {
		TX0(); //импульс сброса (1-15мкс) - начало интервала передачи
		_delay_us(5);
		if (data & 0x01) {
			TX1();
		}
		else {
			TX0();
		}
		_delay_us(60);//пауза для считывания данных таблеткой (60-120мкс)
		TX1();//импульс сброса "1"(1мкс)
		_delay_us(10);
		data >>= 1;
	}
	sei();
}

 

Прием данных осуществляется в массив frame в качестве аргумента функция получает колличество байт, оно зависит от типа команды которую мы послали датчику:

 

/*Чтение length байт данных младшим байтом вперед*/
void oneWireRecv(uint8_t length) {
	cli();
	_delay_us(60);
	for (uint8_t i = 0;i<length;i++) {
		frame[i] = 0x00; //Очистка буфера приема
		/*Цикл для приема очередного байта*/
		for (uint8_t j = 0;j<8;j++) {
			frame[i] >>= 1;
			TX0();			//импульс сброса "0"(1-15мкс) - начало интервала приема
			_delay_us(10);
			TX1();			//импульс сброса "1"
			_delay_us(9);
			frame[i] |= RX() ? 0x80:0;
			_delay_us(50);
		}

	}
	sei();
}

 

В нутри каждой функции есть макросы cli() и sei() для запрета прерываний на время общения с датчиком.

Все базовые функции написаны. Теперь напишем функцию которая мопожет нам обстрагироваться от всех внутренних команд датчика и просто возвратит температуру. Я назавал функцию getT() --> get Temperature вот её содержимое:

 

uint16_t getT() {

	/*Чение адреса термо датчика*/
	if (oneWireInit()) return 255;
	_delay_us(110);			//Ожидание конца presence pulse
	oneWireTans(0x33);		//Чтение ROM подчиненного устройства
	oneWireRecv(8);			//Читаем ROM

	/*Расчет CRC*/
	uint8_t crcResult = 0;
	for (uint8_t i = 0; i<7;i++) {
		crcResult = _crc_ibutton_update(crcResult,frame[i]);
	}
	if (crcResult != frame[7]) return 254;

	/*даем команду конвертации температуры нужному устройсту*/
	if (oneWireInit()) return 253;
	_delay_us(110);			//Ожидание конца presence pulse
	oneWireTans(0x55);
	for (uint8_t i = 0; i<8; i++) {
		oneWireTans(frame[i]);
	}
	oneWireTans(0x44);		//Команда конвертации и записи температуры в регистр

	/*Чтение температуры*/
	if (oneWireInit()) return 252;
	_delay_us(110);			//Ожидание конца presence pulse
	oneWireTans(0x55);
	for (uint8_t i = 0; i<8; i++) {
		oneWireTans(frame[i]);
	}
	oneWireTans(0xBE);		//Комманда чтения регистра с температурой
	oneWireRecv(9);
	crcResult = 0;
	for (uint8_t i =0; i<8;i++) {
		crcResult = _crc_ibutton_update(crcResult,frame[i]);
	}
	if(crcResult != frame[8]) return 251;

	//Store integer
	uint16_t digit=frame[0]>>4;
	digit|=(frame[1]&0xf)<<4;
	//Store decimal digits
	uint8_t decimal=frame[0]&0xf;
	decimal= (decimal*5)/8;

	/*Возвращается только цело значение*/
	return ((uint16_t)digit);
}

 

При проектировании я знал, что теперература возвращаемая датчиком не может быть больше 125С. И все значаения выше 200 я возвращал как сигнал о той или иной ошибке. Используем функцию так. Считываем значение в переменную. Если значение больше 200 значит произошла та или иная ошибка чтения. Если меньше значит все Ок и это искомая температура. Если есть предложения по улучшению кода, пишите в комментариях к статье.

Архив с исходниками.

Дополнительная информация:

Теги: , , ,

Дата: 29 августа 2011

Автор: andreykyz

Комментарии: 421

Комментарии: 421

  1. cialis online overnight [url=https://omgcialis.com/]cheap cialis fast shipping[/url] cialis chpl

  2. cialis eparina [url=https://omgcialis.com/]cialis paypal viagra[/url] cialis preis lilly

  3. It's the best time to make some plans for the future and it is time to be happy.
    I've read this post and if I could I want to
    suggest you few interesting things or tips. Maybe you can write next articles referring to this article.

    I want to read even more things about it! https://atadalafil.online/

  4. cialis effects on eyes [url=https://omgcialis.com/]buy cialis jelly[/url] cialis in miami

  5. does humana pay for cialis [url=https://omgcialis.com/]80mg tadalafil[/url] cialis online italy

  6. online doctor cialis [url=https://omgcialis.com/]liquid cialis[/url] cialis lust

  7. Hi there! Do you use Twitter? I'd like to follow
    you if that would be okay. I'm definitely enjoying your blog and look forward to new posts. http://antiibioticsland.com/Stromectol.htm

  8. plaquenil 200 mg twice a day https://plaquenilx.com/# hydroxichlorquine

  9. First off I want to say awesome blog! I had a quick question that I'd like to ask if you don't mind.
    I was curious to find out how you center yourself and clear your mind before
    writing. I have had a difficult time clearing my
    thoughts in getting my thoughts out there.
    I truly do take pleasure in writing but it just seems like the first 10 to 15 minutes are wasted just trying to figure out how to
    begin. Any ideas or tips? Thank you! http://droga5.net/

  10. What's up, I check your blog daily. Your humoristic style is
    awesome, keep it up! http://cleckleyfloors.com/

  11. Great beat ! I would like to apprentice while you amend
    your site, how could i subscribe for a blog website?
    The account helped me a acceptable deal. I had been tiny bit acquainted of this your broadcast provided bright clear concept https://hhydroxychloroquine.com/

  12. Spot on with this write-up, I honestly feel this web site needs a great deal more attention. I'll probably be returning to read more,
    thanks for the advice! http://www.deinformedvoters.org/hydroxychloroquine

  13. dolquine https://plaquenilx.com/# what is hydroxychloroquine 200 mg

Оставить комментарий

*

Комментарий:

Ваш e-mail не будет опубликован.
Обязательные поля помечены *

Разрешенные HTML теги:

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>