вызов "долгой" функции, не прерывая работы основоного цикла..

AlexMann
Offline
Зарегистрирован: 13.05.2014

Есть долгая функция, передает данные по GPRS на комп. Работает секунд 40. Задержки реализованны глупо через delay, диалоговую реализацию сеанса писать влом. Да и не в том порос... Вопрос в том, если способ выполнять основной код программы параллельно ? Типа переключать контент на время ожидания ответа ? "Многозадачность " отсюда http://robocraft.ru/blog/981.html пробовал, не работает у меня, т.к. я вызываю функции из разных потоков, и там используются прерывания... в общем, не сохраняются регистры...

Кто что посоветует ??

kisoft
kisoft аватар
Offline
Зарегистрирован: 13.11.2012

Самое тупое, наверное, использовать прерывания для выдачи символа в порт. К сожалению статью Di Halta я не нашел, но смысл в следующем. Пишется обработчик прерывания для отправки одного байта в UART. Причем отправка продолжается пока в буфере есть данные. Для работы в буфер заливаются данные и выставляется флажок, после чего данные начинают выводиться в UART, пока буфер не пуст.

 

AlexMann
Offline
Зарегистрирован: 13.05.2014

ээээ ....  вот счас не понял :)

GSM_SendATCmd("AT+SAPBR=3,1,\"CONTYPE\",\"GPRS\"");
	delay(100);
	GSM_SendATCmd("AT+SAPBR=3,1,\"APN\",\"internet.beeline.ru\"");//Set the APN
	delay(100);
	GSM_SendATCmd("AT+SAPBR=3,1,\"USER\",\"beeline\"");// Bring up GPRS connection
	delay(100);
	GSM_SendATCmd("AT+SAPBR=3,1,\"PWD\",\"beeline\"");// Get local IP address
	delay(100);
	GSM_SendATCmd(ip_address);
	delay(2000);
	GSM_SendATCmd("AT+SAPBR=2,1");// MTIU
	delay(100);
	GSM_SendATCmd("AT+SAPBR=1,1");
	delay(10000);
	GSM_SendATCmd("AT+SAPBR=2,1");// MTIU
	delay(100);
	GSM_SendATCmd("AT+CIPSEND");// MTIU
	delay(100);
	SimSerial.print(mesg);//The text you want to send
	delay(500);
	SimSerial.println((char)26);//the ASCII code of the ctrl+z is 26
	delay(1000);
	GSM_SendATCmd("AT+SAPBR=0,1");// MTIU
	delay(3000);
	GSM_SendATCmd("AT+SAPBR=2,1");// MTIU
	delay(1000);
	//GetBuffer();

 < Положим, будет функция, которая записывает комманду в буфер, вызывается irq , пишем в порт, возвращемся в основной код... а задержки ?? на обработку комманд модулем ?? Они же всеодно нужны...

Даже если писать диалог, он будет не сильно быстрее...

AlexMann
Offline
Зарегистрирован: 13.05.2014

Вертиться на уме событийная модель... эвенты ... так сказать :)

Если вынести основной цикл в отдельную функцию, второстипенный цикл с долгой функцией в другой отдельный цикл... а в основном использовать диспетчеризацию прерываний....  на основе событий в тех других циклах...

 

kisoft
kisoft аватар
Offline
Зарегистрирован: 13.11.2012

Тогда ещё понадобится таймер, для задержек, тогда всё получится нормально.
Во флеш пишем строки и задержки. Устанавливаем флажок, начинается передача первой команды в прерываниях, по последнему символу в прерывания запускается таймер, в прерывании которого, формируется флажок для передачи следующей команды.
Т.е. всё в прерываниях, основная прога не замечает этого. Типа так. Какие нюансы ещё всплывут? :)

AlexMann
Offline
Зарегистрирован: 13.05.2014

Ну да, симафоры :)

надо вообще отказаться от задержек, а процедурку все же переписать в диалоговую реализацию... 

тогда ответ модуля ОК будет вызывать прерыввние и след комманду... ну или еще подумать....

kisoft
kisoft аватар
Offline
Зарегистрирован: 13.11.2012

Это если на каждую команду возвращается ОК, тогда одно, а если ошибку, тогда совсем другое. Очереди сообщений нет, потому ивенты.. Условные.
В общем всё делать на прерываниях и проблемы будут другими :)

AlexMann
Offline
Зарегистрирован: 13.05.2014

Ну, на каждую команду что-то возвращается через какой то промежуток времени, вот этот промежуток надо использовать для работы основного кода, это что то писать в глобальную переменную, прерывание вызывать просто на овтет из порта, а функция прерывания уже будет разбираться со значением глобальной переменной... 

Этот же механизм можно использовать для обработки команд , полученных через уарт или от тогоже GSM модуля.... и от исполняемых функций.. т.е. имеем некий соммандный процессор, который "знает" все комманды и все ответы, и рулит вызовами функций в зависимости от полученных данных...

Все управление можно осуществить на основе такой парадигмы. В основном цикле этого процессора осуществляется опрос датчиков, опрос портов,  ответ интерпритируется, и в зависимости от того, что получилось, формируется , к примеру, ответ на комманду в диалоговом протоколе (например АТ комманды в GSM модуле), или директива для испольнительного устройства...

 

 

kisoft
kisoft аватар
Offline
Зарегистрирован: 13.11.2012

Никакие "промежутки" не нужно использовать. Основная программа крутится как обычно, а весь обмен в прерываниях. Плюс понадобится управляющая структура, которая выдает задание на передачу информации. Не нужны никакие ивенты, семафоры и т.п. Всё тупо и просто. Максимум в управляющей структуре можно разместить очередь для отправляемых сообщений. А также следить за записью данных в эту управляющую структуру (т.е. чтобы прерывания не вызывались до того, как заполнится эта структура).

А вообще, пока это всё пустой треп, потому что неясно:

1. Можно ли тупо сформировать данные, а потом включить рубильник и пусть эта вся байда катится в эфир. В главном цикле проверять, отправлено всё или нет, после отправки снова формировать следующие данные.
2. Нужно ли менять отправляемые данные в зависимости от ответа, полученного из эфира. Тогда нужна синхронизайия данных между основным циклом и отправкой данных в прерываниях.
3. Количество и команды всегда одинаковые и только некоторые параметры команд разные?

В общем я уже всё расписал, решение вполне нормальное. Прерывания, таймер и управляющая структура, плюс пара-тройка функций, для "завода" обмена и контроля окончания отправки всех данных. По мне так вполне интересная задачка, а то всё помигать светиком, да передать данные на сервер - скукота.

UPD: Можно еще спереть у Di Haltа его простенький "многозадачник", но он на ассемблере. Он его раздает вместе с Pinboard, на его форуме где то есть и тексты и описание.

 

AlexMann
Offline
Зарегистрирован: 13.05.2014

