Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: спецификатор static
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > MCS51, AVR, PIC, STM8, 8bit
John851
Добрый день,

в какой памяти AVR хранится переменная объявленная со спецификатором static?

есть ли в avr libc (поставляемой вместе с WinAvr) атомарная операция nop?
MrYuran
Цитата(John851 @ May 26 2010, 16:30) *
в какой памяти AVR хранится переменная объявленная со спецификатором static?

Если переменная, то в ОЗУ, где ж ей ещё быть
John851
абсолютно все переменные попадают в ОЗУ? или есть исключения?
Сергей Борщ
Цитата(John851 @ May 26 2010, 15:54) *
абсолютно все переменные попадают в ОЗУ? или есть исключения?
Если они объявлены с макросами PROGMEM (PSTR()), EEMEM - то во флеш и eeprom соответственно. Но доступ к ним должен осуществляться через соответствующие макросы. И static к этому отношения не имеет.
sigmaN
static лишь ограничивает область видимости переменной текущим модулем(в котором она объявлена).
Ещё static внутри функции - отдельная тема. Там область видимости уже не модуль, а функция, но значения переменной сохраняются между вызовами функции.

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

Вообще static немного влияет на размещение переменных, но только в случае локальной переменной(внутри функции).
static переменная не размещается в стеке(как все локальные), а помещается в секцию .bss, ко всем остальным глобальным переменным(если мне не изменяет память).
swisst
Цитата(John851 @ May 26 2010, 15:30) *
есть ли в avr libc (поставляемой вместе с WinAvr) атомарная операция nop?


добавлю свои пять копеек...

Код
#define nop() asm volatile("nop\n\t"::)
John851
Еще немного про ОЗУ:
А как происходит работа с ОЗУ? Переменные туда попадают при каждом старте МК или зашиваются при прошивке? Почему такой маленький объем этой памяти?

что означает спецификатор inline перед функцией? как это отразится МК, т.е. она будет какая то особая?
MrYuran
Цитата(John851 @ May 27 2010, 09:30) *
Еще немного про ОЗУ:
А как происходит работа с ОЗУ? Переменные туда попадают при каждом старте МК или зашиваются при прошивке? Почему такой маленький объем этой памяти?

А информатики в школе не было? biggrin.gif
ОЗУ - это то, что гаснет при выключении питания, а при включении может заполняться произвольными значениями.
В переменные, инициализированные при объявлении, значения заносятся процедурой startup, которая стартует перед main().
Остальные - ваша личная забота.
Объём маленький (по сравнению с флешью), потому что это дорогая, большая по физическим размерам и довольно прожорливая статическая память.
Цитата
что означает спецификатор inline перед функцией? как это отразится МК, т.е. она будет какая то особая?

Таким образом вы сообщаете компилятору, что хотели бы встроить тело функции в месте вызова, вместо того чтобы вызывать функцию через CALL.
Это увеличивает быстродействие, а в случае совсем маленьких функций может даже экономить место.
xelax
Цитата(sigmaN @ May 26 2010, 19:01) *
static переменная не размещается в стеке(как все локальные), а помещается в секцию .bss, ко всем остальным глобальным переменным(если мне не изменяет память).


Уверены, что всегда размещаются в bss секции?
Есть предположение, что в примере переменная ляжет в секцию data.
Код
void function(void)
{
  static uint8_t tempVariable = 0x55;
  ....
}
eracer
Извиняюсь, что влезаю в чужой топик. Возникла непонятка со спецификатором static, поэтому решил запостить сюда вопрос. Программа осуществляет ЦАП с помощью ШИМ. Запись в регистр сравнения осущетсвляется по прерыванию при переполнению счетчика.
Функция обработки прерывания выглядит следующим образом:
Код
__interrupt void T1_OVF_Handler()
{
    static unsigned int num = 0;
    temp = sin(2*pi*Fsin*num/Fpwm); //
    OCR1A = short(temp*TOP_PWM);
    num++;
    if (num >= Fpwm) num = 0;
    IntToChar(UART_out, 4, OCR1A);
    PutTextToUART(UART_out, 4);
}

При пошаговой отладке после вычисления синуса, значение num меняется на 22016 (причем Fpwm=7844), и соответственно при сравнении обнуляется. Если сделать глобальное объявление переменной, то проблема исчезает. Но почему так происходит, к сожалению понять так и не смог.
aaarrr
Цитата(eracer @ May 27 2010, 12:20) *
При пошаговой отладке после вычисления синуса, значение num меняется на 22016 (причем Fpwm=7844), и соответственно при сравнении обнуляется. Если сделать глобальное объявление переменной, то проблема исчезает. Но почему так происходит, к сожалению понять так и не смог.

