Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Использование битовых областей в IAR (ATMega128)
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > MCS51, AVR, PIC, STM8, 8bit
IF_P
Перешел на ATMega128 после 51-го. Не нашел здесь битового пространства. Т.е. либо использовать регистровый файл, либо р-ры I/O 0-1F. С р-рами в/в я уже обжегся, использовав бит аппаратного прерывания. Хотя в документации написано, что данный бит программно R/W.
Начал использовать общие р-ры 8-13:

__no_init bitfield FLAG_2@0x08;
#define flag_wait FLAG_2.bit0
#define flag_ESC FLAG_2.bit1
#define flag_in FLAG_2.bit2

Но вот в некоторых случаях начали проявляться программные глюки - самопроизвольное изменение некоторых бит.
В одном случае это было при использовании

retrurn atoi(...);

В другом случае при использовании локальных переменых в п/п. При входе в п/п мои р-ры сохранялись, а на их место определялись локальные переменные. Не выходя из этой п/п (т.е. не восстанавливая мои биты) я захожу в другую п/п, где использую указанные биты, которых там уже нет.
И я, вроде, делаю все правильно и компилятор тоже.
Как выйти из такой ситуации?. Не использовать р-ровый файл? А что использовать? Р-ры в/в? crying.gif
RAM не хотелось бы использовать, а то при каждой установке/сбросе выполняется аж 5 команд:

str.bitOne=1;

LDI R30, LOW(str)
LDI R31, (str) >> 8
LD R16, Z
ORI R16, 0x01
ST Z, R16

Кто что может посоветовать? IAR только начал изучать. Может есть какие настройки, чтобы избежать подобных ситуаций?
Stanislav_S
Для начала почитайте - AVR035: Efficient C Coding for AVR. Станет немного понятней. Если сильно хотите, то можно использовать регистрв ввода вывода, например регистры таймеров которые не используются, но надо понимать что у АВР нет такого битового пространства как в 51. А лучше все таки почитайте для начала документ.
V_G
Я переходил с 51 на Мегу где-то лет 7-8 назад. Программирую на ассемблере до сих пор. Тоже не хватало битового массива, отвожу несколько регистров из регистрового файла под аналог этого массива. Проблем с самопроизвольным изменением битов нет.
SergeyTT
Цитата(IF_P @ Feb 9 2010, 16:21) *
Перешел на ATMega128 после 51-го. Не нашел здесь битового пространства. Т.е. либо использовать регистровый файл, либо р-ры I/O 0-1F. С р-рами в/в я уже обжегся, использовав бит аппаратного прерывания. Хотя в документации написано, что данный бит программно R/W.
Начал использовать общие р-ры 8-13:

__no_init bitfield FLAG_2@0x08;
#define flag_wait FLAG_2.bit0
#define flag_ESC FLAG_2.bit1
#define flag_in FLAG_2.bit2

Но вот в некоторых случаях начали проявляться программные глюки - самопроизвольное изменение некоторых бит.
В одном случае это было при использовании

retrurn atoi(...);

В другом случае при использовании локальных переменых в п/п. При входе в п/п мои р-ры сохранялись, а на их место определялись локальные переменные. Не выходя из этой п/п (т.е. не восстанавливая мои биты) я захожу в другую п/п, где использую указанные биты, которых там уже нет.
И я, вроде, делаю все правильно и компилятор тоже.
Как выйти из такой ситуации?. Не использовать р-ровый файл? А что использовать? Р-ры в/в? crying.gif
RAM не хотелось бы использовать, а то при каждой установке/сбросе выполняется аж 5 команд:

str.bitOne=1;

LDI R30, LOW(str)
LDI R31, (str) >> 8
LD R16, Z
ORI R16, 0x01
ST Z, R16

Кто что может посоветовать? IAR только начал изучать. Может есть какие настройки, чтобы избежать подобных ситуаций?


Если вы хотите работать с анонимными битовыми полями,попробуйте вот это:
// в хидере,например, flags.h,делаем объявление
__no_init volatile union
{
unsigned char flags;
struct
{
unsigned char flag_wait :1;
unsigned char flag_ESC :1;
unsigned char flag_in :1;
};
}@<здесь пропишите адрес ОЗУ,где будет храниться этот юнион,например,начальный адрес свободного ОЗУ,по вкусу>;

Далее инклудите этот хидер в модули,где есть обращение к нужным флажкам,и спокойно работаете с ними,например:

if(flag_wait)
flag_ESC = 0;
else
flag_in = 1;

Компилятор создаст в ОЗУ переменную _A_flags и будет дергать биты командами установки/сброса конкретного бита.

