реклама на сайте
подробности

 
 
 
Reply to this topicStart new topic
> Передача аргумента в прерывание (язык C), Кто что использует?
Nikitoc
сообщение Nov 27 2010, 20:56
Сообщение #1


Местный
***

Группа: Validating
Сообщений: 207
Регистрация: 14-01-09
Из: Днепропетровск
Пользователь №: 43 367



Всем доброго времени суток. Я тут недавно столкнулся с проблемой глобальных переменных, а точнее с тем, что о них всегда нужно помнить (где они инициализируются, где изменяются и т.д.) со всеми вытекающими трудновылавливаемыми глюками. Альтернатива глобальным переменным - передача указателя в функцию. Но вот как передать указатель в подпрограмму обработки прерывания (имеется в виду программа для какого-нибудь микроконтроллера)? Или еще так можно спросить: кто как избавляется от глобальных переменных? Какие есть способы минимизировать их использование? Интересно послушать мнения форумчан.
Go to the top of the page
 
+Quote Post
sergeeff
сообщение Nov 28 2010, 11:10
Сообщение #2


Профессионал
*****

Группа: Свой
Сообщений: 1 481
Регистрация: 10-04-05
Пользователь №: 4 007



Цитата(Nikitoc @ Nov 27 2010, 23:56) *
Всем доброго времени суток. Я тут недавно столкнулся с проблемой глобальных переменных, а точнее с тем, что о них всегда нужно помнить (где они инициализируются, где изменяются и т.д.) со всеми вытекающими трудновылавливаемыми глюками. Альтернатива глобальным переменным - передача указателя в функцию. Но вот как передать указатель в подпрограмму обработки прерывания (имеется в виду программа для какого-нибудь микроконтроллера)? Или еще так можно спросить: кто как избавляется от глобальных переменных? Какие есть способы минимизировать их использование? Интересно послушать мнения форумчан.


1. В обработчик прерываний нельзя передать параметры. Если несколько задумаетесь, поймете сами почему.

2. Если есть возможность напрячь немного голову и отказаться от глобальных переменных - это хорошо. С другой стороны, глобальные переменные иногда ничем не заменить. Если вы делаете embedded проект, то, как правило, таких переменных не так уж много.

3. Переходите на С++ и инкапсулируйте в классах обращение к таким переменным через соответствующие функции Set... и Get... По крайней мере вся работа с такими переменными будет локализована в одном программном модуле (cpp или h, в зависимости от реализации), а при использовании inline и потерь по скорости практически не будет.
Go to the top of the page
 
+Quote Post
sigmaN
сообщение Nov 28 2010, 11:25
Сообщение #3


I WANT TO BELIEVE
******

Группа: Свой
Сообщений: 2 617
Регистрация: 9-03-08
Пользователь №: 35 751



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

Возможно вам поможет сужение области видимости глобальных переменных одним модулем(файлом). Это достигается путем объявления переменной со словом static. А ещё не забывайте, что переменные, доступ к которым производится из обработчика прерывания - должны быть объявлены как volatile. В случае с UART, к примеру, делаете отдельный модуль(uart.c) в этом модуле обявляете передающий буфер(как static), обработчик прерывания в этот же модуль определите и инициализацию в отдельную функцию. Вот и решатся все ваши проблемы. С внешним миром uart.c связывается по средством функций(типа putch(), getch() и т.д.).
А ещё используйте структуры. Всё, что касается состояния uart - в структуру. Можно для этого дела даже typedef сделать, а все функции в модуле сделать таким образом, чтобы принимали параметром указатель на такую структуру. Тогда ваш uart.c будет универсальным и одинаково хорошо будет справляться с десятком портов uart... нужно только удачно всё спроектировать и будет красиво)

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


--------------------
The truth is out there...
Go to the top of the page
 
+Quote Post
Nikitoc
сообщение Nov 28 2010, 14:07
Сообщение #4


Местный
***

Группа: Validating
Сообщений: 207
Регистрация: 14-01-09
Из: Днепропетровск
Пользователь №: 43 367



sergeeff, sigmaN, большое спасибо за ответы. По поводу передачи аргументов в подпрограмму обработки прерываний: это, конечно, был риторический вопрос, т.с. провокационный wink.gif Мне понравилась идея упаковывать глобальные переменные в структуры и применять static, для ограничения области видимости. Но вот по поводу volatileне совсем понял. Почему это очень важно именно для прерываний (если можно поподробней расскажите)?
To sergeeff: спасибо за совет, я уже давно подумываю начать использовать С++.
Go to the top of the page
 
+Quote Post
sigmaN
сообщение Nov 28 2010, 17:51
Сообщение #5


I WANT TO BELIEVE
******

Группа: Свой
Сообщений: 2 617
Регистрация: 9-03-08
Пользователь №: 35 751



http://www.nongnu.org/avr-libc/user-manual...ml#faq_volatile
И так везде. Не только у AVR.


--------------------
The truth is out there...
Go to the top of the page
 
+Quote Post
sergeeff
сообщение Nov 28 2010, 18:21
Сообщение #6


Профессионал
*****

