Форум РадиоКот • Просмотр темы - Atmega328p работа с TWI в прерываниях (AtmelStudio 6)
Сообщения без ответов | Активные темы
Страница 1 из 1
[ Сообщений: 8 ]
Автор
Сообщение
Angry Engineer
Заголовок сообщения: Atmega328p работа с TWI в прерываниях (AtmelStudio 6)
Добавлено: Чт ноя 16, 2017 18:42:17
Родился
Зарегистрирован: Чт ноя 16, 2017 17:04:14Сообщений: 15Откуда: Сургут
Рейтинг сообщения: 0
День добрый, ваяю тут жестянку которая будет в строго определенное время и по требованию (по 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(); }
работает до зависания чуть дольше
Вернуться наверх
Реклама
uk8amk
Заголовок сообщения: Re: Atmega328p работа с TWI в прерываниях (AtmelStudio 6)
Добавлено: Чт ноя 16, 2017 22:02:55
Поставщик валерьянки для Кота
Карма: 16
Рейтинг сообщений: 329
Зарегистрирован: Вт ноя 27, 2007 11:32:06Сообщений: 2222Откуда: Tashkent
Рейтинг сообщения: 0
Цитата:
но вот некоторые сообщения выводятся на LCD порядка 10 секунд и есть шанс профукать момент включения/выключения нагрузки.
Это чтож за LCD такой, в который слать картинку 10 сек надо?
Цитата:
подскажите в какую сторону копать?
В сторону отделения мух от котлет.
Либо вы делаете опрос программный, либо через автомат по прерываниям. Всё остальное - хороший способ запутаться самому и запутать нас.
Очерёдность посылок между устройствами должна разруливаться самой программой, а не обрывом передачи и приведения интерфейса в непонятное состояние.
Контроль состояния производится посредством анализа кодов статусного регистра TWSR.
Впрочем возможно организовать ещё один I2C канал с помощью программного ногодрыга. Если конечно лапки свободные есть.
Еще когда существует вероятность зависания периферийных микросхем заводят дополнительный таймер(можно виртуальный) и по таймауту вызывается подпрограмма, которая должна что-то там пнуть или иное сделать.
Вернуться наверх
Реклама
Ярослав555
Заголовок сообщения: Re: Atmega328p работа с TWI в прерываниях (AtmelStudio 6)
Добавлено: Чт ноя 16, 2017 22:34:35
Поставщик валерьянки для Кота
Карма: 20
Рейтинг сообщений: 648
Зарегистрирован: Пт май 31, 2013 17:14:38Сообщений: 2081Откуда: Украина, Винница
Рейтинг сообщения: 0
пару месяцев назад на работе была задача переписать глючную прошивку под один ведомый МК. Я не нашел ничего лучше как скопипастить автомат от DiHalt`a, ну а для мастера заюзал атмеловкий аппноут (потому что мастером Хмега). Ну это всё мелочи в данном случае. Объясните что это за LCD такой, сообщения на который выводятся 10 секунд? Модель, контроллер можно в студию? Ну а если там действительно 10 сек и никуда не деться, то рекомендую Вам поступить следующим образом: конфигурируете внутренний таймер МК на отсчет времени, скажем секунд 60. Вычитываете свои часы, видите что включать надо через 3 секунды, ставите свой таймер на 3 секунды и идете пулять свой и2с в дисплей. Через 3 секунды включаете/выключаете нагрузку. Только Вам надо будет при входе в прерывание и2си включать глобальное разрешение прерываний, чтобы не профукать свой таймер. Но я ставлю на то что у Вас неверная работа с дисплеем/и2си.
Вернуться наверх
Реклама
Angry Engineer
Заголовок сообщения: Re: Atmega328p работа с TWI в прерываниях (AtmelStudio 6)
Добавлено: Пт ноя 17, 2017 00:29:33
Родился
Зарегистрирован: Чт ноя 16, 2017 17:04:14Сообщений: 15Откуда: Сургут
Рейтинг сообщения: 0
Тут дело не в дисплее, а в размере сообщения выводимом на него, дисплей самый обычный 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: Но я ставлю на то что у Вас неверная работа с дисплеем/и2си.
Судя по отладке Вы правы, так как ложится только дисплей а шестеренки МК продолжают крутиться. осталось понять где я сворачиваю не туда
Вернуться наверх
Реклама
Выбираем схему BMS для заряда литий-железофосфатных (LiFePO4) аккумуляторов
Обязательным условием долгой и стабильной работы Li-FePO4-аккумуляторов, в том числе и производства EVE Energy, является применение специализированных BMS-микросхем. Литий-железофосфатные АКБ отличаются такими характеристиками, как высокая многократность циклов заряда-разряда, безопасность, возможность быстрой зарядки, устойчивость к буферному режиму работы и приемлемая стоимость. Но для этих АКБ очень важен контроль процесса заряда и разряда для избегания воздействия внешнего зарядного напряжения после достижения 100% заряда. Инженеры КОМПЭЛ подготовили список таких решений от разных производителей.
Подробнее>>
Dimon456
Заголовок сообщения: Re: Atmega328p работа с TWI в прерываниях (AtmelStudio 6)
Добавлено: Пт ноя 17, 2017 09:22:29
Карма: 20
Рейтинг сообщений: 145
Зарегистрирован: Вс дек 25, 2016 08:34:54Сообщений: 1849
Рейтинг сообщения: 0
Блин одна и та же ошибка
Спойлер Код:
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();
Вернуться наверх
Реклама
Реклама
Новый аккумулятор EVE серии PLM для GSM-трекеров, работающих в жёстких условиях (до -40°С)
Компания EVE выпустила новый аккумулятор серии PLM, сочетающий в себе высокую безопасность, длительный срок службы, широкий температурный диапазон и высокую токоотдачу даже при отрицательной температуре.
Эти аккумуляторы поддерживают заряд при температуре от -40/-20°С (сниженным значением тока), безопасны (не воспламеняются и не взрываются) при механическом повреждении (протыкание и сдавливание), устойчивы к вибрации. Они могут применяться как для автотранспорта (трекеры, маячки, сигнализация), так и для промышленных устройств мониторинга, IoT-устройств.
Подробнее>>
uk8amk
Заголовок сообщения: Re: Atmega328p работа с TWI в прерываниях (AtmelStudio 6)
Добавлено: Пт ноя 17, 2017 10:03:39
Поставщик валерьянки для Кота
Карма: 16
Рейтинг сообщений: 329
Зарегистрирован: Вт ноя 27, 2007 11:32:06Сообщений: 2222Откуда: Tashkent
Рейтинг сообщения: 3
Цитата:
Тут дело не в дисплее, а в размере сообщения выводимом на него,
И что? Сообщение(строка) состоит из символов и записывается в такой дисплей только по одной букве. Меж двух букв переключаемся на ту задачу какую надо.
Но не так варварски как это реализовано сейчас.
Какое я вижу решение.
Отказаться от почти всех delay_ms. Ну разве что за исключением задержек отправки команд ЖКИ, которые сильно работу прибора не тормозят с точки зрения пользователя.
Полностью отделить задачи выполнения логики от задач индикации и считывания времени.
Всё это реализовывается на конечных автоматах. Функции между собой общаются посредством передачи буферов и флагов. Но не тормозят работу системы, а возвращают управление автомату так скоро, как это станет возможным. К примеру через 100-200 мкс, а не через 500-1000мс как сейчас.
Чтоб сильно не ломать существующую программу можно написать логику обмена по I2C через прерывания. Там где вызывается слишком большой delay и нет обмена по I2C разрешать запросы таймера для обновления времени.
Вернуться наверх
Реклама
Angry Engineer
Заголовок сообщения: Re: Atmega328p работа с TWI в прерываниях (AtmelStudio 6)
Добавлено: Пт ноя 17, 2017 10:19:41
Родился
Зарегистрирован: Чт ноя 16, 2017 17:04:14Сообщений: 15Откуда: Сургут
Рейтинг сообщения: 0
ну delay в функциях вывода там для "красивого" выбегания букв. вашу идею понял, попробую реализовать
Вернуться наверх
Реклама
Angry Engineer
Заголовок сообщения: Re: Atmega328p работа с TWI в прерываниях (AtmelStudio 6)
Добавлено: Вс ноя 19, 2017 01:44:21
Родился
Зарегистрирован: Чт ноя 16, 2017 17:04:14Сообщений: 15Откуда: Сургут
Рейтинг сообщения: 0
Разобрался. Если на шину подряд запихонить несколько стартов то получаем висяк. Что сделал: - запретил прерывания таймера во время выполнения атомарных функций TWI (чтение байта, запись байта, старт и стоп) - прикрутил флаг выдачи старта в шину (после STA взводится постле STO снимается) - в прерывании проверяю, если старт был то выдаю в шину стоп и опрашиваю RTC, если был стоп то просто опрашиваю RTC. - если не было стопа то перед выходом из прерывания выдаю в шину старт и возвращаюсь к последнему использованному устройству если такое было кстати мух от котлет тоже поделил. спасибо за советы
Вернуться наверх
Реклама
Страница 1 из 1
[ Сообщений: 8 ]
Кто сейчас на форуме
Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 42
Вы не можете начинать темы Вы не можете отвечать на сообщения Вы не можете редактировать свои сообщения Вы не можете удалять свои сообщения Вы не можете добавлять вложения