Тогда в целом о задаче...
нужно опрашивать некий сет датчиков, температуры, давления, расхода воды, тока ... потом на основе их показаний выдавать команды исполняющим устройствам, кто то управляется по 0-10В, кто то просто on\off. Помимо этого, долгая процедура пишет лог на сервер через GPRS. Еще можно управлять устройствами посредством команд. т.е. либо на прямую (к примеру установить такое то значение 0-10В, или что то включить/переключить) либо путем изменения значения глобальных переменных. Команды приходят через хардверный уарт (БТ или шнурок) или софтверный - получить\послать СМС.
Собственно в прототипе все , кроме основной логики , реализовано. с Вашей помощью преодолён последний рубеж периферии - хранение данных датчиков, спасибо большое.
Счас есть функции принимающие\отправляющие СМС, опрашивающие датчики, пишущие в лог на сервер, управляющие реле и устройствами пропорционального управления, есть примитивный парсер команд, которому все равно, откуда пришла команда, СМС, консоль или еще как... осталось выбрать подход к логике работ основного цикла и описать все это...
Теперь по пунктам.
1. да, можно... передала лога это асинхронная задача с низким приоритетом
2. Нет, отправляемые данные, это просто показания датчиков и состояния аттенюаторов.
3. Да, я бы настаивал на жестком описании протокола... :) в случае с диалоговой периферией (GSM модулем) тоже строго определенный набор команд и формализованный набор ответов.

AlexMann
Offline
Зарегистрирован: 13.05.2014

можно попробовать ассинхронную работу со всеми субъектами алгоритма.. Каждое устройство или задачу обслуживает функция, которую вызывают с передачей параметра, директивой, а ответона пишет в буфер... мы читаем буфер и реагируем на то , что там есть... т.е. некий диалоговый режим вызовов... Командный процессор запускается, выполняет первую по коду инструкцию, получает ответ, выполняет следующую... при этом, к примеру функцию передачи через GPRS мы не делаем атомарной, а каждую АТ команду и ответ обрабатываем отдельно...

наверно не буффер. а очередь... FIFO

тут как раз отсудствие многопоточности станет плюсом, а не минусом..

kisoft
kisoft аватар
Offline
Зарегистрирован: 13.11.2012

Создается управляющий массив структур (команда, ответ или задержка). Если таких последовательностей несколько, то несколько таких массивов.

Создается функция, которая инициализирует обмен, в неё передается управляющий массив (один из них). Далее всё катится по прерываниям, с использованием таймера для формирования задержек, если нужно, либо также, по прерываниям, получение ответа и продолжение отправки данных.

Разумеется гемора хватит, но тут я уже не помогу (разве что в деталях), слишком много нюансов, да и работа уже не совсем халявная. А идеи - запросто.

 

AlexMann
Offline
Зарегистрирован: 13.05.2014

Спасибо :)

В целом. я думаю, что  представляю, как это должно работать. очень упрощенно, это сейчас работает. В смысле некий парсер комманд, который получает поманды откуда угодно. Попробую нормально прикрутить основной цикл и разбить функции работы с GSM на отдельные команды. Вот тока это не решит проблем простоя, пока ждем ответ от модуля...  тут же есть тока прерывания от таймеров... 

Нельзя же как то программно формировать прерываение ?

kisoft
kisoft аватар
Offline
Зарегистрирован: 13.11.2012

Почему нет, только непонятно, что значит программно формировать прерывание?

AlexMann
Offline
Зарегистрирован: 13.05.2014

Ну что бы основной цикл прервался на выполенени\продолжение выполнения  процедуры связи с модулем, когда получен ответ...

А! Можно же и не ждать ответ, просто отправить команду и продолжить выполнение, переодически проверяя буффер обмена, на наличие сообщения. А что бы знать, к чему этот ответ относиться, можно завести три флага - GPRS, SndSMS, ResSMS. и счетчик шагов в сеансе с модулем... Но есть еще нюанс. Вызываться эти процедуры должны по расписанию, т.е. , к примеру каждые 5 минут. Значит таймер и шедулер. 

kisoft
kisoft аватар
Offline
Зарегистрирован: 13.11.2012

Правильно заданный вопрос содержит ответ :)

AlexMann
Offline
Зарегистрирован: 13.05.2014

В общем, долго провозившись с enum, понял, что сравнивать лейбы со строковыми константами занятие не тривиальное. Switch/case  в пролете, придется использовать обычные if :) 

В общем, 2 массива команд - инициализации и основного цикла, простой интерпритатор команд. 

 

leOS2 sch;
int cycles = 0;

bool isGPRS =  false;
bool isSMSsend =  false;
bool isSMSresieve =  false;

//-----------------------------------------------------------------------------
void command( char buf[], int arg){
	

	if(strcmp(buf,"I_UTL") == 0) {u_init();}
	if(strcmp(buf,"I_SNS") == 0) {sens_init();}
	if(strcmp(buf,"I_GSM") == 0) {GSM_Inti_();}
	if(strcmp(buf,"I_SMS") == 0) {waitSMS();}
		
	
		
	if(strcmp(buf,"GSNS") == 0) {GSNS(); }
	if(strcmp(buf,"GSMS") == 0) {GSMS(); }
	if(strcmp(buf,"GCON") == 0) {GCON(); }
	if(strcmp(buf,"TLED") == 0) {TLED(); }
	
	if(strcmp(buf,"TGSM") == 0) {GSM_test();}
	
	}
	
//-----------------------------------------------------------------------------	
	

	
 char* startup_commands[] = {
	  "I_UTL",
	  "I_SNS", 
	  "I_GSM", 
	  "I_SMS"
	  };

void setup()
{
	
 for(uint8_t i=0; i< sizeof(startup_commands); i++ )
 { command(startup_commands[i], 256); }
//  SerialPrint_P("started/n");
 }//setup


 char* mainloop_commands[] = {"GSNS", "TGSM", "GSMS", "GCON", "TLED", "F0", "F1"};
 int arg = 255;
 
 void loop()
{
	Serial.flush();
	cycles++;

	 for(uint8_t i=0; i<NUMITEMS(mainloop_commands); i++ )
	 { command(mainloop_commands[i], arg); }
	 
	 delay(3000);
	 
//	  Serial.print("Main cycles :");
	//  Serial.println(cycles);

}

//--------------------------------main inst----------------------------------------------------

uint8_t GSNS(){
	sens_load_all_data();
//	Serial.print("dallas 0: ");
//	Serial.println(sens_load_by_index((uint8_t)1));
	return 0;

}

uint8_t GSMS(){
	// GetBuffer();
	//readSMS();
	getMesg_();
	return 0;

}

uint8_t GCON(){
//	Serial.println("-- >");
	return 0;

}

uint8_t TLED(){
//Serial.println("-- >");
	return 0;
}

//-----------------------------AT commands -------------------------------------

uint8_t _GPRS_init(){
	
	
	return 0;
}

Ну это так... в виде идеи кода основного цикла....

Места тока все это много занимает....

 

kisoft
kisoft аватар
Offline
Зарегистрирован: 13.11.2012

Можно сделать не массив имен команд, а массив структур, которые содержат название команды и функцию, которая эту команду обрабаытвает. Тогда не нужно писать море вызовов типа if(strcmp(buf,"I_UTL") == 0) {u_init();} , а достаточно написать цикл, который найдет нужное имя и вызовет соответствующую функцию. Кроме того позволяет легко добавлять/удалять новые команды.

