ATmega328p - problem with TWI communication in timer interrupt

Go To Last Post
15 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello from Russia everyone.

 

The last time when i were writing code for MCU was in 2009 in university. But now i decided to remember this funny years. So, i have:

- Atmel Studio 6 (because i'm usin XP on my virtual PC)

- mega328p

- RTC DS1370

SH-HC-08 CC2541 Bluetooth 4.0 BLE to UART Transceiver (for communicating with smartphone)

- LCD 2*16 (it seems Hitachi) with PCF8574AT I2C expander

- IRL3705 transistors for my lamps and pump. 

 

What i need to do: i want on and off my stuff just in time and display all info on LCD.

 

So i put RTC communication in TC1 interrupt (every 0.5 s) and LCD routines in main cycle (some information shows on LCD about 10 seconds). When RTC and LCD routines were in main cycle all were fine (exept time accuracy), but when i put communication with RTC in TC1 overflow interrupt something went wrong - device is "hanging up" sometimes.

 

So here is full code, i will be wery appriciated if someone tell me where turned  on wrong way.

 

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

//БИБЛИОТЕКИ
#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>

//УСТРОЙСТВО И ПРОШИВКА
#define Device_type				{"G.E.C.K. - HFG"}
#define Firmware_version		{"FW: v2.2 RC"}

//КОНСТАНТЫ
#define UART_Start_symbol		'*'     //Старт символ пакета
#define UART_Separator_symbol	':'		//Cимвол-разделитель пакета
#define UART_Stop_symbol		'#'     //Стоп символ пакета
#define UART_buffer_size		255		//Буфер для служебного обмена данными с внутренними устройствами

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

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

//I2C АДРЕСА УСТРОЙСТВ

#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

//СТРУКТУРЫ
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];
				char Short_Name[3];
				uint8_t State;
				uint8_t *EEPROM_MWT_HH;
				uint8_t *EEPROM_MWT_MM;
				uint8_t *EEPROM_MWT_SS;

				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 Pump;
				uint8_t Force_Enable;} Channel;

//ЭНЕРГОНЕЗАВИСИМАЯ ПАМЯТЬ
uint8_t System_home_screen		EEMEM = 0;
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_MWT_HH		EEMEM = 0;
uint8_t White_light_MWT_MM		EEMEM = 0;
uint8_t White_light_MWT_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_MWT_HH		EEMEM = 0;
uint8_t Grow_light_MWT_MM		EEMEM = 0;
uint8_t Grow_light_MWT_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_MWT_HH		EEMEM = 0;
uint8_t Water_pump_MWT_MM		EEMEM = 0;
uint8_t Water_pump_MWT_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
Date t_date = {0,0,0};
Time t_time = {0,0,0};

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;

Date System_date = {0,0,0};                                         //Системная дата
bool SSD_command = false;

Channel White_light =	{"White light:",							//Холодный свет
						 "wl",
						 0,
						 &White_light_MWT_HH,
						 &White_light_MWT_MM,
						 &White_light_MWT_SS,

						 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:",								//Фитосвет
						 "gl",
						 0,
						 &Grow_light_MWT_HH,
						 &Grow_light_MWT_MM,
						 &Grow_light_MWT_SS,

						 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:",								//Насос
						 "wp",
						 0,
						 &Water_pump_MWT_HH,
						 &Water_pump_MWT_MM,
						 &Water_pump_MWT_SS,

						 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 SCW_command = false;

bool RSI_command = false;
bool WP_ON_command = false;

bool LDS_command = false;

bool Flash_time_string = true;

uint8_t I2C_last_device;
bool I2C_last_write_mode;
bool I2C_started = false;

uint8_t Home_screen = 0;

//===РАЗНОЕ===
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) != 0 && 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 TIME_to_STRING_for_UART(char *t_string, Time *time)
{
	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);

	int tsi = 0;

	//Время
	for (int hi=0;hi<strlen(Hours_string);hi++)
	{
		t_string[tsi] = Hours_string[hi];
		tsi++;
	}
	for (int mi=0;mi<strlen(Minutes_string);mi++)
	{
		t_string[tsi] = Minutes_string[mi];
		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;
}
void Channel_Manual_Work_Time_String(char *data_string, Channel *channel)
{
	int chsi = 0;

	char MWT_caption[] = {"MWT:    "};

	uint8_t *eeprom_MWT_HH = channel->EEPROM_MWT_HH;
	uint8_t *eeprom_MWT_MM = channel->EEPROM_MWT_MM;
	uint8_t *eeprom_MWT_SS = channel->EEPROM_MWT_SS;

	Time time = {0,0,0};

	time.HH = eeprom_read_byte(eeprom_MWT_HH);
	time.MM = eeprom_read_byte(eeprom_MWT_MM);
	time.SS = eeprom_read_byte(eeprom_MWT_SS);	

	char MWT_time[9];

	TIME_to_STRING(MWT_time, &time, 1);

	for (int i=0;i<strlen(MWT_caption);i++)
	{
		data_string[chsi] = MWT_caption[i];
		chsi++;
	}
	for (int i=0;i<strlen(MWT_time);i++)
	{
		data_string[chsi] = MWT_time[i];
		chsi++;
	}
	data_string[chsi]= String_end_symbol;
}

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

