Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: возможно ли на Си
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > Программирование
Страницы: 1, 2
another_one
Здравствуйте.

Прошу подсказки.

С целью удобства и лучшей читабельности необходимо объединить биты портов микроконтроллера в один структурный тип или объединение.

Биты находятся в разных портах и не последовательно.

Не пойму как назначить адрес бита порта к "битовому типу" структуры.

Заранее благодарен
sergeeff
Никак
DpInRock
Вы всегда смотрите, как именно ваши фантазии будет реализовыватcя на данной системе команд. Имеет ли смысл?
another_one
Цитата(DpInRock @ Jun 13 2009, 23:38) *
Вы всегда смотрите, как именно ваши фантазии будет реализовыватcя на данной системе команд. Имеет ли смысл?

Вариант с опросом разных битов в разных портах не очень удобен.

Я как -то делал для одного порта - присваивал структуре адрес регистра саециального назначения с помощью директивы #byte в компиляторе CCS для пиков.

Сейчас задача для нека, используя ИАР
SSerge
Для читаемости можно оформить доступ к битам в разных портах как макрос примерно так:

#define OUT(x) do{код доступа к битам в разных портах }while(0)

такая конструкция хороша тем, что синтаксически эквивалентна одному оператору и её можно использовать привычным для С образом не рискуя нарваться на маловразумительные сообщения об ошибках.
sergeeff
Почитайте современные книги, которые всячески советуют избегать везде, где только можно, макро. Это грабли, приводящие очень часто к трудно вылавливаемым ошибкам.
zltigo
Цитата(sergeeff @ Jun 14 2009, 03:20) *
Почитайте современные книги.....

Прости, господи sad.gif, а может просто надо не только "читать современные книги", но и читать просто книги, и просто думать, когда пишешь? Причем пишешь не только макросы, а то возникнут "грабли".
Herz
Цитата(sergeeff @ Jun 14 2009, 02:20) *
Почитайте современные книги, которые всячески советуют избегать везде, где только можно, макро. Это грабли, приводящие очень часто к трудно вылавливаемым ошибкам.

Такие книжки читать как раз не нужно, ИМХО. Ибо это из категории вредных советов. biggrin.gif
SSerge
Цитата(Herz @ Jun 14 2009, 12:47) *
Такие книжки читать как раз не нужно, ИМХО. Ибо это из категории вредных советов. biggrin.gif

Да нет, сами по себе советы вместо #define использовать const и темплейты - правильные.
Просто в тех книгах речь идёт о С++ и типичных его применениях - для ваяния многомегабайтных монстров. А тут случай практически противоположный - манипуляции битами на самом нижнем уровне, никакой переносимости не требуется по определению, зато важна эффективность.
Но, разумеется, хотелось бы собрать в одном месте все зависимости от номеров битов в портах, чтобы при правках не искать их по всей программе.

Альтернатива - написать пару функций для чтения и для записи, а для эффективности инлайнить их.
sergeeff
Мне представляется, что:
1. Есть программисты - одиночки, пишущие и поддерживающие проект самостоятельно.
2. Программисты, либо работающие в коллективе разработчиков, либо вынужденные учитывать тот факт, что их проект может/будет сопровождаться и развиваться другими людьми.

Соответственно подходы к написанию программ сильно разнятся и использование в текстах неочевидных конструкций может и облегчают жизнь автору этих конструкций, но могут приводить к обратному результату при использовании другими. Особенно если неправильное их использование не сопровождается никакими предупреждениями ни на этапе компиляции, ни этапе работы программы.
Dog Pawlowa
Цитата(SSerge @ Jun 14 2009, 13:21) *
Но, разумеется, хотелось бы собрать в одном месте все зависимости от номеров битов в портах, чтобы при правках не искать их по всей программе.

Описываю весь доступ к портам через макросы в одном h-файле и не парюсь.
В прочих файлах НИКАКОГО упоминания о портах, только макросы с осмысленными названиями. Просто для понимания. Существенно упрощает портирование.
К сожалению, есть проблема инлайнить функции, определенные в других модулях, теоретически можно тоже через #include, но это уж точно на изврат похоже.
sergeeff
Цитата(Dog Pawlowa @ Jun 14 2009, 14:49) *
К сожалению, есть проблема инлайнить функции, определенные в других модулях, теоретически можно тоже через #include, но это уж точно на изврат похоже.


