Какой тип возвращаемых данных у функции?
- Войдите на сайт для отправки комментариев
Пт, 01/03/2019 - 23:38
Не могу понять почему компилятор не видит тип данных, если я его явно указываю вот так
enum BTN_scan_states{
NOT_PRESSED_ = 0,
PRESSED_ = 1,
HOLDED_ = 2,
RELEASED_ = 3
};При компиляции вылазит: 'BTN_scan_states' does not name a type! То есть компилятор буквально говорит, что это не тип данных?
Подсчечивается строка
BTN_scan_states button_scan(){ Первое слово - тип возращаемого значения функции. По идее она должна вернуть состояние кнопки. Насколько я понял, компилятор не понимает, этот тип данных? Код целиком
#define LED_Pin 0
#define BTN_Pin 4
#define interval_slow 500UL
#define interval_fast 50UL
#define ext_interval 2000UL
void setup(){
pinMode(LED_Pin, OUTPUT);
pinMode(BTN_Pin, INPUT_PULLUP);
}
bool progTimer(unsigned long interval){
static unsigned long prevTime=0;
if(millis()-prevTime>interval){
prevTime=millis();
return false;
}
else return true;
}
enum BTN_scan_states{
NOT_PRESSED = 0,
PRESSED_ = 1,
HOLDED_ = 2,
RELEASED_= 3
};
BTN_scan_states button_scan(){
static bool prev_BTN_State = FALSE; // предыдущее состояние кнопки (нажата или нет)
bool BTN_State = !(digitalRead(BTN_Pin)); // текущее состояние кнопки
if (BTN_State==FALSE && prev_BTN_State==FALSE) {prev_BTN_State==FALSE; return NOT_PRESSED;} // кнопка не нажата
if (BTN_State==TRUE && prev_BTN_State==FALSE) {prev_BTN_State==TRUE; return PRESSED_;} // кнопка нажата
if (BTN_State==TRUE && prev_BTN_State==TRUE) {prev_BTN_State==TRUE; return HOLDED;} // кнопка удерживается
if (BTN_State==FALSE && prev_BTN_State==TRUE) {prev_BTN_State==FALSE; return RELEASED_;} // отпущена
}
void loop(){
static BTN_scan_states b_state = button_scan();
switch(b_state){
case: NOT_PRESSED {Blink (LED_Pin, interval_slow); break;} // не нажата
case: PRESSED {Blink (LED_Pin, interval_fast); break;} // нажатие
case: HOLDED {Blink (LED_Pin, interval_fast); break;} // удержание кнопки нажатой
case: RELEASED {if (progTimer(ext_interval)){Blink (LED_Pin, interval_fast)}
else{Blink (LED_Pin, interval_slow);} break;} //отпускание
}
}Три строчки кода в правильности написания которых сомневаюсь, я выделил! Посмотрите пожалуйста, кто разбирается!
enum это не тип данных , это "способ" переименования ряда целых чисел.
enum становиться типом данных когда :
typedef enum { NOT_PRESSED , PRESSED, HOLD, RELEASED, }BTN_scan_staes;вы его типом обьявляете
enum при более накрученых кодах склонен сбивать компилятор. Так что рекомендую делать так.
и возвращаемый тип будет byte.
Сорри, написал не разобравшись. Удалил
Не, ну почему все идут "через жо..у и сваркой"? Неужели нет других способов ну, например, #define?
Не, ну почему все идут "через жо..у и сваркой"? Неужели нет других способов ну, например, #define?
а что плохого в enum? Когда какая-то переменная принимает несколько фиксированных значений - я как раз обычно enum использую - это и нагляднее, и надежнее. С #define вы можете случайно присвоить переменной какое-то левое значение, а с enum вам компилятор даст выбрать только заранее описанные.
а что плохого в enum? Когда какая-то переменная принимает несколько фиксированных значений - я как раз обычно enum использую - это и нагляднее, и надежнее. С #define вы можете случайно присвоить переменной какое-то левое значение, а с enum вам компилятор даст выбрать только заранее описанные.
Ну, переменной присвоить значение с помощью #define, конечно надо постараться. Но идею я понял. При достаточно больших программах - enum является защитой, но в указанном случае - пожирателем пространства и вые-ом, извините за грубость.
При достаточно больших программах - enum является защитой, но в указанном случае - пожирателем пространства и вые-ом, извините за грубость.
не знаю, что он там пожирает
Вот эти два кода абсолютно идентичны по "пожиранию пространства"
через enum
enum aa {one, two, three, four}; aa bb, cc; void setup() { if (bb == one) bb = four; if (cc == one) cc = two; } void loop() {}через дефайны
#define one 1 #define two 2 #define three 3 #define four 4 int bb, cc; void setup() { if (bb == one) bb = four; if (cc == one) cc = two; } void loop() {}У енума есть хороший побочный эффект: когда его свичуешь, к примеру, компилятор проверяет - все ли значения попали в свич. Если не все, то предупреждает, что какое-то не обрабатывается, не забыл ли про него уважаемый автор исходника?
Не понимаю, как, но этот мой код наконец-то заработал! Примерно так как предполагалось.
#define LED_Pin 0 #define BTN_Pin 4 #define interval_slow 500UL #define interval_fast 50UL #define ext_interval 2000UL void setup(){ pinMode(LED_Pin, OUTPUT); pinMode(BTN_Pin, INPUT_PULLUP); } void Blink (byte _LED_Pin, unsigned long interval){ static unsigned long prevTime=0; if (millis() - prevTime > interval){ prevTime = millis(); digitalWrite(_LED_Pin, !(digitalRead(_LED_Pin))); } } bool progTimer(unsigned long interval){ static unsigned long prevTime=0; if(millis()-prevTime>interval){ prevTime=millis(); return false; } else return true; } enum BTN_st{ NOT_PRESSED_ = 0, PRESSED_ = 1, HOLDED_ = 2, RELEASED_= 3 }; byte button_scan(){ static bool prev_BTN_State = false; // предыдущее состояние кнопки (нажата или нет) bool BTN_State = !(digitalRead(BTN_Pin)); // текущее состояние кнопки if (BTN_State==false && prev_BTN_State==false) {return NOT_PRESSED_; prev_BTN_State==false; } // кнопка не нажата if (BTN_State==true && prev_BTN_State==false) {return PRESSED_; prev_BTN_State==true; } // кнопка нажата if (BTN_State==true && prev_BTN_State==true) {return HOLDED_; prev_BTN_State==true; } // кнопка удерживается if (BTN_State==false && prev_BTN_State==true) {return RELEASED_; prev_BTN_State==false; } // отпущена } void loop(){ byte b_state = button_scan(); static bool t_state; switch(b_state){ case NOT_PRESSED_: if(!t_state) {Blink (LED_Pin, interval_slow); break; }// не нажата case PRESSED_:{ t_state = progTimer(ext_interval); if(t_state) Blink (LED_Pin, interval_fast); break;} } }Хотя интервалы времени (задержки перехода светодиода в другой режим) иногда отличаюся! Наверно стоит добавить ещё защиту от дребезга!
А кусочек кода с enum там такой:
enum BTN_st{ NOT_PRESSED_ = 0, PRESSED_ = 1, HOLDED_ = 2, RELEASED_= 3 };Я не знаю, что такое в данном случае BTN_st. Переменная или название перечисления, но обратите внимние, что в коде её вообще нету! Была строка
Но она закомментирована! А буквально её можно было бы расшифровать так: создать переменную типа BTN_st с названием b_state и присвоить ей значение NOT_PRESSED_ (кнопка не нажата). Или я ошибаюсь, и компилятор понимает это как-то по другому?
Мужики, Вас куда-то понесло, правда.
ТС, Всё Вы правильно объявили, всё нормально. И тип там нормальный и всё нормально (в коде полно других неправильностей на которые ругается компилятор, но с enum как раз всё окей).
Проблема стара как Ардуино IDE - охренительно дружественное для чайников решение, которое выносит все объявления функций в начало файла.
Для того, чтобы тип заработал нормально достаточно этот enum (никак не меняя) вынести в отдельный файл и включить его в основной при помощи #include. Включать надо как можно выше (например, первой строкой программы).
Всё сказанное относится к коду из стартового поста.
У енума есть хороший побочный эффект
И это не единственный его хороший эффект.
Им можно объявлять значения переменных для битовых полей и он сам позаботится, чтобы они влезли ы нужное количество бит. См. пример здесь.
Насколько я запомнил - выносить во внешний .h необязательно, достаточно объявить прототипы после enum и тогда IDE не будет их пихать выше радуги.
А вообще, вот так примерно с енумами обхожусь:
typedef enum { stInit = 0, stReady, stSteady, stGo, stFail } stages_t; stages_t whatStageIs(uint8_t); void setup() { Serial.begin(115200); Serial.println("Stages handling demo"); } void loop() { uint8_t number = random(4); switch (whatStageIs(number)) { case stInit: Serial.println("Init stage running"); break; case stReady: Serial.println("Ready stage running"); break; case stSteady: Serial.println("Steady stage running"); break; case stGo: Serial.println("Go stage running"); break; } } stages_t whatStageIs(uint8_t number) { stages_t returnStage; switch (number) { case 0: Serial.print("Init"); returnStage = stInit; break; case 1: Serial.print("Ready"); returnStage = stReady; break; case 2: Serial.print("Steady"); returnStage = stSteady; break; case 3: Serial.print("Go"); returnStage = stGo; break; default: Serial.print("None"); returnStage = stGo; break; } Serial.println(" stage matched"); return returnStage; }достаточно объявить прототипы после enum и тогда IDE не будет их пихать выше радуги.
Вполне возможно, я подробно не разбирался. Наткунлся как-то - выматерился и запомнил. Мне-то пофиг - я всегда много файлов пложу.
В люьом случае, ТС должен понимать, что у него всё нормально, проблема в "умности" IDE.
В люьом случае, ТС должен понимать, что у него всё нормально, проблема в "умности" IDE.
да где ж нормально, Евгений Петрович? Посмотрите на второй абзац заглавного сообщения,
BTN_scan_states button_scan(){Первое слово - тип возращаемого значения функции. По идее она должна вернуть состояние кнопки.
о какой функции тут вообще идет речь?
О функции button_scan
Вот, пожалуйста.
Файл xxx.ino
#include "kaka.h" BTN_scan_states button_scan() { return NOT_PRESSED; } void loop(void){} void setup(void){}Файл kaka.h
enum BTN_scan_states{ NOT_PRESSED = 0, PRESSED_ = 1, HOLDED_ = 2, RELEASED_= 3 };Можете убедиться, что всё компилируется нормально. И работать будет нормально, уверяю Вас.
Можете убедиться, что всё компилируется нормально. И работать будет нормально, уверяю Вас.
ну да, я уж и сам увидал - после первого вашего сообщения. Поначалу не заметил эту функцию в коде - думал это ТС так enum повторно описывает....
У меня появился ещё вопрос насчет НЕ логичного возвращение функцией значения! Вроде бы проще не бывает.
bool button_scan(){ bool BTN_State = !(digitalRead(BTN_Pin)); // текущее состояние кнопки static bool TimerSet; // активен ли ещё таймер if (BTN_State) {TimerSet = progTimer(ext_interval);} // если нажата, запустить таймер и считать состояние в переменную if (TimerSet) return true; // таймер активен if (!TimerSet) return false; // не активен }Тип bool, то есть функция возвращает 0 или 1. По идее она должна возвращать:
1. false в обычном состоянии - кнопка не нажата
2. true при нажатии кнопки и ещё в течении заданного времени (значение ext_interval) например 2 секунды.
На самом же деле false она возвращает только до нажатия кнопки, а дальше всё время true! Впечатление такое, что таймер запуcкается и прокручивается всё время, даже если кнопка не нажата! То есть условие
if (BTN_State) {TimerSet = progTimer(ext_interval);}как бы игнорируется? Посмотрите пожалуйста, кто разбирается, вот код целиком
#define LED_Pin 0 #define BTN_Pin 4 #define interval_slow 500UL #define interval_fast 50UL #define ext_interval 2000UL void setup(){ pinMode(LED_Pin, OUTPUT); pinMode(BTN_Pin, INPUT_PULLUP); } void Blink (byte _LED_Pin, unsigned long interval){ static unsigned long prevTime=0; if (millis() - prevTime > interval){ prevTime = millis(); digitalWrite(_LED_Pin, !(digitalRead(_LED_Pin))); } } bool progTimer(unsigned long interval){ static unsigned long prevTime=0; if(millis()-prevTime>interval){ prevTime=millis(); return false; } else return true; } bool button_scan(){ bool BTN_State = !(digitalRead(BTN_Pin)); // текущее состояние кнопки static bool TimerSet; // активен ли ещё таймер if (BTN_State) {TimerSet = progTimer(ext_interval);} // если нажата, запустить таймер // и считать состояние в переменную if (TimerSet) return true; // таймер активен if (!TimerSet) return false; // не активен } void loop(){ //button_scan(); if (button_scan()) Blink (LED_Pin, interval_fast); else Blink (LED_Pin, interval_slow); }Я гляну на код, но пока есть методологическое замечание. Ваши рассуждения правильны и полезны, но не на этой стадии работы. Я имею в ввиду вот это:
1. false в обычном состоянии - кнопка не нажата
2. true при нажатии кнопки и ещё в течении заданного времени (значение ext_interval) например 2 секунды.
Так рассуждают, когда проектируют программу и думают как её написать.
А вот на этапе поиска ошибки (на котором Вы сейчас находитесь) от таких рассуждений пользы не много. На этом этапе рассуждают на более низком уровен, а именно "По идее она должна возвращать true, если TimerSet равно true, и false в противном случае".
И, кстати, если бы Вы рассуждали так, то Вы бы немедленно заметили, что код можно упростить, а именно
А более простой код - это не только и не столько машинная эффективность, сколько "лучшая читаемость человеком", а значит лучший поиск ошибок.
Да. Вы правы. Такая запись гораздо проще. Я просто ещё плохо разбираюсь в синтаксисе! Спасибо за подсказку!
Если не сложно, подскажите пожалуйста, в данном случае
if (BTN_State) {TimerSet = progTimer(ext_interval);}таймер ведь будет обнуляться сам? Или нужно ещё что-то дописывать? Точнее переменная TimerSet сама обнулится, когда функция progTimer вернет false?
На самом же деле false она возвращает только до нажатия кнопки, а дальше всё время true! Впечатление такое, что таймер запуcкается и прокручивается всё время, даже если кнопка не нажата! То есть условие
if (BTN_State) {TimerSet = progTimer(ext_interval);}как бы игнорируется?
вы сами написали это условие так, что после отпускания кнопки оно игнорируется, ведь при отпущенной кнопке BTN_State - false. Так что таймер запускается, отсчитывает свои 2 сек и останоавливается, но поскольку переменную TimerSet вы не обновляете - она остается true
переменная TimerSet сама обнулится, когда функция progTimer вернет false?
конечно нет. С чего бы?
а как её можно обнулить? Напишите пожалуйста!
Переходите на стадию размышлений... Иначе как вы поймёте, что написанное кем-то будет работать, как полагается, а не случайным образом?
а как её можно обнулить? Напишите пожалуйста!
например, если TimerSet == true , запрашиваем состояние таймера и обновляем TimerSet
bool button_scan(){ bool BTN_State = !(digitalRead(BTN_Pin)); // текущее состояние кнопки static bool TimerSet; // активен ли ещё таймер if (BTN_State || TimerSet) {TimerSet = progTimer(ext_interval);} // если нажата, запустить таймер и считать состояние в переменную return TimerSet; }Большое спасибо за поссказку!
Те две черточки в строке
if (BTN_State || TimerSet) {TimerSet = progTimer(ext_interval);}Означают ИЛИ. То есть буквально
если кнопка нажата ИЛИ переменная TimerSet равна true, то присвоить переменной TimerSet значение из функции progTimer(ext_interval).
В итоге, если кнопка не нажата, то через интервал (ext_interval) в переменную TimerSet попадет false и функция вернет false!
junior_developer - все верно