//===UART===
void UART_Send_Num(long data_num, int view)
{
	char data_string[255];
	itoa(data_num,data_string,view);

	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
}

void UART_Report_Device_Info(void)
{
	char device_and_firmware [255];
	char keyword[] = {"dfi"};

	uint8_t dfi = 0;

	device_and_firmware[dfi] = UART_Start_symbol;
	dfi++;

	for (uint8_t i=0; i<strlen(keyword); i++)
	{
		device_and_firmware[dfi] = keyword[i];
		dfi++;
	}

	device_and_firmware[dfi] = UART_Separator_symbol;
	dfi++;

	char dt[] = Device_type;

	for (uint8_t i=0; i<strlen(dt); i++)
	{
		device_and_firmware[dfi] = dt[i];
		dfi++;
	}
	device_and_firmware[dfi] = UART_Separator_symbol;
	dfi++;

	char fwv[] = Firmware_version;

	for (uint8_t i=0; i<strlen(fwv); i++)
	{
		device_and_firmware[dfi] = fwv[i];
		dfi++;
	}
	device_and_firmware[dfi] = UART_Stop_symbol;
	dfi++;
	device_and_firmware[dfi] = String_end_symbol;

	UART_Send_String(device_and_firmware);
	UART_Send_String("\n\r");

	UART_Send_String("*chc:wl:White light#");
	UART_Send_String("\n\r");
	UART_Send_String("*chc:gl:Grow light#");
	UART_Send_String("\n\r");
	UART_Send_String("*chc:wp:Water pump#");
	UART_Send_String("\n\r");
}
void UART_Report_CH_Status(Channel *channel)
{

	char UART_output[255];
	uint8_t uoi = 0;

	char pump_s[2];
	itoa(channel->Pump,pump_s,10);

	char state_s[2];
	itoa(channel->State,state_s,10);

	char force_enabled_s[2];
	itoa(channel->Force_Enable,force_enabled_s,10);

	uint8_t AE=0;
	uint8_t AD=0;

	Time AE_time = {0,0,0};
	Time AD_time = {0,0,0};
	Time MW_time = {0,0,0};

    Time E_time = {channel->Enable_Time.HH,channel->Enable_Time.MM,channel->Enable_Time.SS};
	Time D_time = {channel->Disable_Time.HH,channel->Disable_Time.MM,channel->Disable_Time.SS};

	uint8_t *eeprom_AD = channel->EEPROM_AD;
	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;

	AD = eeprom_read_byte(eeprom_AD);
	AD_time.HH = eeprom_read_byte(eeprom_DT_HH);
	AD_time.MM = eeprom_read_byte(eeprom_DT_MM);
	AD_time.SS = eeprom_read_byte(eeprom_DT_SS);

	uint8_t *eeprom_AE = channel->EEPROM_AE;
	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;

	AE = eeprom_read_byte(eeprom_AE);
	AE_time.HH = eeprom_read_byte(eeprom_ET_HH);
	AE_time.MM = eeprom_read_byte(eeprom_ET_MM);
	AE_time.SS = eeprom_read_byte(eeprom_ET_SS);

	uint8_t *eeprom_MWT_HH = channel->EEPROM_MWT_HH;
	uint8_t *eeprom_MWT_MM = channel->EEPROM_MWT_MM;
	uint8_t *eeprom_MWT_SS = channel->EEPROM_MWT_SS;

	MW_time.HH = eeprom_read_byte(eeprom_MWT_HH);
	MW_time.MM = eeprom_read_byte(eeprom_MWT_MM);
	MW_time.SS = eeprom_read_byte(eeprom_MWT_SS);

	char AE_s[2];
	char AD_s[2];

	char AE_time_s[9];
	char AD_time_s[9];
	char MW_time_s[9];

	char E_time_s[9];
	char D_time_s[9];

	itoa(AE,AE_s,10);
	itoa(AD,AD_s,10);

	TIME_to_STRING_for_UART(AE_time_s,&AE_time);
	TIME_to_STRING_for_UART(AD_time_s,&AD_time);
	TIME_to_STRING_for_UART(MW_time_s,&MW_time);

	TIME_to_STRING_for_UART(E_time_s,&E_time);
	TIME_to_STRING_for_UART(D_time_s,&D_time);

	//Формирование посылки

	//Старт символ
	UART_output[uoi] = UART_Start_symbol;
	uoi++;
	//Краткое имя
	for (uint8_t i=0; i<strlen(channel->Short_Name); i++)
	{
		UART_output[uoi] = channel->Short_Name[i];
		uoi++;
	}
	UART_output[uoi] = UART_Separator_symbol;
	uoi++;
	//Признак канала управления жидкостью
	for (uint8_t i=0; i<strlen(pump_s); i++)
	{
		UART_output[uoi] = pump_s[i];
		uoi++;
	}
	UART_output[uoi] = UART_Separator_symbol;
	uoi++;
	//Состояние
	for (uint8_t i=0; i<strlen(state_s); i++)
	{
		UART_output[uoi] = state_s[i];
		uoi++;
	}
	UART_output[uoi] = UART_Separator_symbol;
	uoi++;
	//Признак принудительного включения
	for (uint8_t i=0; i<strlen(force_enabled_s); i++)
	{
		UART_output[uoi] = force_enabled_s[i];
		uoi++;
	}
	UART_output[uoi] = UART_Separator_symbol;
	uoi++;
	//Время включения
	for (uint8_t i=0; i<strlen(E_time_s); i++)
	{
		UART_output[uoi] = E_time_s[i];
		uoi++;
	}
	UART_output[uoi] = UART_Separator_symbol;
	uoi++;
	//Время выключения
	for (uint8_t i=0; i<strlen(D_time_s); i++)
	{
		UART_output[uoi] = D_time_s[i];
		uoi++;
	}
	UART_output[uoi] = UART_Separator_symbol;
	uoi++;
	//Время принудительной работы
	for (uint8_t i=0; i<strlen(MW_time_s); i++)
	{
		UART_output[uoi] = MW_time_s[i];
		uoi++;
	}
	UART_output[uoi] = UART_Separator_symbol;
	uoi++;
	//Авто включение
	for (uint8_t i=0; i<strlen(AE_s); i++)
	{
		UART_output[uoi] = AE_s[i];
		uoi++;
	}
	UART_output[uoi] = UART_Separator_symbol;
	uoi++;
	//Время авто включения
	for (uint8_t i=0; i<strlen(AE_time_s); i++)
	{
		UART_output[uoi] = AE_time_s[i];
		uoi++;
	}
	UART_output[uoi] = UART_Separator_symbol;
	uoi++;
	//Авто выключение
	for (uint8_t i=0; i<strlen(AD_s); i++)
	{
		UART_output[uoi] = AD_s[i];
		uoi++;
	}
	UART_output[uoi] = UART_Separator_symbol;
	uoi++;
	//Время авто включения
	for (uint8_t i=0; i<strlen(AD_time_s); i++)
	{
		UART_output[uoi] = AD_time_s[i];
		uoi++;
	}
	UART_output[uoi] = UART_Stop_symbol;
	uoi++;
	UART_output[uoi] = String_end_symbol;

	UART_Send_String(UART_output);
	UART_Send_String("\n\r");
}

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