Это не изврат, а требование компилятора к видимости тела inline функции в том модуле, где вы хотите, чтобы эта функция была встроена. О чем многократно писалось на форуме.
KRS
На С++ можно с помощью перезагрузки операции присваивания. И потом объеденения полей в класс. Можно еще шаблоны прифигачить smile.gif

Только IMHO лучше, как тут уже писали, функции определить.
Dog Pawlowa
Цитата(sergeeff @ Jun 14 2009, 13:55) *
Это не изврат, а требование компилятора к видимости тела inline функции в том модуле, где вы хотите, чтобы эта функция была встроена. О чем многократно писалось на форуме.

Если Вы о причине, то она именно как Вы указали.
Я же об использовании и собственном впечатлении от такого использования, и буду стоять на своем smile.gif
sergeeff
А почему все макросы в одном h-файле можно поместить, а все inline функции в одном h-файле нельзя? Професиональные принципы не позволяют?
MrYuran
Я бы сделал так:

#define UP(port, bit) port |= (1<<bit)
#define DOWN(port, bit) port &= ~(1<<bit)

Далее:

#define LIGHT P1OUT,1
#define MOTOR P2OUT,3
#define BEEPER P3OUT,2

Итого имеем:

UP(LIGHT);
DOWN(MOTOR);
UP(BEEPER);

Названия регистров взял от МСП, как наиболее актуального для меня

Если хочется именно структуры, то надо немного подумать.
Например, определить структуру Pin{}, в которой указать порт, номер пина и т.д. Например, забить туда все регистры порта (OUT,DIR,IE,SEL).
А потом уже эту структуру включать внутрь других структур.
Но всё равно без макросов не обойтись.
Либо класс рисовать.

Хотя, если взять тот же МСП, то там в io.h порты расписаны в том числе и как структуры, и можно написать
port1.out.pin3 = 1;
port2.out.pin1 = 0;
Тогда всё еще проще:
#define MOTOR port1.out.pin3;
...
MOTOR = 1;
C инициализацией других регистров порта опять же, нужно отдельно думать.
aaarrr
Цитата(Dog Pawlowa @ Jun 14 2009, 14:49) *
К сожалению, есть проблема инлайнить функции, определенные в других модулях, теоретически можно тоже через #include, но это уж точно на изврат похоже.

Напрасно Вы так - вовсе не изврат, а очень полезный в некоторых случаях прием.
Dog Pawlowa
Цитата(aaarrr @ Jun 14 2009, 14:35) *
очень полезный в некоторых случаях прием.

ОК, я подумаю. Хотелось бы уточнить случаи.

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

Если же функция вырождается в дерганье выводом или считывание его состояния, то объясните мне плз, в чем преимущество инлайновой функции по сравнению с простейшим макросом:
#define ON_BACKLIGHT (P1OUT|=P1_BACKLIGHT),
где #define P1_BACKLIGHT 0x02 //output
aaarrr
Цитата(Dog Pawlowa @ Jun 14 2009, 21:09) *
ОК, я подумаю. Хотелось бы уточнить случаи.


Например, есть у меня в модуле display такая функция:
Код
__forceinline void disp_set_dot_alpha(u_int x, u_int y, DISP_COLOR color, u_char alpha)
{
    u_int c0, c1, mask;
    
    if(alpha > 0)
    {
        c0 = color;
        if(alpha < DISP_MAX_ALPHA)
        {
            c1 = *((u_short*)&disp_frame + (y * DISP_WIDTH) + x);
            mask = 0x07e0f81f;
            c0 = (c0 | (c0 << 16)) & mask;
            c1 = (c1 | (c1 << 16)) & mask;
            c0 = ((c0 * alpha) >> 5) & mask;
            c1 = ((c1 * (DISP_MAX_ALPHA - alpha)) >> 5) & mask;
            c0 = c0 + c1;
            c0 |= c0 >> 16;
        }
        *((u_short*)&disp_frame + (y * DISP_WIDTH) + x) = c0;
    }
}


Тащить всю работу с графикой в один модуль неразумно, до макроса не вырождается, зато как инлайн функция существенно повышает производительность.
sergeeff
Цитата(Dog Pawlowa @ Jun 14 2009, 20:09) *
#define ON_BACKLIGHT (P1OUT|=P1_BACKLIGHT),
где #define P1_BACKLIGHT 0x02 //output