А если еще в эту структуру флажки всякие добавить, то можно её использовать не только для поиска команды, а и еще и для других целей.

Типа так:

typedef void (*FuncType)(void);

struct StructName
{
  const char *command_name;
  FuncType function;
};

void hello(void);
void worldvoid);

StructName arr[] =
{
   { "HELLO", hello },
   { "WORLD", world },
   ...
};

Это только идея, код возможно не скомпилится, для понимания only.

AlexMann
Offline
Зарегистрирован: 13.05.2014

Э... а как вызывать то ?? Прошу прощение за тупизну.. 

Идея была в том, что бы 3-4 возможных инициатора команд, могли бы используя единственный стандартный способ, затребовать выполнение нструкций...  т.е.  "интертпритатору команд, парсеру" передается стандартная инструкция , в формате "GTEM;01", "SET01;240", кем угодно, GPRS модулем, через консоль, через вызовы основного цикла, еще как то ...

Структуры удобно, т.к. , как Вы верно заметили, можно использовать флаги состяний и менять их в процессе работы... записывать зеачения переменных, ... да мало ли... 

 

kisoft
kisoft аватар
Offline
Зарегистрирован: 13.11.2012

Легко, рассмотрим на примере функции command. Исходная у Вас такая:

void command( char buf[], int arg)
{
    if(strcmp(buf,"I_UTL") == 0) {u_init();}
    if(strcmp(buf,"I_SNS") == 0) {sens_init();}
    if(strcmp(buf,"I_GSM") == 0) {GSM_Inti_();}
    if(strcmp(buf,"I_SMS") == 0) {waitSMS();}

    if(strcmp(buf,"GSNS") == 0) {GSNS(); }
    if(strcmp(buf,"GSMS") == 0) {GSMS(); }
    if(strcmp(buf,"GCON") == 0) {GCON(); }
    if(strcmp(buf,"TLED") == 0) {TLED(); }

    if(strcmp(buf,"TGSM") == 0) {GSM_test();}
}

В модифицированном варианте будет примерно так:

void command( char buf[], int arg)
{
   for( int i = 0; i < MAX_STRUCTS; ++i )
  {
    const StructName &l_struct = arr[ i ];
    if( stricmp( l_struct.command_name, buf ) )
    {
      l_struct.function();
      break;
    }
  }
}

MAX_STRUCTS думаю разберетесь как определить, примеры уже были. Это количество структур в массиве arr.

 

leshak
Offline
Зарегистрирован: 29.09.2011

Посмотрел скетч из #2. Блин, зачем тут прерывания, управляющие, многозадачности (которых на 8-битном котроллере, толком небыло и не будет)?

1. Забываем о существование delay()
2. Смотрим БАЗОВЫЙ пример, как можно жить без delay() - Мигаем светодиодом без delay()  - пример как выполнять какое-то переодическое действия без блокировки основого скетча.
3. Укладываем все наши команды в какой-то массив строк.
4. Делаем аналогично примеру, только всместо переключения светодиода, делаем отсылку очередной (одной!) строки-команды из массива с помощью  GSM_SendATCmd

P.S. В нашем случае "переодическое действия"=="отсылка очередной команды".

AlexMann
Offline
Зарегистрирован: 13.05.2014

kisoft пишет:

Легко, ...

В модифицированном варианте будет примерно так:

void command( char buf[], int arg)
{
   for( int i = 0; i < MAX_STRUCTS; ++i )
  {
    const StructName &l_struct = arr[ i ];
    if( stricmp( l_struct.command_name, buf ) )
    {
      l_struct.function();
      break;
    }
  }
}

MAX_STRUCTS думаю разберетесь как определить, примеры уже были. Это количество структур в массиве arr.

Ну это я и хотел уточнить, каждый раз перебираем массив до совпадения... так элегантней, конечно :) MAX_STRUCTS определю :) 

 

 

 

 

AlexMann
Offline
Зарегистрирован: 13.05.2014

leshak пишет:

Посмотрел скетч из #2. Блин, зачем тут прерывания, управляющие, многозадачности (которых на 8-битном котроллере, толком небыло и не будет)?

Это не многозадачность... диспетчеризации то нету :)

leshak пишет:

1. Забываем о существование delay()
2. Смотрим БАЗОВЫЙ пример, как можно жить без delay() - Мигаем светодиодом без delay()  - пример как выполнять какое-то переодическое действия без блокировки основого скетча.

 про delay понятно,  проблема не только в нем, но и в единообразности подхода к обработке инструкций... 

leshak пишет:

3. Укладываем все наши команды в какой-то массив строк.
4. Делаем аналогично примеру, только всместо переключения светодиода, делаем отсылку очередной (одной!) строки-команды из массива с помощью  GSM_SendATCmdP.S. В нашем случае "переодическое действия"=="отсылка очередной команды".

 

Дело не в интервалах, а в том, что 

1. они не одинаковы и вообще могут тыть разными после одной и той же АТ команды

2. Нужно не интервалы ловить а ловить ответ модуля, это правильней. и обрабатывать его, ОК это или ERROR

для переодических вызовов там реет призрак leOS :) как шедулера. 

 

leshak
Offline
Зарегистрирован: 29.09.2011

>Это не многозадачность... диспетчеризации то нету :)

И не будет. Да называйте как хотите, вам шашечки или ехать?

>про delay понятно,  проблема не только в нем, но и в единообразности подхода к обработке инструкций... 

Ну вот так однообразоно и делайте все. Через millis() и запоминание когда последний раз выполняли какое-то дейсвие. Однообразно дробите любые задачи на маленькие "под-задачи" и выполнейти по одной "под-задачке" за одни проход Loop().

>1. они не одинаковы и вообще могут тыть разными после одной и той же АТ команды

Пример смотрели? Что мешает вам после отсылки команды, в переменную interval записывать новое значение? Устанавливать новую задержку.. Было бы желание, а его, похоже, нет.

Если бы вы попробовали, вначале хотя-бы с одним и тем же интервалом, то глядишь как сделать разные интервалы - стало было-бы очевидно.

>Нужно не интервалы ловить а ловить ответ модуля, это правильней. и обрабатывать его, ОК это или ERROR

Что мешает, при все приходящие из сериал, по одному символу складывать в какой-то буффер и смотреть что же там "насобиралось"?
Ну не по millis() будете отправлять очередную команду, а по if(strcmp(buff,expectedReponse)==0). В чем принципиальная разница по какому событию отправлять следующую комманду?

И, в  конце концов, вам нужно задачу решить или вы хотите мне объяснить почему мое предложение неправильное? Да мне вообщему-то все равно. Непоходит вам мое видиние - ну и ладно.
 

AlexMann
Offline
Зарегистрирован: 13.05.2014

leshak пишет:
Что мешает, при все приходящие из сериал, по одному символу складывать в какой-то буффер и смотреть что же там "насобиралось"?