Стеком поди затирается. Вообще, использование sin() и прочей плавучки внутри обработчика прерывания - это ну совсем нехорошо по целому ряду причин.
demiurg_spb
Попробуйте сделать табличку значений синуса с нужным шагом во флеши.
И ещё у Вас UART буферизован?
eracer
Цитата(aaarrr @ May 27 2010, 12:31) *
Стеком поди затирается. Вообще, использование sin() и прочей плавучки внутри обработчика прерывания - это ну совсем нехорошо по целому ряду причин.

Действительно стек на 32 байта, заполнен полностью. А можете рассказать про причины, или дать ссылку?
Знаю, что прерывания не должны "подвешивать" программу. Но в данном случае я проверял по количеству циклов, все вычисления уложаться до начала реверсивного счета.

Цитата
Попробуйте сделать табличку значений синуса с нужным шагом во флеши.
И ещё у Вас UART буферизован?

Проблема в том, что потребуется слишком много значений. Можно по идее ограничиться десятью и постепенно подгружать новые, но при этом нужно будет основную программу синхронизировать с прерыванием, чтобы в функцию обработки попадали только "нужные" значения. Это отдельная задача, и я еще над ней не задумывался. Та же проблема с UARTом, который тоже должен работать независимо.
MrYuran
Цитата(eracer @ May 27 2010, 14:31) *
Действительно стек на 32 байта, заполнен полностью.

lol.gif
Да у вас один вызов функции может полстека съесть!
Что ж так жадничаете?
aaarrr
Цитата(eracer @ May 27 2010, 14:31) *
А можете рассказать про причины, или дать ссылку?

Причина в том, что работа с плавающей запятой по определению ресурсоемкая и медленная. Кроме того, данные функции не всегда являются реентерабельными (нужно справится в документации на конкретную библиотеку), что накладывает дополнительные ограничения на их использование в прерываниях.
eracer
Цитата(MrYuran @ May 27 2010, 14:37) *
lol.gif
Да у вас один вызов функции может полстека съесть!
Что ж так жадничаете?

Затруднил себя покопаться поглубже в настройках компилятора )) Мне казалось, что его размер выбирается автоматически
John851
хм, в чем разница объявления глобальной переменной в модуле?

int abc;

static int abc;

Разницы ведь никакой, переменная так и останется глобальной в пределах видимости модуля, дак зачем тогда еще и static прописывать?
MrYuran
Цитата(John851 @ May 27 2010, 16:27) *
Разницы ведь никакой, переменная так и останется глобальной в пределах видимости модуля, дак зачем тогда еще и static прописывать?

Вот именно, "в пределах видимости модуля".
То есть мы сообщаем компилятору, что за пределами данного модуля эта переменная не используется.
Что позволяет ему оптимизировать её в хвост и гриву.
То же самое относится и к функциям.
Вывод:
Если для вас разницы нет, пишите static везде, где можно.
aaarrr
Цитата(John851 @ May 27 2010, 16:27) *
Разницы ведь никакой, переменная так и останется глобальной в пределах видимости модуля, дак зачем тогда еще и static прописывать?

Как это никакой? Во втором случае переменная будет видима только в пределах "своего" модуля.
mempfis_
Цитата(John851 @ May 27 2010, 15:27) *
Разницы ведь никакой, переменная так и останется глобальной в пределах видимости модуля, дак зачем тогда еще и static прописывать?


Если при следующем вызове функции понадобится значение этой переменной (хотя я в своей практике программирования ещё такого не встречал) то объявляйте её static - компилятор выделит под неё память и будет использовать только выделенную область памяти при вызове этой функции и конкретно для этой переменной.

Без static компилятор выделит память в стеке и после использования переменной забудет о ней (при следующем вызове ф-ии эта переменная может быть положена в стек в любом доступном месте и её начальное значение может быть произвольным).

Вобщем IMHO static это ненужный расход оперативной памяти которая могла бы пойти на увеличение стека.
sigmaN
Цитата
Вобщем IMHO static это ненужный расход оперативной памяти которая могла бы пойти на увеличение стека.
IMHO - ничего не понимаете вы в колбасных обрезках smile.gif
Сергей Борщ
Цитата(mempfis_ @ May 27 2010, 17:35) *
Если при следующем вызове функции понадобится значение этой переменной
static для глобальных и локальных переменных имеет разное значение. Вопрос #17 был про глобальные переменные, а вы ответили про локальные.
_Pasha
Цитата(mempfis_ @ May 27 2010, 17:35) *
Если при следующем вызове функции понадобится значение этой переменной (хотя я в своей практике программирования ещё такого не встречал) то объявляйте её static


