Вечер добрый всем. Подскажите пожалуйста как расово правильно делать переходы между блоками программы? На данном этапе делаю примерно так Код (C++): #include <stdio.h> int var = 1; int var_2 = 1; void setup() {} void loop() { while (var ==1) { //режим расчета пузырьков воздуха } clrscr(); while (var ==2) { //режим расчета пузырьков водки } clrscr(); while (var ==3) { //режим расчета пузырьков пива } //при выходе из while основной цикл проходит до конца где и очищает экран перед следущим режимом clrscr(); } блоки программы засовываю в циклы while. Плюсы,- программа работает стабильно, нет никаких взбрыкиваний и вмешательства других блоков кода. удобно делать очистку экрана при переходах между циклами. Минусы, - в каждом блоке, происходит своя собственная проверка нажатий на кнопки, получение данных с датчиков. неудобный переход между блоками. хочу попробовать такой вариант на enum перечислениях и switch case. примерно так. Код (C++): Вариант switch case void loop() { //здесь делаются все проверки нажатий на кнопки // прием данных с датчиков // в switch case делатся обработка по нужным алгоритмам //и вывод на экран switch (var) { case 1: //режим расчета пузырьков воздуха clrscr(); break; case 2: //режим расчета пузырьков водки clrscr(); break; case 3: //режим расчета пузырьков пива switch (var_2) { case 1: //пиво светлое один вариант расчета break; default: // пиво темное другой вариант break; } clrscr(); break; default: break; } } так еще не писал, но вижу очевидные плюсы. обработка данных будет одна в начале цикла, потом переход в нужный раздел. Однако боюсь непредсказуемых ошибок и сложности ветвлений. Как вообще принято объединять блоки программ? если вопрос сложен, то подскажите что можно покурить? учебник по С++ вроде весь скурил, а на этот вопрос так и не нашел ответа. П.С. может тема приживется, чтоб в ней задавать простенькие вопросы, не создавая новых тем. единственно не знаю в каком разделе разместить. если админ такую тему сочтет полезной, создайте подобную тему в разделе который считаете нужным. а пока пусть во флудилке повесит.
Если в пол в профиле указан верно, то расово-правильно - через вычисляемый goto (cм. здесь). Но это точно не для девочек!
блоки - в алгоритмах. В программе - функции. без volatile и с включенной оптимизацией это работать не будет.
а что там сложного то? описания мало только, если правильно вкурил, применяться должно так? Код (C++): int i; int foo; int bar; int hack; void setup() { // put your setup code here, to run once: } void loop() { // put your main code here, to run repeatedly: static void *array[] = { &&foo, &&bar, &&hack }; goto *array[i]; foo: { }; bar: { }; hack: { }; } а так да интересный способ, не знал что так можно
Сложно начнется тогда когда не будет контроля за использованием goto, ведь, так соблазнительно его использовать. Потом начинается использование goto по пустякам. Потом через год надо отредактировать прошивку, а проще окажется написать новую.
таки работает все же. на данном этапе такой подход к моим записюлькам кода, дает самые стабильные результаты. ничего не глючит, никакаких нежданчиков. однако расплата за это в каждом while? по сути самостоятельный цикл. ну и volatile местами присутствует. Запугали вы меня с goto. попробую на enum and switch case поваять.
Ваш начальник, наверное, никогда в ядро Unix не заглядывал, а то заставил бы авторов и его переписать
Заглядывал, начальник был правильный, тот с которым вместе не раз собирали систему. Наверное по этому и говорил.
Как вариант, можно сделать с помощью функций -- каждую функциональность реализовать в отдельной функции. Спойлер: Например Код (C++): // Функции, отвечающие за выполнение работы в определённом режиме, // должны иметь одинаковый набор параметров. // Функции initFunction, countAirBubles, countBeerBubles, countAlcoholBubles // имеют только один аргумент типа int8_t. // Количество параметров может быть любым, главное одинаковым. void countAirBubles(int8_t pressedKey); void countBeerBubles(int8_t pressedKey); void countAlcoholBubles(int8_t pressedKey); // указатель на текущую функцию void (*currentFunction)(int8_t) = NULL; // Ниже реализации функций: void initFunction(int8_t pressedKey) { // Что-то делаем для инициализации. // Если pressedKey положительное число, // то реагируем на нажатие кнопки. // Если pressedKey отрицаетльное число, // то просто делаем свою работу. // Ни каких delay и циклов любого вида. // Функция должна завершить работу как можо быстрее. // Например, если нажата кнопка, // то меняем активную функцию в соответствии с кодом switch (pressedKey) { case 1: currentFunction = countAirBubles; case 2: currentFunction = countBeerBubles; case 3: currentFunction = countAlcoholBubles; } } void countAirBubles(int8_t pressedKey) { // Аналогично initFunction // Например, если нажата любая кнопка, // то меняем активную функцию на начальную if (pressedKey > 0) { currentFunction = initFunction; } } void countBeerBubles(int8_t pressedKey) { // Аналогично initFunction } void countAlcoholBubles(int8_t pressedKey) { // Аналогично initFunction } // Любимые setup() и loop() : void setup() { // Ещё что-то..... // Текущей функцией назначаем функцию initFunction. currentFunction = initFunction; // Ещё что-то..... } void loop() { // фейковая функция // реально что-то должно опрашивать клавиатуру // и возвращать код нажатой кнопки // либо отрицаетльное число, // если не нажато ни одной кнопки int8_t pressedKey = scanKeyboard(); currentFunction(pressedKey); // Больше в loop ни чего не надо. // Вся функциональность по смене режимов и состояний // будет реализована в конкретных функциях // countAirBubles, countBeerBubles и т.п. } Фишка такого подхода в том, что, при написании реализации конкретной функции, концентрируешься именно на этой функции, не растекаясь мыслями по всему коду. Но есть некоторые ограничения, связанные с организацией кода внутри функций: по сути код должен быть аналогичен коду в обработчиках прерываний и все функции должны поддерживать один интерфейс.
А я обычно делаю что-то типа callback. Код (C++): #define MQTT_NUM_SUB_TOP 9 typedef struct _mqtt_subscribe_struct { const char *Mqtt_Sub_String; void (*function)(byte index, byte param); } MQTT_Subscibe_Struct; MQTT_Subscibe_Struct MQTT_Subsc_Data[] = { {"/mh/ds/bs/leo/count_res", &reset_counters }, {"/mh/ds/bs/leo/rel_00", &rel_switch}, {"/mh/ds/bs/leo/rel_01", &rel_switch}, {"/mh/ds/bs/leo/rel_02", &rel_switch}, {"/mh/ds/bs/leo/rel_03", &rel_switch}, {"/mh/ds/bs/leo/rel_10", &rel_switch}, {"/mh/ds/bs/leo/rel_11", &rel_switch}, {"/mh/ds/bs/leo/rel_12", &rel_switch}, {"/mh/ds/bs/leo/rel_13", &rel_switch}, }; void reset_counters(byte index, byte param) { byte i; if (param == 1) { for (i = 0; i < 3; i++) { Main_Data_byte[i] = 0; EEPROM.write(i, Main_Data_byte[i]); } Mqtt_Update_flag = 0xFF; client.publish(MQTT_Subsc_Data[0].Mqtt_Sub_String, "OFF", true); } } void rel_switch(byte index, byte param) { digitalWrite (DIG_Pins[index - 1], param); if( param == 0) Main_Data_byte[RELEY_STATE] &= ~(1 << index-1); else Main_Data_byte[RELEY_STATE] |= (1 << index-1); EEPROM.write(RELEY_STATE, Main_Data_byte[RELEY_STATE]); } void callback(char* topic, byte* payload, unsigned int length) { char message[15]; char i; if(length>14) return; for (i = 0; i < length; i++) message[i] = (char) payload[i]; message[i] = 0; for (i = 0; i < MQTT_NUM_SUB_TOP; i++) { if ( strcmp(topic, MQTT_Subsc_Data[i].Mqtt_Sub_String) == 0 ) { if (strcmp(message, "ON") == 0 ) (*(MQTT_Subsc_Data[i].function))(i, 1); else (*(MQTT_Subsc_Data[i].function))(i, 0); } } } void mqtt_subscribe(void) { byte i; for (i = 0; i < MQTT_NUM_SUB_TOP; i++) { client.subscribe(MQTT_Subsc_Data[i].Mqtt_Sub_String); client.loop(); //mqtt loop } }
спасибо всем большое. Хоть какое то понимание начало приходить, как это делается. Пытаюсь с уровня быдлокодера самоучки, повзрослеть до уровня китайско-индийского программиста.
Доброй ночи всем кто ещё здесь на форуме. Подскажите пожалуйста, хотябы на вскидку почему виснет дуня? Хотел вывести обработку нажатий кнопок в фон. По прерыванию значение порта С скидывается в переменную. Которая затем расшифровывается в основном цикле и возводятся флаги надатий в свитч кейсе, флаги потом сбрасываются после выполнения действий. Вроде явных ошибок нет а она зараза зависает. То несколько десятков нажатий отработает , то после 2 висит. В чем дело не пойму. Код (C++): volatile int buttons =0; bool A = false; volatile unsigned long buttons_Time =0;// volatile void setup() {DDRC = 0b00000000; PCMSK1 = 0b00001111; // разрешаем прерывания на пинах А0, А1, А2, А3 PCICR |= (1 << PCIE1); Serial.begin(9600); } void loop() { if( buttons >0 ) { switch (buttons) { case 0b00000001: //была нажата кнопка А0 Serial.println("knopka111"); break; case 0b00000010: //была нажата кнопка А1 Serial.println("knopka222"); break; case 0b00000100: //была нажата кнопка А2 Serial.println("knopka333"); break; case 0b00001000: //была нажата кнопка А3 Serial.println("knopka444"); break; } if( millis() - buttons_Time > 50 ) // своеобразный антидребезг { //разрешаем прерывания на линии с PCICR |= (1 << PCIE1); //обнуляем переменную buttons =0; Serial.println("Anti Drebaezgg"); } } } ISR(PCINT1_vect) { buttons = PINC; //передаем данные о портах в переменную buttons PCICR &= ~(1 << PCIE1); //запрещаем прерывания на линии C buttons_Time = millis(); Serial.println("PRERYVANIE"); }