Ну не по millis() будете отправлять очередную команду, а по if(strcmp(buff,expectedReponse)==0). В чем принципиальная разница по какому событию отправлять следующую комманду?

Собственно "абтом и речь" ...  есть описание комманд, парсер команд, и структура , управляющая основным циклом, в ней описана регулярная очередность инструкций. Одна их этих инструкций, раз и есть, раз в цикл читать буфер обмена с модулем и решать как жить дальше. Так что Ваша идея вполне в конве наших, с kisoft, рассуждений. 

Сечас я попробую перепереть код на новый лад, как рекомендовал kisoft, так он будет компактней и оптимальней, прикручу запуск работы с модулем по расписанию и посмотрим, что будет...  Я еще не очень представляю, как лучше описать АТ комманды... каждую в отдельную функцию ? или , наверно лучше, тоже в структуру и потом просто из одного из полей брать комманду и отпралять в интерфейс модуля. 

Но в обоих случаях, и в случае описания основного цикла, и в случае описания протокола с модулем, придется делать  еще одну  конструкцию, описывающую очередность выполнения команд, а во втором случае, нужно еще описать ветвление.. 

Счас попробую...

 

AlexMann
Offline
Зарегистрирован: 13.05.2014

компилится...

но!

1. не получится использовать массив структур как конструкцию , определяющую очередность комманд основного цикла. Там же будут описаны все возможн ые команды. Значит массив имен останется ?? как то не очень структурно... либо же вносить езе один флаг, типа - основная инструкция или вспомогательная...

2. а как передать параметры в такой вызов ? { "GSMS", GSMS }, использовать внешнею переменную ??

 

leshak
Offline
Зарегистрирован: 29.09.2011

Начинте кушать слона потихоньку... по кусочкам....

Вначале сделайте возмите свой изначальный пример.... из сообщения №2.  Вначале хотя-бы вот это....

GSM_SendATCmd("AT+SAPBR=3,1,\"CONTYPE\",\"GPRS\"");
	delay(100);
	GSM_SendATCmd("AT+SAPBR=3,1,\"APN\",\"internet.beeline.ru\"");//Set the APN
	delay(100);
	GSM_SendATCmd("AT+SAPBR=3,1,\"USER\",\"beeline\"");// Bring up GPRS connection
	delay(100);
	GSM_SendATCmd("AT+SAPBR=3,1,\"PWD\",\"beeline\"");// Get local IP address
	delay(100);
	GSM_SendATCmd(ip_address);
	delay(2000);
	GSM_SendATCmd("AT+SAPBR=2,1");// MTIU
	delay(100);
	GSM_SendATCmd("AT+SAPBR=1,1");
	delay(10000);
	GSM_SendATCmd("AT+SAPBR=2,1");// MTIU
	delay(100);
	GSM_SendATCmd("AT+CIPSEND");// MTIU
	delay(100);

Где просто отсылаются комманды по очереди...

Для теста, можете вместо GSM_SendAtCmd(...) просто делать Serial.print("CMD:");Serial.println(....)

Положите все комманды в массив строк и отсылайте с какой-то задержкой. Но без delay().Вначале с одной и той же.

Потом сделаете вариальную задержку (еще один массив, только задержек). Потом переделаете два массива в один массив структур...

Потом сделаете неблокирующий прием данных от шилда в какой-то буффер.

ПОтом замените "задержку", на "в буффере оказалось правильное значение" (или прошло слишком много времени...).

Потом сделате несколько разных функций для разных состояний, введете понятие "состояния" (инициализация, отсылка sms, опрос датчиков и т.п.) и получится у вас машина состояний типичная. Вначале с помощью switch(mode), потом с помощью массива "обработчиков режимов"..... и так до бесконечности можно "фен-шуйность наводить...".

Но все то начинаются "просто отсылать строки, с некоторым интервалом, но не блокирую основной (и единственный) поток....)

AlexMann
Offline
Зарегистрирован: 13.05.2014

В ощем логика работ потерялась напроч :)

typedef uint8_t (*FuncType)(void);

	struct Instruction
	{
		const char *command_name;
		FuncType function;
		uint8_t kind;
		
	};

	Instruction Instructions[] =
	{
		{ "GSNS", GSNS, 0 },
		{ "TGSM", GSM_test, 1 },
		{ "GSMS", GSMS, 0 },
		{ "GCON", GCON ,0},
		{ "TLED", TLED_H ,1 },
		{ "TLED", TLED_L ,0 }
			
			
	//	{ "F0", world },
	//	{ "F1", world }
	};
	
	void command( char buf[], int arg){
		
		for( int i = 0; i < sizeof(Instructions); ++i )
		{
			const Instruction &_Instruction = Instructions[ i ];
			if( strcmp( _Instruction.command_name, buf ) )
			{
				_Instruction.function();
				 Serial.print("com_name -- > ");
				 Serial.println(_Instruction.command_name);
				break;
			}
		}
				
	}
	
//-----------------------------------------------------------------------------	
	

void setup()
{
	pinMode(13, OUTPUT);

 }//setup

 void loop()
{
		 for( int i = 0; i < sizeof(Instructions); ++i )
		 {
			const  Instruction &_Instruction = Instructions[ i ];
			 if( Instructions->kind == 0) 
			 {
				  command((char*)_Instruction.command_name,222);
				  Serial.print("inst -- > ");
				  Serial.println((char*)_Instruction.command_name);
				 
			 }
			 
		 }
		 
		 
	 
	  delay(3000);
	 
	  Serial.print("Main cycles :");
	  Serial.println(cycles);

}

//--------------------------------main inst----------------------------------------------------
String mesg;

uint8_t GSNS(){
	sens_load_all_data();
	Serial.print("Dallas 0: ");
	Serial.println(sens_load_by_index((uint8_t)1));
	return 0;
}

uint8_t GSMS(){
	// GetBuffer();
	//readSMS();
	mesg = getMesg_();
	return 0;

}

uint8_t GCON(){
	Serial.print("Rsp from GPRS Module ");
	Serial.println(mesg);
	command("TLED_H",222);
		return 0;

}

uint8_t TLED_H(){
digitalWrite(13, HIGH);
	return 0;
}
uint8_t TLED_L(){
	digitalWrite(13, LOW);
	return 0;
}
//-----------------------------AT commands -------------------------------------

uint8_t _GPRS_init(){
	
	
	return 0;
}

Как то основной цикл перебора команд и собствено цикл в парсере слишком похожи...

Логика нарушилась, счас это вообще не понятно как работает , если чесно...   

AlexMann
Offline
Зарегистрирован: 13.05.2014

leshak, нормальный ход... Просто мне хочется докрутить "основное обеспечение логики" ... АТ команды и моджуль это вторичная перефирия, а хочется придумать сам механизм обработки инструкций... 

AlexMann
Offline
Зарегистрирован: 13.05.2014

Почти заработало в таком виде....

но проблемы  где то в циклах... не вижу где...

//leOS2 sch;
int cycles = 0;

bool isGPRS =  false;
bool isSMSsend =  false;
bool isSMSresieve =  false;

