Atmega328p работа с TWI в прерываниях (AtmelStudio 6)

Обсуждаем контроллеры компании Atmel.
Ответить
Родился
Аватара пользователя
Сообщения: 15
Зарегистрирован: Чт ноя 16, 2017 17:04:14
Откуда: Сургут

Сообщение Angry Engineer »

День добрый, ваяю тут жестянку которая будет в строго определенное время и по требованию (по UART) включать/выключать нагрузку отчитываться об этом на LCD и по UART. LCD и RTC живут на шине TWI и с последовательным опросом проблем нет, но вот некоторые сообщения выводятся на LCD порядка 10 секунд и есть шанс профукать момент включения/выключения нагрузки.

На данный момент не придумал ничего лучше как опрашивать RTC по таймеру раз в 0,5 секунды, но так как при этом переключаю устройство с которым веду диалог по TWI, то при возврате из прерывания получаю висяк в цикле ожидания TWINT.
Спойлер

Код: Выделить всё

void I2C_Init(void)
{
	TWSR = 0;
	TWBR = ((F_CPU/F_SCL)-16)/2;
}
void I2C_TWINT_Wait(void)
{
	while(!(TWCR &(1<<TWINT)))
	{
              Вот тут вот и повисаем
	}
}
void I2C_Start(void)
{
	TWCR =(1<<TWIE)|(1<<TWINT)|(1<<TWSTA)|(1<<TWEN);	
	I2C_TWINT_Wait();
}
void I2C_Stop(void)
{
	TWCR =(1<<TWINT)|(1<<TWEN)|(1<<TWSTO);
}
void I2C_Send_Device_Address(uint8_t dev_address, bool write)
{
	I2C_last_device = dev_address;
	I2C_last_write_mode = write;
	
	if (write == true)
	{
		TWDR = dev_address;
	}
	else
	{
		TWDR = dev_address|1;
	}
	
	TWCR = (1<<TWINT)|(1<<TWEN);
	I2C_TWINT_Wait();
}
void I2C_Send_Register_Address(uint8_t reg_address)
{
	TWDR = reg_address;
	TWCR =(1<<TWINT)|(1<<TWEN);
	I2C_TWINT_Wait();
}
void I2C_Send_Data_ACK(uint8_t data)
{
	TWDR = data;
	TWCR =(1<<TWINT)|(1<<TWEN)|(1<<TWEA);
	I2C_TWINT_Wait();
}
void I2C_Send_Data_NACK(uint8_t data)
{
	TWDR = data;
	TWCR =(1<<TWINT)|(1<<TWEN);
	I2C_TWINT_Wait();
}
uint8_t I2C_Read_Data_ACK(void)
{
	uint8_t Result = 0;
	TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWEA);
	I2C_TWINT_Wait();
	Result = TWDR;
	return Result;
}
uint8_t I2C_Read_Data_NACK(void)
{
	uint8_t Result = 0;
	TWCR = (1<<TWINT)|(1<<TWEN);
	I2C_TWINT_Wait();
	Result = TWDR;
	return Result;
}

ISR(TWI_vect)
{
	UART_Send_String("TWI interrupt ");
	TWCR =(1<<TWIE)|(1<<TWINT)|(1<<TWSTA)|(1<<TWEN);
}
попробовал в прерывании таймера после опроса RTC повторно стартовать работу с последним устройством которое прервали
Спойлер

Код: Выделить всё

SR(TIMER1_OVF_vect)
{
	TCNT1 = 65536-31250;
	
	uint8_t I2C_reurn_device = I2C_last_device;
	bool I2C_return_write_mode = I2C_last_write_mode;
	
	RTC_Get_System_Date_Time();
	
	I2C_Start();
	I2C_Send_Device_Address(I2C_reurn_device,I2C_return_write_mode);
}
стало немного лучше, но периодически все равно подвисает. подскажите в какую сторону копать?

Запись и чтение не выполняю через прерывание по тому что необходимо плясать с бегущими строками и побуквенным выводом

Добавлено after 1 hour 16 minutes 57 seconds:
сейчас запретил прерывания при выполнении атомарных операций TWI
Спойлер

Код: Выделить всё

void I2C_Init(void)
{
	TWSR = 0;
	TWBR = ((F_CPU/F_SCL)-16)/2;
}
void I2C_TWINT_Wait(void)
{
	while(!(TWCR &(1<<TWINT)))
	{

	}
}
void I2C_Start(void)
{
	cli();
	TWCR =(1<<TWINT)|(1<<TWSTA)|(1<<TWEN);	
	I2C_TWINT_Wait();
	sei();
}
void I2C_Stop(void)
{
	cli();
	TWCR =(1<<TWINT)|(1<<TWEN)|(1<<TWSTO);
	sei();
}
void I2C_Send_Device_Address(uint8_t dev_address, bool write)
{
	cli();
	I2C_last_device = dev_address;
	I2C_last_write_mode = write;
	
	if (write == true)
	{
		TWDR = dev_address;
	}
	else
	{
		TWDR = dev_address|1;
	}
	
	TWCR = (1<<TWINT)|(1<<TWEN);
	I2C_TWINT_Wait();
	sei();
}
void I2C_Send_Register_Address(uint8_t reg_address)
{
	cli();
	TWDR = reg_address;
	TWCR =(1<<TWINT)|(1<<TWEN);
	I2C_TWINT_Wait();
	sei();
}
void I2C_Send_Data_ACK(uint8_t data)
{
	cli();
	TWDR = data;
	TWCR =(1<<TWINT)|(1<<TWEN)|(1<<TWEA);
	I2C_TWINT_Wait();
	sei();
}
void I2C_Send_Data_NACK(uint8_t data)
{
	cli();
	TWDR = data;
	TWCR =(1<<TWINT)|(1<<TWEN);
	I2C_TWINT_Wait();
	sei();
}
uint8_t I2C_Read_Data_ACK(void)
{
	cli();
	uint8_t Result = 0;
	TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWEA);
	I2C_TWINT_Wait();
	Result = TWDR;
	return Result;
	sei();
}
uint8_t I2C_Read_Data_NACK(void)
{
	cli();
	uint8_t Result = 0;
	TWCR = (1<<TWINT)|(1<<TWEN);
	I2C_TWINT_Wait();
	Result = TWDR;
	return Result;
	sei();
}
работает до зависания чуть дольше
Реклама
Поставщик валерьянки для Кота
Сообщения: 2222
Зарегистрирован: Вт ноя 27, 2007 11:32:06
Откуда: Tashkent

Сообщение uk8amk »

но вот некоторые сообщения выводятся на LCD порядка 10 секунд и есть шанс профукать момент включения/выключения нагрузки.
Это чтож за LCD такой, в который слать картинку 10 сек надо?
подскажите в какую сторону копать?
В сторону отделения мух от котлет.
Либо вы делаете опрос программный, либо через автомат по прерываниям. Всё остальное - хороший способ запутаться самому и запутать нас.
Очерёдность посылок между устройствами должна разруливаться самой программой, а не обрывом передачи и приведения интерфейса в непонятное состояние.
Контроль состояния производится посредством анализа кодов статусного регистра TWSR.

Впрочем возможно организовать ещё один I2C канал с помощью программного ногодрыга. Если конечно лапки свободные есть.

Еще когда существует вероятность зависания периферийных микросхем заводят дополнительный таймер(можно виртуальный) и по таймауту вызывается подпрограмма, которая должна что-то там пнуть или иное сделать.
Реклама
Поставщик валерьянки для Кота
Аватара пользователя
Сообщения: 2081
Зарегистрирован: Пт май 31, 2013 17:14:38
Откуда: Украина, Винница

Сообщение Ярослав555 »