//===I2C====
void I2C_Init(void)
{
	TWSR = 0;
	TWBR = ((F_CPU/F_SCL)-16)/2;
	TWCR =(1<<TWIE)|(1<<TWEN);
}
void I2C_Start(void)
{
	TC1_Interrupt_DISABLE();
	_delay_us(5);
	TWCR =(1<<TWINT)|(1<<TWEN)|(1<<TWSTA);
	I2C_started = true;
	while(!(TWCR &(1<<TWINT)))
	{
	}
	TC1_Interrupt_ENABLE();
}
void I2C_Stop(void)
{
	TC1_Interrupt_DISABLE();
	TWCR =(1<<TWINT)|(1<<TWEN)|(1<<TWSTO);
	I2C_started = false;
	TC1_Interrupt_ENABLE();
}
void I2C_Send_Device_Address(uint8_t dev_address, bool write)
{
	TC1_Interrupt_DISABLE();
	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)|(1<<TWEA);
	while(!(TWCR &(1<<TWINT)))
	{
	}
	TC1_Interrupt_ENABLE();
}
void I2C_Send_Register_Address(uint8_t reg_address)
{
	TC1_Interrupt_DISABLE();
	TWDR = reg_address;
	TWCR =(1<<TWINT)|(1<<TWEN)|(1<<TWEA);
	while(!(TWCR &(1<<TWINT)))
	{
	}
	TC1_Interrupt_ENABLE();
}
void I2C_Send_Data_ACK(uint8_t data)
{
	TC1_Interrupt_DISABLE();
	TWDR = data;
	TWCR =(1<<TWINT)|(1<<TWEN)|(1<<TWEA);
	while(!(TWCR &(1<<TWINT)))
	{
	}
	TC1_Interrupt_ENABLE();
}
void I2C_Send_Data_NACK(uint8_t data)
{
	TC1_Interrupt_DISABLE();
	TWDR = data;
	TWCR =(1<<TWINT)|(1<<TWEN)|(0<<TWEA);
	while(!(TWCR &(1<<TWINT)))
	{
	}
	TC1_Interrupt_ENABLE();
}
uint8_t I2C_Read_Data_ACK(void)
{
	TC1_Interrupt_DISABLE();
	uint8_t Result = 0;
	TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWEA);
	while(!(TWCR &(1<<TWINT)))
	{
	}
	Result = TWDR;
	return Result;
	TC1_Interrupt_ENABLE();
}
uint8_t I2C_Read_Data_NACK(void)
{
	TC1_Interrupt_DISABLE();
	uint8_t Result = 0;
	TWCR =(1<<TWINT)|(1<<TWEN)|(0<<TWEA);
	while(!(TWCR &(1<<TWINT)))
	{
	}
	Result = TWDR;
	return Result;
	TC1_Interrupt_ENABLE();
}