//-----------------------------------------------------------------------------

	typedef uint8_t (*FuncType)(void);

	struct Instruction
	{
		const char *command_name;
		FuncType function;
		uint8_t kind;
		
	};

	Instruction Instructions[] =
	{
		{ "GSNS", GSNS, 0 },
		{ "TGSM", GSM_test, 1 },
		{ "GSMS", GSMS, 0 },
		{ "GCON", GCON ,0},
		{ "TLE0", TLED_H ,1 },
		{ "TLE1", TLED_L ,0 }
			
			
	//	{ "F0", world },
	//	{ "F1", world }
	};
	
	void command( char buf[], int arg){
		
		if(strcmp(buf,"I_UTL") == 0) {u_init();return;}
		if(strcmp(buf,"I_SNS") == 0) {sens_init();return;}
		if(strcmp(buf,"I_GSM") == 0) {GSM_Inti_();return;}
		if(strcmp(buf,"I_SMS") == 0) {waitSMS();return;}

		
		//for( int i = 0; i < sizeof(Instructions); ++i )
		//{
			//const Instruction &_Instruction = Instructions[ i ];
			//if( strcmp( _Instruction.command_name, buf ) )
			//{
				//_Instruction.function();
				 //Serial.print(" ; get comm: ");
				 //Serial.println(_Instruction.command_name);
				//break;
			//}
		//}
		 //Serial.println("Command's parser ends... ");
				
	}

	
//-----------------------------------------------------------------------------	
	

	
 char* startup_commands[] = {
	  "I_UTL",
	  "I_SNS", 
	  "I_GSM", 
	  "I_SMS"
	  };

void setup()
{
	pinMode(13, OUTPUT);
	
 for(uint8_t i=0; i< sizeof(startup_commands); i++ )
 { command(startup_commands[i], 256); }


 }//setup


 //char* mainloop_commands[] = {"GSNS", "TGSM", "GSMS", "GCON", "TLED", "F0", "F1"};
 //int arg = 255;
 
 char* comma = NULL;
 int size =  NUMITEMS(Instructions);
	 
 void loop()
{
	Serial.flush();
	cycles++;
		  
		  Serial.print("SIZE : ");
		  Serial.println(size);
		 
		 for( int i = 0; i < size; ++i )
		 {
		     const Instruction &_Instruction = Instructions[ i ];
			  
			  if(comma==NULL & _Instruction.kind == 0){
			 			
			 Serial.print("inst: ");
			 Serial.println(_Instruction.command_name);
			 
			 _Instruction.function();
			 }//if 1
			
			 if(comma != NULL)
			 {
				 
			 for( int a = 0; a < size; ++a )
			 {
			const Instruction &__Instruction = Instructions[ a ];
				 if( strcmp( __Instruction.command_name, comma ) )
				 {
					 
					 Serial.print("get comm: ");
					 Serial.println(__Instruction.command_name);
					 __Instruction.function();
					 comma = NULL;
					
					 break;
				 }
			 }//fore 1
			
		 }//if 2
		
		 Serial.println("-----------------------------------------------");
		 
			 }//for 0
			 
		
	 
	  Serial.print("Main cycles :");
	  Serial.println(cycles);
		
	  delay(3000);
}

//--------------------------------main inst----------------------------------------------------
String mesg;

uint8_t GSNS(){
	//sens_load_all_data();
	//Serial.print("Dallas 0: ");
	//Serial.println(sens_load_by_index((uint8_t)1));
	Serial.println("step 1");
	return 0;
}

uint8_t GSMS(){
	// GetBuffer();
	//readSMS();
	//mesg = getMesg_();
	Serial.println("step 2");
	return 0;
}

uint8_t TGSM(){
	// GSM_test();
	// getMesg_();
	Serial.println("step 3");
	return 0;
}

uint8_t GCON(){
	//Serial.print("Rsp from GPRS Module ");
	//Serial.println(mesg);
	Serial.println("step 4");
	comma = "TLE1";
    return 0;

}

uint8_t TLED_H(){
digitalWrite(13, HIGH);
delay(2000);
Serial.println("step 4.1");
	return 0;
}
uint8_t TLED_L(){
	digitalWrite(13, LOW);
	Serial.println("step 5");
	return 0;
}




//-----------------------------AT commands -------------------------------------

uint8_t _GPRS_init(){
	
	
	return 0;
}

 

AlexMann
Offline
Зарегистрирован: 13.05.2014

вот вывод

SIZE : 6
inst: GSNS
step 1
-----------------------------------------------
-----------------------------------------------
inst: GSMS
step 2
-----------------------------------------------
inst: GCON
step 4
get comm: GSNS
step 1
-----------------------------------------------
-----------------------------------------------
inst: TLE1
step 5
-----------------------------------------------
Main cycles :3

 

AlexMann
Offline
Зарегистрирован: 13.05.2014

Заработало в таком виде

 

typedef uint8_t (*FuncType)(void);

struct Instruction
{
	const char *command_name;
	FuncType function;
	uint8_t kind;
	
};


Instruction Instructions[] =
{
	{ "GSNS", GSNS, 0 },
	{ "TGSM", TGSM, 1 },
	{ "GSMS", GSMS, 0 },
	{ "GCON", GCON ,0},
	{ "TLE1", TLED_H ,1},
	{ "TLE0", TLED_L ,0 }
	
};

char* comma = NULL;
int size =  NUMITEMS(Instructions);


for( int i = 0; i < size; ++i )
	{
		const Instruction &_Instruction = Instructions[ i ];
		
		if(comma==NULL & _Instruction.kind == 0){
			
			_Instruction.function();
			
		}//if 1
		
		if(comma != NULL)
		{
			
			for( int a = 0; a < size; ++a ){
			
				const Instruction &__Instruction = Instructions[ a ];
				if( ( __Instruction.command_name == comma ) )
				{
					__Instruction.function();
					comma = NULL;
					break;
				}
			}//for 1
			
		}//if 2
		
		
	}//for 0
	

 

leshak
Offline
Зарегистрирован: 29.09.2011

Совершенно не понятно, зачем у вас for в for-ре, зачем вы ищите команду, по имени два раза...(вернее из-за цикла в цикле - фиг его знает сколько раз) зачем вы вообще ищите ее по имени... у вас имя команды, которое нужно выполнить будет приходить из Serial и вводится человеком?

Честно говоря, я могу ошибаться, но помоему оно работает "только чудом". Просто повезло.

Путаете & и && - это разные операторы.
Сравниваете с помощью оператора "==" типы char*

 

 

kisoft
kisoft аватар
Offline
Зарегистрирован: 13.11.2012

31 строка ошибка, не один амперсанд надо писать, а два. У Вас бинарная операция И, а надо логическую операцию И. Так то заработало - это случайность или порога с ошибками

AlexMann
Offline
Зарегистрирован: 13.05.2014

leshak пишет:

Совершенно не понятно, зачем у вас for в for-ре, зачем вы ищите команду, по имени два раза...(вернее из-за цикла в цикле - фиг его знает сколько раз) зачем вы вообще ищите ее по имени... у вас имя команды, которое нужно выполнить будет приходить из Serial и вводится человеком?