Это значит, что где-то кто-то может встретить в вашей программе:
Код
...
ON_BACKLIGHT;
...


Вы сами-то как оцениваете читабельность такого выражения?
Dog Pawlowa
Цитата(aaarrr @ Jun 14 2009, 20:16) *
зато как инлайн функция существенно повышает производительность.

ОК, спасибо. Видимо, не сталкивался.
Но в таком виде функция не инклюдится, или я не знаю эту среду/компилятор?

Цитата(sergeeff @ Jun 14 2009, 20:29) *
Вы сами-то как оцениваете читабельность такого выражения?

Супер! Превосходная ! Ни у кого такого нет! smile.gif
"Включить подсвет", насколько мне известно...
Большие буквы, отсутствие скобок -> значит это макрос для работы с портами -> см файл project_ports.h
Лет пят-шесть так работаю, маразм наступает, но вот с этим пока проблем не было.
aaarrr
Цитата(Dog Pawlowa @ Jun 14 2009, 21:30) *
Но в таком виде функция не инклюдится, или я не знаю эту среду/компилятор?

Вы имеете в виду __forceinline? Это от RVCT.

Цитата(Dog Pawlowa @ Jun 14 2009, 21:36) *
Супер! Превосходная ! Ни у кого такого нет! smile.gif

Ну не знаю, не могу разделить Ваши восторги. Понятно, что при помощи макросов можно заставить 'C' выглядеть как что-то совсем другое, но, ИМХО, лучше так не делать.
sergeeff
Цитата(Dog Pawlowa @ Jun 14 2009, 20:36) *
Супер! Превосходная ! Ни у кого такого нет! smile.gif

Ну это, условный рефлекс, наверное.
Dog Pawlowa
Цитата(aaarrr @ Jun 14 2009, 20:41) *
Вы имеете в виду __forceinline? Это от RVCT.