Многократное объявление переменной в разных программных модулях(#include flags.h) здесь до лампады,
как-бы гуру-супермодераторы не возмущались по этому поводу ;-)
IF_P
Цитата(SergeyTT @ Feb 9 2010, 18:52) *
Если вы хотите работать с анонимными битовыми полями,попробуйте вот это:
// в хидере,например, flags.h,делаем объявление
__no_init volatile union

...

flag_ESC = 0;

Компилятор создаст в ОЗУ переменную _A_flags


Так я ведь в своем первом посте тоже привел пример битовой переменной, как элемента структуры и ее ассемблерную мнемонику. Только опустил описание самой структуры. Все это я использовал. Но не хотел размещать в RAM, т.к. это уже работа с байтами. При описании структуры в RAM получим:

flag_ESC=1;

LDI R30, 15 (дизассемб)
LDI R31, 0
LD R16, Z
ORI R16, 0x01
ST Z, R16


А при использовании р/р в/в (ADCH) уже совсем иначе:

__no_init volatile bitfield Flag_W@0x25;
#define Flag_W1 Flag_W.bit0
#define Flag_W2 Flag_W.bit1


Flag_W1=1;

SBI 0x05, 0x00

Flag_W2=0;

CBI 0x05, 0x01

Так что придется снова возвращаться к р-рам в/в. Только вот что делать, если в будущем придется задействовать эти р-ры?
SSerge
Неужели эти несколько тактов так критичны, что Вы пускаетесь во все тяжкие?

Оставьте ассемблерные привычки, пишите на С.
Регистры процессора, счётчик команд, указатель стека и регистр состояния - всё это забота компилятора, пусть он ими занимается.
Установите в настройках проекта максимальный уровень оптимизации по скорости и больше не сокрушайтесь об эффективности, лучше потратить время на оптимизацию алгоритма на верхнем уровне, больше выиграете.
Листинг, впрочем, иногда смотреть полезно.
alux
Цитата(IF_P @ Feb 10 2010, 04:11) *
Так что придется снова возвращаться к р-рам в/в. Только вот что делать, если в будущем придется задействовать эти р-ры?