bool I2C_Check_Device(uint8_t dev_address)
{
	bool Result = false;
	I2C_Start();
	TWDR = dev_address;
	TWCR = (1<<TWINT)|(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 bus devices: ");

	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 == true)
	{
		IO_Emergency_OFF();
		Reset();
	}

	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();
}

//EEPROM
void Load_Default_Settings(bool force_load = false)
{
	if (eeprom_read_byte(&System_first_run) != 0 || force_load == true)
	{
		//Белый свет
		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_MWT_HH, 0);
		eeprom_write_byte(&White_light_MWT_MM, 0);
		eeprom_write_byte(&White_light_MWT_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_MWT_HH, 0);
		eeprom_write_byte(&Grow_light_MWT_MM, 0);
		eeprom_write_byte(&Grow_light_MWT_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_MWT_HH, 0);
		eeprom_write_byte(&Water_pump_MWT_MM, 0);
		eeprom_write_byte(&Water_pump_MWT_SS, 30);

		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(&Water_pump_CYCLE, 0);
		eeprom_write_byte(&Water_pump_CSD, 1);

		//Рабочий стол
		eeprom_write_byte(&System_home_screen, 0);

		//Флаг первого запуска
		eeprom_write_byte(&System_first_run, 0);

		//Часы
		I2C_Start();
		I2C_Send_Device_Address(RTC_module, 1);
		I2C_Send_Register_Address(0x00);
		I2C_Send_Data_ACK(0);
		I2C_Send_Data_ACK(0);
		I2C_Send_Data_NACK(0);
		I2C_Stop();

		//Дата
		I2C_Start();
		I2C_Send_Device_Address(RTC_module, 1);
		I2C_Send_Register_Address(0x04);
		I2C_Send_Data_ACK(INT_to_BCD(1));
		I2C_Send_Data_ACK(INT_to_BCD(1));
		I2C_Send_Data_NACK(INT_to_BCD(0));
		I2C_Stop();
	}
}
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);

	Home_screen = eeprom_read_byte(&System_home_screen);
}