Нет, я не только это я имею ввиду. Как тут отмечалось, чтобы функция инлайнилась, нужно, чтобы ее текст попадал в область видимости, то есть ее текст должен быть перенесен в модуль, где она используется, как то так:
#define DISPL_SET_DOT_ALPHA __forceinline void disp_set_dot_alpha(u_int x, u_int y, DISP_COLOR color, u_char alpha) \
{ \
u_int c0, c1, mask; \
if(alpha > 0) \
{ \
...

Цитата(aaarrr @ Jun 14 2009, 20:41) *
Понятно, что при помощи макросов можно заставить 'C' выглядеть как что-то совсем другое, но, ИМХО, лучше так не делать.

Так сложилось в жизни, что был период turbo pascal 6.0/ Pascal Borland 7.0 for embedded applications, so I don't follow strong rules in C smile.gif
aaarrr
Цитата(Dog Pawlowa @ Jun 14 2009, 21:55) *
как то так:
#define DISPL_SET_DOT_ALPHA __forceinline void disp_set_dot_alpha(u_int x, u_int y, DISP_COLOR color, u_char alpha) \
{ \
u_int c0, c1, mask; \
if(alpha > 0) \
{ \
...

Только не так, Боже упаси! Функция в header'е display.h, который и подключается.
Dog Pawlowa
Цитата(sergeeff @ Jun 14 2009, 20:48) *
Ну это, условный рефлекс, наверное.

Форум "электроникс" - 1) достаточно модерируемый и 2) самоорганизующийся форум.
Я удивлен тем фактом, что мне приходится отметать Ваш переход на какие-то посторонние от техники аспекты.
Или Вы так зашорены, что больше нечего сказать?

Цитата(aaarrr @ Jun 14 2009, 20:59) *
Только не так, Боже упаси! Функция в header'е display.h, который и подключается.

А, ну да, конечно...
sergeeff
Цитата(Dog Pawlowa @ Jun 14 2009, 21:04) *
Или Вы так зашорены, что больше нечего сказать?


1. При чем тут зашоренность. Абсолютное большинство программистов, увидев
Код
ABC()
сразу поймет, что вызывается некая функция, т.е. некая локальная обработка данных, а
Код
ABC;
может означать все что угодно. Может это чтение из глобальной переменной ABC в стиле уважаемого гуру zltigo, a может вызов макро.
2. Есть понятие "стиль программирования". Мне кажется, что "стильно" написанная программа это такая, которая легко читается и сопровождается, и не только автором.
another_one
Цитата(MrYuran @ Jun 14 2009, 15:34) *
Я бы сделал так:



Всем большое спасибо за помощь
sergeeff
Цитата(another_one @ Jun 14 2009, 21:41) *
Всем большое спасибо за помощь


Небольшой пример для иллюстрации "прелестей" макро.
Код
#define UP(port, bit) port |= (1<<bit)

где-то в программе напишем:
Код
UP(port,2) + 3;


Понятно, что такое можно написать после долгих праздников, но это может быть и результатом типичной ляпы типа "copy/paste".
Очевидно, что это ляпа, но препроцессор это преобразует в
Код
port |= (1<<2) + 3;

и компилятор не моргнув никакими error/warning откомпилирует. Очевидно, что это ляпа, но сколько времени вы будете ее искать?

Ежели UP оформить в виде inline функции
Код
inline void UP(char port, char bit) {port &= ~(1<<bit);}


компилятор тут же выдаст что-нибудь типа '+' : illegal operand of type 'void' с указанием номера строки (VS 2008).

Если не хочется себе жизнь облегчать, то это, конечно, дело каждого уважаемого участника форума.
aaarrr
Цитата(sergeeff @ Jun 14 2009, 22:59) *
Ежели UP оформить в виде inline функции
Код
inline void UP(char port, char bit) {port &= ~(1<<bit);}

Ну, с тем же успехом можно сделать и в виде дефайна:
Код
#define UP(port, bit) {port &= ~(1<<bit);}
zltigo
Цитата(Dog Pawlowa @ Jun 14 2009, 20:36) *
Большие буквы, отсутствие скобок -> значит это макрос для работы с портами -> см файл project_ports.h

Отсутствующте скобочки они, конечно явно заставляют задуматься а что это такое? Причем задуматься без всякой на то надобности sad.gif.
Для подчеркивания того, что это макрос достаточным является запись большими буквами (хотя для "функций" я этим практически не пользуюсь - никакой информации это собственно не несет) естественным для 'C' является
on_backlight();
Ну или ксли хочется обратить внимание (обычно совсем без надобности) что это псевдофункция:
ON_BACKLIGHT();
Но и это излишество в вашем случае. Хотя иногда, явно полезно, например если что-то написано в незамысловатом стиле
Код
#define DEBUG_PRINT(  mask ) if( cfg_debug & (mask) )

DEBUG_PRINT( DL_RAW|DL_FULL )
    println( "Hello!" );



Цитата(aaarrr @ Jun 14 2009, 22:05) *
Ну, с тем же успехом можно сделать и в виде дефайна:
Код
#define UP(port, bit) {port &= ~(1<<bit);}

Точнее так smile.gif:
Код
#define up(port, bit) {(port) &= ~(1<<(bit));}
aaarrr
Да-да, copy-paste, в первый раз и "char" забыл убрать smile.gif
zltigo
Цитата(sergeeff @ Jun 14 2009, 21:59) *
Небольшой пример для иллюстрации "прелестей" макро.

Просто макросы, как, впрочем и программы, надо уметь писать. Причем умение писать макросы не бог весть какое великое.
sergeeff
Цитата(zltigo @ Jun 14 2009, 22:16) *
Просто макросы, как, впрочем и программы, надо уметь писать. Причем умение писать макросы не бог весть какое великое.


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

Во-вторых, я ведь просто для примера привел первый пришедший на ум пример когда макро, не мной написанное, а приведенное коллегами как пример для подражания, абсолютно молча привело к генерации неправильного С-ного кода.
Dog Pawlowa
Цитата(sergeeff @ Jun 14 2009, 22:38) *
... написать "дуракоустойчивый" макрос сложнее ...

Я то опираюсь на свою статистику - она более чем удовлетворительная.
И вообще, существуют правила, вроде бы очевидные и понятные, например правила проверки равенства (константа на первом месте), затрудняющие чтение программы (по крайней мере лично у меня).
Ну а скобочки ... говорю - из Паскаля я. Меня не заставляют задуматься. Те, кто использует мои тексты - тоже вроде не жалуются.
Хотя сомнение зародили, если такая точка зрения есть, ничего не стоит попробовать.

Кстати, указание inline, насколько я помню, не является безусловным и обязательным для компилятора, или?
aaarrr
Цитата(Dog Pawlowa @ Jun 14 2009, 23:54) *
Кстати, указание inline, насколько я помню, не является безусловным и обязательным для компилятора, или?

Не является. Но, во-первых, есть прагмы/модификаторы, настоятельно рекомендующие это компилятору (типа упомянутого __forceinline для RV); во-вторых, вредительством и саботажем компилятор тоже заниматься не станет.
zltigo
Цитата(sergeeff @ Jun 14 2009, 22:38) *
Согласитесь уважаемый гуру, что написать "дуракоустойчивый" макрос сложнее (хотя бы с точки зрения отладки) эквивалентной inline
функции.

Ну не знаю, не знаю... Сложность очень отностительная, при этом для написания функций тоже надо немного думать и знать механихм заинлайнивания, индивиуальные для компилятора правила требовния (на самом деле просьбы smile.gif )принудительного заинлайтивания, принудительное откючение inline при отключении оптимизации что тоже может привести к проблемам (ногомахание по времени вдруг посыпалось, стек в начал больше использоваться). Кроме того макросы могут быть и много более мощными и читаемыми - у меня нередко встречаются макросы просто и естественно работаюшие, напимер, с десятком разных параметров, да, такой макрос не совсем прост, но и inline (точнее любая) функция более, чем уродлива в таких случаях.
ReAl
Цитата(sergeeff @ Jun 14 2009, 21:41) *
2. Есть понятие "стиль программирования". Мне кажется, что "стильно" написанная программа это такая, которая легко читается и сопровождается, и не только автором.
В общем согласен. Но только с оговорокой "легко читается и сопровождается людьми, имеющими определённый уровень подготовки". Ни в коем случае не всеми, кто написал "Hello, world!".
А то ведь и в "человеческих" языках есть всякие там сложноподчинённые предложения, идиомы с прочими тропами, не говорю уже о профессиональной терминологии - тоже ведь не всё сказанное всем понятно будет, причём не только тем, кто только начал язык осваивать, но и многим "носителям". И это нормально.
Я немного увожу в сторону от основной темы обсуждения, но когда начинается "указательную арифметику не использовать, плохо читается" и т.п. я думаю - может просто надо уровень читателей поднимать?
Ведь в "должно быть понятно" можно докатиться до уровня рекламы стирального порошка или там "ретоны".
Когда вижу как бы на С написанное
Код
  if( flag )
  {
    struct.member[index] = a;
  }
  else
  {
    struct.member[index] = b;
  }
вместо
Код
   struct.member[index] = flag ? a : b;
я просто поражаюсь - насколько надо не любить и не знать С, чтобы так писать. А если это политика "чтобы понятно было", то на кого рассчитывается? И сможет ли этот "кто" понять всю программу?

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

Оптимум где-то посредине, и, на мой взгляд, в случае с С в этот оптимум входит понимание возможностей и ограничений макросов, а не вера в то, что они вредны, почёрпнутая из агитации за С++, причём на примерах ошибок, которые более менее грамотный программист просто не должен уже совершать (а на уровне, на котором они совершаются, и на С++ ничего хорошего не будет написано). Уровень их использования, который обсуждается в этой теме, не должен приводить к каким-то ощутимым на фоне всей программы задержкам понимания текста. Любой знающий язык С, а не некое усечённое подмножество "разрешённое к применению в фирме" должен быстро с ним разобраться.
Это понимание требует какого-то своего опыта. Начинающим сразу с С++ и не собирающимся работать на С может и можно послабление дать. Но с учётом того, что они (теоретически) должны научиться понимать гораздо более сложные вещи - макросы такого уровня они должны понимать легко.

Также в этот оптимум входит достаточное понимание указателей, чтобы не сильно долго задерживаться на строке
Код
a = (flag ? sin : cos)(fi);

Duff's device в него, пожалуй, не включу (хотя для понимания сути switch это весьма полезный пример и он есть в упражнениях у Страуструпа в "Язык программирования С++", причём это упражнение с низким уровнем сложности).


Цитата(sergeeff @ Jun 14 2009, 21:59) *
Небольшой пример для иллюстрации "прелестей" макро.
Код
#define UP(port, bit) port |= (1<<bit)

где-то в программе напишем:
Код
UP(port,2) + 3;
Можно и без макросов и без указателей и без goto наворотить такое, что никто не разберёт и не сможет сопровождать. Точно так же, как и имея словарный запас в три сотни слов можно нести околесицу. Приведенный Вами пример настолько "букварный", что или он из букваря и взят, или написавшему этот код человеку надо наконец-то вдумчиво прочесть книжку по языку С.

Вы никогда не видели примеры "индусского" кода на java, где "корень всех зол" в виде макросов отсутствует?

Что бы Вы сказали, если бы кто-то привёл пример такого кода как доказательство того, что с java надо уходить на С ?

Означате ли то, что некоторые взрослые не умеют правильно поставить запятые в предложении, необходимость исключения из школьной программы этой части курса родного языка или, как минимум, рекомендации пользоваться всем только простыми предложениями?

Цитата(sergeeff @ Jun 14 2009, 21:59) *
Ежели UP оформить в виде inline функции
Код
inline void UP(char port, char bit) {port &= ~(1<<bit);}
То на попытку применить эту функцию к порту будет выдано сообщение об ошибке. А так - она вообще ничего полезного не делает, так как модифицирует свой аргумент типа char.


Да, для avr-gcc можно написать
Код
// для С99 так
static inline void UP( volatile uint8_t *port, uint8_t bit)
{
    *port |= 1 << bit;
}

// а для режима С++ ещё и так
static inline void UP2( volatile uint8_t& port, uint8_t bit)
{
    port |= 1 << bit;
}
Но
1) для IAR это уже не прокатит, там по-другому описаны порты, типы volatile uint8_t * и volatile uint8_t & не подойдут.
А вот правильно написанный макрос UP будет работать и там, и там.
2) а с первого раза и inline-функцию не вышло написать правильно wink.gif За что боролись?