Группа: Свой
Сообщений: 1 481
Регистрация: 10-04-05
Пользователь №: 4 007



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

Go to the top of the page
 
+Quote Post
Nikitoc
сообщение Nov 28 2010, 18:28
Сообщение #7


Местный
***

Группа: Validating
Сообщений: 207
Регистрация: 14-01-09
Из: Днепропетровск
Пользователь №: 43 367



Понятно, volatile это "защита" от сильно умного (оптимизирующего) компилятора. А если оптимизацию не использовать? Или это зависит от конкретного компилятора?

Редактировано: sergeeff Вы меня опередили с ответом на мой вопрос :-) .

Сообщение отредактировал Nikitoc - Nov 28 2010, 18:31
Go to the top of the page
 
+Quote Post
sergeeff
сообщение Nov 28 2010, 18:44
Сообщение #8


Профессионал
*****

Группа: Свой
Сообщений: 1 481
Регистрация: 10-04-05
Пользователь №: 4 007



От "умности" компилятора сильно зависит. Не использовать опции компилятора по оптимизации просто глупо. По сему использование volatile можно рассматривать, как некое соглашение между вами, программистом, и компилятором, по типу "все оптимизируем, кроме...".
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Nov 28 2010, 22:30
Сообщение #9


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



QUOTE (Nikitoc @ Nov 28 2010, 20:28) *
А если оптимизацию не использовать?
Тогда лучше писать на ассемблере. Хотя бы не будут возникать возмущения "что за г.. этот компилятор сотворил из такой простой конструкции, я бы сделал в 10 раз лучше".


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
sigmaN
сообщение Nov 28 2010, 23:04
Сообщение #10


I WANT TO BELIEVE
******

Группа: Свой
Сообщений: 2 617
Регистрация: 9-03-08
Пользователь №: 35 751



Цитата
Насчет volatile все очень просто. Это запрет компилятору оптимизировать операции с переменными этого типа, потому как если внутри некоторой функции выполняются какие либо операции с глобальной переменной, декларированной в другой единице компиляции, оптимизатор, скорее всего, такую операцию просто выкинет, посчитав ее ненужной в рамках данной функции.
Не совсем так. Нужно более тонко понимать как мыслит оптимизатор и что на самом деле делает volatile. А ещё это Ваше
Цитата
оптимизатор, скорее всего, такую операцию просто выкинет
что именно вы имеете ввиду употребляя слово "выкинет"?
Постараюсь внести ясность.
Компилятор при оптимизации практически всегда "кэширует" переменные в регистры, дабы сократить кол-во обращений к памяти. Тем не менее, компилятор лично следит, чтобы те участки кода, которые требуют значения этой переменной - получали его вовремя... Всё это возможно благодаря тому, что компилятор чётко понимает ход выполнения программы.
Но что, если адрес в памяти, по которому лежит переменная, меняется и компилятор не может это проследить? А тут, к примеру, цикл wile( flag ) ; Компилятор может в самом начале функции запихать переменную в регистр и больше не обращаться к памяти. А скорее всего и вовсе этот цикл уберет, т.к. посчитает, что он никогда не исполнится. Или же воспримет цикл как бесконечный и уберет всё, что дальше...зависит от кода.
К чему я клоню.. а к тому, что для компилятора обработчик прерывания - это функция, которая не вызывается никогда. Компилятор просто не может предугадать, когда именно сработает обработчик и изменит flag. И пусть даже он сработает и изменит flag прямо в памяти - ожидающий цикл не будет перечитывать flag из памяти при каждой итерации.
Вот весь механизм и суть тут именно в том, что компилятор не в состоянии отследить изменение переменной. Она меняется за пределами Си кода либо компилятор не в состоянии проследить вызов. То-же самое справедливо и для функций. Компилятор удаляет функции, так или иначе не вызываемые из main(за исключением обработчиков прерываний, они - особый случай).
И если для переменных есть volatile, то для функций как правило предоставляется какая-нибудь #pragma или аттрибут. Суть состоит в том, чтобы показать компилятору, что эта функция вызывается не из Си кода(к примеру из asm модуля) и функцию удалять не следует.

Далее, что касается volatile: такие переменные при каждом обращении считываются из памяти и не кэшируются в регистрах.
Вот так, надеюсь, будет понятно уже)

Цитата
Исходя из этого, вообще лучше все глобальные переменные объявлять как volatile, чтобы не нарваться на трудноуловимые ошибки, связанные в работой оптимизатора.
Не согласен с Вами. Это излишества, к тому-же бьющие оптимизатору ниже пояса, снижая эффективность генерируемого кода.
И дело всё в том, что если работа с переменной ведётся только из Си кода - то без всяких volatile будет всё прекрасно и без глюков работать.


--------------------
The truth is out there...
Go to the top of the page
 
+Quote Post
sergeeff
сообщение Nov 29 2010, 07:22
Сообщение #11


Профессионал
*****

Группа: Свой
Сообщений: 1 481
Регистрация: 10-04-05
Пользователь №: 4 007