В будущем (и настоящем) можно без проблем заменить на новую ATmega1281. В новых микроконтроллерах есть для этой цели отдельные General Purpose I/O Register 0/1/2.
_Pasha
Цитата(SergeyTT @ Feb 9 2010, 19:52) *
Многократное объявление переменной в разных программных модулях(#include flags.h) здесь до лампады,

Если Вы самоубийца, то зачем тянуть за собой остальную компанию?
V_G
На ассемблере для регистрового файла есть битовые операции записи из флага T в бит регистра:
BLD reg,bit
и чтения из регистра во флаг T:
BST reg,bit

Установка/сброс флага T: SET/CLT

Проверка бита на 0: SBRC reg,bit
На 1: SBRS reg,bit

Логика операций с битами несколько отличается от 51 машины, но в принципе достаточно быстра и при работе на ассемблере проблем не вызывает
Dog Pawlowa
Цитата(IF_P @ Feb 9 2010, 17:21) *
Кто что может посоветовать?

Побыстрее бросайте эти немотивированные изыски.
Памяти не хватает? Быстродействия?
Если точно не хватает, замените контроллер.
Зачем плодить непереносимый код - не понимаю.
IF_P
Цитата(SSerge @ Feb 10 2010, 04:09) *
Неужели эти несколько тактов так критичны, что Вы пускаетесь во все тяжкие?
...
Оставьте ассемблерные привычки, пишите на С.
...
Листинг, впрочем, иногда смотреть полезно.

Так ведь и речь идет о С. На ассемблере этих проблем нет. И именно из листинга я и привел ассемблерную мнемонику С-шных команд.
Что касается "несколько тактов", то у меня около 10 байт битовых переменных, которые активно используются (установка, сброс, анализ).
В даном случае для меня абсолютно не критично ни количество тактов, ни размер памяти. Вопрос был в том, чтобы разобраться с использованием битов.

А что касается оптимизации компилятором, то я считаю,что лучше самому продумать, по возможности, все варианты оптимизации и до и во время написания программы, чем полагаться на компилятор. Ведь компиляторы тоже пишут люди и они ошибаются. Мне уже приходилось по несколько дней искать "глюки" (Franklin, Keil). А потом оказывается, что это "глюк" компилятора. И абсолютно правильно написанный код приходится переписывать под компилятор.
У каждого свой подход к программированию. "Делай как можно лучше. А оно все равно будет хуже". Так меня еще в детстве мать учила. А если делать кое-как, то результат может быть плачевным. Я не претендую на истину, но каждому свое.
Спасибо всем за советы.

To alux:

Только General Purpose I/O Register 0 находится в бит-адресуемой области. Остальные за ее пределами (0x1F).
Так что по битовым опрециям AVR уступает 8051.


Цитата(SergeyTT @ Feb 9 2010, 18:52) *
Многократное объявление переменной в разных программных модулях(#include flags.h) здесь до лампады,

Для этих целей я обычно использую extern:

extern bit Enable_Display; // CS для дешифратора LCD P1.0
extern bit DISPLAY_E;

Это для Keil 51-го. Хотя там тоже были проблемы с их использованием
http://electronix.ru/forum/index.php?showt...st&p=525347

Для AVR и IAR пока не сталкивался.
SasaVitebsk
Цитата(IF_P @ Feb 10 2010, 14:44) *
Так ведь и речь идет о С. На ассемблере этих проблем нет. И именно из листинга я и привел ассемблерную мнемонику С-шных команд.
Что касается "несколько тактов", то у меня около 10 байт битовых переменных, которые активно используются (установка, сброс, анализ).
В даном случае для меня абсолютно не критично ни количество тактов, ни размер памяти. Вопрос был в том, чтобы разобраться с использованием битов.


Тогда не понимаю в чём проблема. Используйте узаконенные в Си операции.
Код
struct
{
uint32_t
                  Master :1,
                  LoadActivCom :1,
                  Str : 3,
....
                  gEnd:1;
} Flag;
....

if(Flag.Master) ....
....

Flag.Master = 1; // а хотите TRUE
...
Flag.Master = Flag.gEnd; Flag.Str = 5;


Чем не устраивает, или я чего-то не понимаю?

Хотя я, в последнее время использую для этих целей байты.
========
Кстати о atxmega.
Есть битовое поле и в ATMEGA88(48/168).


The ATmega48/88/168 contains three General Purpose I/O Registers. These registers
can be used for storing any information, and they are particularly useful for storing global
variables and Status Flags. General Purpose I/O Registers within the address range
0x00 - 0x1F are directly bit-accessible using the SBI, CBI, SBIS, and SBIC instructions.

PS: Если речь идет об атомарности доступа, то тут есть проблемы не только с битами, но и с любыми интегральными типами. Для x51, например, с int16/32, и т.д. Решение - запрет прерываний.
Работа с битами на уровне МК, в общем то, не хуже.
_Pasha
Цитата(IF_P @ Feb 10 2010, 15:44) *
А что касается оптимизации компилятором, то я считаю,что лучше самому продумать, по возможности, все варианты оптимизации и до и во время написания программы, чем полагаться на компилятор. Ведь компиляторы тоже пишут люди и они ошибаются. Мне уже приходилось по несколько дней искать "глюки" (Franklin, Keil). А потом оказывается, что это "глюк" компилятора. И абсолютно правильно написанный код приходится переписывать под компилятор.

Ну, это уж слишком! Глюки компилятора, во-первых, интенсивно фикcятся большим кол-вом людей, во-вторых, можно просто заглянуть в листинг и все там увидеть.

По поводу битовых полей. Структуры с размером в 1 бит, объединенные в байты - это самое оптимальное и единственно прямое решение на данной архитектуре, без намека на оверхед.
Код
union
{
uint8_t flags;
struct
{
  unsigned flag0:1;
  unsigned flag1:1;
итд итп
}
}
Сергей Борщ
Цитата(IF_P @ Feb 10 2010, 13:44) *
Мне уже приходилось по несколько дней искать "глюки" (Franklin, Keil). А потом оказывается, что это "глюк" компилятора.
Приносите, показывайте. Тут на весь форум реальных глюков компилятора обнаруживается 2-3 за год, все остальные - от незнания стандарта писателем программы или его же нежелания прочесть документацию на компилятор. Нет, можно конечно предположить, что вы такой везучий и вам их (настоящих глюков) попалось значительно больше, но верится в это с трудом. "Код в студию!".
IF_P
Цитата(SasaVitebsk @ Feb 10 2010, 22:04) *
Тогда не понимаю в чём проблема. Используйте узаконенные в Си операции.

Чем не устраивает, или я чего-то не понимаю?

Да я это все давно использую. Только заглянув в листинг я увидел, что для установки/сброса одного бита выполняется целый ряд команд, котрые я и указал в первом посте. Привожу еще раз:

str.bitOne=1; - установка бита в структуре str

а это ассемблерная мнемоника этой же команды:

LDI R30, LOW(str)
LDI R31, (str) >> 8
LD R16, Z
ORI R16, 0x01
ST Z, R16

Т.е. , вместо одной команды SBI, CBI,... выполняется целых 5. Вот я и начал разбираться. В 51-м для этих целей существует битовое поле. Аналогичное я начал искать здесь. Оказывается AVR этим не богат. Битовые операции поддерживают только р-ры в/в с адресами 0x0-0x1F. А для своих нужд здесь ничего нет. И даже из указанных вами General Purpose I/O Registers только один находится в бит-адресуемом пространстве. К двум другим обращение будет идти указанным выше способом 5 команд). Так что, имеем то, что имеем wassat.gif
Dog Pawlowa
Цитата(IF_P @ Feb 11 2010, 14:30) *
для установки/сброса одного бита выполняется целый ряд команд

Если так страшен целый ряд команд в этом месте, то для этого флага можно использовать один байт.
Сколько таких важных флагов в программе? На три байта насобирали?
Ну будет на 21 байт больше. Об этом спорим? Не хватает?
Или хватает, и нужны "шашечки"?
IF_P
Цитата(Сергей Борщ @ Feb 11 2010, 12:03) *
Приносите, показывайте.
"Код в студию!".

Это было на 51-м, с которым сейчас не работаю. Хотя я помню, где это было, но точный пример не смогу привести, т.к. исправил программу и не обращался на форум. Могу только описать.

if (....проверялось 5-6 условий...) { ...a=1; }

Смотрю в симуляторе. Выполняются все условия. Симулятор выходит на оператор a=1 и после его выполнения a=0 ???
Когда начал разбираться с ассемблерным кодом, то увидел, что компилятор "забыл" обнулить р-р DPTR (есть такой в 51-м) перед его использование , что и привело к такому результату.
Решил проблему заменой одного длинного условного оператор двумя короткими.

Условный оператор был похожим на:

if ((rejym_start==2 && rej__rab==3) || (rejym_start==2 && rej__rab==5) ||
(rejym_start==3 && rej_H_A==0)) {

Эта часть программы была проверена и работала. Когда добавил одно условие в условный оператор, получил неработоспособный код.
О моей ошибке речи быть не может, т.к. выполняется оператор присваивания a=1; с результатом =0;

В следующий раз постараюсь сохранить подобные "глюки".

Цитата(Dog Pawlowa @ Feb 11 2010, 13:16) *
Если так страшен целый ряд команд в этом месте, то для этого флага можно использовать один байт.
Сколько таких важных флагов в программе? На три байта насобирали?
Ну будет на 21 байт больше. Об этом спорим? Не хватает?
Или хватает, и нужны "шашечки"?

На десять байт насобирал. Но не об этом речь. Я уже писал, что хотел разобраться ( см. пост №11). И понял, что операций с битами здесь нет (за исключением р-ров 0-0x1F). Есть операций с байтами. Вот и все.

А если под "шашечками" вы подразумеваете уровень активности, то посмотрите на дату регистрации. За это время можно было уже... (если бы это было целью).
Dog Pawlowa
Цитата(IF_P @ Feb 11 2010, 15:53) *
А если под "шашечками" вы подразумеваете уровень активности, то посмотрите на дату регистрации. За это время можно было уже... (если бы это было целью).

smile.gif если это упрек много пишущим, то у них своя правда - написать фигню, получить по мозгам, и вовремя исправиться.
Вы лишили себя возможности ускоренной корректировки собственных действий.
IF_P
Цитата(Dog Pawlowa @ Feb 11 2010, 15:31) *
smile.gif если это упрек много пишущим, то у них своя правда - написать фигню, получить по мозгам, и вовремя исправиться.
Вы лишили себя возможности ускоренной корректировки собственных действий.

Я привык во всем разбираться, А "делай так, потому, что так нужно" - это не для меня. Потом снова будут возникать какие-то дурацкие вопросы. А так вот сейчас разобрался с битами, посмотрел листиниги и сделал вывод, что буду использовать вместо бит в основном байты. Получается и код эффективнее и быстродействие выше.
Я ведь с AVR (да и с IAR) только начал работать, потому и хочется разобраться до конца, чтоб не наступать в будущем на те же грабли.

P.S.
А упрекать я никого и не собирался. Я так понял, что меня упрекнули в подобных писаниях. Может я и ошибся. Тогда прошу извинить.
IF_P
Цитата(SergeyTT @ Feb 9 2010, 19:52) *
Многократное объявление переменной в разных программных модулях(#include flags.h) здесь до лампады,

Цитата(_Pasha @ Feb 10 2010, 07:09) *
Если Вы самоубийца, то зачем тянуть за собой остальную компанию?

Вот сейчас попробовал сделать, как рекомендовал SergeyTT. Выделил глобальные флаги в отдельный хидер, подцепил его к двум файлам, скомпилил. Вроде все нормально - проверил по листнгу.

Так в чем здесь может быть проблема?
Dog Pawlowa
Цитата(IF_P @ Feb 11 2010, 19:12) *
Я так понял, что меня упрекнули в подобных писаниях.

Наверное, я дал повод. И Вы простите за некоторую эмоциональность.
Увы, жизнь так устроена, что если во всем очень тщательно разбираться, ничего не удается сделать. Иногда нужно делать, не разбираясь самому, на основе советов smile.gif
Интуиция может подсказать, что совет по использованию битовых областей не очень удачный, а может и нет.
SasaVitebsk
Если у вас такая задача, то кто вам мешает использовать 51 ядро? Предложений - вагон.
Тот же Atmel, кроме стандартных кристаллов, сейчас предлагает однотактовые. 20-25 мипсов на выходе, ISP и так далее. Памяти много. Есть и cygnal до 100 мипсов.
_Pasha
Цитата(IF_P @ Feb 11 2010, 13:30) *
str.bitOne=1; - установка бита в структуре str

а это ассемблерная мнемоника этой же команды:

LDI R30, LOW(str)
LDI R31, (str) >> 8
LD R16, Z
ORI R16, 0x01
ST Z, R16

Если Вам уже надоели разговоры ни о чем, то:
1. Расскажите, что это за структура. Если volatile, то чему удивляетесь?
2. Не совсем понятна причина, по которой взрослые дяди зацикливаются на битовых полях. Например, многоэтажный матюк if(()||()||(()&&()&&()) не потянет за собой в область статических переменных ни единого бита, использование конструкций типа
Код
uint_fast8_t work=0;
do
{
if(conditional_expression1) break;
..........................
if(conditional_expressionN) break;
work = 1;
}
while(0);
if(work){do_something}

Это Вам не булева алгебра, все можно навернуть так, что в сумме получается эффективнее работы с флагами
В конце концов
Код
extern uint8_t reg[];
if(reg[0] > 0x80) // check bit 7
if(((reg[0] ^ reg[1])&0xE0) == 0xE0) //проверили 3 бита на изменение

Интересно, сколько будет булевый процессор считать это. И особенно обидно, что нету косвенной адресации бит smile.gif
SasaVitebsk
Цитата(Dog Pawlowa @ Feb 11 2010, 14:16) *
Если так страшен целый ряд команд в этом месте, то для этого флага можно использовать один байт.
Сколько таких важных флагов в программе? На три байта насобирали?
Ну будет на 21 байт больше. Об этом спорим?

+100.
Мне кажется, постепенно все к этому и приходят. Я, к примеру уже пришёл.
Надо давить в себе скрягу. smile.gif
Если реально просмотреть проекты, то памяти, в последнее время, вполне хватает. Но если даже её требуется много, то всё равно, как правило байты, потраченные на флаги, существенно не влияют на общую картину.

Цитата
Зачем плодить непереносимый код - не понимаю.

+1000.
Даже используя 51, я бы скорее всего отказался от спец конструкций. Другое дело если бы компилятор сам справился.

На мой взгляд, надо постепенно менять мышление. Исходить из задачи - выбирать микропроцеесор - писать, задумываясь о результате, но не вылизывая каждую строчку. Стоимость разработки складывается также и из времени разработки. Чем быстрее завершаешь проект - тем быстрее изделие увидет покупателя. А это определяется переносимостью и возможностью развития. То есть универсальность - очень важная составляющая.

Тут выбирал МК для одного проекта. Так получается разница м/у STM32F105V и 107 практически стирается. А во втором MAC. Казалось бы дорогостоющая переферия. Я уже не говорю, что эта stm32f105 дешевле at90can128 c двумя CAN контроллерами, а stm32f103 (с одним CAN) - значительно дешевле. Кристаллы не сопоставимы по функционалу и производительности. И, похоже, процесс развития в этой области всё ускоряется. То есть переход с камня на камень дальше будет происходить всё чаще.
demiurg_spb
Цитата(Dog Pawlowa @ Feb 11 2010, 14:16) *
Если так страшен целый ряд команд в этом месте, то для этого флага можно использовать один байт.
Это бесспорно. Ибо при этом можно не парится с атомарностью доступа к битовым полям и просто битовым флагам в байте.
Как тут уже говорил кто-то:"Каждый сам себе злобный Буратино":)
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.