Ага. Вроде бы это должно работать где угодно.
Код
template<typename PP> inline void
UP3( PP & port, uint8_t bit)
{
    port |= 1 << bit;
}
Но это уже совсем не С, так что может иметь отношение только к разговору о (не)применении макросов в С++, даже к C99 отношения не имеет, а, как тут в параллельной теме выяснилось, и С99 иногда непозволительная роскошь.

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

Код
static inline void hal_SetRTS0(void)
{
    PORTG |= (1 << RTS0);
}

static inline void hal_ClrRTS0(void)
{
    PORTG &= ~(1 << RTS0);
}

static inline void hal_SetDTR0(void)
{
    PORTG |= (1 << DTR0);
}

static inline void hal_ClrDTR0(void)
{
    PORTG &= ~(1 << DTR0);
}


static inline void hal_PutRTS0(U8 val)
{
    if (val)
        hal_SetRTS();
    else
        hal_ClrRTS();
}

static inline void hal_PutDTR0(U8 val)
{
    if (val)
        hal_SetDTR();
    else
        hal_ClrDTR();
}


static inline U8 hal_GetCTS0(void)
{
    return (PINE & (1 << CTS0)) != 0;
}

static inline U8 hal_GetDCD0(void)
{
    return (PINB & (1 << DCD0)) != 0;
}