//===LCD===
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 | 0<<LCD_E;
	I2C_Send_Data_ACK(LCD_input_buffer);
	_delay_us(40);
	LCD_input_buffer = data_H | BL<<LCD_BL| RS<<LCD_RS| RW<<LCD_RW | 1<<LCD_E;
	I2C_Send_Data_ACK(LCD_input_buffer);
	_delay_us(40);
	LCD_input_buffer = data_H | BL<<LCD_BL| RS<<LCD_RS| RW<<LCD_RW| 0<<LCD_E;
	I2C_Send_Data_ACK(LCD_input_buffer);
	_delay_us(40);

	LCD_input_buffer = data_L | BL<<LCD_BL| RS<<LCD_RS| RW<<LCD_RW | 0<<LCD_E;
	I2C_Send_Data_ACK(LCD_input_buffer);
	_delay_us(40);
	LCD_input_buffer = data_L | BL<<LCD_BL| RS<<LCD_RS| RW<<LCD_RW | 1<<LCD_E;
	I2C_Send_Data_ACK(LCD_input_buffer);
	_delay_us(40);
	LCD_input_buffer = data_L | BL<<LCD_BL| RS<<LCD_RS| RW<<LCD_RW | 0<<LCD_E;
	I2C_Send_Data_ACK(LCD_input_buffer);
	_delay_us(40);
}
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_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)
{
	LCD_Send_Command(symbol,1,1,0);
}

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_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_Show_String(char *data_string, int8_t num)
{
	int delay = 500;
	I2C_Start();
	I2C_Send_Device_Address(LCD_module,1);
	LCD_Command_Send_String(data_string, num);
	I2C_Stop();
}

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_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("started", 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 MWT_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->Pump == 1)
	{
		Water_Channel_Enable_String(Enable_Data, channel);
		Water_Channel_Disable_String(Disable_Data, channel);
		Channel_Manual_Work_Time_String(MWT_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->Pump == 1)
	{
		LCD_Command_Clear_String_With_Delay(1);
		LCD_Command_Send_String_With_Delay(Cycle_Data, 1);
		_delay_ms(delay);
		LCD_Command_Clear_String_With_Delay(1);
		LCD_Command_Send_String_With_Delay(MWT_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->Pump == 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->Pump == 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_CH_MWT_Message(Channel *channel)
{
	int delay = 500;

	char MWT_Data[17];

	Channel_Manual_Work_Time_String(MWT_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(MWT_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_Date_Time(void)
{
	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_Time(void)
{
	char Time_Caption[] = {"System time:"};
	char Time_Data[17];

	TIME_to_STRING(Time_Data, &System_time, 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(Time_Caption, 0);
		LCD_Command_Send_String_With_Delay(Time_Data, 1);
		Flash_time_string = false;
	}
	else
	{
		LCD_Command_Send_String(Time_Caption, 0);
		LCD_Command_Send_String(Time_Data, 1);
	}
}
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(Channel *channel)
{
	char timer_caption [] = {"Time:   "};
	char timer_time [9];
	char timer[17]; 

	long interval_s = 0;
	long start = 3600*channel->Enable_Time.HH+60*channel->Enable_Time.MM+channel->Enable_Time.SS;
	long stop = 3600*channel->Disable_Time.HH+60*channel->Disable_Time.MM+channel->Disable_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 && channel->State == 1)
	{
		long HH = interval_s/3600;
		long MM = (interval_s - HH*3600)/60;
		long 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(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;
		}
	}
	LCD_Command_Clear_String(1);
	LCD_Command_Send_String_With_Delay("Finished", 1);
	_delay_ms(500);
	I2C_Stop();
}
void LCD_Show_RTC_Error_Message(void)
{
	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);

	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 Screen_GET(uint8_t *screen, char *input_command)
{
	char screen_ch[2];
	screen_ch[0]= input_command[3];
	screen_ch[1]= String_end_symbol;

	(*screen)=atoi(screen_ch);
}
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 Outputs_SET(void)
{
	PORTD = White_light.State<<PORTD5|Grow_light.State<<PORTD6| Water_pump.State<<PORTD7;
}
void Channel_ENABLE(Channel *channel, bool force_enable = false)
{
	channel->State = 1;
	if (force_enable == true)
	{
		channel->Force_Enable = 1;

		if (channel->Pump == 1)
		{
			Time work_time = {0,0,0};

			uint8_t *eeprom_MWT_HH = channel->EEPROM_MWT_HH;
			uint8_t *eeprom_MWT_MM = channel->EEPROM_MWT_MM;
			uint8_t *eeprom_MWT_SS = channel->EEPROM_MWT_SS;

			work_time.HH = eeprom_read_byte(eeprom_MWT_HH);
			work_time.MM = eeprom_read_byte(eeprom_MWT_MM);
			work_time.SS = eeprom_read_byte(eeprom_MWT_SS);

			Time disable_time = {System_time.HH,System_time.MM,System_time.SS};
			Time_Add(&disable_time, &work_time);

			channel->Auto_Disable = 1;
			channel->Disable_Time.HH = disable_time.HH;
			channel->Disable_Time.MM = disable_time.MM;
			channel->Disable_Time.SS = disable_time.SS;
		}

		channel->Enable_Time.HH = System_time.HH;
		channel->Enable_Time.MM = System_time.MM;
		channel->Enable_Time.SS = System_time.SS;
	}
}
void Channel_DISABLE(Channel *channel, bool force_disable = false)
{
	channel->State = 0;
	channel->Force_Enable = 0;

	uint8_t *eeprom_AD = channel->EEPROM_AD;
	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;

	channel->Auto_Disable = eeprom_read_byte(eeprom_AD);
	channel->Disable_Time.HH = eeprom_read_byte(eeprom_DT_HH);
	channel->Disable_Time.MM = eeprom_read_byte(eeprom_DT_MM);
	channel->Disable_Time.SS = eeprom_read_byte(eeprom_DT_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;

	channel->Enable_Time.HH = eeprom_read_byte(eeprom_ET_HH);
	channel->Enable_Time.MM = eeprom_read_byte(eeprom_ET_MM);
	channel->Enable_Time.SS = eeprom_read_byte(eeprom_ET_SS);
}
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));
	UART_Report_CH_Status(channel);
}
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));
	UART_Report_CH_Status(channel);
}
void Channel_Enable_Time_SET(Channel *channel, Time *time)
{
	channel->Enable_Time.HH = time->HH;
	channel->Enable_Time.MM = time->MM;

	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);

	if (channel->Pump == 1)
	{
		channel->Enable_Time.SS = time->SS;
		eeprom_write_byte(eeprom_ET_SS, time->SS);
	}
	else
	{
		channel->Enable_Time.SS = 0;
		eeprom_write_byte(eeprom_ET_SS, 0);
	}
	UART_Report_CH_Status(channel);
}
void Channel_Disable_Time_SET(Channel *channel, Time *time)
{
	channel->Disable_Time.HH = time->HH;
	channel->Disable_Time.MM = time->MM;

	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);

	if (channel->Pump == 1)
	{
		channel->Disable_Time.SS = time->SS;
		eeprom_write_byte(eeprom_DT_SS, time->SS);
	}
	else
	{
		channel->Disable_Time.SS = 0;
		eeprom_write_byte(eeprom_DT_SS, 0);
	}

	UART_Report_CH_Status(channel);
}
void Channel_State_SET(Channel *channel, uint8_t *state)
{
	if ((*state) == 0)
	{
		Channel_DISABLE(channel, true);
	}
	else
	{
		Channel_ENABLE(channel, true);

		if (channel->Pump)
		{
			WP_ON_command = true;
		}
	}
	Outputs_SET();
	UART_Report_CH_Status(channel);
}
void Channel_Manual_Work_Time_SET(Channel *channel, Time *time)
{
	uint8_t *eeprom_MWT_HH = channel->EEPROM_MWT_HH;
	uint8_t *eeprom_MWT_MM = channel->EEPROM_MWT_MM;
	uint8_t *eeprom_MWT_SS = channel->EEPROM_MWT_SS;

	eeprom_write_byte(eeprom_MWT_HH, time->HH);
	eeprom_write_byte(eeprom_MWT_MM, time->MM);
	eeprom_write_byte(eeprom_MWT_SS, time->SS);

	UART_Report_CH_Status(channel);
}
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));

	UART_Report_CH_Status(channel);
}
void Channel_Cycle_Update(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 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);
			}
		}
	}
}
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;
				}
			}
		}
	}
	if (channel->Disable_Time.HH == System_time.HH)
	{
		if (channel->Disable_Time.MM == System_time.MM)
		{
			if (channel->Disable_Time.SS == System_time.SS)
			{
				Channel_DISABLE(channel);
			}
		}
	}
}
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_Update(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);

	Outputs_SET();
}

