Библиотека AVR для работы с 1-wire датчиком температуры DS18B20

Опубликовано lamazavr - пн, 12/16/2013 - 19:40
Body

При работе с датчиком по шине (да, да один провод - тоже шина) 1-wire следует особое внимание уделять временным задержкам.
Благо для AVR соответствующие функции написаны практически для всех IDE.

Работу с 1-wire я описывал, поэтому заострять внимание не будем..

// частота работы
#define F_CPU 1000000UL

#include <math.h>
#include <avr/io.h>
#include <util/delay.h>
#include <stdio.h>

/* Определяем куда подключен датчик */
#define THERM_PORT PORTC
#define THERM_DDR DDRC
#define THERM_PIN PINC
#define THERM_DQ PC0
/* Макросы для "дергания ноги" и изменения режима ввода/вывода */
#define THERM_INPUT_MODE() THERM_DDR&=~(1<<THERM_DQ)
#define THERM_OUTPUT_MODE() THERM_DDR|=(1<<THERM_DQ)
#define THERM_LOW() THERM_PORT&=~(1<<THERM_DQ)
#define THERM_HIGH() THERM_PORT|=(1<<THERM_DQ)

// сброс датчика
uint8_t therm_reset(){
	uint8_t i;
	// опускаем ногу вниз на 480uS
	THERM_LOW();
	THERM_OUTPUT_MODE();
	_delay_us(480);             // замените функцию задержки на свою
	// подымаем линию на 60uS
	THERM_INPUT_MODE();
	_delay_us(60);
	// получаем значение на линии в период 480uS
	i=(THERM_PIN & (1<<THERM_DQ));
	_delay_us(420);
	// возвращаем значение (0=OK, 1=датчик не найден)
	return i;
}


// функция отправки бита
void therm_write_bit(uint8_t bit){
	// опускаем на 1uS
	THERM_LOW();
	THERM_OUTPUT_MODE();
	_delay_us(1);
	// если хотим отправить 1, поднимаем линию (если нет, оставляем как есть)
	if(bit) THERM_INPUT_MODE();
	// ждем 60uS и поднимаем линию
	_delay_us(60);
	THERM_INPUT_MODE();
}

// чтение бита
uint8_t therm_read_bit(void){
	uint8_t bit=0;
	// опускаем на 1uS
	THERM_LOW();
	THERM_OUTPUT_MODE();
	_delay_us(1);
	// поднимаем на 14uS
	THERM_INPUT_MODE();
	_delay_us(14);
	// читаем состояние
	if(THERM_PIN&(1<<THERM_DQ)) bit=1;
	// ждем 45 мкс и возвращаем значение
	_delay_us(45);
	return bit;
}

// читаем байт
uint8_t therm_read_byte(void){
	uint8_t i=8, n=0;
	while(i--){
		// сдвигаем в право на 1 и сохраняем следующее значение
		n>>=1;
		n|=(therm_read_bit()<<7);
	}
	return n;
}

// отправляем байт
void therm_write_byte(uint8_t byte){
	uint8_t i=8;
	while(i--){
		// отправляем бит и сдвигаем вправо на 1
		therm_write_bit(byte&1);
		byte>>=1;
	}
}


// команды управления датчиком
#define THERM_CMD_CONVERTTEMP 0x44
#define THERM_CMD_RSCRATCHPAD 0xbe
#define THERM_CMD_WSCRATCHPAD 0x4e
#define THERM_CMD_CPYSCRATCHPAD 0x48
#define THERM_CMD_RECEEPROM 0xb8
#define THERM_CMD_RPWRSUPPLY 0xb4
#define THERM_CMD_SEARCHROM 0xf0
#define THERM_CMD_READROM 0x33
#define THERM_CMD_MATCHROM 0x55
#define THERM_CMD_SKIPROM 0xcc
#define THERM_CMD_ALARMSEARCH 0xec

#define THERM_DECIMAL_STEPS_12BIT 625 //.0625

// читаем температуру с датчика
void therm_read_temperature(char *buffer){
	uint8_t temperature[2];
	int8_t digit;
	uint16_t decimal;

	therm_reset();
	therm_write_byte(THERM_CMD_SKIPROM);
	therm_write_byte(THERM_CMD_CONVERTTEMP);

	while(!therm_read_bit());

	therm_reset();
	therm_write_byte(THERM_CMD_SKIPROM);
	therm_write_byte(THERM_CMD_RSCRATCHPAD);

	temperature[0]=therm_read_byte();
	temperature[1]=therm_read_byte();
	therm_reset();

	digit=temperature[0]>>4;
	digit|=(temperature[1]&0x7)<<4;

	decimal=temperature[0]&0xf;
	decimal*=THERM_DECIMAL_STEPS_12BIT;
	
        // я вывожу данные на порт
	PORTA = digit;
	PORTB = decimal >> 8;
	
	sprintf(buffer, "%+d.%04u C", digit, decimal);
}

int main(void)
{
	DDRA = 0xff;
	DDRB = 0xff;
	
	char buffer[100];
	
    while(1)
    {
        therm_read_temperature(buffer); 
    }
}

Не пугайтесь, тут ничего сложного. Чтобы понять все это ознакомтесь со статьей по ссылке выше и почитайте даташит на датчик.
Библиотека для AVR Studio. В Code Vision есть встроенная библиотека, если вы хотите использовать эту, замените функции задержки.

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

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