static inline U8 hal_GetDSR0(void)
{
    return (PINB & (1 << DSR0)) != 0;
}

static inline U8 hal_GetRI0(void)
{
    return (PINB & (1 << RI0)) != 0;
}
....


А уже потом где надо, эти функции с осмысленными названиями назначать структурам:

Код
typedef struct tagFLOW_CONTROL
{
    U8 enabled;   // flow control enabled (check CTS before transmitting)

    // acquiring signals cbs
    void (*On_DCD_Up)(struct tagFLOW_CONTROL *pCtrl);
    void (*On_CTS_Up)(struct tagFLOW_CONTROL *pCtrl);
    void (*On_DSR_Up)(struct tagFLOW_CONTROL *pCtrl);
    void (*On_RI_Up)(struct tagFLOW_CONTROL *pCtrl);

    // losing signals cbs
    void (*On_DCD_Down)(struct tagFLOW_CONTROL *pCtrl);
    void (*On_CTS_Down)(struct tagFLOW_CONTROL *pCtrl);
    void (*On_DSR_Down)(struct tagFLOW_CONTROL *pCtrl);
    void (*On_RI_Down)(struct tagFLOW_CONTROL *pCtrl);
    
    void (*set_rts_cb)(U8 val);
    void (*set_dtr_cb)(U8 val);
    
    U8   (*get_cts_cb)(void);
    U8   (*get_dsr_cb)(void);
    U8   (*get_dcd_cb)(void);
    U8   (*get_ri_cb)(void);
} TFLOW_CONTROL, *PFLOW_CONTROL;