//ВЫПОЛНЕНИЕ ПОЛЬЗОВАТЕЛЬСКИХ КОММАНД
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)
	{
		Channel_State_SET(&White_light, &state);
		t_channel = &White_light;
	}
	if (String_Compare(channel_type, "gl", 0, 0, 2) == true)
	{
		Channel_State_SET(&Grow_light, &state);
		t_channel = &Grow_light;
	}
	if (String_Compare(channel_type, "wp", 0, 0, 2) == true)
	{
		Channel_State_SET(&Water_pump, &state);
		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_Set_CH_Manual_Work_Time(char *input_command)
{
	char channel_type[2];
	Channel_GET(channel_type, input_command);
	Time time = {0,0,0};
	Time_GET(&time, input_command);

	if (3600*time.HH+60*time.MM+time.SS < 5)
	{
		time.HH=0;
		time.MM=0;
		time.SS=5;
	}

	SCW_command =true;

	if (String_Compare(channel_type, "wp", 0, 0, 2) == true)
	{
		Channel_Manual_Work_Time_SET(&Water_pump, &time);
		t_channel = &Water_pump;
	}
}
void IC_Load_Defaults(void)
{
	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;
		UART_Report_CH_Status(&White_light);
	}
	if (String_Compare(channel_type, "gl", 0, 0, 2) == true)
	{
		t_channel = &Grow_light;
		UART_Report_CH_Status(&Grow_light);
	}
	if (String_Compare(channel_type, "wp", 0, 0, 2) == true)
	{
		t_channel = &Water_pump;
		UART_Report_CH_Status(&Water_pump);
	}
}
void IC_Report_Device_Info(void)
{
		UART_Report_Device_Info();
		RSI_command = true;
}
void IC_Set_System_Home_screen(char *input_command)
{
	Flash_time_string = true;

	uint8_t screen_type;
	Screen_GET(&screen_type, input_command);
	eeprom_write_byte(&System_home_screen, screen_type);
	Home_screen = screen_type;
}
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, "scw", 0, 0, 3) == true)	//Цикличность включения канала
	{
		IC_Set_CH_Manual_Work_Time(input_command);
	}
	if (String_Compare(command_type, "rsi", 0, 0, 3) == true)	//Запрос состояния системы
	{
		IC_Report_Device_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);
	}
	if (String_Compare(command_type, "shs", 0, 0, 3) == true)	//Изменение домашнего экрана
	{
		IC_Set_System_Home_screen(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_return_device = I2C_last_device;
	bool I2C_return_write_mode = I2C_last_write_mode;

	if (I2C_started == true)
	{
		I2C_Stop();
	}

	RTC_Get_System_Date_Time();
	Output_Logick_Execute();

	I2C_Start();
	I2C_Send_Device_Address(I2C_return_device,I2C_return_write_mode);
}	

//===ОСНОВНАЯ ПРОГРАММА===
int main(void)
{

	//Инициализация
	TC1_Init();
	I2C_Init();
	UART_Init();
	LCD_Init();
	IO_Init();

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

	//Отображение приветствия на LCD
	LCD_Flash_Start_Message();

	//Чтение из EEPROM
	EEPROM_Read_Data();
	sei();

	while (RTC_error == true)
	{
		cli();
		LCD_Show_RTC_Error_Message();
	}
	while (RTC_error == false)
	{
		//Отображение информации
		switch (Home_screen)
		{
			case 0:
			LCD_Show_Time();
			break;

			case 1:
			LCD_Show_Date_Time();
			break;
		}

		Cycle_Start_Day_Update(&Water_pump);

		if (LDS_command == true)
		{
			cli();
			Load_Default_Settings(true);
			LCD_Flash_Reset_Message();
			Reset();
		}
		if (SSD_command == true)
		{
			cli();
			RTC_Set_System_Date (&t_date);
			LCD_Flash_System_Date_Updated_Message();
			SSD_command = false;
			sei();
		}
		if (SST_command == true)
		{
			cli();
			RTC_Set_System_Time (&t_time);
			LCD_Flash_System_Time_Updated_Message();
			SST_command = false;
			sei();
		}
		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 (SCW_command == true)
		{
			LCD_Flash_CH_MWT_Message(t_channel);
			SCW_command = false;
		}
		if (RSI_command == true)
		{
			LCD_Flash_System_Info_Message();
			RSI_command = false;
		}
		if (WP_ON_command == true)
		{
			LCD_Show_Watering_Message();
			LCD_Show_Timer(&Water_pump);
			WP_ON_command = false;
		}
	}
}

 

Last Edited: Tue. Nov 21, 2017 - 05:03 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Angry Engineer wrote:
when i put communication with RTC in TC1 overflow interrupt something went wrong

So don't do that, then!

 

TWI comms is (relatively) slow - and you don't want to be doing slow stuff in your interrupt handlers.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

i know that it's slow, but i need clock, and i'm not building colider. i,m just need hh.mm.ss info

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Welcome to AVR Freaks!

 

It does not matter if you only need hh.mm.ss. Good practice is to spend as few machine cycles as you can get away with in an interrupt service routine.

 

The standard procedure is to test something (maybe some status bits) or read a register (UART UDR is a good example), set a flag, and get out. Test for that flag in your main loop and act on it there. 

 

You will probably ask - But Why? It seems perfectly logical and setting a flag just takes more memory! The top reason is that, for an AVR, interrupts are blocking (unless you do something "special") - that is, no other interrupt will be recognized as long as some ISR is running. This is the automatic procedure for AVR (Mega and Tiny, not so for XMega). 

 

Second reason is that, even if you make your ISR interruptible, you then have to structure your ISR code so that it will survive being interrupted. 

 

As a result, many of us have learned to structure our main loops into a series of "tasks" for which the execution depends on one or more "flags" or status conditions. Personally, I find that structure more maintainable, easier to debug, and more flexible. For example, I have a data logger that takes samples (measurements) - that is one task. Another is to mathematically process those samples (multiple samples are combined into running averages). Yet another is to format the results into text (strings). Following that is the task to write those strings to removable memory. It was very easy to change this latter task so that the output could be directed either to the memory or to the serial port and none of the rest of the code was touched. Sure, you could do all this in the traditional way, but I find this arrangement MUCH easier to manage.

 

Cheers

Jim

Jim Wagner Oregon Research Electronics, Consulting Div. Tangent, OR, USA http://www.orelectronics.net

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Angry Engineer wrote:
 i'm not building colider.

So what?

 

You have demonstrated that it breaks your code - so just don't do it!

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

A common concept seems to be that if you are not doing something "serious" ( like a colider (sic) ), its not important to be careful about how your program is organized. This reminds me of an old comedy routine that goes  something like this:

 

Patient: But Doctor, when I do this, it hurts!

Doctor: Well, if it hurts, don't do it!

 

That applies to programming, also. 

 

<Warning - philosophical tangent ahead>

 

Here, one might ask one's self what programming really is. At its core, it is figuring out how to use the resources of a given device, whether it be an absolutely minimal tiny micro or a super computer, to achieve some goal. You have to work with the resources that are built into that device because you cannot, generally, create new resources. If that device cannot add two smallest-unit binary quantities, then you either figure out how, or you figure out a different way to do it. Those are your choices. THAT is where creativity comes in. Sort of like the carpenter. Carpenter has saws, hammers, chisels, and such. The carpenter uses those tools, in creative ways when necessary, to make something new. Programmers are no different, except that a carpenter can go to the hardware store for a curly-shaped chisel but a programmer cannot go  to the hardware store for an "interrupt service fixer". A programmer CAN seek help from others about alternate solutions that he or she might not have thought about. But, in the end, it is still all about using the available resources creatively to achieve a goal. Along the way, if you find that your idea does not work the way you planned, then its time to try something different.

 

</Warning>

 

Jim

Jim Wagner Oregon Research Electronics, Consulting Div. Tangent, OR, USA http://www.orelectronics.net

Last Edited: Tue. Nov 21, 2017 - 07:39 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

i agree with you about structures. but information about time for me is on first place (i cant wait when the 15 second report on lcd will ends), the second place is channels tasks. you can't turn on water pump at 02.00.00 for 50 seconds without information what time is now. or if RTC will die i need to know it immidiately and stop watering my wifes flowers , or i will have problems with neighbors a floor below. hope you understand what i'm talking about

Last Edited: Tue. Nov 21, 2017 - 07:21 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

HAve you thought of the arduino structure (eats a timer inerrupt, the interrupt counting elapsed milliseconds since your processor was turned on).

The task of getting seconds from an accurate RTC could be activated "only" every 100 milliseconds -I bet this is overkill, even for plant watering- and stays in the main thread, which can poll for excess of water....

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

i'm just a little don't understand how without using interrupt in my case to tell to the device "stop all and tel me what time is now and check may be it's watering time?"

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

you think that calculations with time since procesdor was turned on is better and easyer then check rtc twice in second? i thought it's not, but may be i was wrong

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Angry Engineer wrote:
i'm just a little don't understand how without using interrupt in my case to tell to the device "stop all and tel me what time is now and check may be it's watering time?"

 

There is a really good tutorial (tutorial forum) on multi-tasking, you may find helpful.

 

Jim

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I would argue that for a task like that, you need no more than about 0.1 second "resolution". That is, if you know from your clock that water is needed now, there is nothing lost if it  takes 100ms to turn that water on. 

 

I might point out that the main part of your code IS organized as I suggested. It appears to be, pretty much, a finite state machine. That's good. The problem is reading the RTC in your timer overflow ISR. That takes way too many clock cycles. You will probably also have problems with interaction between serial and TWI. And, you also have some longer code in your serial rx service routine; that could well cause problems with a delayed timer overflow service.

 

So, for both cases, I would suggest moving that code out of the ISRs. Yes, it will require some reorganization of your code. But, that is what happens when you run into a roadblock.

 

Jim

Jim Wagner Oregon Research Electronics, Consulting Div. Tangent, OR, USA http://www.orelectronics.net

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Your timer overflow interrupt should do nothing except inform (through a volatile global shared variable) that xxx time elapsed since processor started/ RTC clock was read. Your RTC clock has a 1 second granularity: you should look at it say, every 100 ms (but timer interrupt can be 1 ms granularity, if you want).

 

Each time you consult the RTC :

you copy the number of milliseconds (say)  elapsed; this copy (typ 4 bytes) should not be interrupted.

You add the time slice you feel necessary (time between RTC information updates).

 

When you do not consult the RTC :

you do other tasks (which are fairly quick, I hope)

you look at the number of milliseconds (should have called them "ticks") and, if it is greater (or equal, of course) than the time to look at the RTC.... you look at it.

 

BTW : each time main thread consults number of ticks (32 bits : if an interruot occurs and messes bytes, that would be ugly) , the copy should be made non interruptible...

 

Edited A drawback of this stucture is that "tasks" C functions called from the main() thread should be rather short; delays of 1 or 2 milliseconds can be tolerated; delays of 500 milliseconds are much more complicated... if they are ysed to flash a LED/light, maybe they can be rewritten by giving for each LED to be flashed a tick counter, and comparing number of overflows  with time scheduled to change LED's state....

 

 

Last Edited: Tue. Nov 21, 2017 - 08:49 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

thanks a lot to all of you. today i'll think about how to overwrite this

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The very basics of the multitasking approach is ti divide your program into separate "tasks". Your main() function then services these tasks (i.e. calls functions) in some order and priority determined by you. The main() function is essentially a loop calling the functions that constitute your different tasks.

 

In addition to this the ISRs will run when an interrupt event occurs. As said above, keep the ISRs short. Grab any important data (e.g. incoming data on a communications interface like an UART) and have a global variable act as a flag that is set so as to mark that this event has happened.

 

Now you can have your tasks execute conditionally in the main loop. E.g. if the flag for an incoming character on the UART has been set you call a function to deal with this, and then you clear the flag (so that you are ready for another incoming character).

 

If an other interrupt event should occur while running the "incoming char" task then that is no problem. Interrupts are not disabled so that  ISR will run, grab important data, set a flag and exit. The next time around the pool in main() the program will find this flag set and run the task for it.

 

This is the absolute basics. For systems where events come in quick bursts it might be needed to have queues of events waiting to be dealt with, bu this is not likely in a system that switches things like lamps and pumps on and off.

 

For a detailed treatise with example code, go read the tutorial that was pointed out in post above.

 

Finally:

 

1) Don't  be angry - it's not a good state of mind for learning to develop software.

2) Welcome to AVRfreaks!

Happy 75th anniversary to one of the best movies ever made! Rick Blane [Bogart]: "Of all the gin joints, in all the towns, in all the world, she walks into mine."

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]