В каждый проход цикла в первом случае перебираются команды из структуры по очереди, те, где каинд =0, т.е. команды основной очередности. Далее проверяется, не изминилась ли переменная комма, если да (в нее записана команда) то ищется эта команда и выполняется, далее снова по очереди...

Эту переменную может поменять сам процесс, кто то через консоль или через ГСМ модуль... В этом суть, в структуре описаны все команды, и их очередность... Основной цикл перебирает их по очереди, и без очереди выполняет комманду, если она записана в комму... 

Да , сравниваю char через == и добавил апмперсанд...

Работает...

Я не знаю, господа,  оптимально ли так... Но вроде примерно то, о чем говорил kisoft.

 

Вот так работает на домашней меге

#define NUMITEMS(arg) ((unsigned int) (sizeof (arg) / sizeof (arg [0])))

typedef uint8_t (*FuncType)(void);

struct Instruction
{
	const char *command_name;
	FuncType function;
	uint8_t kind;
	
};

Instruction Instructions[] =
{
	{ "GSNS", GSNS, 0 },
	{ "TGSM", TGSM, 1 },
	{ "GSMS", GSMS, 0 },
	{ "GCON", GCON ,0},
	{ "TLE1", TLED_H ,1 },
	{ "TLE0", TLED_L ,0 }
	
};



void setup()
{
	Serial.begin(115200);
	pinMode(13, OUTPUT);
	
}//setup

int cycles = 0;
char* comma = NULL;
int arg = 255;
int size =  NUMITEMS(Instructions);

void loop()
{
	Serial.flush();
	cycles++;
	
	for( int i = 0; i < size; ++i )
	{
		const Instruction &_Instruction = Instructions[ i ];
		
		if(comma==NULL && _Instruction.kind == 0){
			
			_Instruction.function();
			
		}//if 1
		
		if(comma != NULL)
		{
			
			for( int a = 0; a < size; ++a ){
			
				const Instruction &__Instruction = Instructions[ a ];
				if( ( __Instruction.command_name == comma ) )
				{
					__Instruction.function();
					comma = NULL;
					break;
				}
			}//for 1
			
		}//if 2
		
		
	}//for 0
	

	Serial.print("Main cycles :");
	Serial.println(cycles);
	
	delay(3000);
}

uint8_t GSNS(){
	
	Serial.println("step 1");
	return 0;
}

uint8_t GSMS(){
	
	Serial.println("step 2");
	return 0;
}

uint8_t TGSM(){
	
	Serial.println("step 3");
	return 0;
}

uint8_t GCON(){
	
	Serial.println("step 4");
	comma = "TLE1";
	return 0;
}

uint8_t TLED_H(){
	digitalWrite(13, HIGH);
	delay(2000);
	Serial.println("step 4.1");
	return 0;
}
uint8_t TLED_L(){
	digitalWrite(13, LOW);
	Serial.println("step 5");
	return 0;
}

Вот вывод

Main cycles :11
step 1
step 2
step 4
step 4.1
step 5
Main cycles :12
step 1
step 2
step 4
step 4.1
step 5
Main cycles :13
step 1
step 2
step 4
step 4.1
step 5
Main cycles :14
step 1
step 2
step 4
step 4.1
step 5
Main cycles :15

КАк видим, и очередность и последовательность соблюдается, внезапная команда выполняется... :)

leshak
Offline
Зарегистрирован: 29.09.2011

МОжет я чего-то не улавливаю, но в чем, в итоге получилось преимущество по сравнению с 

таким loop()?  (ну кроме того что понять сходу что будет происходить труднее).

void loop()
{
  GSNS();
  GSMS();
  GCON();
  TLED_H();
  TLED_L();
  delay(3000);
}

Сами "шаги" как были блокирующими - так и остались. Сам loop() как блокировался пока все команды не выполнятся - так и продолжает блокироваться.

leshak
Offline
Зарегистрирован: 29.09.2011

А еще, попробуйте, скажем на этом скетче что-бы после "внезапной комманды", выполнилась еще одна внезапная комманда.

