#define 		__1_WIRE_DRIVER_				1			//макробъявление названия библиотеки (поможет скомпилировать :))



/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
типа модуль для 1Wire устройств
пример использования:

#include "1wire.h"											//.h для работы с протоколом 1-wire

int main(void){
 cli();	
  DeviceQ_Init();											//Установка направления порта 1-wire
 
  DeviceQ_FIND_DEVICE_CODE(0x10);							//поиск и заполнение массива только адресами устройств типа 0x10

  sprintf((char *)BufferUSART0,"Count Device = %d\n\r", _deviceQ_find_count);
  USART_Transmit_String(BufferUSART0);

 for (int i = 0; i<_deviceQ_find_count; i++){
  DeviceQ_Read_Temperature(i);
  sprintf((char *)BufferUSART0,"T#%d = %d\n\r", i, Temperature);
  USART_Transmit_String(BufferUSART0);

 sei();														//разрешить все прерывания
 while(1){
   NOP;
 }												
}
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/




#if defined 	_STDBOOL_H															//если библиотека (_STDBOOL_H) подключена  - ни чего не делать
#else																				//если библиотека не подключена ->>>
	#warning "не подключена библиотека stdbool.h - подключаю..."
	#include <stdbool.h>
#endif


#if defined 	__IO_INCLUDE_														//если библиотека (__IO_INCLUDE_) подключена  - ни чего не делать
#else																				//если библиотека не подключена ->>>
	#warning "не подключена библиотека OInclude.h  - воссоздаю необходимый минимум..."
 	#define NOP	asm volatile("nop");

	#define _GetbitL(port,bit) 					(!(port&(1<<bit)))
	#define _GetbitH(port,bit)					(port&(1<<bit))
	#define  GetBitL(x)							_GetbitL(x)
	#define  GetBitH(x)							_GetbitH(x)

	#define _SetBit(port,bit)					(port = port|(1<<bit))				//установить высокий уровень
	#define _ClrBit(port,bit)					(port^= port&(1<<bit))				//снять высокий уровень
	#define _InvBit(port,bit)					(port = port^(1<<bit))				//инвертировать уровень
	#define SetBit(x)							_SetBit(x)
	#define ClrBit(x)							_ClrBit(x)
	#define InvBit(x)							_InvBit(x)

 	#define _until_bit_is_set(port,bit)			loop_until_bit_is_set(port, bit)
 	#define until_bit_is_set(x)					_until_bit_is_set(x);

 	#define _until_bit_is_clear(port,bit)		loop_until_bit_is_clear(port, bit)
 	#define until_bit_is_clear(x)				_until_bit_is_clear(x);
#endif



//=======================================================================================================================
//=========================управляющий вывод для опроса 1-wire  устройства===============================================
//=======================================================================================================================
  #define DeviceQ_IO		PINF
  #define DeviceQ_DDR		DDRF,		7			//Бит для записи
  #define DeviceQ_PIN		PINF,		7			//Бит для чтения
  #define DeviceQ_PORT		PORTF,		7			//Бит порта
  #define _deviceQ_max_count			8			//Максимальное число устройств на шине
 
 
 //=======================================================================================================================
//=====================================команды на работу с 1 wire протоколом=============================================
//=======================================================================================================================
  #define READ_ROM						0x33		//команда позволяет прочитать содержимое ПЗУ. В ответ на эту команду DS18S20 передает 8-битный код семейства (10h), затем 48-битный серийный номер, а затем 8-битную CRC для проверки правильности принятой информации
  #define MATCH_ROM						0x55		//команда позволяет адресовать на шине конкретный термометр. После этой команды мастер должен передать нужный 64-битный код, и только тот термометр, который имеет такой код, будет «откликаться» до следующего импульса сброса
  #define SKIP_ROM						0xCC		//команда позволяет пропустить процедуру сравнения серийного номера и тем самым сэкономить время в системах, где на шине имеется всего одно устройство
  #define OVERDRIVE_SKIP_ROM			0x3C		//то же только быстро
  #define OVERDRIVE_SKIP_MATCH_ROM		0x69		//то же только быстро
  #define SEARCH_ROM					0xF0		//команда позволяет определить серийные номера всех термометров, присутствующих на шине
  #define ALARM_SEARCH					0xEC		//команда аналогична предыдущей, но «откликаться» будут только те термометры, у которых результат последнего измерения температуры выходит за предустановленные пределы TH и TL



//=======================================================================================================================
//==================================ДЛЯ ТЕМПЕРАТУРНЫХ ДОТЧИКОВ (дополнительные функции)==================================
//=======================================================================================================================
//команды на работу с 1 wire DS18x20 (температурный датчик)
  #define CONVERT_T						0x44		//Команда запуска преобразования температуры датчика
  #define READ_SCRATCHPAD				0xBE		//команда позволяет считать данные из промежуточного ОЗУ
  #define WRITE_SCRATCHPAD				0x4E		//команда позволяет записать данные в промежуточное ОЗУ DS18S20
  #define COPY_SCRATCHPAD				0x48		//команда копирует байты TH и TL из промежуточного ОЗУ в энергонезависимую память. Эта операция требует около 10мс
  #define OVERDRIVE						0x0D		//Команда перехода в быстрый обмен
  #define RECALL_E2						0xB8		//команда действует обратным образом по отношению к команде Copy Scratchpad, т.е. она позволяет считать байты TH и TL из энергонезависимой памяти в промежуточное ОЗУ. При включении питания эта команда выполняется автоматически.
  #define READ_POWER_SUPPLY				0xB4		//команда позволяет проверить, использует ли DS18S20 паразитное питание. Дело в том, что DS18S20 можно подключать всего с помощью двух проводов, в этом случае для питания используется линия данных.

  
 
//=======================================================================================================================
//=======================ошибки, возникающие при работе с устройством по 1 wire протоколу================================
//=======================================================================================================================
  volatile unsigned char _1_WIRE_ERROR= 0x00;		// 0x00 - нет устройства на шине
  													// 0x01 - устройство на шине
  													// 0x02 - короткое замыкание на землю
													// 0x03 - нет устройства в базе
													// 0x04 - не сошлось CRC
													// 0x05 - ошибка данных устройства
													// 0x06 - ошибка при прогоне команды CONVERT_T
													// 0x07 - ошибка при прогоне команды READ_SCRATCHPAD
													// 0x08 - неизвестная ошибка ошибка


//=======================================================================================================================
//================================ Рекомендованные задержки от Dallas AppNote 126 =======================================
//=======================================================================================================================
 #define DeviceQ_delay_A				6
 #define DeviceQ_delay_B				64
 #define DeviceQ_delay_C				60
 #define DeviceQ_delay_D				10
 #define DeviceQ_delay_E				9
 #define DeviceQ_delay_F				55
 #define DeviceQ_delay_G				0
 #define DeviceQ_delay_H				480
 #define DeviceQ_delay_I				70
 #define DeviceQ_delay_J				410


 #define DeviceQ_E2_delay_A				1.5
 #define DeviceQ_E2_delay_B				7.5
 #define DeviceQ_E2_delay_C				7.5
 #define DeviceQ_E2_delay_D				2.5
 #define DeviceQ_E2_delay_E				0.75
 #define DeviceQ_E2_delay_F				7
 #define DeviceQ_E2_delay_G				2.5
 #define DeviceQ_E2_delay_H				70
 #define DeviceQ_E2_delay_I				8.5
 #define DeviceQ_E2_delay_J				40
 

//=======================================================================================================================
//======================================== Идентификаторы устройств по типам ============================================
//=======================================================================================================================
 #define DS18S20_FAMILY_CODE 			0x10
 #define DS18B20_FAMILY_CODE 			0x28
 #define DS1822_FAMILY_CODE 			0x22
 #define DS1990_FAMILY_CODE 			0x01
 #define DS2405_FAMILY_CODE				0x05
 #define DS2430_FAMILY_CODE 			0x14
 #define DS2431_FAMILY_CODE 			0x2D
 #define DS2433_FAMILY_CODE 			0x23



//=======================================================================================================================
//=============================== Необходимые переменные для работы с устройсвами =======================================
//=======================================================================================================================
 unsigned char			_deviceQ_power_supply 				= false;						//флаг от чего питается устройство
 unsigned char			_deviceQ_all_rom[_deviceQ_max_count][8];							//массив хранения адресов устройств ([_deviceQ_max_count штук], [тип, адрес, CRC])
 unsigned char			_deviceQ_ScratchPad[9];
 unsigned char			_deviceQ_rom_array[8];												//адрес устройства
 volatile unsigned char	_deviceQ_find_count						= 0;						//количество найденых устройств
 unsigned char			_deviceQ_previus_temp_flag				= 0;						//значение изменения предыдущего значения температуры

 int					_deviceQ_last_discrepancy				= 0;
 int					_deviceQ_last_family_discrepancy		= 0;
 int					_deviceQ_last_device_flag				= 0;

 unsigned char			_deviceQ_overdrive 					= false;						//флаг включенного режима OverDrive

 unsigned char			_deviceQ_temperature_flag 			= false;						//был ли пересчет после запуска?
 volatile int			Temperature 							= 0;						//Непересчитанное и неделенное на 2 значение температуры
 int					TemperH 								= 0,						//верхний 
 						TemperL 								= 0;						//и нижний байт значения температуры


//=======================================================================================================================
//================================================= Таблица CRC8 ========================================================
//=======================================================================================================================
 unsigned char			crc8;																//промежуточное значение CRC
 static unsigned char	dscrc_table[] = {
        0, 94,188,226, 97, 63,221,131,194,156,126, 32,163,253, 31, 65,
      157,195, 33,127,252,162, 64, 30, 95,  1,227,189, 62, 96,130,220,
       35,125,159,193, 66, 28,254,160,225,191, 93,  3,128,222, 60, 98,
      190,224,  2, 92,223,129, 99, 61,124, 34,192,158, 29, 67,161,255,
       70, 24,250,164, 39,121,155,197,132,218, 56,102,229,187, 89,  7,
      219,133,103, 57,186,228,  6, 88, 25, 71,165,251,120, 38,196,154,
      101, 59,217,135,  4, 90,184,230,167,249, 27, 69,198,152,122, 36,
      248,166, 68, 26,153,199, 37,123, 58,100,134,216, 91,  5,231,185,
      140,210, 48,110,237,179, 81, 15, 78, 16,242,172, 47,113,147,205,
       17, 79,173,243,112, 46,204,146,211,141,111, 49,178,236, 14, 80,
      175,241, 19, 77,206,144,114, 44,109, 51,209,143, 12, 82,176,238,
       50,108,142,208, 83, 13,239,177,240,174, 76, 18,145,207, 45,115,
      202,148,118, 40,171,245, 23, 73,  8, 86,180,234,105, 55,213,139,
       87,  9,235,181, 54,104,138,212,149,203, 41,119,244,170, 72, 22,
      233,183, 85, 11,136,214, 52,106, 43,117,151,201, 74, 20,246,168,
      116, 42,200,150, 21, 75,169,247,182,232, 10, 84,215,137,107, 53};


//=======================================================================================================================
//=================================== Ппроверка принятого от устройства по CRC ==========================================
//=======================================================================================================================
unsigned char docrc8(unsigned char value){
   crc8 = dscrc_table[crc8 ^ value];
   return crc8;
}

 
//=======================================================================================================================
//===================== Предопределения процедур и функций для работы с 1 wire протоколом ===============================
//=======================================================================================================================
 void			DeviceQ_Init();																// инициализация протокола, макроопределений и сброс устройства
 void			DeviceQ_Pullup(bool LogicVal);												// подтяжка порта к + для зарядки аккумулятора устройств Dallas

 unsigned char	DeviceQ_reset();															// сброс устройства
 void			DeviceQ_write_1();															// запись 1bit в порт
 void			DeviceQ_write_0();															// запись 0bit в порт
 void			DeviceQ_write_bit(unsigned char data);										// запись 1bit or 0bit в порт
 void			DeviceQ_write_byte(unsigned char data);										// запись 1byte в порт
 unsigned char	DeviceQ_read_bit();															// чтение 1bit из порта
 unsigned char	DeviceQ_read_byte();														// чтение 1byte из порта
 unsigned char	DeviceQ_read_list_array(unsigned char * array, unsigned char i, bool LogicVal);// прочитать массив (приемник, количество принимаемых байт, 1:норм/0:обратная последовательность заполнения массива)

 void			DeviceQ_READ_ROM_COMMAND(void);
 unsigned char	DeviceQ_MATCH_ROM_COMMAND(unsigned char * array_rom);
 int			DeviceQ_SEARCH_ROM_COMMAND(void);
 unsigned char	DeviceQ_ALARM_SEARCH_COMMAND(void);
 unsigned char	DeviceQ_SKIP_ROM_COMMAND(void);
 void			DeviceQ_CONVERT_TEMPERATURE_COMMAND(void);
 void			DeviceQ_COPY_SCARTCHPAD_COMMAND(void);
 void			DeviceQ_WRITE_SCARTCHPAD_COMMAND(unsigned char TH, unsigned char TL);
 void			DeviceQ_READ_SCARTCHPAD_COMMAND(unsigned char * _ScratchPad);
 void			DeviceQ_RECALL_E2_COMMAND(void);
 unsigned char	DeviceQ_READ_POWER_SUPPLY_COMMAND(void);

 void			DeviceQ_OVERDRIVE_COMMAND(bool LogicVal);									// включить быстрый обмен

 int			DeviceQ_First();															// поиск первого устройства на шине (TRUE: есть устройства FALSE: нет устройств)
 int			DeviceQ_Next();																// поиск следующего устройства на шине (TRUE: есть устройства FALSE: нет устройств)
 int			DeviceQ_Verify();															// проверка найденного устройства на шине
 void			DeviceQ_TargetSetup(unsigned char family_code);								// поиск по типу устройства на шине
 void			DeviceQ_FamilySkipSetup();													// пропустить найденое устройство по типу
 int			DeviceQ_FIND_ALL(void);														// найти все устройства на шине
 int 			DeviceQ_FIND_DEVICE_CODE(unsigned char QDevice_code);						// поиск устройств по классу
 int 			DeviceQ_FIND_DEVICE_EXCEPTION_CODE(void);									// искать устройства за исключением....

 unsigned char	docrc8(unsigned char value);												// проверка CRC8

 void			Calc_Temp_ds18S20(char MSByte, char LSByte);								// вычисление температуры для DS18S20
 void			Calc_Temp_ds18B20(char MSByte, char LSByte);								// вычисление температуры для DS18B20
 void			DeviceQ_Read_Temperature(unsigned char Num_QDevice);						// чтение параметров DS18x20 для вычисления температуры


//=======================================================================================================================
//=============================установка начального направления порта для устройства=====================================
//=======================================================================================================================
void DeviceQ_Init(void){
cli();
    DeviceQ_OVERDRIVE_COMMAND(0);					// Скорость обмена по дефолту (нормальная)
	DeviceQ_Pullup(1);								// для зарядки аккумулятора устройства на порту
	DeviceQ_reset();
sei();
}


//=======================================================================================================================
//================================== Включить поддтяжку порта для зарядки устройства=====================================
//=======================================================================================================================
void DeviceQ_Pullup(bool A){
 if (A) {ClrBit(DeviceQ_PORT);	NOP;
	 	 ClrBit(DeviceQ_DDR);	NOP;}				// для зарядки аккумулятора устройства на порту}
 else 	{ClrBit(DeviceQ_PORT);	NOP;
		 SetBit(DeviceQ_DDR);	NOP;}				// передача импульса RESET}
}


//=======================================================================================================================
//=========== Функция DeviceQ__RESET -> сбрасывает шину 1-Wire и определяет наличие подключенных устройств.====================
//================= Сигнал сброса должен быть длинной минимум 480 мкс. Полный цикл 960 минимум ==========================
//=======================================================================================================================
unsigned char DeviceQ_reset(void){
cli();
	_1_WIRE_ERROR = 0x00;							// нет устройства на шине

	DeviceQ_Pullup(1);								// для зарядки аккумулятора устройства на порту

 													//=========================================================================================
 if (_deviceQ_overdrive){									// OVERDRIVE РЕЖИМ СКОРОСТИ
	_delay_us(DeviceQ_E2_delay_G);					//=========================================================================================
	DeviceQ_Pullup(0);								// передача импульса RESET
	_delay_us(DeviceQ_E2_delay_H);					// задержка 70us по Datasheet
	DeviceQ_Pullup(1);								// для зарядки аккумулятора устройства на порту
	_delay_us(DeviceQ_E2_delay_I);					// время реакции для ответа "PRESENCE" от 1-wire устройства 

	if (GetBitL(DeviceQ_PIN))						// если на ножке логический 0 -> (устройство должно замкнуть на землю ногу на 240us) импульс PRESENCE
		_1_WIRE_ERROR = 0x01;						// по предварительным данным на линии есть устройство (ошибки нет)

	_delay_us(DeviceQ_delay_J);						// ждем окончания временного промежутка (420us) по Datasheet для перехода 1-wire устройства в рабочий режим и чтобы убедитьться, что это не замыкание на землю.
 }													//=========================================================================================
 else 												// НОРМАЛЬНЫЙ РЕЖИМ СКОРОСТИ
 {													//=========================================================================================
	_delay_us(DeviceQ_delay_G);
	DeviceQ_Pullup(0);								// передача импульса RESET
	_delay_us(DeviceQ_delay_H);						// задержка 480us по Datasheet
	DeviceQ_Pullup(1);								// для зарядки аккумулятора устройства на порту
	_delay_us(DeviceQ_delay_I);						// время реакции для ответа "PRESENCE" от 1-wire устройства 

	if (GetBitL(DeviceQ_PIN))						// если на ножке логический 0 -> (устройство должно замкнуть на землю ногу на 240us) импульс PRESENCE
		_1_WIRE_ERROR = 0x01;						// по предварительным данным на линии есть устройство (ошибки нет)

	_delay_us(DeviceQ_delay_J);						// ждем окончания временного промежутка (420us) по Datasheet для перехода 1-wire устройства в рабочий режим и чтобы убедитьться, что это не замыкание на землю. 
 }

 if (GetBitL(DeviceQ_PIN))							// если на ножке логический 0 после выдержки ресета по Datasheets -> 
	_1_WIRE_ERROR = 0x02;							// err нет устройства на шине или замыкание на землю

 return _1_WIRE_ERROR;
sei();
}


//=======================================================================================================================
//========================================== WRITE_BIT -> запись 1 в шину ==================================================
//=======================================================================================================================
void DeviceQ_write_1(void){
 if (_deviceQ_overdrive){	
 	DeviceQ_Pullup(0);
		_delay_us(DeviceQ_E2_delay_A);
	DeviceQ_Pullup(1);
		_delay_us(DeviceQ_E2_delay_B);
 }else{
  	DeviceQ_Pullup(0);
		_delay_us(DeviceQ_delay_A);
	DeviceQ_Pullup(1);
		_delay_us(DeviceQ_delay_B);
 }
}


//=======================================================================================================================
//========================================== WRITE_BIT -> запись 0 в шину ==================================================
//=======================================================================================================================
void DeviceQ_write_0(void){
 if (_deviceQ_overdrive){	
 	DeviceQ_Pullup(0);
		_delay_us(DeviceQ_E2_delay_C);
	DeviceQ_Pullup(1);
		_delay_us(DeviceQ_E2_delay_D);
 }else{
 	DeviceQ_Pullup(0);
		_delay_us(DeviceQ_delay_C);
	DeviceQ_Pullup(1);
		_delay_us(DeviceQ_delay_D);
 }
}


//=======================================================================================================================
//================================== WRITE_BIT -> запись бита в шину.====================================================
//=======================================================================================================================
void DeviceQ_write_bit(unsigned char data){
cli();
  if (data !=0)		DeviceQ_write_1();				// выводим очередной бит начиная с младшего
  else				DeviceQ_write_0();
sei();
}


//=======================================================================================================================
//=================================WRITE_BYTE -> запись байта в шину.====================================================
//=======================================================================================================================
void DeviceQ_write_byte(unsigned char data){
cli();
 char count = 8;									// формируем счетчик бит
 do{												// цикл вывода бит на шину
  if (data & 0x01) 	DeviceQ_write_1();				// выводим очередной бит начиная с младшего
  else				DeviceQ_write_0();
  data >>= 1;										// сдвигаем данные вправо и проверяем окончание цикла
 }while(--count);
sei();
}


//=======================================================================================================================
//=================================READ_BIT -> чтение бита из шины.======================================================
//=======================================================================================================================
unsigned char DeviceQ_read_bit(void){
cli();
 unsigned char result = 0x00;
	DeviceQ_Pullup(0);								// установить ножку в 0

 if (_deviceQ_overdrive){	
	_delay_us(DeviceQ_E2_delay_A);					// задержка 15us 
	DeviceQ_Pullup(1);								// установить ножку на подтягиванием резистором (+4,7 в)
	_delay_us(DeviceQ_E2_delay_E);					// задержка 15us на всякий (данные установились на порту)						

    if (GetBitH(DeviceQ_PIN))	result = 0x01;		// если на ножке логическая 1 результат 1
   else 			result = 0x00;

	_delay_us(DeviceQ_E2_delay_F);					// жду конец таймслота
 }else{
	_delay_us(DeviceQ_delay_A);						// задержка 15us 
	DeviceQ_Pullup(1);								// установить ножку на подтягиванием резистором (+4,7 в)
	_delay_us(DeviceQ_delay_E);						// задержка 15us на всякий (данные установились на порту)						

    if (GetBitH(DeviceQ_PIN))	result = 0x01;		// если на ножке логическая 1 результат 1
   else 			result = 0x00;

	_delay_us(DeviceQ_delay_F);						// жду конец таймслота
 }

 return (result);									// возвращаем значение линии данных

sei();
}


//=======================================================================================================================
//======================================READ_BYTE -> чтение байта из шины================================================
//=======================================================================================================================
unsigned char DeviceQ_read_byte(void){
 cli();
  unsigned char	value =	0;

  for(int i = 0; i < 8; i++)
  	value |= DeviceQ_read_bit() << i;

  return(value);
 sei();
}


//=======================================================================================================================
//=====================================Считывание всего ключа массива====================================================
//=======================================================================================================================
unsigned char DeviceQ_read_list_array(unsigned char * array, unsigned char i, bool LogicVal){
 memset(array,0x00,i);											//очищаю предыдущее значение

 if (LogicVal) 
	for(unsigned char j=0;j!=i;j++){							//заполняю массив значениями от 0 до i
		array[j] = DeviceQ_read_byte();
	}		
 else
	while (i--){array[i] = DeviceQ_read_byte();}				//заполняю массив значениями от i до 0

 //_1_WIRE_ERROR = CheckRomCRC8(array,0);						//Проверка контрольной суммы полученных 8 байтов донных

 return _1_WIRE_ERROR;   
}


//=======================================================================================================================
//================================Чтение адреса единственного устройства на шине=========================================
//=======================================================================================================================
void DeviceQ_READ_ROM_COMMAND(void){
 memset(_deviceQ_rom_array,0x00,8);

 if (DeviceQ_reset() == 0x01){
 	DeviceQ_write_byte(READ_ROM);
 	DeviceQ_read_list_array(_deviceQ_rom_array,8,0);
 }
}


//=======================================================================================================================
//================================Выбор единственного устройства на шине по адресу=======================================
//================================= входящий параметр вместе с типом +ключ+CRC ==========================================
//=======================================================================================================================
unsigned char DeviceQ_MATCH_ROM_COMMAND(unsigned char * array_rom){
 if(DeviceQ_reset() == 0x01){
 	DeviceQ_write_byte(MATCH_ROM); 											// посылаю команду поиска адреса если одно устройство
	for(int i=0;i<8;i++) DeviceQ_write_byte(array_rom[i]);					// Получаю адрес
	return true;
 }else return false;
}


//=======================================================================================================================
//============================== Пропуск команд поиска адресa устройства ================================================
//=======================================================================================================================
unsigned char DeviceQ_SKIP_ROM_COMMAND(void){
 if(DeviceQ_reset() == 0x01){
 	DeviceQ_write_byte(SKIP_ROM); 											// посылаю команду поиска адреса если одно устройство
	return true;
 }else return false;
}


//=======================================================================================================================
//===================================== Узнать способ питания устройства ================================================
//=======================================================================================================================
unsigned char DeviceQ_READ_POWER_SUPPLY_COMMAND(void){
 if (_1_WIRE_ERROR ==0x01){
 	DeviceQ_write_byte(READ_POWER_SUPPLY); 									// посылаю команду типа питания устройства
 	_deviceQ_power_supply = DeviceQ_read_bit();
	return _deviceQ_power_supply; 
 }else return false;
}


//=======================================================================================================================
//===================================== Процедура конвертации температуры ===============================================
//=======================================================================================================================
void DeviceQ_CONVERT_TEMPERATURE_COMMAND(void){
 if (_1_WIRE_ERROR == 0x01){
 	if (_deviceQ_power_supply == 1){
		DeviceQ_write_byte(CONVERT_T); 										// посылаю команду типа питания устройства
		DeviceQ_Pullup(1);
		_delay_us(200);														// гарантированое время на окончание вычислений 750 ms
		DeviceQ_Pullup(0);
 	}else{
		DeviceQ_write_byte(CONVERT_T); 										// посылаю команду типа питания устройства
		until_bit_is_set(DeviceQ_PIN);										// ОПАСНО!!!! МОЖЕТ НЕ ВЫЙТИ!!! Проверка на окончание конвертации теппературы
	}
 } 			
}


//=======================================================================================================================
//=========================================== Процедура COPY SCARTCHPAD =================================================
//=======================================================================================================================
void DeviceQ_COPY_SCARTCHPAD_COMMAND(void){
 if (_1_WIRE_ERROR == 0x01){
 	if (_deviceQ_power_supply == 1){
		DeviceQ_write_byte(COPY_SCRATCHPAD); 								// посылаю команду типа питания устройства
		DeviceQ_Pullup(1);
		_delay_us(200);														// гарантированое время на окончание вычислений 750 ms
		DeviceQ_Pullup(0);
 	}else{
		DeviceQ_write_byte(CONVERT_T); 										// посылаю команду типа питания устройства
		until_bit_is_set(DeviceQ_PIN);										// ОПАСНО!!!! МОЖЕТ НЕ ВЫЙТИ!!! Проверка на окончание 
	}
 }	
}


//=======================================================================================================================
//========================================= Процедура WRITE SCARTCHPAD ==================================================
//=======================================================================================================================
void DeviceQ_WRITE_SCARTCHPAD_COMMAND(unsigned char TH, unsigned char TL){
 if (_1_WIRE_ERROR == 0x01){
		DeviceQ_write_byte(WRITE_SCRATCHPAD); 								// посылаю команду типа питания устройства
		DeviceQ_write_byte(TH);
		DeviceQ_write_byte(TL);
 } 			
}


//=======================================================================================================================
//====================================== Процедура READ SCARTCHPAD ======================================================
//=======================================================================================================================
void DeviceQ_READ_SCARTCHPAD_COMMAND(unsigned char * _ScratchPad){
 if (_1_WIRE_ERROR == 0x01){
		memset(_ScratchPad,0x00,9);
		DeviceQ_write_byte(READ_SCRATCHPAD); 						// посылаю команду 
  		DeviceQ_read_list_array(_ScratchPad, 9,1);					// прочитать ответ устройства на команду READ_SCRATCHPAD и записать в массив DeviceQ_ScratchPad[9]
 }
}


//=======================================================================================================================
//============================================ Процедура RECALL E2 ======================================================
//=======================================================================================================================
void DeviceQ_RECALL_E2_COMMAND(void){
 if (_1_WIRE_ERROR == 0x01){
		DeviceQ_write_byte(RECALL_E2); 								// посылаю команду 
		until_bit_is_set(DeviceQ_PIN);								// ОПАСНО!!!! МОЖЕТ НЕ ВЫЙТИ!!! 
 }		
}


//=======================================================================================================================
//======================================== Включить режим быстрого обмена ===============================================
//=======================================================================================================================
void DeviceQ_OVERDRIVE_COMMAND(bool standard){
 if (standard) DeviceQ_write_byte(OVERDRIVE);						//послать команду быстрого обмена
 _deviceQ_overdrive = standard;										// OVERDRIVE увеличенная скорость
}




//***********************************************************************************************************************
//***********************************************************************************************************************
//=======================================================================================================================
//========================================= АЛГОРИТМ ПОИСКА УСТРОЙСТВ НА ШИНЕ ===========================================
//=======================================================================================================================
//***********************************************************************************************************************
//***********************************************************************************************************************

//=======================================================================================================================
//====================================== Поиск первого устройств на шине ================================================
//=======================================================================================================================
int DeviceQ_First(){
	
   _deviceQ_last_discrepancy = 0;									// сброс флагов перед поиском первого
   _deviceQ_last_device_flag = false;
   _deviceQ_last_family_discrepancy = 0;

   return DeviceQ_SEARCH_ROM_COMMAND();  							// Переход на основную функцию поиска


}


//=======================================================================================================================
//=================================== Поиск следующего устройства на шине ===============================================
//=======================================================================================================================
int DeviceQ_Next(){ 
   return DeviceQ_SEARCH_ROM_COMMAND();  							// Переход на основную функцию поиска
}


//=======================================================================================================================
//=========================================== Пропустить устройство по типу =============================================
//============================================== вспомогательная функция ================================================
//=======================================================================================================================
void DeviceQ_TargetSetup(unsigned char family_code){
   int i;
 
   _deviceQ_rom_array[0] = family_code;								// посмотреть тип (класс) найденого устройства

   for (i = 1; i < 8; i++)     _deviceQ_rom_array[i] = 0;

   _deviceQ_last_discrepancy = 64;
   _deviceQ_last_family_discrepancy = 0;
   _deviceQ_last_device_flag = false;
}


//=======================================================================================================================
//======================================= Устоновка исключений во время поиска ==========================================
//============================================== вспомогательная функция ================================================
//=======================================================================================================================
void DeviceQ_FamilySkipSetup(){  
   _deviceQ_last_discrepancy = _deviceQ_last_family_discrepancy;
   _deviceQ_last_family_discrepancy = 0;
   
   if (_deviceQ_last_discrepancy == 0)	_deviceQ_last_device_flag = true;										// check for end of list   
}


//=======================================================================================================================
//============================================ Поиск всех устройств на шине =============================================
//=======================================================================================================================
int DeviceQ_FIND_ALL(void){
 int rslt, i;
 
  _deviceQ_find_count = 0;

 memset(_deviceQ_all_rom,0x00, (_deviceQ_max_count*8));											//чищу массив адресов, а то предыдущий поиск дал больше датчиков и массив не затрет последние

 rslt = DeviceQ_First();																		// поиск хотя бы одного устройства

 while (rslt){																					// если одно найдено - работаем дальше
	for (i = 0; i < 8; i++)	_deviceQ_all_rom[_deviceQ_find_count][i] = _deviceQ_rom_array[i];	// перенос найденного адреса в массив с индексом ([индекс], [тип, код, crc])
   	++_deviceQ_find_count;																		// счетчик найденных устройств
   	rslt = DeviceQ_Next();																		// искать следующее
   }

 return _deviceQ_find_count;																	// возвращаю количество устройств (0 - нет, 1....)
}	


//=======================================================================================================================
//============================================= Поиск устройств по типу =================================================
//=======================================================================================================================
int DeviceQ_FIND_DEVICE_CODE(unsigned char QDevice_code){
 int i;
 
 _deviceQ_find_count = 0;

 DeviceQ_TargetSetup(QDevice_code);

 while (DeviceQ_SEARCH_ROM_COMMAND()){																// check for incorrect type
	if (_deviceQ_rom_array[0] != QDevice_code) break;
 
  	for (i = 7; i >= 0; i--)	_deviceQ_all_rom[_deviceQ_find_count][i] = _deviceQ_rom_array[i];	// перенос найденного адреса в массив с индексом ([индекс], [тип, код, crc])
    ++_deviceQ_find_count;
 }

 return _deviceQ_find_count;
}


//=======================================================================================================================
//=================================== Поиск устройств по типу не соответствующих перечню=================================
//===============================================0x04;0x1A;0x01;0x23;0x0A;0x10===========================================
//=======================================================================================================================
int DeviceQ_FIND_DEVICE_EXCEPTION_CODE(void){
 int rslt,i;

 _deviceQ_find_count = 0;

 rslt = DeviceQ_First();																					// поиск хотя бы одного устройства
 while (rslt){																								// check for incorrect type
      if ((_deviceQ_rom_array[0] == 0x04) || (_deviceQ_rom_array[0] == 0x1A) || 
          (_deviceQ_rom_array[0] == 0x01) || (_deviceQ_rom_array[0] == 0x23) ||
          (_deviceQ_rom_array[0] == 0x0A) || (_deviceQ_rom_array[0] == 0x10))
          DeviceQ_FamilySkipSetup();
      else{																									// print device found
   		 for (i = 8; i >= 0; i--)	_deviceQ_all_rom[_deviceQ_find_count][i] = _deviceQ_rom_array[i];		// перенос найденного адреса в массив с индексом ([индекс], [тип, код, crc])
    	 ++_deviceQ_find_count;
      }

      rslt = DeviceQ_Next();
   }

 return _deviceQ_find_count;
}


//=======================================================================================================================
//===========================================Поиск устройств на шине по адресу===========================================
//=======================================================================================================================
int DeviceQ_SEARCH_ROM_COMMAND(void){
   int id_bit_number;
   int last_zero, rom_byte_number, search_result;
   int id_bit, cmp_id_bit;
   unsigned char rom_byte_mask, search_direction;

  
   id_bit_number = 1;																		// предустановка перед поиском
   last_zero = 0;
   rom_byte_number = 0;
   rom_byte_mask = 1;
   search_result = 0;
   crc8 = 0;

   if (!_deviceQ_last_device_flag){
      if (!DeviceQ_reset()){																// if the last call was not the last one1-Wire reset reset the search
         _deviceQ_last_discrepancy = 0;
         _deviceQ_last_device_flag = false;
         _deviceQ_last_family_discrepancy = 0;
         return false;
      }


      DeviceQ_write_byte(SEARCH_ROM);														// посылаем в порт команду поиска

      do {																					// read a bit and its complement
         id_bit = DeviceQ_read_bit();
         cmp_id_bit = DeviceQ_read_bit();
 
         if ((id_bit == 1) && (cmp_id_bit == 1)){
		 	DeviceQ_reset();
			break;}																			// check for no devices on 1-wire
         else{
            if (id_bit != cmp_id_bit) search_direction = id_bit;							// all devices coupled have 0 or 1 bit write value for search
            else{																			// if this discrepancy if before the Last Discrepancy on a previous next then pick the same as last time
               if (id_bit_number < _deviceQ_last_discrepancy)        search_direction = ((_deviceQ_rom_array[rom_byte_number] & rom_byte_mask) > 0);
               else   search_direction = (id_bit_number == _deviceQ_last_discrepancy);		// if equal to last pick 1, if not then pick 0
               if (search_direction == 0){													// if 0 was picked then record its position in LastZero
                  last_zero = id_bit_number;
               	  if (last_zero < 9)  _deviceQ_last_family_discrepancy = last_zero;			// check for Last discrepancy in family
               }
            }
            
            if (search_direction == 1)		_deviceQ_rom_array[rom_byte_number] |= rom_byte_mask;		// set or clear the bit in the ROM byte rom_byte_number with mask rom_byte_mask
            else							_deviceQ_rom_array[rom_byte_number] &= ~rom_byte_mask;

            DeviceQ_write_bit(search_direction);											// serial number search direction write bit

            id_bit_number++;																// increment the byte counter id_bit_number and shift the mask rom_byte_mask
            rom_byte_mask <<= 1;
            
            if (rom_byte_mask == 0){														// if the mask is 0 then go to new SerialNum byte rom_byte_number and reset mask
                docrc8(_deviceQ_rom_array[rom_byte_number]);								// accumulate the CRC
                rom_byte_number++;
                rom_byte_mask = 1;
            }
         }
      } while(rom_byte_number < 8);															// loop until through all ROM bytes 0-7

      
      if (!((id_bit_number < 65) || (crc8 != 0))){											// if the search was successful then
         _deviceQ_last_discrepancy = last_zero;												// search successful so set _deviceQ_last_discrepancy,_deviceQ_last_device_flag,search_result
         if (_deviceQ_last_discrepancy == 0) _deviceQ_last_device_flag = true;				// check for last device
         search_result = true;
      }
   }

   
   if (!search_result || !_deviceQ_rom_array[0]){											// if no device found then reset counters so next 'search' will be like a first
      _deviceQ_last_discrepancy = 0;
      _deviceQ_last_device_flag = false;
      _deviceQ_last_family_discrepancy = 0;
      search_result = false;
   }

   return search_result;
}


//=======================================================================================================================
//================================Поиск устройств настроенных как термостат на шине =====================================
//=======================================================================================================================
unsigned char DeviceQ_ALARM_SEARCH_COMMAND(void){
	
   int id_bit_number;
   int last_zero, rom_byte_number, search_result;
   int id_bit, cmp_id_bit;
   unsigned char rom_byte_mask, search_direction;

  
   id_bit_number = 1;																		// предустановка перед поиском
   last_zero = 0;
   rom_byte_number = 0;
   rom_byte_mask = 1;
   search_result = 0;
   crc8 = 0;

   if (!_deviceQ_last_device_flag){
      if (!DeviceQ_reset()){																// if the last call was not the last one1-Wire reset reset the search
         _deviceQ_last_discrepancy = 0;
         _deviceQ_last_device_flag = false;
         _deviceQ_last_family_discrepancy = 0;
         return false;
      }


      DeviceQ_write_byte(ALARM_SEARCH);														// посылаем в порт команду поиска термостатов

      do {																					// read a bit and its complement
         id_bit = DeviceQ_read_bit();
         cmp_id_bit = DeviceQ_read_bit();
 
         if ((id_bit == 1) && (cmp_id_bit == 1)) break;										// check for no devices on 1-wire
         else{
            if (id_bit != cmp_id_bit) search_direction = id_bit;							// all devices coupled have 0 or 1 bit write value for search
            else{																			// if this discrepancy if before the Last Discrepancy on a previous next then pick the same as last time
               if (id_bit_number < _deviceQ_last_discrepancy)        search_direction = ((_deviceQ_rom_array[rom_byte_number] & rom_byte_mask) > 0);
               else   search_direction = (id_bit_number == _deviceQ_last_discrepancy);		// if equal to last pick 1, if not then pick 0
               if (search_direction == 0){													// if 0 was picked then record its position in LastZero
                  last_zero = id_bit_number;
               	  if (last_zero < 9)  _deviceQ_last_family_discrepancy = last_zero;			// check for Last discrepancy in family
               }
            }
            
            if (search_direction == 1)		_deviceQ_rom_array[rom_byte_number] |= rom_byte_mask;		// set or clear the bit in the ROM byte rom_byte_number with mask rom_byte_mask
            else							_deviceQ_rom_array[rom_byte_number] &= ~rom_byte_mask;

            DeviceQ_write_bit(search_direction);											// serial number search direction write bit

            id_bit_number++;																// increment the byte counter id_bit_number and shift the mask rom_byte_mask
            rom_byte_mask <<= 1;
            
            if (rom_byte_mask == 0){														// if the mask is 0 then go to new SerialNum byte rom_byte_number and reset mask
                docrc8(_deviceQ_rom_array[rom_byte_number]);								// accumulate the CRC
                rom_byte_number++;
                rom_byte_mask = 1;
            }
         }
      } while(rom_byte_number < 8);															// loop until through all ROM bytes 0-7

      
      if (!((id_bit_number < 65) || (crc8 != 0))){											// if the search was successful then
         _deviceQ_last_discrepancy = last_zero;												// search successful so set _deviceQ_last_discrepancy,_deviceQ_last_device_flag,search_result
         if (_deviceQ_last_discrepancy == 0) _deviceQ_last_device_flag = true;				// check for last device
         search_result = true;
      }
   }

   
   if (!search_result || !_deviceQ_rom_array[0]){											// if no device found then reset counters so next 'search' will be like a first
      _deviceQ_last_discrepancy = 0;
      _deviceQ_last_device_flag = false;
      _deviceQ_last_family_discrepancy = 0;
      search_result = false;
   }
 
   return search_result;

   DeviceQ_reset();
}




//***********************************************************************************************************************
//***********************************************************************************************************************
//=======================================================================================================================
//=========================================== ДАТЧИК ТЕМПЕРАТУРЫ DS18x20 ================================================
//=======================================================================================================================
//***********************************************************************************************************************
//***********************************************************************************************************************

//=======================================================================================================================
//================================Получение температуры с устройства на шине=============================================
//=======================================================================================================================
void DeviceQ_Read_Temperature(unsigned char Num_QDevice){							//по результату выдает результат вычисления температуры
 unsigned char ID = 0, TH = 0, TL = 0;
 if (_deviceQ_temperature_flag == false){											//запрос температуры в первый раз после запуска устройства (холостой пересчет)
	if(DeviceQ_SKIP_ROM_COMMAND() == true)	/*=======>>>>>>>>>>*/	DeviceQ_CONVERT_TEMPERATURE_COMMAND();
 	if(DeviceQ_SKIP_ROM_COMMAND() == true)							DeviceQ_READ_SCARTCHPAD_COMMAND(_deviceQ_ScratchPad);
 } 	
 
 if (_deviceQ_find_count != 0){
	if (_deviceQ_find_count == 1){
		if(DeviceQ_SKIP_ROM_COMMAND() == true)						DeviceQ_CONVERT_TEMPERATURE_COMMAND();
 		if(DeviceQ_SKIP_ROM_COMMAND() == true)						DeviceQ_READ_SCARTCHPAD_COMMAND(_deviceQ_ScratchPad);
 	}else{
  		for (int i = 8; i >= 0; i--)
			_deviceQ_rom_array[i] = _deviceQ_all_rom[Num_QDevice][i];														//перекидываю адрес устройства (64bit) во временную переменную
  		if(DeviceQ_MATCH_ROM_COMMAND(_deviceQ_rom_array) == true)	DeviceQ_CONVERT_TEMPERATURE_COMMAND();
		if(DeviceQ_MATCH_ROM_COMMAND(_deviceQ_rom_array) == true) 	DeviceQ_READ_SCARTCHPAD_COMMAND(_deviceQ_ScratchPad);
 	}

 ID = _deviceQ_rom_array[0];
 TH = _deviceQ_ScratchPad[1];
 TL = _deviceQ_ScratchPad[0];

 	if (ID == DS18S20_FAMILY_CODE)																							// 0 бит = 0x10 означает что датчик или 1820 или 18s20
 		Calc_Temp_ds18S20(TH, TL);							
 		
 	if (ID == DS18B20_FAMILY_CODE)																							// 0 бит = 0x10 означает что датчик или 1820 или 18s20
 		Calc_Temp_ds18B20(TH, TL);							
 }

 _deviceQ_temperature_flag = true;				
}


//=======================================================================================================================
//===================================== Считаю температуру для 1820(+S) =================================================
//=======================================================================================================================
void Calc_Temp_ds18S20(char MSByte, char LSByte){
 int _temp = 1;
	
 if (MSByte != 0x00){
	LSByte = 0xFF - LSByte + 1;
	_temp = -1;
 }

 Temperature = (int)LSByte*10/2;
 TemperH = _temp*Temperature/10;
 TemperL = Temperature%10; 	
}


//=======================================================================================================================
//===================================== Считаю температуру для 18b20 ====================================================
//=======================================================================================================================
void Calc_Temp_ds18B20(char MSByte, char LSByte){
int temp = 0x0000;

 temp = (MSByte<<4)|(LSByte);

 if (MSByte <= 0xF0)	Temperature = (int)temp /16;
 else				 	Temperature = (int)((0xFFFF-temp)>>8);
}