Ну а я вам такую штуку про оптимизации расскажу. Для меня было большим удивлением. Работаю под MS VS2008 C/C++. Имею библиотеку функций, подключаемую к проекту. Появилась идея написать некий простенький модуль, который выводил бы мне на консоль версию и дату последних изменений файлов библиотеки в svn, и аналогичные модули поместить во все библиотеки, используемые в проекте.

Делаем файл revision.h

Код
#ifndef __REVISION_H__
#define __REVISION_H__

#define REV_STRING   888
#define DATE_STRING  "11:11:11 22-11-2010"
#define LIB_NAME     "aaa.lib"

#endif //__REVISION_H__


файл crevision.h

Код
#ifndef _CREVISION_H_
#define _CREVISION_H_

#include <stdio.h>
#include "revision.h"

class CRevision
{
   public:
   CRevision()
   {
      printf("LIB :: %s, Rev.%d [%s]\n", LIB_NAME, REV_STRING, DATE_STRING);
   }
};          


#endif   // _CREVISION_H_


и, наконец, crevision.cpp

Код
#include "CRevision.h"

const CRevision caaa;


Во всех книгах по C++ написано, что для переменной гарантировано будет вызван конструктор. Так вот: фига с два. Основная программа никогда не обращается к caaa, ее благополучно "соптимизировали" компилятор/линкер.

Если в основной программе объявить

Код
const CRevision caaa;


все работает.
Go to the top of the page
 
+Quote Post
MrYuran
сообщение Nov 29 2010, 07:31
Сообщение #12


Беспросветный оптимист
******

Группа: Свой
Сообщений: 4 640
Регистрация: 26-12-07
Из: Н.Новгород
Пользователь №: 33 646



Цитата(sergeeff @ Nov 28 2010, 14:10) *
3. Переходите на С++ и инкапсулируйте в классах обращение к таким переменным через соответствующие функции Set... и Get... По крайней мере вся работа с такими переменными будет локализована в одном программном модуле (cpp или h, в зависимости от реализации), а при использовании inline и потерь по скорости практически не будет.

А в си какие проблемы то же самое сделать?
Объявили статические переменные в модуле и функции сеттера и геттера (или аксессора и мутатора smile.gif )


--------------------
Программирование делится на системное и бессистемное. ©Моё :)
— а для кого-то БГ — это Bill Gilbert =)
Go to the top of the page
 
+Quote Post
dxp
сообщение Nov 29 2010, 07:45
Сообщение #13


Adept
******

Группа: Свой
Сообщений: 3 469
Регистрация: 6-12-04
Из: Novosibirsk
Пользователь №: 1 343



Цитата(Nikitoc @ Nov 29 2010, 00:28) *
Понятно, volatile это "защита" от сильно умного (оптимизирующего) компилятора. А если оптимизацию не использовать? Или это зависит от конкретного компилятора?

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

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

К оптимизации все это имеет несколько опосредованное отношение, просто на практике чем выше уровень оптимизации, тем агрессивнее компилятор минимизирует размер кода и борется за его скорость. Но если асинхронно изменяемую переменную не объявить как volatile, то правильность работы не гарантируется и на самых низких уровнях оптимизации. Поэтому для гарантировано правильно работающего и надежного кода такие переменные всегда надлежит объявлять соответствующим образом. Ведь переменная становится таковой по замыслу разработчика, и никто другой (включая самый умный компилятор) не знает, как с ней правильно обращаться. Для этого в языке и предусмотрено средство для выражения этого замысла.

Цитата(sergeeff @ Nov 29 2010, 13:22) *
Во всех книгах по C++ написано, что для переменной гарантировано будет вызван конструктор. Так вот: фига с два.

Конструктор будет вызван для объекта, который реально создается. А тут просто сам объект был выкинут из программы, т.к. на него нигде не присутствует ссылок. Раз нет объекта, значит и конструировать нечего и конструктор вызывать не зачем.

Цитата(sergeeff @ Nov 29 2010, 13:22) *
Основная программа никогда не обращается к caaa, ее благополучно "соптимизировали" компилятор/линкер.

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

Помнится у IAR было даже специально расширение для подобных случаев: __root. Объекты, объявленные с таким квалификатором не выбрасывались из программы ни при каких обстоятельствах.


--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
Go to the top of the page
 
+Quote Post
MrYuran
сообщение Nov 29 2010, 07:50
Сообщение #14


Беспросветный оптимист
******

Группа: Свой
Сообщений: 4 640
Регистрация: 26-12-07
Из: Н.Новгород
Пользователь №: 33 646



Цитата(dxp @ Nov 29 2010, 10:45) *
Помнится у IAR было даже специально расширение для подобных случаев: __root. Объекты, объявленные с таким квалификатором не выбрасывались из программы ни при каких обстоятельствах.

А в GCC бывает__attribute__((used))


--------------------
Программирование делится на системное и бессистемное. ©Моё :)
— а для кого-то БГ — это Bill Gilbert =)
Go to the top of the page
 
+Quote Post

Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 18th July 2025 - 16:31
Рейтинг@Mail.ru


Страница сгенерированна за 0.01521 секунд с 7
ELECTRONIX ©2004-2016