...

#if (UART1_FULL_RS232)
    uart_con.u1_rs232_control.set_dtr_cb = hal_PutDTR0;
    uart_con.u1_rs232_control.set_rts_cb = hal_PutRTS0;
    uart_con.u1_rs232_control.get_cts_cb = hal_GetCTS0;
    uart_con.u1_rs232_control.get_dsr_cb = hal_GetDSR0;
    uart_con.u1_rs232_control.get_dcd_cb = hal_GetDCD0;
    uart_con.u1_rs232_control.get_ri_cb  = hal_GetRI0;

    uart_con.u1.pCtrl = &uart_con.u1_rs232_control;
    Kernel_SetTask( u1_DispatchRemoteFlowCtrlEvents, 5, TASK_PERIODIC);
#endif


Зачем нужны всякие макросы и прочая фигня для работы с портами то?
ReAl
====================
Кстати, об исходной теме и проблемах её автора :-)

В этой теме может что-то полезное найдётся.
zltigo
Цитата(defunct @ Jun 14 2009, 23:52) *
Зачем нужны всякие макросы и прочая фигня для работы с портами то?

Зачем нужна вся эта фигня для работы с портами то?
defunct
Цитата(zltigo @ Jun 15 2009, 00:03) *
Зачем нужна вся эта фигня для работы с портами то?

Как правило __работать__ с портами не нужно.
Нужно работать с какими-то внешними объектами, так уж получается что через порты. Порты - промежуточное звено, о котором лучше всего забыть вообще.
Упоминания о портах у меня заканчиваются в hal и нигде более в программе не вспоминаются.
zltigo
Цитата(defunct @ Jun 15 2009, 00:07) *
Нужно работать с какими-то внешними объектами, так уж получается что через порты. Порты - промежуточное звено, о котором лучше всего забыть вообще.

А вместо декларируемого HAL для "объекта" получена просто заумная работа с отдельными битам sad.gif. Вы не одиноки sad.gif, а заумные HAL пишут с неменьшим "успехом" и на макросах. Уму не растяжимой "красоты" пример HAL можно глянуть в SimpliciTI от TI. Ну их еще можно понять - а нефиг читать и портировать - берите и пользуйте только с нашими продуктами, как есть.
defunct
Цитата(zltigo @ Jun 15 2009, 00:16) *
А вместо декларируемого HAL для "объекта" получена просто заумная работа с отдельными битам sad.gif.

HAL у меня не декларирует непосредственно объекты (объекты описываются уже в соответствующих им файлах).
HAL у меня отделяет программу от МК. (Двухступенчатый HAL получается). В примере выше, TFLOW_CONTROL описан не в HAL, а в uart.h, т.к. это объект связанный с UART'ом.

Если мне нужно включить реле1 то я предпочту написать

hal_RelayOn();

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

hal_GreenLedOn();

вместо

SET_BIT( PORT_HZx, PIN_HZx);
CLR_BIT( PORT_HZy, PIN_HZy);

или других извратов.


В свою очередь, это дает возможность, легко управлять временем.
Например отключить реле __через 2 секунды__ после включения, я могу сразу же при включении реле:

hal_RelayOn();
Kernel_SetCb( hal_RelayOff, 2000, SEMA_NULL);

Ну и полностью забыть о GPIO портах как о классе, вне HAL.

Цитата
Вы не одиноки , а заумные HAL пишут с неменьшим "успехом" и на макросах.

на макросах такая конструкция
hal_RelayOn();
Kernel_SetCb( hal_RelayOff, 2000, SEMA_NULL);
непрокатит.
singlskv
Цитата(defunct @ Jun 15 2009, 01:28) *
на макросах такая конструкция
hal_RelayOn()
Kernel_SetCb( hal_RelayOff, 2000, SEMA_NULL);
непрокатит.
а почему не прокатит-то ?
почему макрос "Kernel_SetCb" не сможет укладывать countdown значение 2000 в соответствующую ячейку массива ?
defunct
Цитата(singlskv @ Jun 15 2009, 00:39) *
а почему не прокатит-то ?
почему макрос "Kernel_SetCb" не сможет укладывать countdown значение 2000 в соответствующую ячейку массива ?