Код
void do_something(void)
{
static unsigned int ticks;
unsigned int tick_last;
//.................................
   tick_last = get_tick();
   if((tick_last - tick) > TIME_INTERVAL)
     {
        set_relay(1);
        tick = tick_last;
     }
}

Пример вызова ф-ции, включающей реле по наступлению момента времени TIME_INTERVAL с использованием некоей системы генерации системных тиков. А шо, не использовать же delay() в прерываниях!? biggrin.gif
MrYuran
Цитата(_Pasha @ May 28 2010, 09:52) *
А шо, не использовать же delay() в прерываниях!? biggrin.gif

А действительно, я как-то и не думал о таком применении.
Это ж можно макрос накатать типа
TIMER(interval,action)
и существенно обкультурить исходники
mempfis_
Цитата(sigmaN @ May 28 2010, 00:42) *
IMHO - ничего не понимаете вы в колбасных обрезках smile.gif

Может быть всех тонкостей применения static не знаю - учился на электронщика а не программиста smile.gif
Но для глобальных переменных никогда его не применял smile.gif

Были конструкции такого типа (когдато подсказали сдесь на форуме)
Код
#define PutString(x) do{static __flash char  str[]=x; _putstring(str);}while(0);


Ну ещё в прерываниях по таймеру если нужно было с фиксированным периодом чтото выполнять
Код
void ISR_PIT();
{
  static unsigned int i=1000;

//вызов задачи раз в секунду
if(i>0) i--;
else
{
   i=1000;
   TaskON(5);
}
}



Цитата(Сергей Борщ @ May 28 2010, 02:24) *
static для глобальных и локальных переменных имеет разное значение. Вопрос #17 был про глобальные переменные, а вы ответили про локальные.


Вы правы - действительно мой ответ касался локальных переменных laughing.gif
В глобальных не приходилось применять - небыло необходимости объявлять переменные видимые только в одном модуле smile.gif
sigmaN
Цитата
В глобальных не приходилось применять - небыло необходимости объявлять переменные видимые только в одном модуле
Странно, а я напротив часто пару-тройку глобальных статиков имею.... Может быть не задумывались просто, что эта глобальная переменная только в этом файле нужна и можно немного ограничить её глобальность smile.gif

А может быть вместо нормально связывания - вяжете всё через глобальные переменные. А это как-то.... sad.gif
demiurg_spb
Цитата(mempfis_ @ May 28 2010, 11:04) *
В глобальных не приходилось применять - небыло необходимости объявлять переменные видимые только в одном модуле smile.gif
Какие Ваши годы:-) Рассматривайте механизм применения static для локалных объектов внутри одного модуля трансляции (файла) ещё и как дополнительный способ самодокументирования программы и всё встанен на свои места.

Также стоит понимать, что локальная статическая переменная внутри функции (более-менее существенного размера) не несёт накладных расходов на выделение стекового фрейма этой функции и если всё укладывается в регистры, то скорость выполнения этой функции возрастает а её размер уменьшается.
Но злоупотреблять этим не стоит...
John851
хм, а если я создам массив большой >1 Кб а памяти ОЗУ у меня всего 1Кб, тогда чего будет динамическая подгрузка данных из флэши?))
demiurg_spb
Цитата(John851 @ May 28 2010, 14:02) *
хм, а если я создам массив большой >1 Кб а памяти ОЗУ у меня всего 1Кб, тогда чего будет динамическая подгрузка данных из флэши?))
Со статиком Вы обнаружите эту каку ещё на стадии билда проекта,
а без оного при первом его запуске в кристалле.
MrYuran
Цитата(MrYuran @ May 28 2010, 10:25) *
Это ж можно макрос накатать типа

Вот, накатал...
Попробовать, правда, пока не могу, некогда...
Код
/*********************************************************
*   Макрос для установки локального таймера
*   realtime - переменная системного времени
*   type - тип realtime
*   timer - временной интервал в тиках системного времени
*   action - действие по окончании интервала
*   continue - флаг "перезарядки" таймера
*********************************************************/
#define SET_TIMER(realtime, type, timer, action, continue)    \
do{ \
    static type timerVar = realtime + timer;    \
    if(timerVar>realtime){    \
        action;    \
        if(continue) timerVar = realtime + timer;   \
    }   \
}while(0)

Пример применения:
SET_TIMER(RealTime, unsigned int, 1000, DoSomething(), 1);
По идее, должен завести статическую переменную unsigned int под таймер,
отсчитать 1000 тиков, выполнить DoSomething() и перезапустить таймер

Вопрос на засыпку: локальную переменную создаст для do-while или для обёртывающей функции?
XVR
Цитата
Вопрос на засыпку: локальную переменную создаст для do-while или для обёртывающей функции?
Для do-while
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.