Если мы в TLED_H тоже установим comma="TLE2" (ну и само собой напишем для этой команды функцию и добавим ее в Instructions[] она выполнится?

А еще, чисто из любопыства запустите такой скетчик, предварительно попытавшись угадать что он выведет

void setup(){
  Serial.begin(115200);
  char* comma="TLE2";
  
  if(comma=="TLE1");Serial.println("First Command");
  if(comma=="TLE2");Serial.println("Second command");
}

void loop(){
}

сравните реальность с тем что ожидали, и представте себе что будет если у вас в с именами комманд случится такая же "обознатушка".

 

 

leshak
Offline
Зарегистрирован: 29.09.2011

А еще, давайте представим, что нам нужно что-бы GSMS() выполнялся раз за разом, пока не наступит некое событие (пользователь нажмет кнопку, прийдет строка из Serial). Как это вы сделаете с таким управляющим циклом? Так что-бы при этом сам цикл loop() не блокировался (что-бы можно было продолжать следить за датчиками, другими кнопками, мигать диодом с нужной частотой и т.п.)

AlexMann
Offline
Зарегистрирован: 13.05.2014

leshak пишет:
 Как это вы сделаете с таким управляющим циклом? Так что-бы при этом сам цикл loop() не блокировался (что-бы можно было продолжать следить за датчиками, другими кнопками, мигать диодом с нужной частотой и т.п.)

Ну в чистом виде этого не добиться. В принципе. Без применения диспетчеризации времени проца...

Теперь про цикл. 

Команды "типа 0" и должны быть атомарными и "блокирующими". Команды типа 1 напротив, носят вспомогательный характер, могут быть разделены на шаги или фазы выполнения.

Вообще, идея в неком "командном процесоре" как я уже писал, куда команды передаются разными источникаи , включая сам код, и гарантировано выполняются одинаково. 

 

leshak
Offline
Зарегистрирован: 29.09.2011

Вообщем я уже упоминал вам про "машину состояний" (state machine/конечный автомат). Погуглите что это такое подробней... когда в голове разложится по полочкам "что же в принципе нужно", тогда и одну из реализаций ее будет легче писать. 

 

 

 

leshak
Offline
Зарегистрирован: 29.09.2011

AlexMann пишет:

leshak пишет:
 Как это вы сделаете с таким управляющим циклом? Так что-бы при этом сам цикл loop() не блокировался (что-бы можно было продолжать следить за датчиками, другими кнопками, мигать диодом с нужной частотой и т.п.)

Ну в чистом виде этого не добиться. В принципе. Без применения диспетчеризации времени проца...

Ну... так этим и нужно занятся. Програмной диспетчирезацией. Главный цикл отдает управление обработчикам, а уж обработчики должны "отработать как можно быстрее".

Помоему вы вообще начали "шарахаться" от одной хотелки к другой. Вы свой стартовый пост сами читали? Помните изначальную задачу?

AlexMann пишет:

Есть долгая функция, передает данные по GPRS на комп. Работает секунд 40. Задержки реализованны глупо через delay, диалоговую реализацию сеанса писать влом. Да и не в том порос... Вопрос в том, если способ выполнять основной код программы параллельно ? Типа переключать контент на время ожидания ответа ? 

Эта задача решена? Почему вы поехали решать проблемы ветвления потока управления, приема внешних комманд и т.п.?

Сделать "универсально" - это общая болезнь програмеров. Даже на PC это зачастую заканчивается печально (получает "универсальный монстр", которого запыхаешься поддерживать), а уж на микроконтроллере и подавно это противопоказано.

Да вообщем-то и "универсальность" тут не получилась. Скажем реагировать на кнопки нормально - уже не получится (ну "получится", но прийдется их костылями вбивать, а так каждая добавка...).

Команды хотите "со стороны"? Ну предположим будут команды приходить из Serial. Только.... у вас же, весь цикл целиком является "блокирующим". Значит оперативно и ПОСТОЯННО смотреть что прищло в сериал - не получится. Ну разве что впихнуть прослушивание Serial в этот ваш for. То есть - костыль. Ну или вводить еще один тип комманды. Которая должна выполняться "постоянно". А потом выяснится что таких комманд требуется несколько... будет у нас третий for в for-е, который в for-e... А потом выяснится что эти "постоянные" нужно будет отключать/выключать... значит еще флаги натыкаем. if-фоф набросаем..... Упс. А ведь аттомарные-то у нас блокирующие.... следовательно расчитывать на предсказуемое (хотя-бы приблизительно) время выполнение "постоянных" и "вспомогательных" - не приходится (то есть изначальную задачу - так и не решили).

Далее... со сравнением строк разобрались?  Я вам скетчик давал демонстрирующий глючность выбранного вами способа. Запускали?

Хотя.. честно говоря, я вообще нефига не понимаю нафига тут используются строки для идентификации комманд. Что-бы побольше нагрузить проц и увеличить расход памяти?  Что-бы увеличить вероятность очепятки в комманде и потом биться с дебагом? (раз строка, следовательно на этапе компиляции уже ошибки не вылезует, если в comma впихнете команду которой нет. трабла вылезет уже только во время выполнения). Что-бы, не дай бог, когда потребуется поменять имя команды лазить по всему скетчу и аккуратно исправлять все "магические строки"?

Строки имееют смысл только в одном случае, когда:
Предполагает что где-то в цепочке учавствует человек (посылает комманды, пишет текстовый файлик который нужно обработать и т.п.). И то.. даже в этом случае имеет смысл разделить "коммандый процессор" и "анализ строк". Полученные от человека комманды, вначале "распознавать" (переводить их в какой-то int-представление, базирующие скажем на enum), а уж "коммандный  процессор", работает только с цифрами. Если что... и хранить такие цепочки - гораздо меньше места занимает.

Это если отбросить в сторону что непонятно зачем вообще нужен поиск комманд. Причем КАЖДЫЙ РАЗ. Их список - не меняется во время выполняния. Индекс каждой - известен на момент компиляции. Почему не пользоватся индексами/enum-мами, вместо имен? Сразу понятно какую команду нужно выполнять. Ничего искать не нужно. 

Непонятно зачем вы вообще перемешали (запихнули в один массив) основные и дополнительные комманды. Что-бы потом было не скучно, и постоянно нужно было в runtime их фильтровать/разделять по kind? У вас что, в процессе выполнения команда может поменять свой тип (если "да", то "это не есть good")?

У вас же, может в один момент поставиться в состояние "нужно выполнить", только одна дополнительная комманда. Нафига вам вообще их в массив  запихивать?

FuncType aCommand=0;
void loop(){
  
 ...... освновной код....
  if(Какое-то условие) aCommand=TLED_H;  // указали что нужно выполнитель дополнительную комманду


 ...... освновной код....
  
 // если освновной код дал указание выполнитель дополнительную - выполнем
  if(aCommand){
    aCommand();
    aCommand=0;
  }
}

Чем aCommand=TLED_H, хуже чем comma="TLE1"?  Помоему только тем, что никаких циклов/поисков не нужно. Если я, случаной напишу aCommand=tled_h - компилятор сразу завопит. А если напишу comma="tle1"  - все скомпилируется тихо, но работать не будет.

 

AlexMann
Offline
Зарегистрирован: 13.05.2014

Да, привер занятный...

Давайте начнем с начала... 

Этот ПАК должен выполнять ряд действий...

1. Опросить 30 датчиков, возможно сразу среагировать на выход перемтров за критические пределы

2. Основываясь на данных датчиков, изменить состояние аттенюаторов, 6 устройств 2-10 В, 8 реле

3. по расписанию, скажем каждые 5 минут отправить данные по GPRS на серевер

4.Принимать и отсылать СМС с данными и командами.

5. Принимать команды из консоли. 

6. логировать директивы, полностью или частично

Как себе я это видел - организовать внутреннею жизнь на основе директив, как единицы принятия решения, Директивы универсальны, через них инкапсулируются все действия, к примеру изменить значение переменной t_LOW можно только директивой SET;t_LOW;25 , и не важно откуда директива пришла , через перефирию или ее сгенерировал исполняемый код. Изменить состояние аттенюатора (к примеру обороты на насосе с частотником) можно только директивой SET;w_PUMP1;100 (по сути опять таки изменить значение определенной переменной), и только так. Код на прямую не может изменить состояние переменных. Директивы логируются. 

Значит, нам нужно описание этих директив, некий парсер команд и то, что эти команды исполняет. Кроме этого, некая структра, описывающая нормальную последовательность исполнения команд основного цикла...

1. Опросить датчики

2. сравнить состяние основных переменных и показаниями датчиков

3. записать новые значения переменных аттенюаторов

4. привести состяние аттенюаторов к этим переменным

6. записать лог

7 опросить порты и по расписанию отправить состояие основных переменных на сервер.

 

Что конкретно Вы предлагаете ? 

 

leshak
Offline
Зарегистрирован: 29.09.2011

>Как себе я это видел - организовать внутреннею жизнь на основе директив, как единицы принятия решения,

Еще раз говорю... почитайте про "машину состояний". Вы сейчас пытаетесь изобрести велосипед. В том числе и терминологически.

Почитайте, но не кидайтесь сразу реализовыать... 

>Что конкретно Вы предлагаете ? 

Я уже говорил "кушайте слона по кусочкам". Написали вы кучу пунктов. Которые ЯВНО предполагают, что ВСЯ работа должна быть не блокирующей. Вот, значит, вот этому и нужно вначале научится.

Реализуйте один пункт, потом другой... потом попытайтесь их сцепить. Причем обычный

loop(){
   func1();
   func2();
}

Или switch(mode) - тоже не плохое решение. С++ в своем ситаксисе уже содержить все средства для "описывающая нормальную последовательность исполнения команд". И воротить какие-то "коммандные процессоры", нужно начинать только когда вы увидите что "без этого никак".  Не нужно городить "структуры", "процессоры" только ради того что "это круто".

Вообщем начните с начала. С того чем ваша ветка и начиналась.

GSM_SendATCmd("AT+SAPBR=3,1,\"CONTYPE\",\"GPRS\"");
	delay(100);
	GSM_SendATCmd("AT+SAPBR=3,1,\"APN\",\"internet.beeline.ru\"");//Set the APN
	delay(100);
	GSM_SendATCmd("AT+SAPBR=3,1,\"USER\",\"beeline\"");// Bring up GPRS connection
	delay(100);
	GSM_SendATCmd("AT+SAPBR=3,1,\"PWD\",\"beeline\"");// Get local IP address
	delay(100);
	GSM_SendATCmd(ip_address);
	delay(2000);
	GSM_SendATCmd("AT+SAPBR=2,1");// MTIU
	delay(100);
	GSM_SendATCmd("AT+SAPBR=1,1");
	delay(10000);
	GSM_SendATCmd("AT+SAPBR=2,1");// MTIU
	delay(100);
	GSM_SendATCmd("AT+CIPSEND");// MTIU
	delay(100);
	SimSerial.print(mesg);//The text you want to send
	delay(500);
	SimSerial.println((char)26);//the ASCII code of the ctrl+z is 26
	delay(1000);
	GSM_SendATCmd("AT+SAPBR=0,1");// MTIU
	delay(3000);
	GSM_SendATCmd("AT+SAPBR=2,1");// MTIU
	delay(1000);
	//GetBuffer();

Без блокировки. Сделайте вначале "тупо". Пусть вначале заработает "хоть как-то". Потом уже будете смотреть как это можно сделать "более красиво", "более универсально" и т.п.

К "универсальности" вообще лучше переходить, когда уже будут работающие паралельно два/три пункта. Когда не "умозрительно", а реально будете видеть "что между ними общего". Вот это общее уже и выносить в какие-то "процессоры" и т.п.

AlexMann
Offline
Зарегистрирован: 13.05.2014

 Я знаю что такое МТ, хоть и не разработчик. Но не вижу связи, если честно. Мы явно не понимаем друг друга. Хоть как то, это работает,  по крайней мере работает некая модель, в которую не внесена логика основных процессов. Я хотел бы вносить эту самую логику уже в отрыве от реализации, т.е. должна работать некая оболочка, отвечающа за переферию и основной цикл, куда уже будут добавляться конкретная реализация процессов... в виде инструкций или директив. Хорошо, попробую вернуться к "многозадачности" :) 

