/ sz: делаем каноничненько - алиасим тип указателя на функцию Спойлер
Код:
typedef void (*TvvPtr)(void);
ничешно так-то
Цитата:
Код:
uint8_t *PtrPunkt;
// sz: когда устанете бороться с компилятором - напишите так: TvvPtr PtrPunkt;
ну это после ваших вмешательств придется так написать
Цитата:
Код:
PtrPunkt=&(LEVEL1 MENU_LEVEL1->Ptr1HWS);
// sz: не выйдет в мышь впихнуть кота - любой заметит: - "Фактура не та!"Синтакс - ужасен - достаточно
Код:
PtrPunkt=MENU_LEVEL1->Ptr1HWS;
здесь да,чет тупанул,этоже и так все адреса.
Цитата:
// sz: да и за полностью прописные имена типов/переменных и прочих не #define-ов - тру-Сишники из вас кактус сделают. Ибо заповедано: -"Прописными - только #define-ы!"
пока вроде как ничего не выкатывали,но намотаю на ус!
//
Цитата:
sz: а если-бы функция имела аргументы?
тут я позабочусь об этом
Цитата:
Код:
*PtrPunkt;
И таблицу приоритетов посмотрите - кто кого перетянет.
тут вроде перетягивать нечему :
Код:
dont_know: (*PtrPunkt);
если так то скобки в приоритете.но у меня и так нет ничего кроме того что в скобках
И таблицу приоритетов посмотрите - кто кого перетянет.
тут вроде перетягивать нечему :
Код:
dont_know: (*PtrPunkt);
если так то скобки в приоритете.но у меня и так нет ничего кроме того что в скобках
Я про те скобки, которые function call. Они с высшим приоритетом, а указатель ешё и разыменовать надо - и у этой операции (dereference) приоритет ниже. За ассоциативность не утверждаю, но
Код:
(*PtrPunkt)();
должно сработать как надо.
_________________ Одновременным нажатием LIGHT и POWER, РП Sangean ATS-909X (ver 1.29) превращается в ATS-909XR!
Обязательным условием долгой и стабильной работы Li-FePO4-аккумуляторов, в том числе и производства EVE Energy, является применение специализированных BMS-микросхем. Литий-железофосфатные АКБ отличаются такими характеристиками, как высокая многократность циклов заряда-разряда, безопасность, возможность быстрой зарядки, устойчивость к буферному режиму работы и приемлемая стоимость. Но для этих АКБ очень важен контроль процесса заряда и разряда для избегания воздействия внешнего зарядного напряжения после достижения 100% заряда. Инженеры КОМПЭЛ подготовили список таких решений от разных производителей.
до этой строчки у меня уже компилятор кипит ошибками и предупреждениями. Для более ясной картины выложу весь код. ошибки такие: 1) при инициализации указетелей структуры,для того чтобы использовать операцию (->) пишет мол conflicting types for 'Ptr_MeNU_LEVEL2_HWS чем ему не нравятся мои типы не пойму. При этом еще выдает invalid type argument of '->' (have 'int') в строках использования операции (->). 2) при использовании операции (.)все устраивает.
P.S В PtrPunkt мне нужно сохранить адрес где хранится указатель на функцию и уже после этого нужно ее вызвать с помощью PtrPunkt Menu_v20.h Спойлер
Код:
#ifndef MENUv20_H_ #define MENUv20_H_
void opredelenieUkazatela(uint8_t);// определения указателя //---------- //---------- //---------- вывода на дисплей------------------------------------------------------------------------------------------------------------------ void output_level_1_GWS (void); // выводит на дисплей уровень 1 для ГВС "GWS" void output_level_21_GWS(void); // выводит на дисплей уровень 2.1(1 подпункт 2 уровня) для ГВС "TEK" текущие параметры void output_level_22_GWS(void); // выводит на дисплей уровень 2.2(2 подпункт 2 уровня) для ГВС "YAHR" потребление за год void output_level_23_GWS(void); // выводит на дисплей уровень 2.3(3 подпункт 2 уровня) для ГВС "TEMPER_MIN" минимальная //----------
void output_level_1_HWS (void); // выводит на дисплей уровень 1 для ХВС "HWS" void output_level_21_HWS(void); // выводит на дисплей уровень 2.1(1 подпункт 2 уровня) для ХВС "TEK" текущие параметры void output_level_22_HWS(void); // выводит на дисплей уровень 2.2(2 подпункт 2 уровня) для ХВС "YAHR" потребление за год void output_level_23_HWS(void); // выводит на дисплей уровень 2.2(3 подпункт 2 уровня) для ХВС "TEMPER_MIN" минимальная
//---------- typedef void(*TvvPtr)(void); // новый тип указателя на функцию TvvPtr PtrPunkt; // указатель для хранения адреса последненго пункта
//---тип структуры 1 уровня-------------------------------------------------------------------------------------------------------------------------------------------------- typedef struct { TvvPtr PtrGWS; // пункт меню на первом уровне TvvPtr PtrHWS; // пункт меню на первом уровне }Level1; //---тип структуры 1 уровня
//----тип структуры 2 уровня------------------------------------------------------------------------------------------------------------------------------------------------------------------- typedef struct { TvvPtr PtrTEK; // пункт меню на втором уровне TvvPtr PtrYAHR; // пункт меню на втором уровне TvvPtr PtrTEMP_min; }Level2; //тип структуры 2 уровня
//--объявление структур уровней-------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Level1 MeNU_LEVEL1; // структура 1 уровня Level2 MeNU_LEVEL2_GWS; // структура 2 уровня для GWS Level2 MeNU_LEVEL2_HWS; // структура 2 уровня для HWS
//---указатель на структуры уровней--------------------------------------------------------------------------------------------------------------------------------------------------- Level1 *Ptr_MeNU_LEVEL1; //указатель на Левел Level2 *Ptr_MeNU_LEVEL2_GWS; //указатель на Левел 2 ГВС Level2 *Ptr_MeNU_LEVEL2_HWS; //указатель на Левел 2 ХВС
//----------
//---------- #endif /*MENUv20_H_*/
Menu_v20.c Спойлер
Код:
#include "Menu_v2.0.h" #include <stdio.h> #define ENTER 0x25 #define UP 0x23 #define DN 0x56 #define CANCEL 0x26
//---инициализация структур----------------------------------------------------------------------------------------------------- Level1 MeNU_LEVEL1={output_level_1_GWS,output_level_1_HWS}; // инициализируем структуру 1 уровня Level2 MeNU_LEVEL2_GWS={output_level_21_GWS,output_level_22_GWS,output_level_23_GWS}; // инициализируем структуру 2 уровня для GWS Level2 MeNU_LEVEL2_HWS={output_level_21_HWS,output_level_22_HWS,output_level_23_HWS}; // инициализируем структуру 2 уровня для HWS
//----инициализация указателей на структуру-------------------------------------------------------------------- Ptr_MeNU_LEVEL1=MeNU_LEVEL1; // указетелю присваиваем адрес структуры MeNU_LEVEL1 Ptr_MeNU_LEVEL2_GWS=MeNU_LEVEL2_GWS; // указетелю присваиваем адрес структуры MeNU_LEVEL2_GWS; Ptr_MeNU_LEVEL2_HWS=MeNU_LEVEL2_HWS; // указетелю присваиваем адрес структурыMeNU_LEVEL2_HWS
void opredelenieUkazatela(uint8_t key_kod) // получает код нажатой клавиши { switch(key_kod) {
//---вниз------------------------------------------------------------------------------------------------------------------------------------------- case DN: if(PtrPunkt==(MeNU_LEVEL1.PtrGWS)) PtrPunkt=MeNU_LEVEL1.PtrHWS; break; // переход с в 1 if(PtrPunkt==(MeNU_LEVEL2_GWS.PtrTEK)) PtrPunkt=MeNU_LEVEL2_GWS.PtrYAHR; break; // переход if(PtrPunkt==(MeNU_LEVEL2_GWS.PtrYAHR)) PtrPunkt=MeNU_LEVEL2_GWS.PtrTEMP_min; break; // переход с в 2 if(PtrPunkt==(MeNU_LEVEL2_HWS.PtrTEK)) PtrPunkt=MeNU_LEVEL2_HWS.PtrYAHR; break; // if(PtrPunkt==(MeNU_LEVEL2_HWS.PtrYAHR)) PtrPunkt=MeNU_LEVEL2_HWS.PtrTEMP_min; break; // переход с в 2
//---вверх----------------------------------------------------------------------------------------------------------------------------------------------- case UP: if(PtrPunkt==(MeNU_LEVEL1.PtrHWS) ) PtrPunkt=MeNU_LEVEL1.PtrGWS; break; // переход с в 1 if(PtrPunkt==(MeNU_LEVEL2_GWS.PtrTEMP_min)) PtrPunkt=MeNU_LEVEL2_GWS.PtrYAHR; break; // переход с в 2 if(PtrPunkt==(MeNU_LEVEL2_GWS.PtrYAHR) ) PtrPunkt=MeNU_LEVEL2_GWS.PtrTEK; break; // переход с в 2 уровне if(PtrPunkt==(MeNU_LEVEL2_HWS.PtrTEMP_min)) PtrPunkt=MeNU_LEVEL2_HWS.PtrYAHR; break; // переход с в if(PtrPunkt==(MeNU_LEVEL2_HWS.PtrYAHR)) PtrPunkt=MeNU_LEVEL2_GWS.PtrTEK; break; // переход с в 2
case CANCEL: if(PtrPunkt==(MeNU_LEVEL2_GWS.PtrYAHR)||(MeNU_LEVEL2_GWS.PtrTEMP_min)||(MeNU_LEVEL2_GWS.PtrTEK)) PtrPunkt=MeNU_LEVEL1.PtrGWS; break; // переход с в 1 уровне меню на подменю if(PtrPunkt==(MeNU_LEVEL2_HWS.PtrYAHR)||(MeNU_LEVEL2_HWS.PtrTEMP_min)||(MeNU_LEVEL2_HWS.PtrTEK)) PtrPunkt=MeNU_LEVEL1.PtrGWS;break; // переход с в 2 уровне меню на подменю if(PtrPunkt==(MeNU_LEVEL1.PtrGWS)||(MeNU_LEVEL1.PtrHWS)) PtrPunkt=NULL; break; // переход с в 2 уровне меню на подменю //----------
Компания EVE выпустила новый аккумулятор серии PLM, сочетающий в себе высокую безопасность, длительный срок службы, широкий температурный диапазон и высокую токоотдачу даже при отрицательной температуре.
Эти аккумуляторы поддерживают заряд при температуре от -40/-20°С (сниженным значением тока), безопасны (не воспламеняются и не взрываются) при механическом повреждении (протыкание и сдавливание), устойчивы к вибрации. Они могут применяться как для автотранспорта (трекеры, маячки, сигнализация), так и для промышленных устройств мониторинга, IoT-устройств.
1) Двигайтесь последовательно. Исправляйте самую первую ошибку, которую выдал компилятор. При ее исправлении двигайтесь дальше - компилируйте и переходите к п. 1)
Для начала:
Menu_v20.h:
Код:
Level1 MeNU_LEVEL1;
Код:
... #include "Menu_v2.0.h" // в Menu_v20.h уже определена MeNU_LEVEL1 ... Level1 MeNU_LEVEL1={output_level_1_GWS,output_level_1_HWS}; // Здесь MeNU_LEVEL1 определяется второй раз!!!!
Продолжаем:
Код:
// MeNU_LEVEL2_GWS имеет тип Level2, а MeNU_LEVEL2_GWS имеет тип 'Level2 *'. разница огромная Ptr_MeNU_LEVEL2_GWS=MeNU_LEVEL2_GWS; // Возможно Вы хотели написать Ptr_MeNU_LEVEL2_GWS = &MeNU_LEVEL2_GWS;
Последний раз редактировалось viiv Пт мар 23, 2018 13:08:04, всего редактировалось 4 раз(а).
операция -> применима только к указателю слева, операция . - только к статическому экземпляру структуры. поэтому недопустимо их смешивать.
Код:
typedef struct{ int a; int b; } my_ struct;
my_struct var1; my_struct *var2 = &var1;
var1.a = 12; // правильно var1->a = 12; // ошибка
var2->b = 13; // правильно var2.b = 13; // ошибка
Добавлено after 1 minute 18 seconds: И еще чисто моё личное, предвзятое, мнение: вас, случайно, не в Майкрософте программированию обучали? это у них приняты длиннючие типы с тремя и более подчеркиваниями и мешаниной заглавных и прописных букв...
_________________ если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе при взгляде на многих сверху ничего не меняется...
с понятиями определена, описана,объявлена, инициализирована одни путаницы. мое понимание: ОПРЕДЕЛЕНИЕ ОПИСАНИЕ ОБЪЯВЛЕНИЕ это одно и тоже ИНИЦИАЛИЗАЦИЯ это присвоение уже ОПРЕДЕЛЕННОМУ, ОПИСАННОМУ, ОБЪЯВЛЕННОМУ так что есть что?
// MeNU_LEVEL2_GWS имеет тип Level2, а MeNU_LEVEL2_GWS имеет тип 'Level2 *'. разница огромная Ptr_MeNU_LEVEL2_GWS=MeNU_LEVEL2_GWS; [/quote] здесь надо подумать
[quote]// Возможно Вы хотели написать [code]Ptr_MeNU_LEVEL2_GWS = &MeNU_LEVEL2_GWS;
операция -> применима только к указателю слева, операция . - только к статическому экземпляру структуры.
это я понимаю, так у меня в коде где используется операция стрелка слева указатель на структуру а где операция точка сама структура.
[quote]И еще чисто моё личное, предвзятое, мнение: вас, случайно, не в Майкрософте программированию обучали? это у них приняты длиннючие типы с тремя и более подчеркиваниями и мешаниной заглавных и прописных букв...
нет к сожалению,приходиться самому и с помощью форума обучаться!Мне главное, чтоб не запутаться, при этом ничего не нарушать
с понятиями определена, описана,объявлена, инициализирована одни путаницы.
это плохо. если своими словами, то: 1. каждая сущность программы на Си может быть ОПИСАНА, РЕАЛИЗОВАНА и ИСПОЛЬЗОВАНА. 2. описана (объявлена) - это значит, что компилятор уведомлен о том, что в программе такая сущность МОЖЕТ существовать. где - пока не ясно 3. реализация сущности - это команда компилятору выделить память и(возможно) заполнить её какими-то данными. теперь эта сущность существует на самом деле. 4. использование - это работа с описанной и реализованой сущностью. 5. описание, реализация и использование могут быть не все сразу, а частично, минимально необходимый вариант - реализация, если её нет - считай, все остальное смысла не имеет 6. любое использование должно быть после реализации, любая реализация - после описания. и никак иначе. при этом реализация заменяет собой описание, т.е. при наличии реализации описание становится необязательным. но при наличии описания не обязательна реализация.
под сущностью я подразумеваю любую элементарную конструкцию языка Си: тип, переменную, структуру, функцию. макрос не является в строгом понимании элементом языка Си (это к препроцессору относится), и поэтому не в полной мере удовлетворяет этому описанию.
примеры
Код:
extern int var; // описание переменной int var; // реализация переменной var = 12; // использование переменной
int foo(void); // описание функции int foo(void){ return 12; } // реализация функции
var = foo(); // использование функции
разве тут есть путаница?
_________________ если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе при взгляде на многих сверху ничего не меняется...
ничего тонкого: первая строка просто рассказывает, что где-то там (extern - вовне, снаружи) переменная типа int и идентификатором var МОЖЕТ БЫТЬ ЕСТЬ. вторая явно показывает, что эта переменная ЕСТЬ.
другое дело, что часто применяют термин ОПРЕДЕЛЕНА вместо РЕАЛИЗОВАНА, подразумевая, что определенность - признак существования, но фактически это не корректно (хотя и широко используется). например, никогда не говорят об ОПРЕДЕЛЕНИИ методов класса, но только о РЕАЛИЗАЦИИ (это уже из С++, но сути не меняет). поэтому я сам для себя использую вышеприведенную классификацию, меня понимают все программисты, а я не путаюсь. чего и вам желаю.
_________________ если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе при взгляде на многих сверху ничего не меняется...
Т.е мы дали понять компилятору, что возможно есть такой тип
нет, тип в момент описания уже существует, для него два этапа (описание и реализация) неразделимы по по определению, т.к. тип - это не материальное явление, а описательное.
ROMan2947 писал(а):
правильно мыслю?
в общем и целом - да, но по-моему, Си не позволяет производить присваивания переменным структурного типа кроме как в момент реализации.
Здравствуйте! Работу модуля опроса клавиатуры нужно отладить с основным модулем. 1) Опрос клавиатуры происходит по таймеру. Где нужно помещать обработчик прерывании, в основном модуле или же в исходнике модуля клавиатуры? На практике пока разницы не заметил.На данный момент обработчик я поместил в исходник главного модуля. 2) Имеется переменная BuTTOn,она объявлена в исходнике главного модуля.при прерывании по таймеру я передаю ее адрес в функцию опроса в модуль клавиатуры. Там по ее адресу присваиваю код кнопки. По выходу из прерывания идет проверка на наличие в переменной BuTTON кода,при ее наличии передаю адрес этой переменной в модуль Меню.Компилируется все хорошо,ошибок нет.Отладчиком проходил, программа производит опрос кнопок и правильно присваивает переменной BuTTON код нажатой кнопки. но не переходит в модуль меню. 3) В чем разница использования внешней переменной и работать просто с адресом переменной? я работаю с адресом переменной в сторонних модулях и ниче вроде все работает как надо. main.h Спойлер
Где нужно помещать обработчик прерывании, в основном модуле или же в исходнике модуля клавиатуры?
Там, где он логически согласуется с принятой структурой программы. Если у вас принято все обработчики держать в главном модуле, то там. А если вы их хотите держать в модулях (с логикой подобное к подобному), то держите там.
Цитата:
Имеется переменная BuTTOn,она объявлена в исходнике главного модуля.при прерывании по таймеру я передаю ее адрес в функцию опроса в модуль клавиатуры. Там по ее адресу присваиваю код кнопки.
Вам нужен модификатор volatile при объявлении переменной BuTTOn. Компилятор не знает, что эта переменная может измениться где-то ещё, потому способен "оптимизировать" все обращения к этой переменной. Ну и красиво было бы запрещать прерывания при работе с переменной в основном потоке.
Цитата:
В чем разница использования внешней переменной и работать просто с адресом переменной? я работаю с адресом переменной в сторонних модулях и ниче вроде все работает как надо.
Работайте так, как вам удобно. Правда, смысла передавать адрес нет никакого в вашем случае. Объявите переменную как extern в модулях, её использующих, и она станет там доступна как обычно, по имени. Я так понимаю, вы именно из-за недоступности этой переменной в key.c и придумали передавать адрес?
Там, где он логически согласуется с принятой структурой программы. Если у вас принято все обработчики держать в главном модуле, то там. А если вы их хотите держать в модулях (с логикой подобное к подобному), то держите там
Для меня логичнее ее держать в модуле клавиатуры,т.к. обработчик относиться к клавиатуре.Я хотел узнать наличие разницы кроме как логики.
Цитата:
Вам нужен модификатор volatile при объявлении переменной BuTTOn. Компилятор не знает, что эта переменная может измениться где-то ещё, потому способен "оптимизировать" все обращения к этой переменной.
Учту!Хотя изменения этой переменной происходят без проблем, да и предупреждение думаю было бы,а его нет.
Цитата:
Ну и красиво было бы запрещать прерывания при работе с переменной в основном потоке.
Понял!
Цитата:
И имейте в виду вот что - компилятор не обязан все инструкции выполнять по-порядку.
как это не обязан это же страшно важно!!!
Цитата:
Я так понимаю, вы именно из-за недоступности этой переменной в key.c и придумали передавать адрес?
Нет! просто пока мне не совсем понятна работы c extern на практике, а с указателями понятно, вот решил работать с ними.
Для меня логичнее ее держать в модуле клавиатуры,т.к. обработчик относиться к клавиатуре.Я хотел узнать наличие разницы кроме как логики.
Тогда там и держите. Разницы никакой.
Цитата:
как это не обязан это же страшно важно!!!
Вот чтобы вас не пугать и не запутать, я и стёр то, что написал. Не беспокойтесь - для вашего прерывания это не важно - пока вы не выйдете из прерывания, основная программа не продолжится. Но в настоящих многопоточных приложениях просто имейте это в виду. Подробности вы прочтете в "Барьеры памяти и компилятора". Например, тут: http://scrutator.me/post/2015/05/16/mem ... riers.aspx
Цитата:
Нет! просто пока мне не совсем понятна работы c extern на практике, а с указателями понятно, вот решил работать с ними.
На практике в модуле key.h вы пишете после #include extern uint8_t BuTTON;
И дальше работаете с этой переменной, как с глобальной.
Цитата:
Учту!Хотя изменения этой переменной происходят без проблем, да и предупреждение думаю было бы,а его нет.
Предупреждения и не будет. Это не ошибка. Кстати, у вас этот самый BuTTON стоит инициализировать. Фишка в том, что вот это:
Код:
if(BuTTON) { opredelenieUkazatela(&BuTTON); }
после компиляции (не в Debug-конфигурации!) превратится в:
Код:
if(0) { opredelenieUkazatela(&BuTTON); }
И будет выброшено из программы. А что? BuTTON внутри цикла не меняется.
Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 35
Вы не можете начинать темы Вы не можете отвечать на сообщения Вы не можете редактировать свои сообщения Вы не можете удалять свои сообщения Вы не можете добавлять вложения