пару месяцев назад на работе была задача переписать глючную прошивку под один ведомый МК. Я не нашел ничего лучше как скопипастить автомат от DiHalt`a, ну а для мастера заюзал атмеловкий аппноут (потому что мастером Хмега). Ну это всё мелочи в данном случае. Объясните что это за LCD такой, сообщения на который выводятся 10 секунд? Модель, контроллер можно в студию? Ну а если там действительно 10 сек и никуда не деться, то рекомендую Вам поступить следующим образом: конфигурируете внутренний таймер МК на отсчет времени, скажем секунд 60. Вычитываете свои часы, видите что включать надо через 3 секунды, ставите свой таймер на 3 секунды и идете пулять свой и2с в дисплей. Через 3 секунды включаете/выключаете нагрузку. Только Вам надо будет при входе в прерывание и2си включать глобальное разрешение прерываний, чтобы не профукать свой таймер. Но я ставлю на то что у Вас неверная работа с дисплеем/и2си.
Родился
Аватара пользователя
Сообщения: 15
Зарегистрирован: Чт ноя 16, 2017 17:04:14
Откуда: Сургут

Сообщение Angry Engineer »

Тут дело не в дисплее, а в размере сообщения выводимом на него, дисплей самый обычный 16*2 Hitachi что ли, рулится платой PCF8574AT. То что обрывать передачу плохо прекрасно понимаю, но как этого избежать если честно не очень.

с другой стороный, судя по даташиту PCF8574AT посылки к дисплею все полностью идут с ACK. тоесть не вижу проблемы в том, чтобы завершить передачу посылки в дисплей, уйти в прерывание где опрашивается RTC. стопнуть TWI стартовать TWI указать устройством назначения RTC, опросить RTC стартовать TWI указать устройством назначения LCD и продолжить гадить туда буквами. опять же судя по тому что я вычитал: можно вообще не передавать стоп в шину (если конечно там только один мастер) а просто повторно выдавать старт и адрес с признаком r/w ну и далее по пьесе.

в принципе опрашивать 2 раза в секунду RTC и сравнивать время включения и выключения каналов все что нужно. но хочется иметь возможность смотреть, чем занята железка в данный момент да и не спортивно сдаваться вот так сразу

вот полный листинг
Спойлер

Код: Выделить всё

/*
*  main.cpp
*  Project: G.E.C.K.
*  Created: 21.10.2017 20:18:55
*  Author:  Сергей Набоков
*/

//КОНСТАНТЫ
#define F_CPU 16000000UL          //задаем частоту МК
#define F_SCL  100000L		   //задаем частоту I2C

#define UART_Start_symbol '*'     //Старт символ пакета
#define UART_Stop_symbol '#'      //Стоп символ пакета
#define UART_buffer_size 255	  //Буфер для служебного обмена данными с внутренними устройствами

#define Input_command_size 13      //Размер входного пакета данных

#define String_end_symbol '\0'    //Стоп символ строки


#define RTC_module  0xD0		  // Адрес RTC на шине I2C
#define LCD_module  0x7e		  // Адрес LCD на шине I2C

#define LCD_RS 0
#define LCD_RW 1
#define LCD_E 2
#define LCD_BL 3

//----------------------------------------
#define Device_type			{"G.E.C.K. - HFG"}
#define Firmware_version	        {"FW: v1.5b"}
//-----------------------------------------

//БИБЛИОТЕКИ
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
#include <avr/eeprom.h>
#include <avr/wdt.h>

//СТРУКТУРЫ
typedef struct {uint8_t HH; 
				uint8_t MM; 
				uint8_t SS;} Time;
				
typedef struct {uint8_t DD; 
				uint8_t MM; 
				uint8_t YY;} Date;
				
typedef struct {char Name[17]; 
				uint8_t State;
				 
				uint8_t Auto_Enable;
				uint8_t *EEPROM_AE;
				
				Time Enable_Time;
				uint8_t *EEPROM_ET_HH;
				uint8_t *EEPROM_ET_MM;
				uint8_t *EEPROM_ET_SS; 
				
				uint8_t Auto_Disable;
				uint8_t *EEPROM_AD; 
				
				Time Disable_Time;
				uint8_t *EEPROM_DT_HH;
				uint8_t *EEPROM_DT_MM;
				uint8_t *EEPROM_DT_SS;
				 
				uint8_t Cycle;
				uint8_t *EEPROM_CYCLE;
				 
				uint8_t Cycle_Start_Day;
				uint8_t *EEPROM_CSD;
				 
				uint8_t Water;
				uint8_t Force_Enable;} Channel;
 
 //ЭНЕРГОНЕЗАВИСИМАЯ ПАМЯТЬ
 uint8_t System_first_run		EEMEM = 0;

 uint8_t White_light_AE			EEMEM = 0;
 uint8_t White_light_ET_HH		EEMEM = 0;
 uint8_t White_light_ET_MM		EEMEM = 0;
 uint8_t White_light_ET_SS		EEMEM = 0;
 uint8_t White_light_AD			EEMEM = 0;
 uint8_t White_light_DT_HH		EEMEM = 0;
 uint8_t White_light_DT_MM		EEMEM = 0;
 uint8_t White_light_DT_SS		EEMEM = 0;
 
 uint8_t White_light_CYCLE		EEMEM = 0;
 uint8_t White_light_CSD		EEMEM = 1;

 uint8_t Grow_light_AE			EEMEM = 0;
 uint8_t Grow_light_ET_HH		EEMEM = 0;
 uint8_t Grow_light_ET_MM		EEMEM = 0;
 uint8_t Grow_light_ET_SS		EEMEM = 0;
 uint8_t Grow_light_AD			EEMEM = 0;
 uint8_t Grow_light_DT_HH		EEMEM = 0;
 uint8_t Grow_light_DT_MM		EEMEM = 0;
 uint8_t Grow_light_DT_SS		EEMEM = 0;
 
 uint8_t Grow_light_CYCLE		EEMEM = 0;
 uint8_t Grow_light_CSD			EEMEM = 1;

 uint8_t Water_pump_AE			EEMEM = 0;
 uint8_t Water_pump_ET_HH		EEMEM = 0;
 uint8_t Water_pump_ET_MM		EEMEM = 0;
 uint8_t Water_pump_ET_SS		EEMEM = 0;

 uint8_t Water_pump_AD			EEMEM = 0;
 uint8_t Water_pump_DT_HH		EEMEM = 0;
 uint8_t Water_pump_DT_MM		EEMEM = 0;
 uint8_t Water_pump_DT_SS		EEMEM = 0;

 uint8_t Water_pump_CYCLE		EEMEM = 0;
 uint8_t Water_pump_CSD			EEMEM = 1;
 
//ПЕРЕМЕННЫЕ
uint8_t Calendar[12] = {31,28,31,30,31,30,31,31,30,31,30,31};		//Календарь
uint8_t Calendar_leap[12] = {31,29,31,30,31,30,31,31,30,31,30,31};	//Високосный календарь

bool RTC_error = false;												//Ошибка модуля RTC

char UART_input_buffer[50];
bool UART_start_symbol_detected = false;                            //Обнаружен стартовый символ
bool UART_stop_symbol_detected = false;								//Обнаружен стоповый символ
bool UART_user_control = true;

char Input_command[Input_command_size];								//Входящая команда
uint8_t IC_c = 0;

Time System_time = {0,0,0};											//Системное время
bool SST_command = false;
Time t_time = {0,0,0};
	
Date System_date = {0,0,0};                                         //Системная дата
bool SSD_command = false;
Date t_date = {0,0,0};
 
Channel White_light =	{"White light:",							//Холодный свет
						 0, 
						 0,
						 &White_light_AE, 
						 {0,0,0},
						 &White_light_ET_HH,
						 &White_light_ET_MM,
						 &White_light_ET_SS,
						 0,
						 &White_light_AD, 
						 {0,0,0},
						 &White_light_DT_HH,
						 &White_light_DT_MM,
						 &White_light_DT_SS,
						 0,
						 &White_light_CYCLE,
						 1,
						 &White_light_CSD,
						 0,
						 0};	
Channel Grow_light =    {"Grow light:",								//Фитосвет
						 0,
						 0,
						 &Grow_light_AE,
						 {0,0,0},
						 &Grow_light_ET_HH,
						 &Grow_light_ET_MM,
						 &Grow_light_ET_SS,
						 0,
						 &Grow_light_AD, 
						 {0,0,0},
						 &Grow_light_DT_HH,
						 &Grow_light_DT_MM,
						 &Grow_light_DT_SS,
					     0,
						 &Grow_light_CYCLE,
						 1,
						 &Grow_light_CSD,
						 0,
						 0};	
Channel Water_pump =    {"Water pump:",								//Насос
						 0,
						 0,
						 &Water_pump_AE,
						 {0,0,0},
						 &Water_pump_ET_HH,
						 &Water_pump_ET_MM,
						 &Water_pump_ET_SS,
						 0,
						 &Water_pump_AD,
						 {0,0,0},
						 &Water_pump_DT_HH,
						 &Water_pump_DT_MM,
						 &Water_pump_DT_SS,
						 
						 0,
						 &Water_pump_CYCLE,
						 
						 1,
						 &Water_pump_CSD,
						 
						 1,
						 0};										
Channel *t_channel;

bool SET_command = false;
bool SDT_command = false;
bool RCS_command = false;
bool SAE_command = false;
bool SAD_command = false;
bool SCS_command = false;
bool SCC_command = false;

bool RSI_command = false;
bool WP_ON_command = false;
Time WP_manual_time = {0,0,30};

bool LDS_command = false;

bool First_run = false;
bool Flash_time_string = true;

uint8_t I2C_last_device;
bool I2C_last_write_mode;
		  	  
//===РАЗНОЕ===
void Segment_Normalize(char *d_t_segment)
{
	if (strlen(d_t_segment)<2)
	{
		d_t_segment[2]=String_end_symbol;
		d_t_segment[1]=d_t_segment[0];
		d_t_segment[0]='0';
	}
}
uint8_t BCD_to_INT(uint8_t BCD)
{
	return (((BCD>>4)& 0b00001111)*10+(BCD & 0b00001111));
}
uint8_t INT_to_BCD(uint8_t Integer)
{
	uint8_t BCD_1=0;
	uint8_t BCD_2=0;
	uint8_t j=0;

	for (uint8_t i=0; i<90; i=i+10)
	{
		if (Integer-i<10 && Integer-i>=0)
		{
			BCD_1 = j;
			BCD_2 = Integer-i;
		}
		j++;
	}
	return (((BCD_1<<4)&0b11110000)|(BCD_2&0b00001111));
}	  
void DATE_to_STRING(char *d_string, Date *date)
{
	char Date_string[3];
	char Month_string[3];
	char Year_string[3];

	itoa(date->DD,Date_string,10);
	itoa(date->MM,Month_string,10);
	itoa(date->YY,Year_string,10);

	//Нормализация строки даты
	Segment_Normalize(Date_string);
	Segment_Normalize(Month_string);
	Segment_Normalize(Year_string);
	
	int dsi = 0;

	//Дата
	for (int di=0;di<strlen(Date_string);di++)
	{
		d_string[dsi] = Date_string[di];
		dsi++;
	}
	d_string[dsi] = '.';
	dsi++;
	for (int mi=0;mi<strlen(Month_string);mi++)
	{
		d_string[dsi] = Month_string[mi];
		dsi++;
	}
	d_string[dsi] = '.';
	dsi++;
	for (int yi=0;yi<strlen(Year_string);yi++)
	{
		d_string[dsi] = Year_string[yi];
		dsi++;
	}
	d_string[dsi]= String_end_symbol;
}
void TIME_to_STRING(char *t_string, Time *time, bool show_sec=false, bool flash = false)
{
	char Hours_string[3];
	char Minutes_string[3];
	char Seconds_string[3];
	
	itoa(time->HH,Hours_string,10);
	itoa(time->MM,Minutes_string,10);
	itoa(time->SS,Seconds_string,10);

	//Нормализация строки времени
	Segment_Normalize(Hours_string);
	Segment_Normalize(Minutes_string);
	Segment_Normalize(Seconds_string);
	
	char dots = ' ';
	
	if ((time->SS % 2) == 1 && flash == true)
	{
		dots = ' ';
	}
	else
	{
		dots = ':';
	}
	
	int tsi = 0;
	
	//Время
	for (int hi=0;hi<strlen(Hours_string);hi++)
	{
		t_string[tsi] = Hours_string[hi];
		tsi++;
	}
	t_string[tsi] = dots;
	tsi++;
	for (int mi=0;mi<strlen(Minutes_string);mi++)
	{
		t_string[tsi] = Minutes_string[mi];
		tsi++;
	}
	
	if (show_sec == true)
	{
		t_string[tsi] = dots;
		tsi++;
		for (int si=0;si<strlen(Seconds_string);si++)
		{
			t_string[tsi] = Seconds_string[si];
			tsi++;
		}
	}
	t_string[tsi]= String_end_symbol;
}
void DATE_TIME_to_STRING(char *d_t_string, Date *date, Time *time, bool show_sec=false, bool flash = false)
{
	char date_string[9];
	char time_string[6];
	
	DATE_to_STRING(date_string, date);
	TIME_to_STRING(time_string, time, show_sec, flash);
	
	int dtsi = 0;
	
	//Дата
	for (int i=0;i<strlen(date_string);i++)
	{
		d_t_string[dtsi] = date_string[i];
		dtsi++;
	}
	d_t_string[dtsi] = ' ';
	dtsi++;
	d_t_string[dtsi] = ' ';
	dtsi++;
	d_t_string[dtsi] = ' ';
	dtsi++;
	//Время
	for (int i=0;i<strlen(time_string);i++)
	{
		d_t_string[dtsi] = time_string[i];
		dtsi++;
	}
	d_t_string[dtsi]= String_end_symbol;
}	    
bool String_Compare(char *ds1, char *ds2, int ds1_start_pos, int ds2_start_pos, int length)
{
	bool Result = true;

	for (int i = 0; i<length; i++)
	{
		if (ds1[i+ds1_start_pos] != ds2[i+ds2_start_pos])
		{
			Result = false;
		}
	}
	
	return Result;
}
uint8_t Days_In_Month(uint8_t month, uint8_t year)
{
	if (year%4 == 0 && year != 0)
	{
		return Calendar_leap[month-1];
	}
	else
	{
		return Calendar[month-1];
	}
}
void Time_Add(Time *time, Time *add_time)
{
	if ((time->SS + add_time->SS) >= 60)
	{
		time->MM++;
		time->SS = time->SS + add_time->SS-60;
	}
	else
	{
		time->SS = time->SS + add_time->SS;
	}
	if ((time->MM + add_time->MM) >= 60)
	{
		time->HH++;
		time->MM = time->MM + add_time->MM-60;
	}
	else
	{
		time->MM = time->MM + add_time->MM;
	}
	if ((time->HH + add_time->HH) >= 24)
	{
		time->HH = time->HH + add_time->HH - 24;
	}
	else
	{
		time->HH = time->HH + add_time->HH;
	}
}
void Date_Add(Date *date, uint8_t days)
{
	for (uint8_t i=0; i<days;i++)
	{
		date->DD++;
		uint8_t d_i_m = Days_In_Month(date->MM, date->YY);
		if (date->DD > d_i_m)
		{
			date->MM++;
			if(date->MM >12)
			{
				date->YY++;
				if(date->YY >99)
				{
					date->YY = date->YY - 99;
				}
				date->MM = date->MM -12;
			}
			date->DD = date->DD - d_i_m;
		}
	}
}
void (*Reset)(void) = 0x0000;

void Light_Channel_Enable_String(char *data_string, Channel *channel)
{
	int chsi = 0;
	
	char En_caption[] = {"On:        "};
	char En_time[9];

	TIME_to_STRING(En_time, &channel->Enable_Time, 0);

	for (int i=0;i<strlen(En_caption);i++)
	{
		data_string[chsi] = En_caption[i];
		chsi++;
	}
	for (int i=0;i<strlen(En_time);i++)
	{
		data_string[chsi] = En_time[i];
		chsi++;
	}
	data_string[chsi]= String_end_symbol;
}
void Light_Channel_Disable_String(char *data_string, Channel *channel)
{
	int chsi = 0;
		
	char Dis_caption[] = {"Off:       "};
	char Dis_time[9];

	TIME_to_STRING(Dis_time, &channel->Disable_Time , 0);

	for (int i=0;i<strlen(Dis_caption);i++)
	{
		data_string[chsi] = Dis_caption[i];
		chsi++;
	}
	for (int i=0;i<strlen(Dis_time);i++)
	{
		data_string[chsi] = Dis_time[i];
		chsi++;
	}			
	data_string[chsi]= String_end_symbol;
}
void Water_Channel_Enable_String(char *data_string, Channel *channel)
{
	int chsi = 0;
	
	char En_caption[] = {"On:     "};
	char En_time[9];

	TIME_to_STRING(En_time, &channel->Enable_Time, 1);

	for (int i=0;i<strlen(En_caption);i++)
	{
		data_string[chsi] = En_caption[i];
		chsi++;
	}
	for (int i=0;i<strlen(En_time);i++)
	{
		data_string[chsi] = En_time[i];
		chsi++;
	}	
	data_string[chsi]= String_end_symbol;
}
void Water_Channel_Disable_String(char *data_string, Channel *channel)
{
	int chsi = 0;
	
	char Dis_caption[] = {"Off:    "};
	char Dis_time[9];

	TIME_to_STRING(Dis_time, &channel->Disable_Time , 1);

	for (int i=0;i<strlen(Dis_caption);i++)
	{
		data_string[chsi] = Dis_caption[i];
		chsi++;
	}
	for (int i=0;i<strlen(Dis_time);i++)
	{
		data_string[chsi] = Dis_time[i];
		chsi++;
	}				
	data_string[chsi]= String_end_symbol;
}
void Channel_AE_String(char *data_string, Channel *channel)
{
	char caption_ON[] =  {"Auto on:      On"};
	char caption_OFF[] = {"Auto on:     Off"};
		
	if (channel->Auto_Enable == 1)
	{
		strcpy(data_string,"Auto on:      On");
	}
	else
	{
		strcpy(data_string,"Auto on:     Off");
	}
}
void Channel_AD_String(char *data_string, Channel *channel)
{	
	if (channel->Auto_Disable == 1)
	{
		strcpy(data_string,"Auto off:     On");
	}
	else
	{
		strcpy(data_string,"Auto off:    Off");
	}
}
void Channel_State_String(char *data_string, Channel *channel)
{
	if (channel->State == 1)
	{
		strcpy(data_string,"Activated");
	}
	else
	{
		strcpy(data_string,"Deactivated");
	}
}
void Channel_Cycle_String(char *data_string, Channel *channel)
{
	uint8_t dsi = 0;

	char cycle[3];
	char cycle_caption_1[]= {"Cycle:"};
	char cycle_caption_2_1[]= {" day"};
	char cycle_caption_2_2[]= {" days"};
	
	itoa(channel->Cycle, cycle, 10);
	
	if (channel->Cycle != 0)
	{
		if (channel->Cycle > 1)
		{
			if (channel->Cycle > 9)
			{
				for (uint8_t i=0; i<strlen(cycle_caption_1); i++)
				{
					data_string[dsi]= cycle_caption_1[i];
					dsi++;
				}
				data_string[dsi]= ' ';
				dsi++;
				data_string[dsi]= ' ';
				dsi++;
				data_string[dsi]= ' ';
				dsi++;
				
				for (uint8_t i=0; i<strlen(cycle); i++)
				{
					data_string[dsi]= cycle[i];
					dsi++;
				}
				for (uint8_t i=0; i<strlen(cycle_caption_2_2); i++)
				{
					data_string[dsi]= cycle_caption_2_2[i];
					dsi++;
				}
				data_string[dsi] = String_end_symbol;
			}
			else
			{
				for (uint8_t i=0; i<strlen(cycle_caption_1); i++)
				{
					data_string[dsi]= cycle_caption_1[i];
					dsi++;
				}
				data_string[dsi]= ' ';
				dsi++;
				data_string[dsi]= ' ';
				dsi++;
				data_string[dsi]= ' ';
				dsi++;
				data_string[dsi]= ' ';
				dsi++;
				
				for (uint8_t i=0; i= strlen(cycle); i++)
				{
					data_string[dsi]= cycle[i];
					dsi++;
				}
				for (uint8_t i=0; i<strlen(cycle_caption_2_1); i++)
				{
					data_string[dsi]= cycle_caption_2_1[i];
					dsi++;
				}
				data_string[dsi] = String_end_symbol;
			}
		}
		else
		{
			strcpy(data_string,"Cycle:     1 day");
		}
	}
	else
	{
		strcpy(data_string,"Cycle:  everyday");
	}
}
void Channel_Cycle_Start_Day_String(char *data_string, Channel *channel)
{
	uint8_t dsi = 0;
	char cycle_start_day[3];
	char cycle_start_day_caption[]= {"Next cycle:   "};
	
	itoa(channel->Cycle_Start_Day, cycle_start_day, 10);
	Segment_Normalize(cycle_start_day);
	
	for (uint8_t i=0; i<strlen(cycle_start_day_caption); i++)
	{
		data_string[dsi]= cycle_start_day_caption[i];
		dsi++;
	}
	
	for (uint8_t i=0; i<strlen(cycle_start_day); i++)
	{
		data_string[dsi]= cycle_start_day[i];
		dsi++;
	}
	data_string[dsi] = String_end_symbol;
}

//TIMERS
void TC1_Init(void)
{
	TCCR1B = (1 << CS12);
	TCNT1 = 65536-31250;        
	TIMSK1 = (1 << TOIE1);
}	

//===UART===
void UART_Send_Num(uint8_t data_num)
{
	char data_string[3];
	itoa(data_num,data_string,16);
	
	PORTB = 1<< PORTB5;
	for (int i=0; i<strlen(data_string); i++)
	{
		while( !(UCSR0A & (1<<UDRE0)))
		{
		}
		UDR0 = data_string[i];
	}
	PORTB = 0<< PORTB5;
}
void UART_Send_Char(char data_char)
{
	PORTB = 1<< PORTB5;
	
	while( !(UCSR0A & (1<<UDRE0)))
	{
	}
	UDR0 = data_char;
	
	PORTB = 0<< PORTB5;
}
void UART_Send_String(char *data_string)
{
	PORTB = 1<< PORTB5;
	for (int i=0; i<strlen(data_string); i++)
	{
		while( !(UCSR0A & (1<<UDRE0)))
		{
		}
		UDR0 = data_string[i];
	}
	PORTB = 0<< PORTB5;
}
void UART_Init(void)
{
	UBRR0H = 0;
	UBRR0L = 8;                                                                        //скорость передачи 115200 бит/с
	UCSR0B = (1<<RXEN0)|(1<<TXEN0)|(1<<RXCIE0);										   //активируем Tx, Rx и прерывания
	UCSR0C = (0<<UPM01)|(0<<UPM00)|(0<<USBS0)|(0<<UCSZ02)|(1<<UCSZ01)|(1<<UCSZ00);     //8 bit, 1 stop bit
}

//EEPROM
void EEPROM_Init(void)
{
	if (eeprom_read_byte(&System_first_run) != 0)
	{
		eeprom_write_byte(&White_light_AE, 0);
		eeprom_write_byte(&White_light_ET_HH, 0);
		eeprom_write_byte(&White_light_ET_MM, 0);
		eeprom_write_byte(&White_light_ET_SS, 0);
		
		eeprom_write_byte(&White_light_AD, 0);
		eeprom_write_byte(&White_light_DT_HH, 0);
		eeprom_write_byte(&White_light_DT_MM, 0);
		eeprom_write_byte(&White_light_DT_SS, 0);
		eeprom_write_byte(&White_light_CYCLE, 0);
		eeprom_write_byte(&White_light_CSD, 1);
		
		eeprom_write_byte(&Grow_light_AE, 0);
		eeprom_write_byte(&Grow_light_ET_HH, 0);
		eeprom_write_byte(&Grow_light_ET_MM, 0);
		eeprom_write_byte(&Grow_light_ET_SS, 0);
		
		eeprom_write_byte(&Grow_light_AD, 0);
		eeprom_write_byte(&Grow_light_DT_HH, 0);
		eeprom_write_byte(&Grow_light_DT_MM, 0);
		eeprom_write_byte(&Grow_light_DT_SS, 0);
		eeprom_write_byte(&Grow_light_CYCLE, 0);
		eeprom_write_byte(&Grow_light_CSD, 1);
		
		eeprom_write_byte(&Water_pump_AE, 0);
		eeprom_write_byte(&Water_pump_ET_HH, 0);
		eeprom_write_byte(&Water_pump_ET_MM, 0);
		eeprom_write_byte(&Water_pump_ET_SS, 0);
		eeprom_write_byte(&Water_pump_CYCLE, 0);
		eeprom_write_byte(&Water_pump_CSD, 1);
		
		eeprom_write_byte(&Water_pump_AD, 0);
		eeprom_write_byte(&Water_pump_DT_HH, 0);
		eeprom_write_byte(&Water_pump_DT_MM, 0);
		eeprom_write_byte(&Water_pump_DT_SS, 0);
		
		eeprom_write_byte(&System_first_run, 0);
		
		First_run = true;
	}
}
void EEPROM_Read_Data(void)
{
	White_light.Auto_Enable = eeprom_read_byte(&White_light_AE);
	White_light.Enable_Time.HH = eeprom_read_byte(&White_light_ET_HH);
	White_light.Enable_Time.MM = eeprom_read_byte(&White_light_ET_MM);
	White_light.Enable_Time.SS = eeprom_read_byte(&White_light_ET_SS);
	
	White_light.Auto_Disable = eeprom_read_byte(&White_light_AD);
	White_light.Disable_Time.HH = eeprom_read_byte(&White_light_DT_HH);
	White_light.Disable_Time.MM = eeprom_read_byte(&White_light_DT_MM);
	White_light.Disable_Time.SS = eeprom_read_byte(&White_light_DT_SS);
	
	Grow_light.Auto_Enable = eeprom_read_byte(&Grow_light_AE);
	Grow_light.Enable_Time.HH = eeprom_read_byte(&Grow_light_ET_HH);
	Grow_light.Enable_Time.MM = eeprom_read_byte(&Grow_light_ET_MM);
	Grow_light.Enable_Time.SS = eeprom_read_byte(&Grow_light_ET_SS);
	
	Grow_light.Auto_Disable = eeprom_read_byte(&Grow_light_AD);
	Grow_light.Disable_Time.HH = eeprom_read_byte(&Grow_light_DT_HH);
	Grow_light.Disable_Time.MM = eeprom_read_byte(&Grow_light_DT_MM);
	Grow_light.Disable_Time.SS = eeprom_read_byte(&Grow_light_DT_SS);
	
	Water_pump.Auto_Enable = eeprom_read_byte(&Water_pump_AE);
	Water_pump.Enable_Time.HH = eeprom_read_byte(&Water_pump_ET_HH);
	Water_pump.Enable_Time.MM = eeprom_read_byte(&Water_pump_ET_MM);
	Water_pump.Enable_Time.SS = eeprom_read_byte(&Water_pump_ET_SS);
	Water_pump.Cycle = eeprom_read_byte(&Water_pump_CYCLE);
	Water_pump.Cycle_Start_Day = eeprom_read_byte(&Water_pump_CSD);
	
	Water_pump.Auto_Disable = eeprom_read_byte(&Water_pump_AD);
	Water_pump.Disable_Time.HH = eeprom_read_byte(&Water_pump_DT_HH);
	Water_pump.Disable_Time.MM = eeprom_read_byte(&Water_pump_DT_MM);
	Water_pump.Disable_Time.SS = eeprom_read_byte(&Water_pump_DT_SS);
}

//===IO Ports===
void IO_Init(void)
{
	DDRB  = 1<<PORTB5;                                               //Индикатор UART
	DDRD  = 1<<PORTD5 |1<<PORTD6|1<<PORTD7;                          //Исполнительные механизмы
}

//===I2C====
void I2C_Init(void)
{
	TWSR = 0;
	TWBR = ((F_CPU/F_SCL)-16)/2;
}
void I2C_TWINT_Wait(void)
{
	while(!(TWCR &(1<<TWINT)))
	{
		
	}
}
void I2C_Start(void)
{
	cli();
	_delay_us(10);
	TWCR =(1<<TWINT)|(1<<TWSTA)|(1<<TWEN);	
	I2C_TWINT_Wait();
	sei();
}
void I2C_Stop(void)
{
	cli();
	TWCR =(1<<TWINT)|(1<<TWEN)|(1<<TWSTO);
	_delay_us(10);
	sei();
}
void I2C_Send_Device_Address(uint8_t dev_address, bool write)
{
	cli();
	I2C_last_device = dev_address;
	I2C_last_write_mode = write;
	
	if (write == true)
	{
		TWDR = dev_address;
	}
	else
	{
		TWDR = dev_address|1;
	}
	
	TWCR = (1<<TWINT)|(1<<TWEN);
	I2C_TWINT_Wait();
	sei();
}
void I2C_Send_Register_Address(uint8_t reg_address)
{
	cli();
	TWDR = reg_address;
	TWCR =(1<<TWINT)|(1<<TWEN);
	I2C_TWINT_Wait();
	sei();
}
void I2C_Send_Data_ACK(uint8_t data)
{
	cli();
	TWDR = data;
	TWCR =(1<<TWINT)|(1<<TWEN)|(1<<TWEA);
	I2C_TWINT_Wait();
	sei();
}
void I2C_Send_Data_NACK(uint8_t data)
{
	cli();
	TWDR = data;
	TWCR =(1<<TWINT)|(1<<TWEN);
	I2C_TWINT_Wait();
	sei();
}
uint8_t I2C_Read_Data_ACK(void)
{
	cli();
	uint8_t Result = 0;
	TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWEA);
	I2C_TWINT_Wait();
	Result = TWDR;
	return Result;
	sei();
}
uint8_t I2C_Read_Data_NACK(void)
{
	cli();
	uint8_t Result = 0;
	TWCR = (1<<TWINT)|(1<<TWEN);
	I2C_TWINT_Wait();
	Result = TWDR;
	return Result;
	sei();
}

bool I2C_Check_Device(uint8_t dev_address)
{
	bool Result = false;
	I2C_Start();
	TWDR = dev_address;
	TWCR =(1<<TWINT)|(1<<TWSTA)|(1<<TWEN);
	while(!(TWCR &(1<<TWINT)))
	{
	}
	if((TWSR & 0xF8)== 0x18)
	{
		Result = true;
	}
	I2C_Stop();
	return Result;
}
void I2C_Device_Map(void)
{
	UART_Send_String("I2C network:");
	
	for (uint8_t dev_address=0x00; dev_address<0xFF; dev_address++)
	{
		if (I2C_Check_Device(dev_address)==true)
		{
			char text[25];
			itoa(dev_address,text,16);
			UART_Send_String(" 0x");
			UART_Send_String(text);
		}
	}
}

//===RTC===
void RTC_Set_System_Time(Time *time)
{
	I2C_Start();
	I2C_Send_Device_Address(RTC_module, 1);
	I2C_Send_Register_Address(0x00);
	I2C_Send_Data_ACK(INT_to_BCD(time->SS));
	I2C_Send_Data_ACK(INT_to_BCD(time->MM));
	I2C_Send_Data_NACK(INT_to_BCD(time->HH));
	I2C_Stop();
}
void RTC_Set_System_Date(Date *date)
{
	I2C_Start();
	I2C_Send_Device_Address(RTC_module, 1);
	I2C_Send_Register_Address(0x04);
	I2C_Send_Data_ACK(INT_to_BCD(date->DD));
	I2C_Send_Data_ACK(INT_to_BCD(date->MM));
	I2C_Send_Data_NACK(INT_to_BCD(date->YY));
	I2C_Stop();
}
void RTC_Get_System_Date_Time(void)
{
	RTC_error = !I2C_Check_Device(RTC_module);
	if (RTC_error == false)
	{
		I2C_Start();
		I2C_Send_Device_Address(RTC_module, 1);
		I2C_Send_Register_Address(0x00);
		I2C_Start();
		I2C_Send_Device_Address(RTC_module, 0);
		System_time.SS = BCD_to_INT(I2C_Read_Data_ACK());
		System_time.MM = BCD_to_INT(I2C_Read_Data_ACK());
		System_time.HH = BCD_to_INT(I2C_Read_Data_ACK());
		int8_t day_of_week = BCD_to_INT(I2C_Read_Data_ACK());
		System_date.DD = BCD_to_INT(I2C_Read_Data_ACK());
		System_date.MM = BCD_to_INT(I2C_Read_Data_ACK());
		System_date.YY = BCD_to_INT(I2C_Read_Data_NACK());
		I2C_Stop();
	}
	else
	{
		White_light.State = 0;
		Grow_light.State = 0;
		Water_pump.State = 0;
		PORTD = White_light.State<<PORTD5|Grow_light.State<<PORTD6| Water_pump.State<<PORTD7;
		Reset();
	}
}

//===LCD===
void LCD_Write_Command(uint8_t command)
{
	command = command & ~(1<<LCD_E);
	command = command | (1<<LCD_E);
	I2C_Send_Data_ACK(command);
	_delay_us(40);
	command = command & ~(1<<LCD_E);
	command = command | (0<<LCD_E);
	I2C_Send_Data_ACK(command);
	_delay_us(40);
}
void LCD_Send_Command(uint8_t data, bool BL, bool RS, bool RW)
{
	uint8_t LCD_input_buffer = 0;
	uint8_t data_H = data & 0b11110000;
	uint8_t data_L = (data<<4) & 0b11110000;

	LCD_input_buffer = data_H | BL<<LCD_BL| RS<<LCD_RS| RW<<LCD_RW;
	I2C_Send_Data_ACK(LCD_input_buffer);
	LCD_Write_Command(LCD_input_buffer);
	
	LCD_input_buffer = data_L | BL<<LCD_BL| RS<<LCD_RS| RW<<LCD_RW;
	I2C_Send_Data_ACK(LCD_input_buffer);
	LCD_Write_Command(LCD_input_buffer);
}
void LCD_Command_Clear_Display(void)
{
	LCD_Send_Command(0b00000001,1,0,0);		//Clear display
	_delay_ms(2);
}
void LCD_Command_Cursor_Return(void)
{
	LCD_Send_Command(0b00000010,0,0,0);
}
void LCD_Command_Put_Cursor(uint8_t x, uint8_t y)
{
	uint8_t addr = 0;  // line 0 begins at addr 0x00
	switch (y)
	{
		case 0: addr = 0x00;  break;
		case 1: addr = 0x40;  break;
	}
	
	LCD_Send_Command(0b10000000 + addr + x,1,0,0);
}
void LCD_Command_Display_Shift_Right(uint8_t count)
{
	for (uint8_t i=0;i<count;i++)
	{
		LCD_Send_Command(0b00011000,1,0,0);		//Cursor/display shift
	}
}
void LCD_Command_Cursor_Shift_Right(uint8_t count)
{
	for (uint8_t i=0;i<count;i++)
	{
		LCD_Send_Command(0b00010100,1,0,0);		//Cursor/display shift
	}
}
void LCD_Command_Cursor_Direction_Right(void)
{
	LCD_Send_Command(0b00000110,1,0,0);		//Entry mode set
}
void LCD_Command_Cursor_Direction_Left(void)
{
	LCD_Send_Command(0b00000100,1,0,0);		//Entry mode set
}

void LCD_Command_Send_Char(char symbol)
{
	uint8_t LCD_input_buffer = 0;
	uint8_t data_H = symbol & 0b11110000;
	uint8_t data_L = (symbol<<4) & 0b11110000;

	LCD_input_buffer = data_H | 1<<LCD_BL| 1<<LCD_RS| 0<<LCD_RW;
	I2C_Send_Data_ACK(LCD_input_buffer);
	LCD_Write_Command(LCD_input_buffer);
	
	LCD_input_buffer = data_L | 1<<LCD_BL| 1<<LCD_RS| 0<<LCD_RW;
	I2C_Send_Data_ACK(LCD_input_buffer);
	LCD_Write_Command(LCD_input_buffer);
}
void LCD_Command_Send_String_With_Delay(char *data_string, int8_t num)
{
	int delay = 100;
	LCD_Command_Put_Cursor(0,num);
	LCD_Command_Cursor_Direction_Right();
	for (int8_t i=0; i<strlen(data_string); i++)
	{
		LCD_Command_Send_Char(data_string[i]);
		_delay_ms(delay);
	}
}
void LCD_Command_Send_String(char *data_string, int8_t num)
{
	LCD_Command_Put_Cursor(0,num);
	LCD_Command_Cursor_Direction_Right();
	for (int8_t i=0; i<strlen(data_string); i++)
	{
		LCD_Command_Send_Char(data_string[i]);
	}
}

void LCD_Command_Clear_String_With_Delay(int8_t num)
{
	int delay = 25;
	LCD_Command_Put_Cursor(15,num);
	LCD_Command_Cursor_Direction_Left();
	for (int8_t i=0; i<16; i++)
	{
		LCD_Command_Send_Char(' ');
		_delay_ms(delay);
	}
	LCD_Command_Put_Cursor(0,num);
}
void LCD_Command_Clear_String(int8_t num)
{
	LCD_Command_Put_Cursor(15,num);
	LCD_Command_Cursor_Direction_Left();
	for (int8_t i=0; i<16; i++)
	{
		LCD_Command_Send_Char(' ');
	}
	LCD_Command_Put_Cursor(0,num);
}
void LCD_Init()
{
	_delay_ms(50);

	//Инициализация LCD в соответствии с блок-схемой в даташите
	I2C_Start();
	I2C_Send_Device_Address(LCD_module,1);
	LCD_Send_Command(0b00110011,0,0,0);
	_delay_us(100);
	LCD_Send_Command(0b00110010,0,0,0);
	_delay_ms(5);

	//Настройка LCD
	LCD_Send_Command(0b00101000,0,0,0);		//Function set
	LCD_Send_Command(0b00001000,0,0,0);		//Display on/off control
	LCD_Send_Command(0b00000001,0,0,0);		//Clear display
	_delay_ms(2);
	LCD_Send_Command(0b00000110,0,0,0);		//Entry mode set
	//Включение LCD
	LCD_Send_Command(0b00001100,1,0,0);		//Display on/off control
	I2C_Stop();
}

void LCD_Show_String(char *data_string, int8_t num)
{
	I2C_Start();
	I2C_Send_Device_Address(LCD_module,1);
	LCD_Command_Send_String_With_Delay(data_string, num);
	I2C_Stop();
}
void LCD_Clear_Display(void)
{
	I2C_Start();
	I2C_Send_Device_Address(LCD_module,1);
	LCD_Command_Clear_Display();
	I2C_Stop();
}
void LCD_Flash_String(char *data_string, int8_t num)
{
	int delay = 500;
	I2C_Start();
	I2C_Send_Device_Address(LCD_module,1);
	LCD_Command_Send_String_With_Delay(data_string, num);
	_delay_ms(delay);
	LCD_Command_Clear_String_With_Delay(num);
	I2C_Stop();
}

void LCD_Flash_First_Run_Message(void)
{
	if (First_run == true)
	{
		int delay = 500;
		
		I2C_Start();
		I2C_Send_Device_Address(LCD_module,1);
		
		LCD_Command_Send_String_With_Delay("G.E.C.K.", 0);
		LCD_Command_Send_String_With_Delay("defaults loaded", 1);
		_delay_ms(delay);		
		I2C_Stop();
		
		First_run = false;
	}
}
void LCD_Flash_Reset_Message(void)
{
	int delay = 500;
	
	I2C_Start();
	I2C_Send_Device_Address(LCD_module,1);
	
	LCD_Command_Clear_String_With_Delay(1);
	LCD_Command_Clear_String_With_Delay(0);
	
	LCD_Command_Send_String_With_Delay("G.E.C.K.", 0);
	LCD_Command_Send_String_With_Delay("loading defaults", 1);
	_delay_ms(delay);
	LCD_Command_Clear_String_With_Delay(1);
	LCD_Command_Clear_String_With_Delay(0);
	
	LCD_Command_Send_String_With_Delay("G.E.C.K.", 0);
	LCD_Command_Send_String_With_Delay("restarting", 1);
	_delay_ms(delay);
	
	I2C_Stop();		
}
void LCD_Flash_Start_Message(void)
{
	int delay = 500;
	
	I2C_Start();
	I2C_Send_Device_Address(LCD_module,1);
	
	LCD_Command_Send_String_With_Delay("G.E.C.K.", 0);
	LCD_Command_Send_String_With_Delay("started", 1);
	_delay_ms(delay);
	
	I2C_Stop();
}
void LCD_Flash_RTC_Error_Message(void)
{
	int delay = 1000;
	
	I2C_Start();
	I2C_Send_Device_Address(LCD_module,1);
	LCD_Command_Clear_String_With_Delay(1);
	LCD_Command_Clear_String_With_Delay(0);
	LCD_Command_Send_String_With_Delay("G.E.C.K. error!", 0);
	LCD_Command_Send_String_With_Delay("check RTC", 1);
	_delay_ms(delay);
	
	I2C_Stop();
}

void LCD_Flash_System_Time_Updated_Message(void)
{
	int delay = 500;
	
	I2C_Start();
	I2C_Send_Device_Address(LCD_module,1);
	
	LCD_Command_Clear_String_With_Delay(1);
	LCD_Command_Clear_String_With_Delay(0);
	
	LCD_Command_Send_String_With_Delay("G.E.C.K.", 0);
	LCD_Command_Send_String_With_Delay("Time updated", 1);
	_delay_ms(delay);
	
	I2C_Stop();
	
	Flash_time_string = true;
}
void LCD_Flash_System_Date_Updated_Message(void)
{
	int delay = 500;
	
	I2C_Start();
	I2C_Send_Device_Address(LCD_module,1);
	
	LCD_Command_Clear_String_With_Delay(1);
	LCD_Command_Clear_String_With_Delay(0);
	
	LCD_Command_Send_String_With_Delay("G.E.C.K.", 0);
	LCD_Command_Send_String_With_Delay("Date updated", 1);
	_delay_ms(delay);
	
	I2C_Stop();
	
	Flash_time_string = true;
}
void LCD_Flash_Ch_Info_Message(Channel *channel)
{
	int delay = 500;
	
	char Enable_Data[17];
	char Disable_Data[17];
	char State_Data[17];
	char AE_Data[17];
	char AD_Data[17];
	char Cycle_Data[17];
	char Cycle_Start_Day_Data[17];

	Channel_State_String(State_Data, channel);
	Channel_AE_String(AE_Data, channel);
	Channel_AD_String(AD_Data, channel);
	
	if (channel->Water == 1)
	{
		Water_Channel_Enable_String(Enable_Data, channel);
		Water_Channel_Disable_String(Disable_Data, channel);
		Channel_Cycle_String(Cycle_Data, channel);
		Channel_Cycle_Start_Day_String(Cycle_Start_Day_Data, channel);
	}
	else
	{
		Light_Channel_Enable_String(Enable_Data, channel);
		Light_Channel_Disable_String(Disable_Data, channel);
	}
	
	I2C_Start();
	I2C_Send_Device_Address(LCD_module,1);
	
	LCD_Command_Clear_String_With_Delay(1);
	LCD_Command_Clear_String_With_Delay(0);
	
	LCD_Command_Send_String_With_Delay(channel->Name, 0);
	LCD_Command_Send_String_With_Delay(State_Data, 1);
	_delay_ms(delay);
	LCD_Command_Clear_String_With_Delay(1);
	LCD_Command_Send_String_With_Delay(AE_Data, 1);
	_delay_ms(delay);
	LCD_Command_Clear_String_With_Delay(1);
	LCD_Command_Send_String_With_Delay(Enable_Data, 1);
	_delay_ms(delay);
	LCD_Command_Clear_String_With_Delay(1);
	LCD_Command_Send_String_With_Delay(AD_Data, 1);
	_delay_ms(delay);
	LCD_Command_Clear_String_With_Delay(1);
	LCD_Command_Send_String_With_Delay(Disable_Data, 1);
	_delay_ms(delay);
	if (channel->Water == 1)
	{
		LCD_Command_Clear_String_With_Delay(1);
		LCD_Command_Send_String_With_Delay(Cycle_Data, 1);
		_delay_ms(delay);
		if (channel->Cycle>0)
		{
			LCD_Command_Clear_String_With_Delay(1);
			LCD_Command_Send_String_With_Delay(Cycle_Start_Day_Data, 1);
			_delay_ms(delay);
		}	
	}
	I2C_Stop();

	Flash_time_string = true;
}
void LCD_Flash_Ch_ET_Set_Message(Channel *channel)
{
	int delay = 500;
	
	char Enable_Data[17];
	
	if (channel->Water == 1)
	{
		Water_Channel_Enable_String(Enable_Data, channel);
	}
	else
	{
		Light_Channel_Enable_String(Enable_Data, channel);
	}
	I2C_Start();
	I2C_Send_Device_Address(LCD_module,1);
	
	LCD_Command_Clear_String_With_Delay(1);
	LCD_Command_Clear_String_With_Delay(0);
	
	LCD_Command_Send_String_With_Delay(channel->Name, 0);
	LCD_Command_Send_String_With_Delay(Enable_Data, 1);
	_delay_ms(delay);
	
	I2C_Stop();
	
	Flash_time_string = true;
}
void LCD_Flash_Ch_AE_Message(Channel *channel)
{
	int delay = 500;
	
	char Data[17];
	
	if (channel->Auto_Enable == 1)
	{
		strcpy(Data,"Auto enable ON");
	}
	else
	{
		strcpy(Data,"Auto enable OFF");
	}
	I2C_Start();
	I2C_Send_Device_Address(LCD_module,1);
	
	LCD_Command_Clear_String_With_Delay(1);
	LCD_Command_Clear_String_With_Delay(0);
	
	LCD_Command_Send_String_With_Delay(channel->Name, 0);
	LCD_Command_Send_String_With_Delay(Data, 1);
	_delay_ms(delay);
	
	I2C_Stop();
	
	Flash_time_string = true;
}
void LCD_Flash_Ch_DT_Set_Message(Channel *channel)
{
	int delay = 500;
	
	char Enable_Data[17];
	char Disable_Data[17];
	
	if (channel->Water == 1)
	{
		Water_Channel_Disable_String(Disable_Data, channel);
	}
	else
	{
		Light_Channel_Disable_String(Disable_Data, channel);
	}
	I2C_Start();
	I2C_Send_Device_Address(LCD_module,1);
	
	LCD_Command_Clear_String_With_Delay(1);
	LCD_Command_Clear_String_With_Delay(0);
	
	LCD_Command_Send_String_With_Delay(channel->Name, 0);
	LCD_Command_Send_String_With_Delay(Disable_Data, 1);
	_delay_ms(delay);
	
	I2C_Stop();
	
	Flash_time_string = true;
}
void LCD_Flash_Ch_AD_Message(Channel *channel)
{
	int delay = 500;
	
	char Data[17];
	
	if (channel->Auto_Disable == 1)
	{
		strcpy(Data,"Auto disable ON");
	}
	else
	{
		strcpy(Data,"Auto disable OFF");
	}
	I2C_Start();
	I2C_Send_Device_Address(LCD_module,1);
	
	LCD_Command_Clear_String_With_Delay(1);
	LCD_Command_Clear_String_With_Delay(0);
	
	LCD_Command_Send_String_With_Delay(channel->Name, 0);
	LCD_Command_Send_String_With_Delay(Data, 1);
	_delay_ms(delay);
	
	I2C_Stop();
	
	Flash_time_string = true;
}
void LCD_Flash_Ch_State_Message(Channel *channel)
{
	int delay = 500;
	
	char Data[17];
	
	Channel_State_String(Data, channel);

	I2C_Start();
	I2C_Send_Device_Address(LCD_module,1);
	
	LCD_Command_Clear_String_With_Delay(1);
	LCD_Command_Clear_String_With_Delay(0);
	
	LCD_Command_Send_String_With_Delay(channel->Name, 0);
	LCD_Command_Send_String_With_Delay(Data, 1);
	_delay_ms(delay);
	
	I2C_Stop();
	
	Flash_time_string = true;
}
void LCD_Flash_Ch_Cycle_Message(Channel *channel)
{
	int delay = 500;
	
	char cycle_data[17];
	char cyc_st_day_data[17];
	
	Channel_Cycle_String(cycle_data, channel);
	Channel_Cycle_Start_Day_String(cyc_st_day_data, channel);

	I2C_Start();
	I2C_Send_Device_Address(LCD_module,1);
	
	LCD_Command_Clear_String_With_Delay(1);
	LCD_Command_Clear_String_With_Delay(0);
	
	LCD_Command_Send_String_With_Delay(channel->Name, 0);
	LCD_Command_Send_String_With_Delay(cycle_data, 1);
	_delay_ms(delay);
	if (channel->Cycle>0)
	{
		LCD_Command_Clear_String_With_Delay(1);
		LCD_Command_Send_String_With_Delay(cyc_st_day_data, 1);
		_delay_ms(delay);
	}
	
	I2C_Stop();
	
	Flash_time_string = true;
}
void LCD_Flash_System_Info_Message(void)
{
	int delay = 500;
	
	I2C_Start();
	I2C_Send_Device_Address(LCD_module,1);
	
	LCD_Command_Clear_String_With_Delay(1);
	LCD_Command_Clear_String_With_Delay(0);
	
	LCD_Command_Send_String_With_Delay(Device_type, 0);
	LCD_Command_Send_String_With_Delay(Firmware_version, 1);
	_delay_ms(delay);
	
	I2C_Stop();
	
	Flash_time_string = true;
}

void LCD_Show_Time(void)
{
	int delay = 500;
	char Date_Time_Caption[] = {"Date & time:    "};
	char Date_Time_Data[17];
	
	DATE_TIME_to_STRING(Date_Time_Data, &System_date, &System_time, false, true);
	
	I2C_Start();
	I2C_Send_Device_Address(LCD_module,1);
	
	if (Flash_time_string == true)
	{
		LCD_Command_Clear_String_With_Delay(1);
		LCD_Command_Clear_String_With_Delay(0);
		LCD_Command_Send_String_With_Delay(Date_Time_Caption, 0);
		LCD_Command_Send_String_With_Delay(Date_Time_Data, 1);
		Flash_time_string = false;
	}
	else
	{
		LCD_Command_Send_String(Date_Time_Caption, 0);
		LCD_Command_Send_String(Date_Time_Data, 1);
	}
	
	I2C_Stop();
}
void LCD_Show_Watering_Message(void)
{
	char watering_caption[] = {"Watering..."};
	
	I2C_Start();
	
	I2C_Send_Device_Address(LCD_module,1);
	LCD_Command_Clear_String_With_Delay(1);
	LCD_Command_Clear_String_With_Delay(0);
	
	LCD_Command_Send_String_With_Delay(watering_caption, 0);
	
	I2C_Stop();
	
	Flash_time_string = true;
}
void LCD_Show_Timer(Time *stop_time)
{
	char timer_caption [] = {"Time:   "};
	char timer_time [9];
	char timer[17]; 
		
	int interval_s = 0;
	int start = 3600*System_time.HH+60*System_time.MM+System_time.SS;
	int stop = 3600*stop_time->HH+60*stop_time->MM+stop_time->SS;
	
	if (stop>=start)
	{
		interval_s = stop-start;
	}
	else
	{
		interval_s = 86400 - start + stop;
	}
	
	I2C_Start();
	I2C_Send_Device_Address(LCD_module,1);	
	
	while (interval_s > 0)
	{
		int HH = interval_s/3600;
		int MM = (interval_s - HH*3600)/60;
		int SS = interval_s - HH*3600 - MM*60;
		
		Time interval = {HH,MM,SS};
		TIME_to_STRING(timer_time, &interval, true, false);

		uint8_t tsi = 0;

		for (uint8_t i=0; i<strlen(timer_caption); i++)
		{
			timer[tsi] = timer_caption[i];
			tsi++;
		}
		for (uint8_t i=0; i<strlen(timer_time); i++)
		{
			timer[tsi] = timer_time[i];
			tsi++;
		}
		timer[tsi]=String_end_symbol;

		LCD_Command_Send_String_With_Delay(timer, 1);
		
		int start = 3600*System_time.HH+60*System_time.MM+System_time.SS;
		
		if (stop>=start)
		{
			interval_s = stop-start;
		}
		else
		{
			interval_s = 86400 - start + stop;
		}
	}
	I2C_Stop();
}
void LCD_Close_Watering_Message(void)
{
	I2C_Start();
	I2C_Send_Device_Address(LCD_module,1);	
	LCD_Command_Clear_String_With_Delay(1);
	LCD_Command_Send_String_With_Delay("Finished",1);
	_delay_ms(500);
	LCD_Command_Clear_String_With_Delay(1);
	LCD_Command_Clear_String_With_Delay(0);
	
	I2C_Stop();
}

//===ОБРАБОТКА ВХОДНОЙ КОМАНДЫ
void Command_GET(char *command_string, char *input_command)
{
	for (uint8_t i=0; i<3; i++)
	{
		command_string[i]=input_command[i];
	}
}
void Channel_GET(char *channel_string, char *input_command)
{
	for (uint8_t i=3; i<5; i++)
	{
		channel_string[i-3]=input_command[i];
	}
}
void State_GET(uint8_t *state, char *input_command)
{
	if (input_command[5]=='1')
	{
		(*state) = 1;
	}
	else
	{
		(*state) = 0;
	}
}
void Cycle_GET(uint8_t *cycle, uint8_t *cycle_start_day, char *input_command)
{
	uint8_t cycle_result;
	char cycle_string[3];
	for (uint8_t i=5; i<7; i++)
	{
		cycle_string[i-5]=input_command[i];
	}
	cycle_string[2]=String_end_symbol;
	cycle_result = atoi(cycle_string);
		
	uint8_t day_result;
	char day_string[3];
	for (uint8_t i=7; i<9; i++)
	{
		day_string[i-7]=input_command[i];
	}
	day_string[2]=String_end_symbol;
	day_result = atoi(day_string);
	
	if (day_result > 27)
	{
		day_result = 27;
	}
	if (day_result == 0)
	{
		day_result = 1;
	}
	if (cycle_result > 27)
	{
		cycle_result = 27;
	}
	
	(*cycle) = cycle_result;
	(*cycle_start_day) = day_result;
}

uint8_t Time_HH_GET(char *input_command)
{
	uint8_t result;
	char HH[3];
	for (int i=6; i<8; i++)
	{
		HH[i-6]=input_command[i];
	}
	HH[2]=String_end_symbol;
	result = atoi(HH);
	
	if (result > 24)
	{
		return 0;
	}
	else
	{
		return result;
	}
}
uint8_t Time_MM_GET(char *input_command)
{
	uint8_t result;
	char MM[3];
	for (int i=8; i<10; i++)
	{
		MM[i-8]=input_command[i];
	}
	MM[2]=String_end_symbol;
	result =   atoi(MM);
	
	if (result > 59)
	{
		return 0;
	}
	else
	{
		return result;
	}
}
uint8_t Time_SS_GET(char *input_command)
{
	uint8_t result;
	char SS[3];
	for (int i=10; i<12; i++)
	{
		SS[i-10]=input_command[i];
	}
	SS[2]=String_end_symbol;	
	result = atoi(SS);
	
	if (result > 59)
	{
		return 0;
	}
	else
	{
		return result;
	}
}
void Time_GET(Time *time, char *input_command)
{
	time->HH = Time_HH_GET(input_command);
	time->MM = Time_MM_GET(input_command);
	time->SS = Time_SS_GET(input_command);
}

uint8_t Date_DD_GET(char *input_command)
{
	uint8_t result;
	char DD[3];
	for (int i=6; i<8; i++)
	{
		DD[i-6]=input_command[i];
	}
	DD[2]=String_end_symbol;
	result = atoi(DD);
	
	if (result > 31 || result == 0)
	{
		return 1;
	}
	else
	{
		return result;
	}
}
uint8_t Date_MM_GET(char *input_command)
{
	uint8_t result;
	char MM[3];
	for (int i=8; i<10; i++)
	{
		MM[i-8]=input_command[i];
	}
	MM[2]=String_end_symbol;
	result = atoi(MM);
	
	if (result > 12 || result == 0)
	{
		return 1;
	}
	else
	{
		return result;
	}
}
uint8_t Date_YY_GET(char *input_command)
{
	char YY[3];
	for (int i=10; i<12; i++)
	{
		YY[i-10]=input_command[i];
	}
	YY[2]=String_end_symbol;
	return atoi(YY);
}
void Date_GET(Date *date, char *input_command)
{
	date->DD = Date_DD_GET(input_command);
	date->MM = Date_MM_GET(input_command);
	date->YY = Date_YY_GET(input_command);
}

void Channel_Auto_Enable_SET(Channel *channel, uint8_t *state)
{
	channel->Auto_Enable = (*state);
	uint8_t *eeprom_AE = channel->EEPROM_AE;
	eeprom_write_byte(eeprom_AE, (*state));
}
void Channel_Auto_Disable_SET(Channel *channel, uint8_t *state)
{
	channel->Auto_Disable = (*state);
	uint8_t *eeprom_AD = channel->EEPROM_AD;
	eeprom_write_byte(eeprom_AD, (*state));
}
void Channel_Enable_Time_SET(Channel *channel, Time *time)
{
	channel->Enable_Time.HH = time->HH;
	channel->Enable_Time.MM = time->MM;
	channel->Enable_Time.SS = time->SS;
	
	uint8_t *eeprom_ET_HH = channel->EEPROM_ET_HH;
	uint8_t *eeprom_ET_MM = channel->EEPROM_ET_MM;
	uint8_t *eeprom_ET_SS = channel->EEPROM_ET_SS;
	
	eeprom_write_byte(eeprom_ET_HH, time->HH);
	eeprom_write_byte(eeprom_ET_MM, time->MM);
	eeprom_write_byte(eeprom_ET_SS, time->SS);
}
void Channel_Disable_Time_SET(Channel *channel, Time *time)
{
	channel->Disable_Time.HH = time->HH;
	channel->Disable_Time.MM = time->MM;
	channel->Disable_Time.SS = time->SS;
	
	uint8_t *eeprom_DT_HH = channel->EEPROM_DT_HH;
	uint8_t *eeprom_DT_MM = channel->EEPROM_DT_MM;
	uint8_t *eeprom_DT_SS = channel->EEPROM_DT_SS;
	
	eeprom_write_byte(eeprom_DT_HH, time->HH);
	eeprom_write_byte(eeprom_DT_MM, time->MM);
	eeprom_write_byte(eeprom_DT_SS, time->SS);
}
void Channel_Cycle_SET(Channel *channel, uint8_t *cycle, uint8_t *cycle_start_day)
{
	channel->Cycle = (*cycle);
	channel->Cycle_Start_Day = (*cycle_start_day);
	
	uint8_t *eeprom_CYCLE = channel->EEPROM_CYCLE;
	uint8_t *eeprom_CSD = channel->EEPROM_CSD;
	
	eeprom_write_byte(eeprom_CYCLE, (*cycle));
	eeprom_write_byte(eeprom_CSD, (*cycle_start_day));
}


//===ЛОГИКА ВЫХОДНЫХ КАНАЛОВ===
void Channel_ENABLE(Channel *channel, bool force_enable = false)
{
	channel->State = 1;
	if (force_enable == true)
	{
		channel->Force_Enable = 1;
	}
}
void Channel_DISABLE(Channel *channel, bool force_disable = false)
{
	channel->State = 0;
	channel->Force_Enable = 0;
	
	if (force_disable == true)
	{
		Channel_Auto_Enable_SET(channel, 0);
	}
}
void Outputs_SET(void)
{
	PORTD = White_light.State<<PORTD5|Grow_light.State<<PORTD6| Water_pump.State<<PORTD7;
}
void Light_Channel_Logick(Channel *channel)
{
	if (channel->Auto_Enable == 1)
	{
		if (channel->Enable_Time.HH == System_time.HH)
		{
			if (channel->Enable_Time.MM == System_time.MM)
			{
				Channel_ENABLE(channel);
			}
		}
	}
	if (channel->Auto_Disable == 1)
	{
		if (channel->Disable_Time.HH == System_time.HH)
		{
			if (channel->Disable_Time.MM == System_time.MM)
			{
				Channel_DISABLE(channel);
			}
		}
	}
	Outputs_SET();
}
void Water_Channel_Timer_ON (Channel *channel)
{
	Time disable_time;
	if (channel->Force_Enable == 1)
	{
		disable_time = {System_time.HH, System_time.MM, System_time.SS};
		Time_Add(&disable_time, &WP_manual_time);
	}
	else
	{
		disable_time = {channel->Disable_Time.HH, channel->Disable_Time.MM, channel->Disable_Time.SS};
	}

	LCD_Show_Watering_Message();
	LCD_Show_Timer(&disable_time);
	Channel_DISABLE(channel);
	Outputs_SET();
	LCD_Close_Watering_Message();
}
void Water_Channel_Logick(Channel *channel)
{	
	bool start_timer = false;	

	if (((channel->Cycle > 0 && channel->Cycle_Start_Day == System_date.DD)||(channel->Cycle ==0))&&(channel->Auto_Enable == 1 && channel->Auto_Disable == 1))
	{
		if (channel->Enable_Time.HH == System_time.HH)
		{
			if (channel->Enable_Time.MM == System_time.MM)
			{
				if (channel->Enable_Time.SS == System_time.SS)
				{
					Channel_ENABLE(channel);
					WP_ON_command = true;
				}
			}
		}	
	}
}
void Cycle_Start_Day_Update(Channel *channel)
{
	if (channel->Cycle >0)
	{
		Date cycle_start_date = {channel->Cycle_Start_Day, System_date.MM, System_date.YY};
	
		while (System_date.DD>cycle_start_date.DD && System_date.MM==cycle_start_date.MM)
		{
			Date_Add(&cycle_start_date, channel->Cycle+1);
		}
		uint8_t cycle_start_day = cycle_start_date.DD;
		uint8_t cycle = channel->Cycle;
	
		Channel_Cycle_SET(channel, &cycle, &cycle_start_day);
	}
}
void Output_Logick_Execute(void)
{
	Light_Channel_Logick(&White_light);
	Light_Channel_Logick(&Grow_light);
	Water_Channel_Logick(&Water_pump);
}

//ВЫПОЛНЕНИЕ ПОЛЬЗОВАТЕЛЬСКИХ КОММАНД
void IC_Set_System_Date(char *input_command)
{
	Date_GET(&t_date, input_command);
	SSD_command = true;
}
void IC_Set_System_Time(char *input_command)
{
	Time_GET(&t_time, input_command);
	SST_command = true;
}
void IC_Set_Ch_Enable_Time(char *input_command)
{
	char channel_type[2];
	Channel_GET(channel_type, input_command);
	Time time = {0,0,0};
	Time_GET(&time, input_command);
	SET_command = true;
	
	if (String_Compare(channel_type, "wl", 0, 0, 2) == true)
	{
		Channel_Enable_Time_SET(&White_light, &time);
		t_channel = &White_light;
	}
	if (String_Compare(channel_type, "gl", 0, 0, 2) == true)
	{
		Channel_Enable_Time_SET(&Grow_light, &time);
		t_channel = &Grow_light;
	}
	if (String_Compare(channel_type, "wp", 0, 0, 2) == true)
	{
		Channel_Enable_Time_SET(&Water_pump, &time);
		t_channel = &Water_pump;
	}
}
void IC_Set_Ch_Auto_Enable_State(char *input_command)
{
	char channel_type[2];
	Channel_GET(channel_type, input_command);
	uint8_t state = 0;
	State_GET(&state, input_command);
	SAE_command = true;
	
	if (String_Compare(channel_type, "wl", 0, 0, 2) == true)
	{
		Channel_Auto_Enable_SET(&White_light, &state);
		t_channel = &White_light;
	}
	if (String_Compare(channel_type, "gl", 0, 0, 2) == true)
	{
		Channel_Auto_Enable_SET(&Grow_light, &state);
		t_channel = &Grow_light;
	}
	if (String_Compare(channel_type, "wp", 0, 0, 2) == true)
	{
		Channel_Auto_Enable_SET(&Water_pump, &state);
		t_channel = &Water_pump;
	}
}
void IC_Set_Ch_Disable_Time(char *input_command)
{
	char channel_type[2];
	Channel_GET(channel_type, input_command);
	Time time = {0,0,0};
	Time_GET(&time, input_command);
	SDT_command = true;

	if (String_Compare(channel_type, "wl", 0, 0, 2) == true)
	{
		Channel_Disable_Time_SET(&White_light, &time);
		t_channel = &White_light;
	}
	if (String_Compare(channel_type, "gl", 0, 0, 2) == true)
	{
		Channel_Disable_Time_SET(&Grow_light, &time);
		t_channel = &Grow_light;
	}
	if (String_Compare(channel_type, "wp", 0, 0, 2) == true)
	{
		Channel_Disable_Time_SET(&Water_pump, &time);
		t_channel = &Water_pump;
	}
}
void IC_Set_Ch_Auto_Disable_State(char *input_command)
{
	char channel_type[2];
	Channel_GET(channel_type, input_command);
	uint8_t state = 0;
	State_GET(&state, input_command);
	SAD_command = true;
	
	if (String_Compare(channel_type, "wl", 0, 0, 2) == true)
	{
		Channel_Auto_Disable_SET(&White_light, &state);
		t_channel = &White_light;
	}
	if (String_Compare(channel_type, "gl", 0, 0, 2) == true)
	{
		Channel_Auto_Disable_SET(&Grow_light, &state);
		t_channel = &Grow_light;
	}
	if (String_Compare(channel_type, "wp", 0, 0, 2) == true)
	{
		Channel_Auto_Disable_SET(&Water_pump, &state);
		t_channel = &Water_pump;
	}
}
void IC_Set_Ch_State(char *input_command)
{
	char channel_type[2];
	Channel_GET(channel_type, input_command);
	uint8_t state = 0;
	State_GET(&state, input_command);
	SCS_command =true;
	
	if (String_Compare(channel_type, "wl", 0, 0, 2) == true)
	{
		if (state == 0)
		{
			Channel_DISABLE(&White_light, true);
		}
		else
		{
			Channel_ENABLE(&White_light, true);
		}
		Outputs_SET();
		t_channel = &White_light;
	}
	if (String_Compare(channel_type, "gl", 0, 0, 2) == true)
	{
		if (state == 0)
		{
			Channel_DISABLE(&Grow_light, true);
		}
		else
		{
			Channel_ENABLE(&Grow_light, true);
		}
		Outputs_SET();
		t_channel = &Grow_light;
	}
	if (String_Compare(channel_type, "wp", 0, 0, 2) == true)
	{
		if (state == 0)
		{
			Channel_DISABLE(&Water_pump, true);
		}
		else
		{
			Channel_ENABLE(&Water_pump, true);
			WP_ON_command = true;
		}
		t_channel = &Water_pump;
	}
}
void IC_Set_Ch_Cycle(char *input_command)
{
	char channel_type[2];
	Channel_GET(channel_type, input_command);
	uint8_t cycle = 0;
	uint8_t cycle_start_day = 1;
	Cycle_GET(&cycle, &cycle_start_day, input_command);
	SCC_command =true;

	if (String_Compare(channel_type, "wp", 0, 0, 2) == true)
	{
		Channel_Cycle_SET(&Water_pump, &cycle, &cycle_start_day);
		t_channel = &Water_pump;
	}
}
void IC_Load_Defaults(void)
{
	eeprom_write_byte(&System_first_run, 1);
	LDS_command = true;
}
void IC_Report_Ch_Settings(char *input_command)
{
	char channel_type[2];
	Channel_GET(channel_type, input_command);
	RCS_command = true;
	
	if (String_Compare(channel_type, "wl", 0, 0, 2) == true)
	{
		t_channel = &White_light;
	}
	if (String_Compare(channel_type, "gl", 0, 0, 2) == true)
	{
		t_channel = &Grow_light;
	}
	if (String_Compare(channel_type, "wp", 0, 0, 2) == true)
	{
		t_channel = &Water_pump;
	}
}
void IC_Report_System_Info()
{
		UART_Send_String(Device_type);
		UART_Send_String("\n\r");
		UART_Send_String(Firmware_version);
		UART_Send_String("\n\r");
		
		RSI_command = true;
}
void Input_Command_Execute(char *input_command)
{
	char command_type[3];
	Command_GET(command_type, input_command);
	
	if (String_Compare(command_type, "ssd", 0, 0, 3) == true)	//Установка системной даты
	{
		IC_Set_System_Date(input_command);
	}
	if (String_Compare(command_type, "sst", 0, 0, 3) == true)	//Установка системного времени
	{
		IC_Set_System_Time(input_command);
	}
	if (String_Compare(command_type, "set", 0, 0, 3) == true)	//Установка времени автоматического включения
	{
		IC_Set_Ch_Enable_Time(input_command);
	}
	if (String_Compare(command_type, "sae", 0, 0, 3) == true)	//Разрешения автоматического включения
	{
		IC_Set_Ch_Auto_Enable_State(input_command);
	}
	if (String_Compare(command_type, "sdt", 0, 0, 3) == true)	//Установка времени автоматического выключения
	{
		IC_Set_Ch_Disable_Time(input_command);
	}
	if (String_Compare(command_type, "sad", 0, 0, 3) == true)	//Разрешения автоматического выключения
	{
		IC_Set_Ch_Auto_Disable_State(input_command);
	}
	if (String_Compare(command_type, "scs", 0, 0, 3) == true)	//Включение или выключение канала вручную
	{
		IC_Set_Ch_State(input_command);		
	}
	if (String_Compare(command_type, "scc", 0, 0, 3) == true)	//Цикличность включения канала
	{
		IC_Set_Ch_Cycle(input_command);
	}
	if (String_Compare(command_type, "rsi", 0, 0, 3) == true)	//Запрос состояния системы
	{
		IC_Report_System_Info();
	}
	if (String_Compare(command_type, "lds", 0, 0, 3) == true)	//Сброс настроек на умолчание
	{
		IC_Load_Defaults();
	}
	if (String_Compare(command_type, "rcs", 0, 0, 3) == true)	//Запрос настроек канала
	{
		IC_Report_Ch_Settings(input_command);
	}
}	

//ОБРАБОТКА ПАКЕТОВ ОТ ВНУТРЕННИХ УСТРОЙСТВ


//===ПРЕРЫВАНИЯ===
ISR(USART_RX_vect)
{	
	char UART_symbol = UDR0;
	
	if (UART_user_control == true)
	{
		if (UART_symbol == UART_Stop_symbol)
		{
			UART_stop_symbol_detected = true;
			Input_command[IC_c]=String_end_symbol;
		}
		if(UART_start_symbol_detected == true && UART_stop_symbol_detected == false)
		{
			Input_command[IC_c]=UART_symbol;
			IC_c++;
		}
		if (UART_symbol == UART_Start_symbol)
		{
			UART_start_symbol_detected = true;
			UART_stop_symbol_detected = false;
			IC_c = 0;
		}
		if (UART_start_symbol_detected == true && UART_stop_symbol_detected == true)
		{
			Input_Command_Execute(Input_command);
			
			UART_start_symbol_detected = false;
			UART_stop_symbol_detected = false;
		}
		if (IC_c == Input_command_size)
		{
			IC_c = 0;
			UART_start_symbol_detected = false;
			UART_stop_symbol_detected = false;
		}
	}
	else
	{
		
	}		
			
}
ISR(TIMER1_OVF_vect)
{
	TCNT1 = 65536-31250;
	
	uint8_t I2C_reurn_device = I2C_last_device;
	bool I2C_return_write_mode = I2C_last_write_mode;

	I2C_Stop();
	
	RTC_Get_System_Date_Time();
	Output_Logick_Execute();
	
	I2C_Start();
	I2C_Send_Device_Address(I2C_reurn_device,I2C_return_write_mode);
}	
ISR(TWI_vect)
{
}

//===ОСНОВНАЯ ПРОГРАММА===
int main(void)
{
	//Инициализация
	TC1_Init();
	I2C_Init();
	UART_Init();
	LCD_Init();
	IO_Init();
	EEPROM_Init();

	//Если выполняется первый запуск
	LCD_Flash_First_Run_Message();
	
	//Чтение из EEPROM
	EEPROM_Read_Data();

	//Отображение приветствия на LCD
	LCD_Flash_Start_Message();
	
	sei();
	
	while (RTC_error == true)
	{
		LCD_Flash_RTC_Error_Message();
		cli();
	}			
	while (RTC_error != true)
	{
		//Отображение информации
		LCD_Show_Time();
		//Обновление цикла включения
		Cycle_Start_Day_Update(&Water_pump);
		
		if (LDS_command == true)
		{
			LCD_Flash_Reset_Message();
			Reset();
		}
		if (SSD_command == true)
		{
			RTC_Set_System_Date (&t_date);
			LCD_Flash_System_Date_Updated_Message();
			SSD_command = false;	
		}
		if (SST_command == true)
		{
			RTC_Set_System_Time (&t_time);
			LCD_Flash_System_Time_Updated_Message();
			SST_command = false;
		}	
		if (SET_command == true)
		{
			LCD_Flash_Ch_ET_Set_Message(t_channel);
			SET_command = false;
		}
		if (SDT_command == true)
		{
			LCD_Flash_Ch_DT_Set_Message(t_channel);
			SDT_command = false;
		}
		if (RCS_command == true)
		{
			LCD_Flash_Ch_Info_Message(t_channel);
			RCS_command = false;
		}
		if (SAE_command == true)
		{
			LCD_Flash_Ch_AE_Message(t_channel);
			SAE_command = false;
		}
		if (SAD_command == true)
		{
			LCD_Flash_Ch_AD_Message(t_channel);
			SAD_command = false;
		}
		if (SCS_command == true)
		{
			LCD_Flash_Ch_State_Message(t_channel);
			SCS_command = false;
		}
		if (SCC_command == true)
		{
			LCD_Flash_Ch_Cycle_Message(t_channel);
			SCC_command = false;
		}
		if (RSI_command == true)
		{	
			LCD_Flash_System_Info_Message();
			RSI_command = false;
		}
		if (WP_ON_command == true)
		{
			Water_Channel_Timer_ON(&Water_pump);
			WP_ON_command = false;
		}
	}
}
Добавлено after 56 minutes 7 seconds:
[uquote="Ярослав555",url="/forum/viewtopic.php?p=3234868#p3234868"]Но я ставлю на то что у Вас неверная работа с дисплеем/и2си.[/uquote]
Судя по отладке Вы правы, так как ложится только дисплей а шестеренки МК продолжают крутиться. осталось понять где я сворачиваю не туда
Реклама
Эиком - электронные компоненты и радиодетали
Мудрый кот
Сообщения: 1849
Зарегистрирован: Вс дек 25, 2016 08:34:54

Сообщение Dimon456 »

Блин одна и та же ошибка
Спойлер

Код: Выделить всё

uint8_t I2C_Read_Data_NACK(void)
{
   cli();
   uint8_t Result = 0;
   TWCR = (1<<TWINT)|(1<<TWEN);
   I2C_TWINT_Wait();
   Result = TWDR;
   return Result;
   sei();
}
Надо так
Спойлер

Код: Выделить всё

uint8_t I2C_Read_Data_NACK(void)
{
   cli();
   uint8_t Result = 0;
   TWCR &= (~(1<<(TWEA)));
   TWCR |= (1<<TWINT)|(1<<TWEN);
   I2C_TWINT_Wait();
   Result = TWDR;
   return Result;
   sei();
}
У вас NASK не формируется, а бит TWEA остается поднятым, смотрите в отладчике.
И еще при передаче байта не надо формировать NASK, передачу закончили командой СТОП.
Если вы формируете NASK при передаче
Спойлер

Код: Выделить всё

void I2C_Send_Data_NACK(uint8_t data)
{
   cli();
   TWDR = data;
   TWCR =(1<<TWINT)|(1<<TWEN);
   I2C_TWINT_Wait();
   sei();
}
то сбрасывайте бит TWEA
Спойлер

Код: Выделить всё

void I2C_Send_Data_NACK(uint8_t data)
{
   cli();
   TWDR = data;
   TWCR &= (~(1<<(TWEA)));
   TWCR |=(1<<TWINT)|(1<<TWEN);
   I2C_TWINT_Wait();
   sei();
}
И за чем это I2C_TWINT_Wait();, лишний void (void), вы этим не сэкономите, пишите нормально while(!(TWCR &(1<<TWINT))) { } , и еще вроде как цикл while () {} должен заканчиваться этим знаком ;
Жесть
Спойлер

Код: Выделить всё

   return Result;
   sei();
Реклама
Поставщик валерьянки для Кота
Сообщения: 2222
Зарегистрирован: Вт ноя 27, 2007 11:32:06
Откуда: Tashkent

Сообщение uk8amk »

Тут дело не в дисплее, а в размере сообщения выводимом на него,
И что? Сообщение(строка) состоит из символов и записывается в такой дисплей только по одной букве. Меж двух букв переключаемся на ту задачу какую надо.
Но не так варварски как это реализовано сейчас.

Какое я вижу решение.
Отказаться от почти всех delay_ms. Ну разве что за исключением задержек отправки команд ЖКИ, которые сильно работу прибора не тормозят с точки зрения пользователя.
Полностью отделить задачи выполнения логики от задач индикации и считывания времени.
Всё это реализовывается на конечных автоматах. Функции между собой общаются посредством передачи буферов и флагов. Но не тормозят работу системы, а возвращают управление автомату так скоро, как это станет возможным. К примеру через 100-200 мкс, а не через 500-1000мс как сейчас.

Чтоб сильно не ломать существующую программу можно написать логику обмена по I2C через прерывания. Там где вызывается слишком большой delay и нет обмена по I2C разрешать запросы таймера для обновления времени.
Реклама
Родился
Аватара пользователя
Сообщения: 15
Зарегистрирован: Чт ноя 16, 2017 17:04:14
Откуда: Сургут

Сообщение Angry Engineer »

ну delay в функциях вывода там для "красивого" выбегания букв. вашу идею понял, попробую реализовать
Родился
Аватара пользователя
Сообщения: 15
Зарегистрирован: Чт ноя 16, 2017 17:04:14
Откуда: Сургут

Сообщение Angry Engineer »

Разобрался. Если на шину подряд запихонить несколько стартов то получаем висяк.

Что сделал:
- запретил прерывания таймера во время выполнения атомарных функций TWI (чтение байта, запись байта, старт и стоп)
- прикрутил флаг выдачи старта в шину (после STA взводится постле STO снимается)
- в прерывании проверяю, если старт был то выдаю в шину стоп и опрашиваю RTC, если был стоп то просто опрашиваю RTC.
- если не было стопа то перед выходом из прерывания выдаю в шину старт и возвращаюсь к последнему использованному устройству если такое было

кстати мух от котлет тоже поделил. спасибо за советы
Ответить

Вернуться в «AVR»