Потому что Kernel_SetCb делает то что написано в названии - одноразово вызывает заданную функцию по таймауту или по событию в зависимости от того, что произойдет раньше.
Если вместо функции первым параметром дадите макрос (CLR/SET_PIN_X), думаю очевидно, что программа даже нескомпилится, т.к. у макроса не может быть адреса.
singlskv
Цитата(defunct @ Jun 15 2009, 01:46) *
Потому что Kernel_SetCb делает то что написано в названии - одноразово вызывает заданную функцию по таймауту или по событию в зависимости от того, что произойдет раньше.
Если вместо функции первым параметром дадите макрос (CLR/SET_PIN_X), думаю очевидно, что программа даже нескомпилится, т.к. у макроса не может быть адреса.
простите, а кто Вас заставляет давать в качестве параметра именно функцию, почему не передавать просто идентификатор пина ?
ну а если уж нужна разная обработка для разных пинов то можно и ссылку передавать и маску пина.
zltigo
Цитата(defunct @ Jun 15 2009, 00:28) *
если зажечь зеленый светодиод, а не красный и не желтый.

hal_GreenLedOn();

вместо

SET_BIT( PORT_HZx, PIN_HZx);
CLR_BIT( PORT_HZy, PIN_HZy);

Ровным счетом никаких отличий sad.gif Вы написали "десяток функций" для дергания пином с разными именами, кто-то напишет десяток макросов с разными именами, кто-то опишет десяток дефайнов для макросов а-ля Волков.. На самом деле из всех этих вариантов самый правильный скорее всего будет тот, кто банально содержит минимум разных букв. Зачастую меня более всего устраивает и такое самое простое и незатейливое:
Код
#define P0B_SPI0_FSEL0    BIT22
#define P0B_SPI0_FSEL1    BIT31
#define IOSET_SPI0 IO0SET
#define SPI0_SEL_MASK    (P0B_SPI0_FSEL1|P0B_SPI0_FSEL0)
....
IOSET_SPI0 = SPI0_SEL_MASK;


И даже для тех-же светодиодов уровень абстакции может, и я считаю- должен, быть заметно выше, нежели ON/OFF
void led_mode( Led_e led, Led_mode_e mode );
led_mode( LED_RED, LM_FLASH_1 );
Задается какой светодиод и десяток режимов миганий. Несклько десятков строк в отдельном файле посященном светодиодам. В файле без всяких слишком многоэтажных наворотов пишется, все , что нужно. Такой HAL, я понимаю.
defunct
Цитата(singlskv @ Jun 15 2009, 00:54) *
простите, а кто Вас заставляет давать в качестве параметра именно функцию, почему не передавать просто идентификатор пина ?
ну а если уж нужна разная обработка для разных пинов то можно и ссылку передавать и маску пина.

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

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

Точно также как в примере с реле я работаю и с более сложными процессами:

modem_Dial();
Kernel_SetCb( modem_Dial, 60000, SEMA_NULL); // повторный дозвон через минуту если не удалось дозвониться.

Цитата(zltigo @ Jun 15 2009, 01:00) *
Ровным счетом никаких отличий sad.gif

Ну как же никаких...
Вы можете поставить макрос в очередь задачь?
А инлайн функцию - запросто, компилер поймет что от него хотят. Там где можно заинлайнит, там где нужно вызовет по адресу.
singlskv
Цитата(defunct @ Jun 15 2009, 02:03) *
Вы читали о чем я пишу? Я пишу что надо забыть о портах, номерах пинов, и т.п. чтобы спалось спокойно.
Наверное пока не уловил, поэтому и переспрашиваю... smile.gif
Цитата
Kernel у меня работает с функциями и с задачами а не с идентификаторами пинов.
А может Вашему кернелу уже работать с объектами а не с отдельными сущностями ?
Цитата
Точно также как в примере с реле я работаю и с более сложными процессами:
modem_Dial();
Kernel_SetCb( modem_Dial, 60000, SEMA_NULL); // повторный дозвон через минуту если не удалось дозвониться.
совсем не уловил почему countdown счетчик для пина должен принципиально отличаться от таково же для модема ?
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.