Создание библиотек в среде Arduino
- Войдите на сайт для отправки комментариев
Ср, 23/12/2015 - 01:27
При написании программы для Arduino UNO всвязи в большим количеством функций возникла необходимость вынести их в отдельный файл или создать библиотеку ( в идеале).
Нашел две темы на вашем форуме, ссылки привожу: http://arduino.ru/forum/programmirovanie/kak-vynesti-funktsii-v-otdelnyi-fail-podklyuchaemyi-k-proektu, http://arduino.ru/Hacking/LibraryTutorial
Однако создать файлы с расширением "h" или "cpp" в среде Arduino невозможно.
Более того эти файлы и не открываются в среде Arduino. Можно, конечно, вынести их в текстовый редактор, например, WordPad или Блокнот, но как эти файлы компилировать, да и очень неудобно писать программу. Убедительная просьба, к тем, кто сталкивался с такой задачей, подскажите, что нужно сделать без установки Visual Studio.
Однако создать файлы с расширением "h" или "cpp" в среде Arduino невозможно.
1. Открываете любой скетч
2. В меню выбираете Эскиз|Добавить файл
3. Идетё к папке в которой лежит открытый скетч
4. Дойдя до папки, просто набираете имя файла (.cpp или .h) и файл создаётся и остаётся открытым у Вас в дополнительной вкладке.
Как отладите, переносите библиотеку в папку libraries или просто оставляете многофайловый скетч - я постоянно так делаю
Евгений, за совет спасибо. Попробовал. Работает. Буду разбираться дальше.
Тут правда, есть одна неприятность: среда почему-то открывает сразу все файлы, лежащие в текущей папаке. Если их больше 3-4 пар, то все вкладки в окошке уже не помещаются. Выбрать их, коначно, можно из ниспадающего списка, но IDE не показывает, с каким именно файлом в данный момет работаешь (если он не входит в число тех нескольких первых, которые помещаются на экране).
Тут правда, есть одна неприятность: среда почему-то открывает сразу все файлы, лежащие в текущей папаке. Если их больше 3-4 пар, то все вкладки в окошке уже не помещаются. Выбрать их, коначно, можно из ниспадающего списка, но IDE не показывает, с каким именно файлом в данный момет работаешь (если он не входит в число тех нескольких первых, которые помещаются на экране).
это не неприятность а фишка, причем очень удобная.
насчет вкладок - кто запрещает растянуть окно пошире, или вообще развернуть?
А еще можно дисплей купить пошире ;)
А еще можно дисплей купить пошире ;)
три
для ассемблерных портянок переворачиваем дисплей на 90 градусов,для ардуины добавляем 3 дисплея, ага?
ура,в 1.6.7 наконец появилось сворачивание блоков,может и вкладки сдвигаются,не пробовал,23 дюйма пока хватает и поработать и поиграться
У меня вооще 80см по диогонали телевизор в место монитора. :-)
Привет коллеги!
Подскажите где скачать библиотеку "ethernetudp.h"?
Заранее спасибо.
Ничего скачивать не надо. Это файл из библиотеки Ethernet, которая изначально есть в Arduino IDE.
Господа, в продолжение темы.
Выяснилась одна неприятность.
В файлы "cpp" и "h" перенес функции из основной программы.
Первое с чем стокнулся. Глобальные переменные - назначение входов/выходов контроллера, объявленные
в основной программе, функции в "cpp" файле не видят. Хотя по моему мнению они должны быть видны для всего проекта.
Второе. В исходной программе была подключена библиотека Ultrasonic.h. Так как ее нет в составе библиотек Arduino, пришлось загружать ее в среду через zip файл. В Include Library она оказалась в разделе "Contributed libraries". Принимаю на веру такое подключение сторонних библиотек.
В исходной программе библиотека подключилась и работает. Но "cpp" файл ее не видит. Включил в "cpp" файл
#include <Ultrasonic.h>. Теперь ругается компилятор:
sketch\lib_Robot_truck.cpp:1:24: fatal error: Ultrasonic.h: No such file or directory
#include <Ultrasonic.h>
Что я делаю не так???
Первое с чем стокнулся. Глобальные переменные - назначение входов/выходов контроллера, объявленные в основной программе, функции в "cpp" файле не видят. Хотя по моему мнению они должны быть видны для всего проекта.
А Вы их там объявили? Если нет, то с какого перепугу они будут видны? Глобальную переменную, определённую в одном файле, в другом необходимо объявить с аттрибутом extern
Про библиотеку. Победить безусловно можно, но я не слишком много балуюсь со сторонникими библиотеками, поэтому заочно дать рецепт не могу. Будь проблема у меня. я бы поэкспериментировал и победил бы.
Есть "лом", против которого не приёма - забудьте про zip и разместие её честно вместе со всеми системными библиотеками - должно сработать.
Если подняться вверх этой страницы, то Вы увидите ссылку: "Программирование", перейдя по ней, увидите другую ссылку: "Написание библиотеки для Arduino".
Ну а вообще, можно скачать любую, желательно простенькую библиотеку и посмотреть, как там все организовано.
Спасибо за ответ!
И еще вопросы, если не затруднит.
Я провел небольшое исследование по совместимости сред разработки и различных скетчей для Ping:
http://arduino.ru/forum/programmirovanie/platformy-arduino
Платформы Arduino.
Что посоветуете?
С уважением, alexnik100
это не неприятность а фишка, причем очень удобная.
насчет вкладок - кто запрещает растянуть окно пошире, или вообще развернуть?
Интересно, наскоько нужно распахнуть окно, чтобы в нем помещались названия 60 файлов. При том, что осмысленные названия, как правило, не короче 15-20 символов.
А еще если синхронно программируешь две Ардуины, и нужно два окошка IDE и две консоди COM-порта...
В общем, для серьезных проектов фишка ОЧЕНЬ неудобная.
Здравствуйте, ранее не создал собственных библиотек в среде, Создал папку "common" и перенес туда все реализации h*,c*. После перенес ее в хранилище сторонних библиотек (Мои документы\Arduino\libraries). Но среда сильно ругается, подскажите как решить
Файл с расширением .ino
#include "common.h" #include <LiquidCrystal.h> LiquidCrystal lcd(7, 6, 5, 4, 3, 2); //####################################################################################################################### uint8_t pageNum = 0; // счетчик нажатий кнопки enum switchVariants : byte { // Определения для переключателя пунктов меню; MAIN_MENU, MENU_MANUAL, MENU_AUTO, MENU_SETUP, MENU_DEBUG//, EXITSAVE }; switchVariants switchPointer = MAIN_MENU; // С чего начнем цикл; enum manuState : byte { // Определения для переключателя ручного режима; EDIT_PARAM, HEAT_ZONE, COOL_ZONE, STOP_PROCESS, EXIT_PROCESS }; manuState mode = EDIT_PARAM; // С чего начнем цикл; static SELECTION menu_m0[]={ {MENU_MANUAL , MAIN_MENU}, }; static SELECTION menu_m1[]={ {MENU_AUTO, MAIN_MENU}, }; static SELECTION menu_m2[]={ {MENU_SETUP, MAIN_MENU} }; static SELECTION menu_m3[]={ {MENU_DEBUG, MAIN_MENU} }; static PAGE_MENU menu[] = { menu_m0, //Меню 1 menu_m1, //Меню 2 menu_m2, //Меню 3 menu_m3 //Меню 4 }; const uint8_t MN000[] PROGMEM="REWORK v05\0"; //меню 1 const uint8_t MN100[] PROGMEM="SETTINGS\0"; //подпункт меню const uint8_t MN101[] PROGMEM="STEPS:\0"; const uint8_t MN102[] PROGMEM="DWELL:\0"; const uint8_t MN103[] PROGMEM="PWR:\0"; const uint8_t MN104[] PROGMEM="RAMP:\0"; const uint8_t MN105[] PROGMEM="TARGET:\0"; //меню 2 const uint8_t MN200[] PROGMEM="MANUAL\0"; //подпункт меню 2 const uint8_t MN201[] PROGMEM="EDIT\0"; const uint8_t MN202[] PROGMEM="HEAT\0"; //меню 3 const uint8_t MN300[] PROGMEM="AUTO\0"; //подпункт меню 3 const uint8_t MN301[] PROGMEM="TEMP\0"; //меню 4 const uint8_t MN400[] PROGMEM="DEBUG\0"; //подпункт меню 4 const uint8_t MN401[] PROGMEM="COM\0"; //Массивы указателей на строки меню, хранящиеся на флэш const uint8_t *MENU[] ={ MN100, //menu 1 string MN200, //menu 2 string MN300, //menu 3 string MN400 //menu 4 string }; const uint8_t *SUBMENU[] ={ MN101, MN102, MN103, MN104, MN105, //подпункты меню 1 MN201, MN202, //подпункты меню 2 MN301, //подпункты меню 3 MN401, //подпункты меню 4 }; //Структура меню //[0] -Number of level 0 menu items //[1]...[n] number of second level menu items //Eg. MSTR2[1] shows that menu item 1 has 3 subMenus const uint8_t MSTR2[] PROGMEM ={ 4, // количество пунктов меню 5, //Количество подпунктов в пункте меню 1 2, //Количество подпунктов в пункте меню 2 1, //Количество подпунктов в пункте меню 3 1 //Количество подпунктов в пункте меню 4 }; //Прототипы функций //Инициализация Timer2 void init_timer2(void); //Начальное меню //void menu_Init(void); //Назначаем порты для кнопок и светодиодов void ports_Init(void); //Функции для каждого пункта меню void func101(void); void func102(void); void func103(void); void func104(void); void func105(void); void func201(void); void func202(void); void func301(void); void func401(void); //#define NULL_FUNC (void*)0 //Массив указателей на функции во флэш const FuncPtr FuncPtrTable[] PROGMEM= { func101, func102, func103, func104, func105, //functions for subMenus of menu 1 func201, func202, //functions for subMenus of menu 2 func301, //functions for subMenus of menu 3 func401 //functions for subMenus of menu 4 }; //subMenu and Function table pointer update uint8_t MFIndex(uint8_t, uint8_t); //------------------------------------------ //####################################################################################################################### //current editing step pointer uint8_t editStep = 0; struct reflowStation : public Printable { uint8_t rampRateStep = 0; // uint8_t temperatureStep = 0; // uint8_t dwellTimerStep = 0; // uint8_t pwr_TOP = 60; //максимальная мощность верхнего нагревателя uint8_t pwr_BOTTOM = 90; //максимальная мощность нижнего нагревателя size_t printTo(Print& p) const { size_t res; if (MN.subMenu == 1) res = p.print(pwr_BOTTOM); else if (MN.subMenu == 2) res = p.print(pwr_TOP); else if (MN.subMenu == 3) res = p.print(rampRateStep); else if (MN.subMenu == 4) res = p.print(temperatureStep); else if (MN.subMenu == 5) res = p.print(dwellTimerStep); return res; } } profile; //################################################################################## void setup() { //Serial.begin(9600); lcd.begin(20, 4); lcd.home(); //Приветствие CopyStringtoLCD(MN000, 3, 1); _delay_ms(100); lcd.clear(); //Настройка таймера 2 ports_Init(); init_timer2(); // каждые 100 Гц sei(); // разрешаем прерывания глобально interrupts(); } void loop() { char BtnMask = BtnGet(); /* lcd.clear(); //Display menu item CopyStringtoLCD(MENU[MN.menu-1], 0, 0 ); //Display subMenu item CopyStringtoLCD(SUBMENU[MFIndex(MN.menu, MN.subMenu)], 0, 1 ); //Assign function to function pointer FPtr=(FuncPtr)pgm_read_word(&FuncPtrTable[MFIndex(MN.menu, MN.subMenu)]); */ if (BtnMask == BTN_SHRT_OK) { lcd.clear(); static uint8_t i = 0; if (!i) { switchPointer = (switchVariants) menu[pageNum].m[0].ent_f; i=1; menu_Init(&pageNum); //Initial menu and initial function } //switchPointer = current_menu; //last_item=current_poz; //f = menu[pageNum].m[0].esc_f; else { switchPointer = (switchVariants) menu[pageNum].m[0].esc_f; i=0; } }//обработка короткого нажатия ВВЕРХ if (BtnMask == BTN_SHRT_CANSEL) { }//обработка короткого нажатия ВЛЕВО switch (switchPointer) // Все делаем в одном операторе и одной функции; { case MAIN_MENU: /***************** Главное меню ***************/ startMenu(); //формирование меню if (BtnMask == BTN_SHRT_RIGHT) //обработка короткого нажатия ВПРАВО { pageNum++; // с каждым нажатием pageNum++ пока pageNum<4 if (pageNum > 3) pageNum = 0; } if (BtnMask == BTN_SHRT_LEFT) { //pageNum--; //if (pageNum <= 0) pageNum = 0; }//обработка короткого нажатия ВЛЕВО //if (BtnMask == BTN_LONG_UP) { }//обработка длинного нажатия ВВЕРХ //if (BtnMask == BTN_LONG_DN) {}//обработка длинного нажатия ВНИЗ //if (BtnMask == BTN_LONG_RIGHT) {}//обработка длинного нажатия ВПРАВО //if (BtnMask == BTN_LONG_LEFT) {}//обработка длинного нажатия ВЛЕВО break; case MENU_MANUAL: /***************** Ручной режим ***************/ if (BtnMask == BTN_SHRT_RIGHT) //обработка короткого нажатия ВПРАВО { if (MN.subMenu<pgm_read_byte(&MSTR2[MN.mMenu])) MN.subMenu++; else MN.subMenu=1; alexMenu(); } if (BtnMask == BTN_SHRT_UP) { if (MN.subMenu == 1) profile.pwr_BOTTOM++; else if (MN.subMenu == 2) profile.pwr_TOP+=5; else if (MN.subMenu == 3) profile.temperatureStep+=5; else if (MN.subMenu == 4) profile.temperatureStep+=1; else if (MN.subMenu == 5) profile.dwellTimerStep+=1; }//обработка короткого нажатия ВВЕРХ if (BtnMask == BTN_SHRT_DN) { } lcd.setCursor(0,2); lcd.print(profile); switch (mode) { // Выбор режима работы ручного режима case EDIT_PARAM: // Режим редактирования break; case HEAT_ZONE: break; case COOL_ZONE: break; case STOP_PROCESS: break; } break; case MENU_AUTO: /***************** Автоматический режим ***************/ break; case MENU_SETUP: /***************** Настройки ***************/ break; case MENU_DEBUG: /***************** Настройки ***************/ break; } } //####################################################################################################################### //----------------------------------------------------------------------------------------------------------------------- void ports_Init(void) { BTN_DDR &= ~(BTN_LINE_UP| BTN_LINE_DN| BTN_LINE_OK| BTN_LINE_LEFT| BTN_LINE_RIGHT| BTN_LINE_CANSEL); // кнопки на ввод BTN_PORT |= (BTN_LINE_UP| BTN_LINE_DN| BTN_LINE_OK| BTN_LINE_LEFT| BTN_LINE_RIGHT| BTN_LINE_CANSEL); //подтяжка вкл } //----------------------------------------------------------------------------------------------------------------------- void CopyStringtoLCD(const uint8_t *FlashLoc, uint8_t x, uint8_t y) { uint8_t i; lcd.setCursor(x,y); for(i=0;(uint8_t)pgm_read_byte(&FlashLoc[i]);i++) { lcd.write((uint8_t)pgm_read_byte(&FlashLoc[i])); } } //------------------------------------------ void menu_Init(uint8_t *page) { MN.mMenu = *page+1; MN.subMenu = 1; lcd.clear(); CopyStringtoLCD(MENU[MN.mMenu-1], 0, 0 ); CopyStringtoLCD(SUBMENU[MFIndex(MN.mMenu, MN.subMenu)], 0, 1 ); //FPtr=(FuncPtr)pgm_read_word(&FuncPtrTable[0]); } //------------------------------------------ void alexMenu(void) { lcd.clear(); //Display menu item CopyStringtoLCD(MENU[MN.mMenu-1], 0, 0 ); //Display subMenu item CopyStringtoLCD(SUBMENU[MFIndex(MN.mMenu, MN.subMenu)], 0, 1 ); //Assign function to function pointer //FPtr=(FuncPtr)pgm_read_word(&FuncPtrTable[MFIndex(MN.mMenu, MN.subMenu)]); } //------------------------------------------ uint8_t MFIndex(uint8_t mn, uint8_t sb) { uint8_t p=0;//points to menu in table of function pointer for(uint8_t i=0; i<(mn-1); i++) { p=p+pgm_read_byte(&MSTR2[i+1]); } p=p+sb-1; return p; } //------------------------------------------ void func101(void) { } void func102(void) { } void func103(void) { } void func104(void) { } void func105(void) { } void func201(void) { } void func202(void) { } void func301(void) { } void func302(void) { } void func401(void) { } void setString(unsigned char *bcount) { static uint8_t pos_y_curs = 4; lcd.setCursor(0, *bcount); lcd.write(62); if (bcount == 0) *bcount = pos_y_curs; lcd.setCursor(0, *bcount - 1); lcd.write(32); } void startMenu(){ setString(&pageNum); // включаем отображение стрелки выбора меню lcd.setCursor(1, 0); // 1 строка lcd.print(F("PY HO ")); // ручной режим lcd.setCursor(1, 1); // 2 строка lcd.print(F("ABTOMAT ECK")); // автоматический режим lcd.setCursor(1, 2); // 3 строка lcd.print(F("HACTPO K ")); // настройки lcd.setCursor(1, 3); // 4 строка lcd.print(F("OT A KA")); // отладка }Файлы библиотеки
common.h
buttonLib.h
buttonLib.c
#include "buttonLib.h" void BtnExe (void) { static unsigned char BtnLockBit = 0; //защелка (защита от дребезга) static unsigned char BtnLockCount = 0; //счетчик защелки (защита от дребезга) static unsigned char BtnLongCount = 0; //счетчик длинного нажатия static unsigned char BtnLastState= 0; //последнее состояние кнопок перед отпусканием char mask = 0; /*if (! (BTN_PIN & BTN_LINE_UP)) mask = BTN_SHRT_UP; if (! (BTN_PIN & BTN_LINE_DN)) mask = BTN_SHRT_DN; if (! (BTN_PIN & BTN_LINE_LEFT)) mask = BTN_SHRT_LEFT; if (! (BTN_PIN & BTN_LINE_RIGHT)) mask = BTN_SHRT_RIGHT;*/ if (! (BTN_PIN & BTN_LINE_DN)) mask = BTN_SHRT_DN; if (! (BTN_PIN & BTN_LINE_UP)) mask = BTN_SHRT_UP; if (! (BTN_PIN & BTN_LINE_OK)) mask = BTN_SHRT_OK; if (! (BTN_PIN & BTN_LINE_LEFT)) mask = BTN_SHRT_LEFT; if (! (BTN_PIN & BTN_LINE_RIGHT)) mask = BTN_SHRT_RIGHT; if (! (BTN_PIN & BTN_LINE_CANSEL)) mask = BTN_SHRT_CANSEL; if (mask){ //опрос состояния кнопки if (BtnLockCount < (BTN_LOCK_TIME/10)){ //клавиша нажата BtnLockCount++; return; //защелка еще не дощитала - возврат } BtnLastState = mask; BtnLockBit =1; //нажатие зафиксировано //if (BtnLongCount >= (BTN_LONG_TIME/10)) // return; //возврат, т.к. счетчик длинн нажат досчитал до максимума еще раньше //if (++BtnLongCount >= (BTN_LONG_TIME/10)) // BtnFlags |= (BtnLastState<<4); //счетчик досчитал до максимума - устанавливаем биты длинного нажатия } else{ //клавиша отжата if (BtnLockCount){ BtnLockCount --; return; //защелка еще не обнулилась - возврат } if (! BtnLockBit) //СТАТИЧЕСКИЙ ВОЗВРАТ return; BtnLockBit =0; //отжатие зафиксировано if (BtnLongCount < (BTN_LONG_TIME/10)) BtnFlags |= BtnLastState; //установка бита короткого нажатия //BtnLongCount = 0; //сброс счетчика длительности нажатия } }def.h
menu_config.h
#ifndef MENU_CONFIG_H #define MENU_CONFIG_H //#include "main.h" //------------------------------------------ typedef void (*FuncPtr)(void); //указатель на функции FuncPtr FPtr; //Структура описывает текущее состояние меню и подменю struct Menu_State{ uint8_t mMenu;//1,2,3,4 uint8_t subMenu;//1,2,3 }MN; typedef struct _selection { unsigned char ent_f : 4; //Флаг входа 4 бита — обычно ID меню в которое надо войти unsigned char esc_f : 4; //Флаг выхода 4 бита — обычно ID меню в которое надо вернуться }SELECTION; typedef struct _menu { //unsigned char id; //Номер меню/подменю //unsigned char num_selections; //Количество Punktов данного меню/подменю SELECTION *m; //Указатель намассив Punktов данного меню/подменю } PAGE_MENU; #endifpin_config.h
#ifndef PIN_CONFIG_H #define PIN_CONFIG_H //#include "commmon.h" //настройка параметров работы функций #define BTN_LOCK_TIME 30 /*время обработки дребезга в милисекундах (10-100)*/ #define BTN_LONG_TIME 1000 /*время фиксации длинного нажатия в милисекундах (1000 - 2500)*/ //настройки портов #define BTN_PORT PORTB /*порт чтения кнопок*/ #define BTN_DDR DDRB #define BTN_PIN PINB #define BTN_LINE_DN (1<<0) /*пины чтения кнопок*/ #define BTN_LINE_UP (1<<1) #define BTN_LINE_OK (1<<2) #define BTN_LINE_LEFT (1<<3) #define BTN_LINE_RIGHT (1<<4) #define BTN_LINE_CANSEL (1<<5) //глобальные переменные volatile uint8_t BtnFlags; //байт флагов нажатия кнопки //#define BTN_LONG_UP (1<<4) /*бит длинного нажатия кнопки up*/ //#define BTN_LONG_DN (1<<5) /*бит длинного нажатия кнопки dn*/ //#define BTN_LONG_LEFT (1<<6) /*бит длинного нажатия кнопки left*/ //#define BTN_LONG_RIGHT (1<<7) /*бит длинного нажатия кнопки right*/ #define BTN_SHRT_DN (1<<0) /*бит короткого нажатия кнопки up*/ #define BTN_SHRT_UP (1<<1) /*бит короткого нажатия кнопки dn*/ #define BTN_SHRT_OK (1<<2) /*бит короткого нажатия кнопки up*/ #define BTN_SHRT_LEFT (1<<3) /*бит короткого нажатия кнопки left*/ #define BTN_SHRT_RIGHT (1<<4) /*бит короткого нажатия кнопки right*/ #define BTN_SHRT_CANSEL (1<<5) /*бит короткого нажатия кнопки right*/ //############################################################################################################## #define RELAY_PORT PORTC /*порт чтения кнопок*/ #define RELAY_BTM PC0 //назначаем пин "НИЖНЕГО" нагревателя #define RELAY_TOP PC1 //назначаем пин "ВЕРХНЕГО" нагревателя #define PIN_BUZZER 3 // назначаем пин для пьезодинамика #endiftimer.h
timer.c
#include "timer.h" void init_timer2(void) { TCCR2B=0; // таймер2 остановлен TCNT2=0; //счётный регистр обнулён OCR2B=0; TIFR2&=0xff; //отчистить флаги прерываний TCCR2A = (1<<WGM21); // Режим CTC (сброс по совпадению) TCCR2B = (1<<CS20)|(1<<CS21)|(1<<CS22); // CLK/1024 OCR2A = 155; TIMSK2 = (1<<OCIE2A); // Разрешить прерывание по совпадению } ISR(TIMER2_COMPA_vect) { //BtnExe(); }положите все эти файлы в одну папку со скетчем
Выдало множество ошибок
Build options changed, rebuilding all Using library LiquidCrystal in folder: D:\Саша\1.6.0\arduino-1.6.0\libraries\LiquidCrystal D:\Саша\1.6.0\arduino-1.6.0/hardware/tools/avr/bin/avr-gcc -c -g -Os -w -ffunction-sections -fdata-sections -MMD -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=10600 -DARDUINO_AVR_UNO -DARDUINO_ARCH_AVR -ID:\Саша\1.6.0\arduino-1.6.0\hardware\arduino\avr\cores\arduino -ID:\Саша\1.6.0\arduino-1.6.0\hardware\arduino\avr\variants\standard -ID:\Саша\1.6.0\arduino-1.6.0\libraries\LiquidCrystal\src C:\DOCUME~1\9335~1\LOCALS~1\Temp\build7163073385139009280.tmp\buttonLib.c -o C:\DOCUME~1\9335~1\LOCALS~1\Temp\build7163073385139009280.tmp\buttonLib.c.o C:\DOCUME~1\9335~1\LOCALS~1\Temp\build7163073385139009280.tmp\buttonLib.c: In function 'BtnExe': C:\DOCUME~1\9335~1\LOCALS~1\Temp\build7163073385139009280.tmp\buttonLib.c:16:12: error: 'BTN_PIN' undeclared (first use in this function) if (! (BTN_PIN & BTN_LINE_DN)) mask = BTN_SHRT_DN; ^ C:\DOCUME~1\9335~1\LOCALS~1\Temp\build7163073385139009280.tmp\buttonLib.c:16:12: note: each undeclared identifier is reported only once for each function it appears in C:\DOCUME~1\9335~1\LOCALS~1\Temp\build7163073385139009280.tmp\buttonLib.c:16:22: error: 'BTN_LINE_DN' undeclared (first use in this function) if (! (BTN_PIN & BTN_LINE_DN)) mask = BTN_SHRT_DN; ^ C:\DOCUME~1\9335~1\LOCALS~1\Temp\build7163073385139009280.tmp\buttonLib.c:16:50: error: 'BTN_SHRT_DN' undeclared (first use in this function) if (! (BTN_PIN & BTN_LINE_DN)) mask = BTN_SHRT_DN; ^ C:\DOCUME~1\9335~1\LOCALS~1\Temp\build7163073385139009280.tmp\buttonLib.c:17:22: error: 'BTN_LINE_UP' undeclared (first use in this function) if (! (BTN_PIN & BTN_LINE_UP)) mask = BTN_SHRT_UP; ^ C:\DOCUME~1\9335~1\LOCALS~1\Temp\build7163073385139009280.tmp\buttonLib.c:17:50: error: 'BTN_SHRT_UP' undeclared (first use in this function) if (! (BTN_PIN & BTN_LINE_UP)) mask = BTN_SHRT_UP; ^ C:\DOCUME~1\9335~1\LOCALS~1\Temp\build7163073385139009280.tmp\buttonLib.c:18:22: error: 'BTN_LINE_OK' undeclared (first use in this function) if (! (BTN_PIN & BTN_LINE_OK)) mask = BTN_SHRT_OK; ^ C:\DOCUME~1\9335~1\LOCALS~1\Temp\build7163073385139009280.tmp\buttonLib.c:18:50: error: 'BTN_SHRT_OK' undeclared (first use in this function) if (! (BTN_PIN & BTN_LINE_OK)) mask = BTN_SHRT_OK; ^ C:\DOCUME~1\9335~1\LOCALS~1\Temp\build7163073385139009280.tmp\buttonLib.c:19:22: error: 'BTN_LINE_LEFT' undeclared (first use in this function) if (! (BTN_PIN & BTN_LINE_LEFT)) mask = BTN_SHRT_LEFT; ^ C:\DOCUME~1\9335~1\LOCALS~1\Temp\build7163073385139009280.tmp\buttonLib.c:19:50: error: 'BTN_SHRT_LEFT' undeclared (first use in this function) if (! (BTN_PIN & BTN_LINE_LEFT)) mask = BTN_SHRT_LEFT; ^ C:\DOCUME~1\9335~1\LOCALS~1\Temp\build7163073385139009280.tmp\buttonLib.c:20:22: error: 'BTN_LINE_RIGHT' undeclared (first use in this function) if (! (BTN_PIN & BTN_LINE_RIGHT)) mask = BTN_SHRT_RIGHT; ^ C:\DOCUME~1\9335~1\LOCALS~1\Temp\build7163073385139009280.tmp\buttonLib.c:20:50: error: 'BTN_SHRT_RIGHT' undeclared (first use in this function) if (! (BTN_PIN & BTN_LINE_RIGHT)) mask = BTN_SHRT_RIGHT; ^ C:\DOCUME~1\9335~1\LOCALS~1\Temp\build7163073385139009280.tmp\buttonLib.c:21:22: error: 'BTN_LINE_CANSEL' undeclared (first use in this function) if (! (BTN_PIN & BTN_LINE_CANSEL)) mask = BTN_SHRT_CANSEL; ^ C:\DOCUME~1\9335~1\LOCALS~1\Temp\build7163073385139009280.tmp\buttonLib.c:21:50: error: 'BTN_SHRT_CANSEL' undeclared (first use in this function) if (! (BTN_PIN & BTN_LINE_CANSEL)) mask = BTN_SHRT_CANSEL; ^ C:\DOCUME~1\9335~1\LOCALS~1\Temp\build7163073385139009280.tmp\buttonLib.c:24:29: error: 'BTN_LOCK_TIME' undeclared (first use in this function) if (BtnLockCount < (BTN_LOCK_TIME/10)){ //клавиша нажата ^ C:\DOCUME~1\9335~1\LOCALS~1\Temp\build7163073385139009280.tmp\buttonLib.c:43:29: error: 'BTN_LONG_TIME' undeclared (first use in this function) if (BtnLongCount < (BTN_LONG_TIME/10)) ^ C:\DOCUME~1\9335~1\LOCALS~1\Temp\build7163073385139009280.tmp\buttonLib.c:44:13: error: 'BtnFlags' undeclared (first use in this function) BtnFlags |= BtnLastState; //установка бита короткого нажатия ^ Ошибка компиляции.Какой тайный смысл Вы видите в строке
#include "common.h"
?
скажу Вам по секрету, она ищет файл common.h в той же попке, что и скетч.
Если у Вас все файлы лежат папке common, а та, в свою очередь в arduino\libraries, так Вы так и пишите
#include <common/common.h>
Какой тайный смысл Вы видите в строке
#include "common.h"
?
скажу Вам по секрету, она ищет файл common.h в той же попке, что и скетч.
Если у Вас все файлы лежат папке common, а та, в свою очередь в arduino\libraries, так Вы так и пишите
#include <common/common.h>
Спасибо за достаточно подробный ответ. Теперь мне стало понятно почему следует поместить файлы в папке со скетчем
А мне нет. Если эти файлы предполагается использовать во многих скетчах, то поместить их надо как раз в общую папку, просто ссылаться на них надо правильно.
Я собираюсь их использовать только в текущем скетче. Поэтому все заголовочные файлы и скетч будут лежать в одной папке
Нормально. Можете в подпапке скетча (чтобы под ногами не путались), тогда укажете
#include "podpapka/common.h"
За хороший совет благодарю но оставил как есть
Посоветуйте как мне решить часть ошибок
Файл с расширением .ino
#include "common.h" #include <LiquidCrystal.h> LiquidCrystal lcd(7, 6, 5, 4, 3, 2); //####################################################################################################################### uint8_t pageNum = 0; // счетчик нажатий кнопки //unsigned char current_menu=0; //Переменная указывает на текущее меню //unsigned char current_poz=0; //Переменная указывает на текущий Punkt меню/подменю //char last_item; unsigned char f; //####################################################################################################################### enum switchVariants : byte { // Определения для переключателя пунктов меню; MAIN_MENU, MENU_MANUAL, MENU_AUTO, MENU_SETUP, MENU_DEBUG//, EXITSAVE }; switchVariants switchPointer = MAIN_MENU; // С чего начнем цикл; enum manuState : byte { // Определения для переключателя ручного режима; EDIT_PARAM, HEAT_ZONE, COOL_ZONE, STOP_PROCESS, EXIT_PROCESS }; manuState mode = EDIT_PARAM; // С чего начнем цикл; static SELECTION menu_m0[]={ {MENU_MANUAL , MAIN_MENU}, }; static SELECTION menu_m1[]={ {MENU_AUTO, MAIN_MENU}, }; static SELECTION menu_m2[]={ {MENU_SETUP, MAIN_MENU} }; static SELECTION menu_m3[]={ {MENU_DEBUG, MAIN_MENU} }; static PAGE_MENU menu[] = { menu_m0, //Меню 1 menu_m1, //Меню 2 menu_m2, //Меню 3 menu_m3 //Меню 4 }; const uint8_t MN000[] PROGMEM="REWORK v05\0"; //меню 1 const uint8_t MN100[] PROGMEM="SETTINGS\0"; //подпункт меню const uint8_t MN101[] PROGMEM="STEPS:\0"; const uint8_t MN102[] PROGMEM="DWELL:\0"; const uint8_t MN103[] PROGMEM="PWR:\0"; const uint8_t MN104[] PROGMEM="RAMP:\0"; const uint8_t MN105[] PROGMEM="TARGET:\0"; //меню 2 const uint8_t MN200[] PROGMEM="MANUAL\0"; //подпункт меню 2 const uint8_t MN201[] PROGMEM="EDIT\0"; const uint8_t MN202[] PROGMEM="HEAT\0"; //меню 3 const uint8_t MN300[] PROGMEM="AUTO\0"; //подпункт меню 3 const uint8_t MN301[] PROGMEM="TEMP\0"; //меню 4 const uint8_t MN400[] PROGMEM="DEBUG\0"; //подпункт меню 4 const uint8_t MN401[] PROGMEM="COM\0"; //Массивы указателей на строки меню, хранящиеся на флэш const uint8_t *MENU[] ={ MN100, //menu 1 string MN200, //menu 2 string MN300, //menu 3 string MN400 //menu 4 string }; const uint8_t *SUBMENU[] ={ MN101, MN102, MN103, MN104, MN105, //подпункты меню 1 MN201, MN202, //подпункты меню 2 MN301, //подпункты меню 3 MN401, //подпункты меню 4 }; //Структура меню //[0] -Number of level 0 menu items //[1]...[n] number of second level menu items //Eg. MSTR2[1] shows that menu item 1 has 3 subMenus const uint8_t MSTR2[] PROGMEM ={ 4, // количество пунктов меню 5, //Количество подпунктов в пункте меню 1 2, //Количество подпунктов в пункте меню 2 1, //Количество подпунктов в пункте меню 3 1 //Количество подпунктов в пункте меню 4 }; //Прототипы функций //Инициализация Timer2 void init_timer2(void); //Начальное меню //void menu_Init(void); //Назначаем порты для кнопок и светодиодов void ports_Init(void); //Функции для каждого пункта меню void func101(void); void func102(void); void func103(void); void func104(void); void func105(void); void func201(void); void func202(void); void func301(void); void func401(void); //#define NULL_FUNC (void*)0 //Массив указателей на функции во флэш const FuncPtr FuncPtrTable[] PROGMEM= { func101, func102, func103, func104, func105, //functions for subMenus of menu 1 func201, func202, //functions for subMenus of menu 2 func301, //functions for subMenus of menu 3 func401 //functions for subMenus of menu 4 }; //subMenu and Function table pointer update uint8_t MFIndex(uint8_t, uint8_t); //------------------------------------------ //####################################################################################################################### //current editing step pointer uint8_t editStep = 0; /*struct reflowStation : public Printable { uint8_t rampRateStep = 0; // uint8_t temperatureStep = 0; // uint8_t dwellTimerStep = 0; // uint8_t pwr_TOP = 60; //максимальная мощность верхнего нагревателя uint8_t pwr_BOTTOM = 90; //максимальная мощность нижнего нагревателя //int Setpoint2; //float kp1, kd1, ki1; // коэффициенты пид "НИЖНЕГО" нагревателя //float kp2, kd2, ki2; // коэффициенты пид "ВЕРХНЕГО" нагревателя size_t printTo(Print& p) const { size_t res; if (MN.subMenu == 1) res = p.print(pwr_BOTTOM); else if (MN.subMenu == 2) res = p.print(pwr_TOP); else if (MN.subMenu == 3) res = p.print(rampRateStep); else if (MN.subMenu == 4) res = p.print(temperatureStep); else if (MN.subMenu == 5) res = p.print(dwellTimerStep); return res; } } profile;*/ //################################################################################## void setup() { //Serial.begin(9600); lcd.begin(20, 4); lcd.home(); //Приветствие CopyStringtoLCD(MN000, 3, 1); _delay_ms(100); lcd.clear(); //Настройка таймера 2 ports_Init(); init_timer2(); // каждые 100 Гц sei(); // разрешаем прерывания глобально interrupts(); } void loop() { char BtnMask = BtnGet(); /* lcd.clear(); //Display menu item CopyStringtoLCD(MENU[MN.menu-1], 0, 0 ); //Display subMenu item CopyStringtoLCD(SUBMENU[MFIndex(MN.menu, MN.subMenu)], 0, 1 ); //Assign function to function pointer FPtr=(FuncPtr)pgm_read_word(&FuncPtrTable[MFIndex(MN.menu, MN.subMenu)]); */ if (BtnMask == BTN_SHRT_OK) { lcd.clear(); static uint8_t i = 0; if (!i) { switchPointer = (switchVariants) menu[pageNum].m[0].ent_f; i=1; menu_Init(&pageNum); //Initial menu and initial function } //switchPointer = current_menu; //last_item=current_poz; //f = menu[pageNum].m[0].esc_f; else { switchPointer = (switchVariants) menu[pageNum].m[0].esc_f; i=0; } }//обработка короткого нажатия ВВЕРХ if (BtnMask == BTN_SHRT_CANSEL) { }//обработка короткого нажатия ВЛЕВО switch (switchPointer) // Все делаем в одном операторе и одной функции; { case MAIN_MENU: /***************** Главное меню ***************/ startMenu(); //формирование меню if (BtnMask == BTN_SHRT_RIGHT) //обработка короткого нажатия ВПРАВО { pageNum++; // с каждым нажатием pageNum++ пока pageNum<4 if (pageNum > 3) pageNum = 0; } if (BtnMask == BTN_SHRT_LEFT) { //pageNum--; //if (pageNum <= 0) pageNum = 0; }//обработка короткого нажатия ВЛЕВО //if (BtnMask == BTN_LONG_UP) { }//обработка длинного нажатия ВВЕРХ //if (BtnMask == BTN_LONG_DN) {}//обработка длинного нажатия ВНИЗ //if (BtnMask == BTN_LONG_RIGHT) {}//обработка длинного нажатия ВПРАВО //if (BtnMask == BTN_LONG_LEFT) {}//обработка длинного нажатия ВЛЕВО break; case MENU_MANUAL: /***************** Ручной режим ***************/ if (BtnMask == BTN_SHRT_RIGHT) //обработка короткого нажатия ВПРАВО { if (MN.subMenu<pgm_read_byte(&MSTR2[MN.mMenu])) MN.subMenu++; else MN.subMenu=1; alexMenu(); } if (BtnMask == BTN_SHRT_UP) { /*if (MN.subMenu == 1) profile.pwr_BOTTOM++; else if (MN.subMenu == 2) profile.pwr_TOP+=5; else if (MN.subMenu == 3) profile.temperatureStep+=5; else if (MN.subMenu == 4) profile.temperatureStep+=1; else if (MN.subMenu == 5) profile.dwellTimerStep+=1;*/ }//обработка короткого нажатия ВВЕРХ if (BtnMask == BTN_SHRT_DN) { } //lcd.setCursor(0,2); //lcd.print(profile); switch (mode) { // Выбор режима работы ручного режима case EDIT_PARAM: // Режим редактирования break; case HEAT_ZONE: break; case COOL_ZONE: break; case STOP_PROCESS: break; } break; case MENU_AUTO: /***************** Автоматический режим ***************/ break; case MENU_SETUP: /***************** Настройки ***************/ break; case MENU_DEBUG: /***************** Настройки ***************/ break; } } //####################################################################################################################### //----------------------------------------------------------------------------------------------------------------------- //функция настройки библиотеки работы с кнопками void ports_Init(void) { BTN_DDR &= ~(BTN_LINE_UP| BTN_LINE_DN| BTN_LINE_OK| BTN_LINE_LEFT| BTN_LINE_RIGHT| BTN_LINE_CANSEL); // кнопки на ввод BTN_PORT |= (BTN_LINE_UP| BTN_LINE_DN| BTN_LINE_OK| BTN_LINE_LEFT| BTN_LINE_RIGHT| BTN_LINE_CANSEL); //подтяжка вкл } //----------------------------------------------------------------------------------------------------------------------- void CopyStringtoLCD(const uint8_t *FlashLoc, uint8_t x, uint8_t y) { uint8_t i; lcd.setCursor(x,y); for(i=0;(uint8_t)pgm_read_byte(&FlashLoc[i]);i++) { lcd.write((uint8_t)pgm_read_byte(&FlashLoc[i])); } } //------------------------------------------ void menu_Init(uint8_t *page) { MN.mMenu = *page+1; MN.subMenu = 1; lcd.clear(); CopyStringtoLCD(MENU[MN.mMenu-1], 0, 0 ); CopyStringtoLCD(SUBMENU[MFIndex(MN.mMenu, MN.subMenu)], 0, 1 ); //FPtr=(FuncPtr)pgm_read_word(&FuncPtrTable[0]); } //------------------------------------------ void alexMenu(void) { lcd.clear(); //Display menu item CopyStringtoLCD(MENU[MN.mMenu-1], 0, 0 ); //Display subMenu item CopyStringtoLCD(SUBMENU[MFIndex(MN.mMenu, MN.subMenu)], 0, 1 ); //Assign function to function pointer //FPtr=(FuncPtr)pgm_read_word(&FuncPtrTable[MFIndex(MN.mMenu, MN.subMenu)]); } //------------------------------------------ uint8_t MFIndex(uint8_t mn, uint8_t sb) { uint8_t p=0;//points to menu in table of function pointer for(uint8_t i=0; i<(mn-1); i++) { p=p+pgm_read_byte(&MSTR2[i+1]); } p=p+sb-1; return p; } //------------------------------------------ void func101(void) { } void func102(void) { } void func103(void) { } void func104(void) { } void func105(void) { } void func201(void) { } void func202(void) { } void func301(void) { } void func302(void) { } void func401(void) { } void setString(unsigned char *bcount) { static uint8_t pos_y_curs = 4; lcd.setCursor(0, *bcount); lcd.write(62); if (bcount == 0) *bcount = pos_y_curs; lcd.setCursor(0, *bcount - 1); lcd.write(32); } void startMenu(){ setString(&pageNum); // включаем отображение стрелки выбора меню lcd.setCursor(1, 0); // 1 строка lcd.print(F("PY HO ")); // ручной режим lcd.setCursor(1, 1); // 2 строка lcd.print(F("ABTOMAT ECK")); // автоматический режим lcd.setCursor(1, 2); // 3 строка lcd.print(F("HACTPO K ")); // настройки lcd.setCursor(1, 3); // 4 строка lcd.print(F("OT A KA")); // отладка } /*void ButtonClick(unsigned char *ButtonId) { if (*ButtonId == 0) switchPointer = MENU_MANUAL; // Клик [Menu] Выход из меню else if (*ButtonId == 1) switchPointer = MENU_AUTO; //MenuCurent--; // Клик [Prev] Позицию ниже else if (*ButtonId == 2) switchPointer = MENU_SETUP; //MenuCurent++; // Клик [Next] Позиция выше else if (*ButtonId == 3) switchPointer = MENU_DEBUG; }*/buttonLib.c
#include "buttonLib.h" #include "pin_config.h" void BtnExe (void) { static unsigned char BtnLockBit = 0; //защелка (защита от дребезга) static unsigned char BtnLockCount = 0; //счетчик защелки (защита от дребезга) static unsigned char BtnLongCount = 0; //счетчик длинного нажатия static unsigned char BtnLastState= 0; //последнее состояние кнопок перед отпусканием char mask = 0; /*if (! (BTN_PIN & BTN_LINE_UP)) mask = BTN_SHRT_UP; if (! (BTN_PIN & BTN_LINE_DN)) mask = BTN_SHRT_DN; if (! (BTN_PIN & BTN_LINE_LEFT)) mask = BTN_SHRT_LEFT; if (! (BTN_PIN & BTN_LINE_RIGHT)) mask = BTN_SHRT_RIGHT;*/ if (! (BTN_PIN & BTN_LINE_DN)) mask = BTN_SHRT_DN; if (! (BTN_PIN & BTN_LINE_UP)) mask = BTN_SHRT_UP; if (! (BTN_PIN & BTN_LINE_OK)) mask = BTN_SHRT_OK; if (! (BTN_PIN & BTN_LINE_LEFT)) mask = BTN_SHRT_LEFT; if (! (BTN_PIN & BTN_LINE_RIGHT)) mask = BTN_SHRT_RIGHT; if (! (BTN_PIN & BTN_LINE_CANSEL)) mask = BTN_SHRT_CANSEL; if (mask){ //опрос состояния кнопки if (BtnLockCount < (BTN_LOCK_TIME/10)){ //клавиша нажата BtnLockCount++; return; //защелка еще не дощитала - возврат } BtnLastState = mask; BtnLockBit =1; //нажатие зафиксировано //if (BtnLongCount >= (BTN_LONG_TIME/10)) // return; //возврат, т.к. счетчик длинн нажат досчитал до максимума еще раньше //if (++BtnLongCount >= (BTN_LONG_TIME/10)) // BtnFlags |= (BtnLastState<<4); //счетчик досчитал до максимума - устанавливаем биты длинного нажатия } else{ //клавиша отжата if (BtnLockCount){ BtnLockCount --; return; //защелка еще не обнулилась - возврат } if (! BtnLockBit) //СТАТИЧЕСКИЙ ВОЗВРАТ return; BtnLockBit =0; //отжатие зафиксировано if (BtnLongCount < (BTN_LONG_TIME/10)) BtnFlags |= BtnLastState; //установка бита короткого нажатия //BtnLongCount = 0; //сброс счетчика длительности нажатия } } //функция чтения данных о нажатии кнопок char BtnGet (void) { cli(); char temp = BtnFlags; BtnFlags = 0; sei(); return temp; }buttonLib.h
common.h
def.h
menu_config.h
#ifndef MENU_CONFIG_H #define MENU_CONFIG_H //#include "main.h" //------------------------------------------ typedef void (*FuncPtr)(void); //указатель на функции FuncPtr FPtr; //Структура описывает текущее состояние меню и подменю struct Menu_State{ uint8_t mMenu;//1,2,3,4 uint8_t subMenu;//1,2,3 }MN; typedef struct _selection { unsigned char ent_f : 4; //Флаг входа 4 бита — обычно ID меню в которое надо войти unsigned char esc_f : 4; //Флаг выхода 4 бита — обычно ID меню в которое надо вернуться }SELECTION; typedef struct _menu { //unsigned char id; //Номер меню/подменю //unsigned char num_selections; //Количество Punktов данного меню/подменю SELECTION *m; //Указатель намассив Punktов данного меню/подменю } PAGE_MENU; #endifpin_config.h
#ifndef PIN_CONFIG_H #define PIN_CONFIG_H #include "common.h" //настройка параметров работы функций #define BTN_LOCK_TIME 30 /*время обработки дребезга в милисекундах (10-100)*/ #define BTN_LONG_TIME 1000 /*время фиксации длинного нажатия в милисекундах (1000 - 2500)*/ //настройки портов #define BTN_PORT PORTB /*порт чтения кнопок*/ #define BTN_DDR DDRB #define BTN_PIN PINB #define BTN_LINE_DN (1<<0) /*пины чтения кнопок*/ #define BTN_LINE_UP (1<<1) #define BTN_LINE_OK (1<<2) #define BTN_LINE_LEFT (1<<3) #define BTN_LINE_RIGHT (1<<4) #define BTN_LINE_CANSEL (1<<5) //глобальные переменные volatile uint8_t BtnFlags; //байт флагов нажатия кнопки //#define BTN_LONG_UP (1<<4) /*бит длинного нажатия кнопки up*/ //#define BTN_LONG_DN (1<<5) /*бит длинного нажатия кнопки dn*/ //#define BTN_LONG_LEFT (1<<6) /*бит длинного нажатия кнопки left*/ //#define BTN_LONG_RIGHT (1<<7) /*бит длинного нажатия кнопки right*/ #define BTN_SHRT_DN (1<<0) /*бит короткого нажатия кнопки up*/ #define BTN_SHRT_UP (1<<1) /*бит короткого нажатия кнопки dn*/ #define BTN_SHRT_OK (1<<2) /*бит короткого нажатия кнопки up*/ #define BTN_SHRT_LEFT (1<<3) /*бит короткого нажатия кнопки left*/ #define BTN_SHRT_RIGHT (1<<4) /*бит короткого нажатия кнопки right*/ #define BTN_SHRT_CANSEL (1<<5) /*бит короткого нажатия кнопки right*/ //############################################################################################################## #define RELAY_PORT PORTC /*порт чтения кнопок*/ #define RELAY_BTM PC0 //назначаем пин "НИЖНЕГО" нагревателя #define RELAY_TOP PC1 //назначаем пин "ВЕРХНЕГО" нагревателя #define PIN_BUZZER 3 // назначаем пин для пьезодинамика #endiftimer.c
#include "timer.h" #include "common.h" void init_timer2(void) { TCCR2B=0; // таймер2 остановлен TCNT2=0; //счётный регистр обнулён OCR2B=0; TIFR2&=0xff; //отчистить флаги прерываний TCCR2A = (1<<WGM21); // Режим CTC (сброс по совпадению) TCCR2B = (1<<CS20)|(1<<CS21)|(1<<CS22); // CLK/1024 OCR2A = 155; TIMSK2 = (1<<OCIE2A); // Разрешить прерывание по совпадению } ISR(TIMER2_COMPA_vect) { BtnExe(); }timer.h
2) в Файле "buttonLib.c" (или в любом другом .ino / .c файле, но только в одном!) добавляете описание этой переменной точно так, как она сейчас описана в "pin_config.h" (без "extern")
Да после первого поста я не поправил на сайте хотя у себя все файлы переделал с правильным расширением .срр, по причине того что вчера ради интереса проглядывал прошивку для 3D принтера Marlin для среды, и там все заголовочные файлы .h, .срр.
Здравствуте, чем больше капаюсь, тем больше ошибаюсь. ЕвгенийП не затруднит вас мне еще указать правильное решение
sketch.ino
#include "common.h" #include <LiquidCrystal.h> LiquidCrystal lcd(7, 6, 5, 4, 3, 2); //####################################################################################################################### uint8_t pageNum = 0; // счетчик нажатий кнопки FuncPtr FPtr; //unsigned char current_menu=0; //Переменная указывает на текущее меню //unsigned char current_poz=0; //Переменная указывает на текущий Punkt меню/подменю //char last_item; unsigned char f; //Структура описывает текущее состояние меню и подменю struct Menu_State{ uint8_t mMenu;//1,2,3,4 uint8_t subMenu;//1,2,3 } MN; struct _selection { unsigned char ent_f : 4; //Флаг входа 4 бита — обычно ID меню в которое надо войти unsigned char esc_f : 4; //Флаг выхода 4 бита — обычно ID меню в которое надо вернуться } SELECTION; struct _menu { //unsigned char id; //Номер меню/подменю //unsigned char num_selections; //Количество Punktов данного меню/подменю SELECTION *m; //Указатель намассив Punktов данного меню/подменю } PAGE_MENU; //####################################################################################################################### enum switchVariants : byte { // Определения для переключателя пунктов меню; MAIN_MENU, MENU_MANUAL, MENU_AUTO, MENU_SETUP, MENU_DEBUG//, EXITSAVE }; switchVariants switchPointer = MAIN_MENU; // С чего начнем цикл; enum manuState : byte { // Определения для переключателя ручного режима; EDIT_PARAM, HEAT_ZONE, COOL_ZONE, STOP_PROCESS, EXIT_PROCESS }; manuState mode = EDIT_PARAM; // С чего начнем цикл; static SELECTION menu_m0[]={ {MENU_MANUAL , MAIN_MENU}, }; static SELECTION menu_m1[]={ {MENU_AUTO, MAIN_MENU}, }; static SELECTION menu_m2[]={ {MENU_SETUP, MAIN_MENU} }; static SELECTION menu_m3[]={ {MENU_DEBUG, MAIN_MENU} }; static PAGE_MENU menu[] = { menu_m0, //Меню 1 menu_m1, //Меню 2 menu_m2, //Меню 3 menu_m3 //Меню 4 }; const uint8_t MN000[] PROGMEM="REWORK v05\0"; //меню 1 const uint8_t MN100[] PROGMEM="SETTINGS\0"; //подпункт меню const uint8_t MN101[] PROGMEM="STEPS:\0"; const uint8_t MN102[] PROGMEM="DWELL:\0"; const uint8_t MN103[] PROGMEM="PWR:\0"; const uint8_t MN104[] PROGMEM="RAMP:\0"; const uint8_t MN105[] PROGMEM="TARGET:\0"; //меню 2 const uint8_t MN200[] PROGMEM="MANUAL\0"; //подпункт меню 2 const uint8_t MN201[] PROGMEM="EDIT\0"; const uint8_t MN202[] PROGMEM="HEAT\0"; //меню 3 const uint8_t MN300[] PROGMEM="AUTO\0"; //подпункт меню 3 const uint8_t MN301[] PROGMEM="TEMP\0"; //меню 4 const uint8_t MN400[] PROGMEM="DEBUG\0"; //подпункт меню 4 const uint8_t MN401[] PROGMEM="COM\0"; //Массивы указателей на строки меню, хранящиеся на флэш const uint8_t *MENU[] ={ MN100, //menu 1 string MN200, //menu 2 string MN300, //menu 3 string MN400 //menu 4 string }; const uint8_t *SUBMENU[] ={ MN101, MN102, MN103, MN104, MN105, //подпункты меню 1 MN201, MN202, //подпункты меню 2 MN301, //подпункты меню 3 MN401, //подпункты меню 4 }; //Структура меню //[0] -Number of level 0 menu items //[1]...[n] number of second level menu items //Eg. MSTR2[1] shows that menu item 1 has 3 subMenus const uint8_t MSTR2[] PROGMEM ={ 4, // количество пунктов меню 5, //Количество подпунктов в пункте меню 1 2, //Количество подпунктов в пункте меню 2 1, //Количество подпунктов в пункте меню 3 1 //Количество подпунктов в пункте меню 4 }; //Прототипы функций //Инициализация Timer2 void init_timer2(void); //Начальное меню //void menu_Init(void); //Назначаем порты для кнопок и светодиодов void ports_Init(void); //Функции для каждого пункта меню void func101(void); void func102(void); void func103(void); void func104(void); void func105(void); void func201(void); void func202(void); void func301(void); void func401(void); //#define NULL_FUNC (void*)0 //Массив указателей на функции во флэш const FuncPtr FuncPtrTable[] PROGMEM= { func101, func102, func103, func104, func105, //functions for subMenus of menu 1 func201, func202, //functions for subMenus of menu 2 func301, //functions for subMenus of menu 3 func401 //functions for subMenus of menu 4 }; //subMenu and Function table pointer update uint8_t MFIndex(uint8_t, uint8_t); //------------------------------------------ //####################################################################################################################### //current editing step pointer uint8_t editStep = 0; struct reflowStation : public Printable { uint8_t rampRateStep = 0; // uint8_t temperatureStep = 0; // uint8_t dwellTimerStep = 0; // uint8_t pwr_TOP = 60; //максимальная мощность верхнего нагревателя uint8_t pwr_BOTTOM = 90; //максимальная мощность нижнего нагревателя //int Setpoint2; //float kp1, kd1, ki1; // коэффициенты пид "НИЖНЕГО" нагревателя //float kp2, kd2, ki2; // коэффициенты пид "ВЕРХНЕГО" нагревателя size_t printTo(Print& p) const { size_t res; if (MN.subMenu == 1) res = p.print(pwr_BOTTOM); else if (MN.subMenu == 2) res = p.print(pwr_TOP); else if (MN.subMenu == 3) res = p.print(rampRateStep); else if (MN.subMenu == 4) res = p.print(temperatureStep); else if (MN.subMenu == 5) res = p.print(dwellTimerStep); return res; } } profile; //################################################################################## void setup() { //Serial.begin(9600); lcd.begin(20, 4); lcd.home(); //Приветствие CopyStringtoLCD(MN000, 3, 1); _delay_ms(100); lcd.clear(); //Настройка таймера 2 ports_Init(); init_timer2(); // каждые 100 Гц sei(); // разрешаем прерывания глобально interrupts(); } void loop() { char BtnMask = BtnGet(); /* lcd.clear(); //Display menu item CopyStringtoLCD(MENU[MN.menu-1], 0, 0 ); //Display subMenu item CopyStringtoLCD(SUBMENU[MFIndex(MN.menu, MN.subMenu)], 0, 1 ); //Assign function to function pointer FPtr=(FuncPtr)pgm_read_word(&FuncPtrTable[MFIndex(MN.menu, MN.subMenu)]); */ if (BtnMask == BTN_SHRT_OK) { lcd.clear(); static uint8_t i = 0; if (!i) { switchPointer = (switchVariants) menu[pageNum].m[0].ent_f; i=1; menu_Init(&pageNum); //Initial menu and initial function } //switchPointer = current_menu; //last_item=current_poz; //f = menu[pageNum].m[0].esc_f; else { switchPointer = (switchVariants) menu[pageNum].m[0].esc_f; i=0; } }//обработка короткого нажатия ВВЕРХ if (BtnMask == BTN_SHRT_CANSEL) { }//обработка короткого нажатия ВЛЕВО switch (switchPointer) // Все делаем в одном операторе и одной функции; { case MAIN_MENU: /***************** Главное меню ***************/ startMenu(); //формирование меню if (BtnMask == BTN_SHRT_RIGHT) //обработка короткого нажатия ВПРАВО { pageNum++; // с каждым нажатием pageNum++ пока pageNum<4 if (pageNum > 3) pageNum = 0; } if (BtnMask == BTN_SHRT_LEFT) { //pageNum--; //if (pageNum <= 0) pageNum = 0; }//обработка короткого нажатия ВЛЕВО //if (BtnMask == BTN_LONG_UP) { }//обработка длинного нажатия ВВЕРХ //if (BtnMask == BTN_LONG_DN) {}//обработка длинного нажатия ВНИЗ //if (BtnMask == BTN_LONG_RIGHT) {}//обработка длинного нажатия ВПРАВО //if (BtnMask == BTN_LONG_LEFT) {}//обработка длинного нажатия ВЛЕВО break; case MENU_MANUAL: /***************** Ручной режим ***************/ if (BtnMask == BTN_SHRT_RIGHT) //обработка короткого нажатия ВПРАВО { if (MN.subMenu<pgm_read_byte(&MSTR2[MN.mMenu])) MN.subMenu++; else MN.subMenu=1; alexMenu(); } if (BtnMask == BTN_SHRT_UP) { if (MN.subMenu == 1) profile.pwr_BOTTOM++; else if (MN.subMenu == 2) profile.pwr_TOP+=5; else if (MN.subMenu == 3) profile.temperatureStep+=5; else if (MN.subMenu == 4) profile.temperatureStep+=1; else if (MN.subMenu == 5) profile.dwellTimerStep+=1; }//обработка короткого нажатия ВВЕРХ if (BtnMask == BTN_SHRT_DN) { } lcd.setCursor(0,2); lcd.print(profile); switch (mode) { // Выбор режима работы ручного режима case EDIT_PARAM: // Режим редактирования break; case HEAT_ZONE: break; case COOL_ZONE: break; case STOP_PROCESS: break; } break; case MENU_AUTO: /***************** Автоматический режим ***************/ break; case MENU_SETUP: /***************** Настройки ***************/ break; case MENU_DEBUG: /***************** Настройки ***************/ break; } } //####################################################################################################################### //----------------------------------------------------------------------------------------------------------------------- //функция настройки библиотеки работы с кнопками void ports_Init(void) { BTN_DDR &= ~(BTN_LINE_UP| BTN_LINE_DN| BTN_LINE_OK| BTN_LINE_LEFT| BTN_LINE_RIGHT| BTN_LINE_CANSEL); // кнопки на ввод BTN_PORT |= (BTN_LINE_UP| BTN_LINE_DN| BTN_LINE_OK| BTN_LINE_LEFT| BTN_LINE_RIGHT| BTN_LINE_CANSEL); //подтяжка вкл } //----------------------------------------------------------------------------------------------------------------------- void CopyStringtoLCD(const uint8_t *FlashLoc, uint8_t x, uint8_t y) { uint8_t i; lcd.setCursor(x,y); for(i=0;(uint8_t)pgm_read_byte(&FlashLoc[i]);i++) { lcd.write((uint8_t)pgm_read_byte(&FlashLoc[i])); } } //------------------------------------------ void menu_Init(uint8_t *page) { MN.mMenu = *page+1; MN.subMenu = 1; lcd.clear(); CopyStringtoLCD(MENU[MN.mMenu-1], 0, 0 ); CopyStringtoLCD(SUBMENU[MFIndex(MN.mMenu, MN.subMenu)], 0, 1 ); //FPtr=(FuncPtr)pgm_read_word(&FuncPtrTable[0]); } //------------------------------------------ void alexMenu(void) { lcd.clear(); //Display menu item CopyStringtoLCD(MENU[MN.mMenu-1], 0, 0 ); //Display subMenu item CopyStringtoLCD(SUBMENU[MFIndex(MN.mMenu, MN.subMenu)], 0, 1 ); //Assign function to function pointer //FPtr=(FuncPtr)pgm_read_word(&FuncPtrTable[MFIndex(MN.mMenu, MN.subMenu)]); } //------------------------------------------ uint8_t MFIndex(uint8_t mn, uint8_t sb) { uint8_t p=0;//points to menu in table of function pointer for(uint8_t i=0; i<(mn-1); i++) { p=p+pgm_read_byte(&MSTR2[i+1]); } p=p+sb-1; return p; } //------------------------------------------ void func101(void) { } void func102(void) { } void func103(void) { } void func104(void) { } void func105(void) { } void func201(void) { } void func202(void) { } void func301(void) { } void func302(void) { } void func401(void) { } void setString(unsigned char *bcount) { static uint8_t pos_y_curs = 4; lcd.setCursor(0, *bcount); lcd.write(62); if (bcount == 0) *bcount = pos_y_curs; lcd.setCursor(0, *bcount - 1); lcd.write(32); } void startMenu(){ setString(&pageNum); // включаем отображение стрелки выбора меню lcd.setCursor(1, 0); // 1 строка lcd.print(F("PY HO ")); // ручной режим lcd.setCursor(1, 1); // 2 строка lcd.print(F("ABTOMAT ECK")); // автоматический режим lcd.setCursor(1, 2); // 3 строка lcd.print(F("HACTPO K ")); // настройки lcd.setCursor(1, 3); // 4 строка lcd.print(F("OT A KA")); // отладка }buttonLib.cpp
#include "buttonLib.h" #include "pin_config.h" volatile uint8_t BtnFlags; void BtnExe (void) { static unsigned char BtnLockBit = 0; //защелка (защита от дребезга) static unsigned char BtnLockCount = 0; //счетчик защелки (защита от дребезга) static unsigned char BtnLongCount = 0; //счетчик длинного нажатия static unsigned char BtnLastState= 0; //последнее состояние кнопок перед отпусканием char mask = 0; /*if (! (BTN_PIN & BTN_LINE_UP)) mask = BTN_SHRT_UP; if (! (BTN_PIN & BTN_LINE_DN)) mask = BTN_SHRT_DN; if (! (BTN_PIN & BTN_LINE_LEFT)) mask = BTN_SHRT_LEFT; if (! (BTN_PIN & BTN_LINE_RIGHT)) mask = BTN_SHRT_RIGHT;*/ if (! (BTN_PIN & BTN_LINE_DN)) mask = BTN_SHRT_DN; if (! (BTN_PIN & BTN_LINE_UP)) mask = BTN_SHRT_UP; if (! (BTN_PIN & BTN_LINE_OK)) mask = BTN_SHRT_OK; if (! (BTN_PIN & BTN_LINE_LEFT)) mask = BTN_SHRT_LEFT; if (! (BTN_PIN & BTN_LINE_RIGHT)) mask = BTN_SHRT_RIGHT; if (! (BTN_PIN & BTN_LINE_CANSEL)) mask = BTN_SHRT_CANSEL; if (mask){ //опрос состояния кнопки if (BtnLockCount < (BTN_LOCK_TIME/10)){ //клавиша нажата BtnLockCount++; return; //защелка еще не дощитала - возврат } BtnLastState = mask; BtnLockBit =1; //нажатие зафиксировано //if (BtnLongCount >= (BTN_LONG_TIME/10)) // return; //возврат, т.к. счетчик длинн нажат досчитал до максимума еще раньше //if (++BtnLongCount >= (BTN_LONG_TIME/10)) // BtnFlags |= (BtnLastState<<4); //счетчик досчитал до максимума - устанавливаем биты длинного нажатия } else{ //клавиша отжата if (BtnLockCount){ BtnLockCount --; return; //защелка еще не обнулилась - возврат } if (! BtnLockBit) //СТАТИЧЕСКИЙ ВОЗВРАТ return; BtnLockBit =0; //отжатие зафиксировано if (BtnLongCount < (BTN_LONG_TIME/10)) BtnFlags |= BtnLastState; //установка бита короткого нажатия //BtnLongCount = 0; //сброс счетчика длительности нажатия } } //функция чтения данных о нажатии кнопок char BtnGet (void) { cli(); char temp = BtnFlags; BtnFlags = 0; sei(); return temp; }menu_config.h
pin_config.h
#ifndef PIN_CONFIG_H #define PIN_CONFIG_H #include "common.h" //настройка параметров работы функций #define BTN_LOCK_TIME 30 /*время обработки дребезга в милисекундах (10-100)*/ #define BTN_LONG_TIME 1000 /*время фиксации длинного нажатия в милисекундах (1000 - 2500)*/ //настройки портов #define BTN_PORT PORTB /*порт чтения кнопок*/ #define BTN_DDR DDRB #define BTN_PIN PINB #define BTN_LINE_DN (1<<0) /*пины чтения кнопок*/ #define BTN_LINE_UP (1<<1) #define BTN_LINE_OK (1<<2) #define BTN_LINE_LEFT (1<<3) #define BTN_LINE_RIGHT (1<<4) #define BTN_LINE_CANSEL (1<<5) //глобальные переменные extern volatile uint8_t BtnFlags; //байт флагов нажатия кнопки //#define BTN_LONG_UP (1<<4) /*бит длинного нажатия кнопки up*/ //#define BTN_LONG_DN (1<<5) /*бит длинного нажатия кнопки dn*/ //#define BTN_LONG_LEFT (1<<6) /*бит длинного нажатия кнопки left*/ //#define BTN_LONG_RIGHT (1<<7) /*бит длинного нажатия кнопки right*/ #define BTN_SHRT_DN (1<<0) /*бит короткого нажатия кнопки up*/ #define BTN_SHRT_UP (1<<1) /*бит короткого нажатия кнопки dn*/ #define BTN_SHRT_OK (1<<2) /*бит короткого нажатия кнопки up*/ #define BTN_SHRT_LEFT (1<<3) /*бит короткого нажатия кнопки left*/ #define BTN_SHRT_RIGHT (1<<4) /*бит короткого нажатия кнопки right*/ #define BTN_SHRT_CANSEL (1<<5) /*бит короткого нажатия кнопки right*/ //############################################################################################################## #define RELAY_PORT PORTC /*порт чтения кнопок*/ #define RELAY_BTM PC0 //назначаем пин "НИЖНЕГО" нагревателя #define RELAY_TOP PC1 //назначаем пин "ВЕРХНЕГО" нагревателя #define PIN_BUZZER 3 // назначаем пин для пьезодинамика #endifАлек97, Вы конечно занимаетесь меню не просто так а для подключения к какому-то устройству, которое будет сидеть в том же МК. Допустим у Вас уже сидит это устройство в МК и работает. И вам надо 1- отображать текущие данные и 2 менять режимы работы оперативно. Так вот для этого система меню не подходит. Потому что надо постоянно бегать по пунктам меню и вносить изменения. Причем во время бегания по пунктам меню вы уже не можете видеть оперативную информацию и пользоваться кнопками для оперативного управлиния, так с помощью их вы бегаете по пунктам меню.
Вы опять не пишете, что хотели сделать, опять придётся догадываться, хотя на этот раз это нелегко, т.к. Вы в разных местах делаете разные вещи. А что хотели – непонятно, потому и непонятно в каком из мест правильно, а в каком ошибка.
Вот из этих сток (файл "sxetch.h", стоки №№20-30):
struct _selection { unsigned char ent_f : 4; //Флаг входа 4 бита — обычно ID меню в которое надо войти unsigned char esc_f : 4; //Флаг выхода 4 бита — обычно ID меню в которое надо вернуться } SELECTION; struct _menu { //unsigned char id; //Номер меню/подменю //unsigned char num_selections; //Количество Punktов данного меню/подменю SELECTION *m; //Указатель намассив Punktов данного меню/подменю } PAGE_MENU;я предположил, что Вы, наверное хотели создать тип данных с именем SELECTION и использовать его как тип данных (для объявления переменных, как в строке №29 и позже, в строка №№ 44, 47, 50 и 53.
И я уже было собираюсь говорить об ошибке в строке №20
Но потом Вы пишете в файле "menu_config.h" строку №7
и окончательно сбиваете меня с толку. Если Вы хотите так, то строка №20 у Вас правильная, а ошибки как раз в строках №№ 29, 44, 47, 50 и 53.
Вот и пойми Вас - новичков.
В обще так, то как сейчас написаны строки 20-24, означает следующее:
1.
Объявлен тип данных с именем "struct _selection" или просто "_selection. Можете использовать и так и так. Разница, конечно, есть, на этом этапе изучения будем считать, что её нет. Работать будет и так и эдак.
2.
Объявлена переменная типа struct _selection с именем SELECTION.
Если Вы так и хотели, то у Вас всё правильно в строке №7 файла ""menu_config.h", а вот в строках №№ 29, 44, 47, 50 и 53 Вы при объявлении переменных зачем-то вместо типа данных struct _selection используете имя переменной SELECTION - Вот Вам и говорят, что такого типа нет.
Если же Вы хотели, чтобы SELECTION был типом данных, то в строке 20 в самом начале нужно было написать слово typedef. Тогда строки №№ 29, 44, 47, 50 и 53 были бы правильными, а вот строка №7 файла ""menu_config.h" была бы ошибочной, т.к. в ней Вы определяете внешнюю переменную с именем, которое совпадает с существующим типом данных.
Как-то так. Хотите внятнее, спрашивайте внятнее - пишите, что хотели сделать.
Алек97, Вы конечно занимаетесь меню не просто так а для подключения к какому-то устройству, которое будет сидеть в том же МК. Допустим у Вас уже сидит это устройство в МК и работает. И вам надо 1- отображать текущие данные и 2 менять режимы работы оперативно. Так вот для этого система меню не подходит. Потому что надо постоянно бегать по пунктам меню и вносить изменения. Причем во время бегания по пунктам меню вы уже не можете видеть оперативную информацию и пользоваться кнопками для оперативного управлиния, так с помощью их вы бегаете по пунктам меню.
В моем случае бегать по пунктам меню не нужно, достаточно задать начальные настройки либо выбрать готовый профиль из EEPROM. Меню состоит из четырех пунктов, поьзоваться в основном придется максимум двумя, удобно.
В моем случае бегать по пунктам меню не нужно, достаточно задать начальные настройки либо выбрать готовый профиль из EEPROM. Меню состоит из четырех пунктов, поьзоваться в основном придется максимум двумя, удобно.
Теперь по меню -там тоже просто . Создать тип структура - строка меню и функции работы с этой строкой :вывод на экран этой строки, увеличить на шаг данные этой строки, уменьшить на шаг данные этой строки , запуск данных ....
То есть все это отработка работы компонентов нижнего уровня. Вот когда они будут работать четко, то можно и собирать их в кучу. А так ковыряться в вашей простыне и догадываться что не так работает сложновато. Можно это задумано для сложности чтения другими программистами.
Теперь по меню -там тоже просто . Создать тип структура - строка меню и функции работы с этой строкой :вывод на экран этой строки, увеличить на шаг данные этой строки, уменьшить на шаг данные этой строки , запуск данных ....
То есть все это отработка работы компонентов нижнего уровня. Вот когда они будут работать четко, то можно и собирать их в кучу. А так ковыряться в вашей простыне и догадываться что не так работает сложновато. Можно это задумано для сложности чтения другими программистами.
По поводу вывода строк проблем нет, идея создания отдельной структуры для записи-чтения из EEPROM хорошая не спорю.
Скорее усложняю жизнь себе тем, что до конца не вникнув в суть задачи чего-то требую от других. Да недостаток знаний и не четко сформулированная мысль заставляет видеть во мне не годного программиста. За это прошу прощения в том числе и у ЕвгенияП.
Евгений, ваши рассуждения прочел и пока не тороплюсь делать какие - то выводы. Пока не разберусь в сути построения программы вашей помощи просить не буду. Если появится действительно стоящий вопрос который будет понятен не только мне но и форуму, тогда я постараюсь все максимально четко передать. Спасибо