AlexMann
Offline
Зарегистрирован: 13.05.2014

leshak пишет:

Или switch(mode) - тоже не плохое решение. С++ в своем ситаксисе уже содержить все средства для "описывающая нормальную последовательность исполнения команд". 

Вот это вообще не понятно.

AlexMann
Offline
Зарегистрирован: 13.05.2014

В общем, не выходит пока каменный цветок.... Пробовал библиотеки четыре, protothread,mtread,arcos  еще ккие то... Все не то. Проблема в том, что потоки можно тормазить тока в конце его выполнения. Protothread вроде получше, но пока не всЕ там понял... 

leshak
Offline
Зарегистрирован: 29.09.2011
А все потому, что вы упорно пытаетесь сразу сесть на шпагат. Ступенек через пять.
 
Еще раз. У нас тут НЕТ ПОТОКОВ. У нас есть поток. ОДИН. Все. Больше не будет. И нужно учится "выкручиваться в заданных рамках" (что и есть суть "программирование микроконтроллеров"). Любые библиотеки, могут только помогать выкручиваться (но в 80%, по личному опыту, при этом накладывают ограничения, которые их помощь делают сомнительной 50 на 50).
 
Какую-то бы библиотеку вы не взяли, ограничение в один поток будет предполагать что прикладной код учитывает это. Поэтому нужно учится писать код именно в таком стиле "делим работу на кванты и не блокируем поток".
 
А когда научитесь в таком стиле писать прикладной код, вот тогда можно начинать библиотеку подбирать (если это вообще потребуется, в большинстве случаев логика диспетчирезации настолько тривиальна, что проще самому ее написать, чем втискиваться в рамки сторонней библиотеки).
 
Для того что-бы научится, нужно, как ни странно начать пробовать писать в этом стиле. Уже ДВА раза говорил - начините с простого. Начините с отсылки серии конманд на свой шилд. Вначале с одинаковыми интервалами. Но не блокируя основной поток.
 
Более того. Я в принципе изначально описал "как это делать", только закодить нужно...
 
А то "не выходит цветок". C чем вначале, Данило-Мастер разбирался?
 
     Данилушко  запончик  надел,  подошел  к  станку и давай рассказывать да
показывать.  Что приказчик спросит - у него на все ответ готов. Как околтать
камень,  как распилить, фасочку снять, чем когда склеить, как полер навести,
как на медь присадить, как на дерево.

Что он дальше делал? Бляшки точить начал. Не цветок. А невеста его, Катя-Мертвякова, когда приперло и пришлось учится каменному делу..?

И стал ей Прокопьич рассказывать, да так, всё по пустякам:

Вот так, мол, делаю бляшку, так - ручки к вилкам, ножам.

Так что, "запончик надел и пошел бляшки да ручки к вилкам точить".

А цветок-то, кстати, был примером именно задачи "не по зубам". Задачи которая крышу сорвала. Решения которой пришлось брать со стороны и расплачиваться за это по цене ставящей под сомнение целесообразность этого. Решение которой, по большому счету ничего кроме горя - не принесло.

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

 

 

AlexMann
Offline
Зарегистрирован: 13.05.2014

Спасибо на добром слове :)

Но на шпагат я таки сел, все работает и не блокируется...  я имею в виду долгую функцию..., теперь вернусь к основному циклу и командам:) Решил с использованием протопотоков. Хорошее примитивное решение. Чего то дружище kisoft молчит :)  а сейчас как раз будет время оптимизации памяти :) , придется все команды снова запихивать во флеш...  

AlexMann
Offline
Зарегистрирован: 13.05.2014

Чето я посмотрел, как расходуется память на 328, и захотелось сразу перейти на stm32 :)

kisoft
kisoft аватар
Offline
Зарегистрирован: 13.11.2012

Ага и юзать какую нибудь RTOS :) Я, правда не пробовал, но Tiva C & STM32F103 время от времени мучаю.

PS Я молчу, потому что времени маловато, да и диалог вроде идет. А еще я далеко не всё понимаю и уже подзабыл, что было в начале, потому надо читать снова :) Ну а в выходные я поеду смотреть Мировую серию Рено за 140 км от нас, потому на весь день. Хорошо хоть иногда есть время форум полистать на работе.

PPS Потоки можно тормозить и не в только в конце, но это на "больших компах", в Ардуине я потоков (нитей) даже не видел еще, да и смысла особого не вижу в них.

 

AlexMann
Offline
Зарегистрирован: 13.05.2014

Я сегодня приобрел stm32m4 discavery, воткнул туда clr, и буду пробовать с# на этом :) и пототом freeRTOS.

Вещь! Ну а по нашим делам, не я так не про потоки а про задачи при кооперативном шеделере, просто везде кроме протопотоков , эти задачи тормазатся в конце ... Не суть, на протопотоках все ок. Есть кооперация:)