Управление качеством разработки микроконтроллерных систем

Вопросы настройки, программирования, прошивки микроконтроллеров и микросхем программируемой логики
Закрыто
Опытный кот
Аватара пользователя
Сообщения: 736
Зарегистрирован: Пн янв 10, 2011 03:06:36
Откуда: Ростов-на-Дону

Сообщение Goldsmith »

Goodefine писал(а): Такой вариант сразу вызывает вопросы.
1. Что будет если обработчик прерывания таймера вынужденно размещен в другом .с модуле? Это не надумано, ведь задач, которые используют таймер, может быть много - пусть в общем случае обработчик располагается в файле interrupt.c .
Пусть располагается, имя файла не играет большой роли. Мы точно так же можем включить в interrupt.c заголовок Timer.h с тем же содержимым, ничего принципиально не изменится. Клиенты видят единственную функцию для доступа к счетчику тиков, внутрь модуля доступ закрыт.

Хотя в принципе даже в случае множества задач, которые работают с таймером, можно заставить их работать через интерфейс.
Goodefine писал(а):2. Значение надо иногда еще и корректировать (обнулять счетчик или флаг). Если добавить интерфейсную функцию записи, то мы получим вариант уж совсем не отличающийся по безопасности доступа от глобальной переменной.
Не совсем так. Функцию записи можно вынести в отдельный интерфейс, скажем, TimerModify.h . Этот интерфейс включаем лишь в те избранные модули, которые имеют право модифицировать часы. Все остальные работают с таймером через общедоступный интерфейс только на чтение. Это принципиально отличается от глобального варианта, ведь выставив объект на всеобщее обозрение, мы теряем дальнейший контроль над его модификациями.

В метод записи в закрытую переменную можно добавить еще и контроль допустимости действий. Например, если клиент пытается записать недопустимое значение (для нашего примитивного примера это, возможно, лишено смысла, но в других приложениях может оказаться полезным), его попытка игнорируется. Или, скажем, в определенные моменты сбрасывать таймер запрещено. С глобальным объектом таких возможностей нет принципиально - любой клиент с ошибкой в коде может изменить его целостность.
Любой дурак может писать код. Настоящий профессионал - это тот, кто способен постоянно создавать продукт высокого качества, укладываясь при этом в бюджет.
J. Ganssle
Контактная информация:
Реклама
Держит паяльник хвостом
Аватара пользователя
Сообщения: 906
Зарегистрирован: Ср апр 16, 2008 13:22:54
Откуда: Приднестровье, Тирасполь

Сообщение Goodefine »

Goldsmith писал(а):Пусть располагается, имя файла не играет большой роли. Мы точно так же можем включить в interrupt.c заголовок Timer.h с тем же содержимым, ничего принципиально не изменится. Клиенты видят единственную функцию для доступа к счетчику тиков, внутрь модуля доступ закрыт.
Хорошо, а как обработчик будет модифицировать статик переменную-счетчик, если она расположена в timer.c? Инклуд timer.h ничего не даст... Во всяком случае как в примере выше.
Вторую часть сейчас почитаю...
Почитал. Но возражения есть. Которые не совсем удобно приводить на абстрактном примере - лучше конкретный - безо всяких дополнительных фишек типа проверок допустимости действий и значений. Если не трудно, на примере выше...
Любой, заслуживающий внимания, опыт приобретается себе в убыток...
Реклама
Опытный кот
Аватара пользователя
Сообщения: 736
Зарегистрирован: Пн янв 10, 2011 03:06:36
Откуда: Ростов-на-Дону

Сообщение Goldsmith »

Goodefine писал(а):Но согласитесь, что иногда есть исключения.
Конечно. Они именно потому и исключения, что встречаются ну очень редко, а кое-кому и вовсе не повезет сними столкнуться. Значит, эти редчайшие случаи заслуживают особого подхода, отличающегося от повседневной рутины. И это намекает, что неисключительные случаи нужно обрабатывать как-то иначе, иначе в чем смысл выделять эти исключения?
Goodefine писал(а):Во всех учебниках нынче пишут, что глобальные переменные следует использовать только в самом крайнем случае. Но нигде не пишут в каких.
Да, этим они грешат. Я и сам порой на всякий случай так говорю - "в самом крайнем случае". Но сам затрудняюсь привести подобный пример. Скорее всего, страхуются на случай, если кто-то особо дотошный все-таки выкопает такой случай и закричит торжествующе: "Ну что, умники, трещит ваша теория по швам?". Тут-то они и прикроются поправкой: "Не всегда, а почти всегда".

Я не могу с ходу назвать реальный пример, где глобальный объект окажется лучшим решением. Разве что в случае крохотного контроллера, где накладные расходы на вызов нескольких функций выйдут за рамки скудных ресурсов, и эти несколько байт окажутся решающими.
Goodefine писал(а):Другими словами, если подходить по умному, необходимо взвесить все за и против и принять решение. Все что я от вас добиваюсь - это ответа, указанный случай является крайним или нет?
Я не смог увидеть в нем этой самой крайности. Может, чего-то не заметил. По-моему, самый типичный случай и решение самое типичное - открытый интерфейс на чтение для всех желающих, эксклюзивный интерфейс на модификацию для облеченных особым доверием модулей. Возможно, дополнительная логика при чтении/записи, а не просто передача "голых" значений спрятанной в модуле переменной.
Любой дурак может писать код. Настоящий профессионал - это тот, кто способен постоянно создавать продукт высокого качества, укладываясь при этом в бюджет.
J. Ganssle
Контактная информация:
Держит паяльник хвостом
Аватара пользователя
Сообщения: 906
Зарегистрирован: Ср апр 16, 2008 13:22:54
Откуда: Приднестровье, Тирасполь

Сообщение Goodefine »

Goldsmith писал(а):Я не смог увидеть в нем этой самой крайности. Может, чего-то не заметил. По-моему, самый типичный случай и решение самое типичное - открытый интерфейс на чтение для всех желающих, ...
Все таки пока и с чтением не совсем прозрачно - я выше написал, думаю после выяснения этого момента можно двигаться далее.
Любой, заслуживающий внимания, опыт приобретается себе в убыток...
Реклама
Эиком - электронные компоненты и радиодетали
Опытный кот
Аватара пользователя
Сообщения: 736
Зарегистрирован: Пн янв 10, 2011 03:06:36
Откуда: Ростов-на-Дону

Сообщение Goldsmith »

Goodefine писал(а): Хорошо, а как обработчик будет модифицировать статик переменную-счетчик, если она расположена в timer.c? Инклуд timer.h ничего не даст...
Немного не так. Мы договорились, что вынуждены разместить все обработчики внутри interrupt.c . Счетчик тиков (статический) также локален в этом модуле, и в нем же определена (глобально доступная) функция доступа к счетчику. Объявлена она в интерфейсном модуле timer.h, который включает interrupt.c и все клиенты, которые заинтересованы в получении текущего времени.

Хотя не вижу объективных причин группировать все обработчики прерываний от логически независимых устройств в один модуль. Большой модуль - это всегда лишние проблемы.
Любой дурак может писать код. Настоящий профессионал - это тот, кто способен постоянно создавать продукт высокого качества, укладываясь при этом в бюджет.
J. Ganssle
Контактная информация:
Реклама
Держит паяльник хвостом
Аватара пользователя
Сообщения: 906
Зарегистрирован: Ср апр 16, 2008 13:22:54
Откуда: Приднестровье, Тирасполь

Сообщение Goodefine »

Goldsmith писал(а): Счетчик тиков (статический) также локален в этом модуле, и в нем же определена (глобально доступная) функция доступа к счетчику. Объявлена она в интерфейсном модуле timer.h, который включает interrupt.c и все клиенты, которые заинтересованы в получении текущего времени.
Т.е. реализация функции в interrupt.c, а прототип - timer.h? А в interrupt.h как указать прототип функции доступа? Получается сам модуль timer вырождается в прослойку, не особо нужную (что останется в timer.c?). Предложение вынести обработчик в interrupt.c было сделано, чтобы показать что он не должен быть привязан к конкретному си-модулю. Сейчас мы тики считаем, потом флаги ставим, периферию вкл/откл и т.д. По этой логике получается, что все эти разнородные данные, структуры и макросы надо вставлять локально именно в тот модуль, где находится сам обработчик, несмотря на то что логика построения модулей будет рушится? Когда появится чуть времени, я сделаю специальный тестовый компилируемый проект на winavr, на котором можно потренироваться и увидеть воочию.
Goldsmith писал(а):
Хотя не вижу объективных причин группировать все обработчики прерываний от логически независимых устройств в один модуль...
Да, но почему так я выше написал. Но мы будем группировать логически независимые переменные в один и тот же модуль где обработчик... А если не дай бог, одну и ту же переменную будет использовать два обработчика, код которых разнесен по разным модулям?...
Любой, заслуживающий внимания, опыт приобретается себе в убыток...
Реклама
Опытный кот
Аватара пользователя
Сообщения: 736
Зарегистрирован: Пн янв 10, 2011 03:06:36
Откуда: Ростов-на-Дону

Сообщение Goldsmith »

Goodefine писал(а):Т.е. реализация функции в interrupt.c, а прототип - timer.h?
Точно.
Goodefine писал(а):А в interrupt.h как указать прототип функции доступа?
interrupt.h может вообще не понадобиться. Весь сервис модуля прерываний, который обслуживает несколько разнородных ресурсов, мы можем вынести в независимые интерфейсы типа timer.h, pwm.h, uart.h и так далее. Главный принцип - "меньше знают, крепче спят". Тот модуль, которому нужен таймер, необязательно работает с UART, и наоборот. Если кому-то нужно несколько ресурсов этого модуля - пусть инклюдит несколько интерфейсов, остальные не видят лишнего.
Goodefine писал(а):Получается сам модуль timer вырождается в прослойку, не особо нужную (что останется в timer.c?).
Его вообще не останется. Тот код, который я планировал в него поместить, просто переедет в общий модуль работы с периферией (сам я предпочитаю модули минимального размера, в которых собрано все, относящееся к одному ресурсу).
Goodefine писал(а):Предложение вынести обработчик в interrupt.c было сделано, чтобы показать что он не должен быть привязан к конкретному си-модулю. Сейчас мы тики считаем, потом флаги ставим, периферию вкл/откл и т.д. По этой логике получается, что все эти разнородные данные, структуры и макросы надо вставлять локально именно в тот модуль, где находится сам обработчик, несмотря на то что логика построения модулей будет рушится?
Для подобных задач (например, модификация флагов по событиям от таймера и т.п.) есть очень красивое решение - паттерн MCH (Model-Conductor-Hardware). Он очень похож на паттерн "Модель-Вид-Контроллер", по которому строятся многие приложения для настольных компьютеров, и эффективно отделяет оборудование от логики приложений. Но к нему вернемся при случае, а то получится большая каша. Сначала поставим точку на глобальных объектах, а то погонимся да двумя зайцами.
Goodefine писал(а):Да, но почему так я выше написал. Но мы будем группировать логически независимые переменные в один и тот же модуль где обработчик... А если не дай бог, одну и ту же переменную будет использовать два обработчика, код которых разнесен по разным модулям?...
См. выше (MCH).
Любой дурак может писать код. Настоящий профессионал - это тот, кто способен постоянно создавать продукт высокого качества, укладываясь при этом в бюджет.
J. Ganssle
Контактная информация:
Опытный кот
Аватара пользователя
Сообщения: 736
Зарегистрирован: Пн янв 10, 2011 03:06:36
Откуда: Ростов-на-Дону

Сообщение Goldsmith »

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

Вопрос: как избавиться от глобальной переменной?

Ответ:
1. Ограничить видимость этой переменной в пределах модуля (в C это static, для Pascal пример см. выше).
2. Создать глобальную функцию для доступа к содержимому этой переменной на чтение и поместить ее объявление в интерфейс (в С это заголовочный файл).
3. Если нужна модификация содержимого переменной, сделать глобальную функцию для записи значения в переменную и поместить ее объявление в интерфейс. Если право на запись нужно ограничить, то вынести эту функцию в отдельный привилегированный интерфейс, который доступен только некоторым модулям.

Вопрос: какую пользу мы получим от этого?

Ответ: Прежде всего защиту от случайной модификации значения глобальной переменной. Не каждый модуль, имеющий доступ к значению, может его изменить. Кроме того, исключены коллизии имен (например, в случае опечатки). Также можно включить контроль целостности значений (например, если у нас есть глобальная структура календаря в формате день-месяц-год, функция записи не позволит записать в него 47 число 15-го месяца).

Вопрос: чем мы за это заплатим?

Ответ: Возможно, небольшими накладными расходами на вызов функции во время выполнения программы, плюс несколько "лишних" строк в исходниках.
Любой дурак может писать код. Настоящий профессионал - это тот, кто способен постоянно создавать продукт высокого качества, укладываясь при этом в бюджет.
J. Ganssle
Контактная информация:
Держит паяльник хвостом
Аватара пользователя
Сообщения: 906
Зарегистрирован: Ср апр 16, 2008 13:22:54
Откуда: Приднестровье, Тирасполь

Сообщение Goodefine »

Goldsmith писал(а):interrupt.h может вообще не понадобиться. Весь сервис модуля прерываний, который обслуживает несколько разнородных ресурсов, мы можем вынести в независимые интерфейсы типа timer.h, pwm.h, uart.h и так далее. Главный принцип - "меньше знают, крепче спят". Тот модуль, которому нужен таймер, необязательно работает с UART, и наоборот. Если кому-то нужно несколько ресурсов этого модуля - пусть инклюдит несколько интерфейсов, остальные не видят лишнего.
Идея понятна. По сути это есть простое ограничение видимости - но реальный эффект может быть ниже ожидаемого. Вот смотрите, если мы просто, с помощью глобальной переменной хотим передать данные из одного модуля в другой, то нужно в одном модуле объявить переменную с квалификатором extern (иначе ее никакой модуль не увидит), плюс еще нужно в другом модуле (который получает индульгенцию от первого на использование переменной) ее следует объявить с тем же именем но без экстерна. Получаем практически ту же ситуацию - другие модули ее не видят - только тот где она объявлена. Практически та же ситуация что и с инклудом интерфейсных файлов - они тоже открывают всем функциям в модуле доступ, где включены. Т.е. что там, что тут - разграничение доступа идет по модулям, но никак не по функциям. Единственное неудобство - можно случайно объявить переменную (глобальную) с тем же именем, со всеми вытекающими. Но это, как показывает практика не слишком опасно - достаточно осмысленно формировать имена и в 95% случаев это неопасно.
Любой, заслуживающий внимания, опыт приобретается себе в убыток...
Держит паяльник хвостом
Аватара пользователя
Сообщения: 906
Зарегистрирован: Ср апр 16, 2008 13:22:54
Откуда: Приднестровье, Тирасполь

Сообщение Goodefine »

Goldsmith писал(а): Вопрос:..
Ответ:...
Несмотря на то что все верно, нет гарантии, что это позволит избежать ошибок. Любой уровень абстракции привносит дополнительную возможность совершить ошибку. Иногда прозрачность работы модели дорого стоит. В любом случае, нужно думать. Это особенность такая, программирования как процесса.

Вопрос:
Являются ли глобальные переменные вселенским злом?
Любой, заслуживающий внимания, опыт приобретается себе в убыток...
Опытный кот
Аватара пользователя
Сообщения: 736
Зарегистрирован: Пн янв 10, 2011 03:06:36
Откуда: Ростов-на-Дону

Сообщение Goldsmith »

Goodefine писал(а):Идея понятна. По сути это есть простое ограничение видимости - но реальный эффект может быть ниже ожидаемого. Вот смотрите, если мы просто, с помощью глобальной переменной хотим передать данные из одного модуля в другой, то нужно в одном модуле объявить переменную с квалификатором extern (иначе ее никакой модуль не увидит), плюс еще нужно в другом модуле (который получает индульгенцию от первого на использование переменной) ее следует объявить с тем же именем но без экстерна.
Так вроде бы это и есть те самые глобальные переменные, о которых мы говорили. Объявление extern совместно с определением без оного создаст глобальный символ в объектном файле, который виден всем желающим.
Goodefine писал(а):Получаем практически ту же ситуацию - другие модули ее не видят - только тот где она объявлена.
...
Единственное неудобство - можно случайно объявить переменную (глобальную) с тем же именем, со всеми вытекающими.
Мы упускаем еще один очень важный аспект - возможность ограничивать доступ только по чтению. Если уж открыли, то полный доступ. И плюс нет контроля целостности, который порой очень важен.
Любой дурак может писать код. Настоящий профессионал - это тот, кто способен постоянно создавать продукт высокого качества, укладываясь при этом в бюджет.
J. Ganssle
Контактная информация:
Опытный кот
Аватара пользователя
Сообщения: 736
Зарегистрирован: Пн янв 10, 2011 03:06:36
Откуда: Ростов-на-Дону

Сообщение Goldsmith »

Goodefine писал(а): Вопрос:
Являются ли глобальные переменные вселенским злом?
С учетом потенциальных проблем и сложности их диагностики (а в случае микроконтроллеров эта сложность возрастает многократно), хуже глобальных переменных для хорошей программы, пожалуй, вряд ли что-то можно придумать. Обильные GOTO не в счет, они уже давно вышли из моды. (Само собой, если программа не пренебрежимо мала).
Любой дурак может писать код. Настоящий профессионал - это тот, кто способен постоянно создавать продукт высокого качества, укладываясь при этом в бюджет.
J. Ganssle
Контактная информация:
Держит паяльник хвостом
Аватара пользователя
Сообщения: 906
Зарегистрирован: Ср апр 16, 2008 13:22:54
Откуда: Приднестровье, Тирасполь

Сообщение Goodefine »

Goldsmith писал(а):Так вроде бы это и есть те самые глобальные переменные, о которых мы говорили. Объявление extern совместно с определением без оного создаст глобальный символ в объектном файле, который виден всем желающим.
Только в том модуле, в котором есть второе дублирующиеся объявление. Аналог инклуда интерфейса.
Goldsmith писал(а):]Мы упускаем еще один очень важный аспект - возможность ограничивать доступ только по чтению. Если уж открыли, то полный доступ. И плюс нет контроля целостности, который порой очень важен.
Только чтение не всегда нужно, а если мы используем модификацию, то инкапсуляции по отношению к какой-то одной функции, в пределах модуля все равно нет. Я к тому, что универсального рецепта нет - язык Си потому и является дним из самых мощных, потому что программист может сделать очень много... Иногда не нужно себе тупить скальпель :)
С учетом потенциальных проблем и сложности их диагностики (а в случае микроконтроллеров эта сложность возрастает многократно), хуже глобальных переменных для хорошей программы, пожалуй, вряд ли что-то можно придумать.
Все эти проблемы известны, они не трудно обходятся. Но положительные моменты тоже присутствуют - это даже бессмысленно отрицать. ИМХО, для МК как раз проблем меньше, а необходимости больше - ибо размер и быстродействие иногда определяют все. Иногда имеется настолько тесная связь обработчиков железных прерываний с основной программой, что сомнительным видится решение без глобальных структур. Вся работа в МК ведется практически в "нулевом кольце"...
Любой, заслуживающий внимания, опыт приобретается себе в убыток...
Опытный кот
Аватара пользователя
Сообщения: 736
Зарегистрирован: Пн янв 10, 2011 03:06:36
Откуда: Ростов-на-Дону

Сообщение Goldsmith »

Goodefine писал(а):язык Си потому и является дним из самых мощных, потому что программист может сделать очень много...
Для контроллеров - однозначно, скорее потому, что других все равно фактически нет, выбирать не из чего. Для "больших" приложений давно уже слабоват, да и немудрено, при таком почтенном возрасте... Он еще ЭВМ-монстров третьего поколения помнит.
Goodefine писал(а):Иногда имеется настолько тесная связь обработчиков железных прерываний с основной программой, что сомнительным видится решение без глобальных структур. Вся работа в МК ведется практически в "нулевом кольце"...
Есть очень интересные паттерны, разработанные в компании Atomic Object специально для систем реального времени. Там все построено на очень слабой связанности модулей (сделано специально для легкости тестирования, они делают управление для полностью автоматических промышленных систем транспортировки деталей в цехах, требования к надежности высокие).
Любой дурак может писать код. Настоящий профессионал - это тот, кто способен постоянно создавать продукт высокого качества, укладываясь при этом в бюджет.
J. Ganssle
Контактная информация:
Нашел транзистор. Понюхал.
Сообщения: 186
Зарегистрирован: Пн авг 18, 2008 13:13:29

Сообщение andrej »

Goldsmith писал(а):Есть очень интересные паттерны, разработанные в компании Atomic Object специально для систем реального времени. Там все построено на очень слабой связанности модулей (сделано специально для легкости тестирования, они делают управление для полностью автоматических промышленных систем транспортировки деталей в цехах, требования к надежности высокие).
а можно ссылочку, а лучше сразу перевод. :))
Опытный кот
Аватара пользователя
Сообщения: 736
Зарегистрирован: Пн янв 10, 2011 03:06:36
Откуда: Ростов-на-Дону

Сообщение Goldsmith »

andrej писал(а):а можно ссылочку, а лучше сразу перевод. :))
Конечно. Перевел я пока только две из них, самые вводные:

http://club.shelek.ru/viewart.php?id=335
http://club.shelek.ru/viewart.php?id=337

Оригиналы находятся на сайте фирмы Atomic Object, которая является разработчиком упомянутых инструментов для тестирования:

http://www.atomicobject.com/pages/Papers
http://www.atomicobject.com/pages/Embedded+Practices

Здесь я выбрал статьи, которые относятся непосредственно к MCH:

http://www.atomicobject.com/pages/Searc ... &q=MCH#477

Ну и еще с недавних пор я, не надеясь на дырявую память, веду небольшой дневничок, куда заношу заметки о прочитанных книгах и статьях. Там должно быть кое-что из других источников: http://forum.shelek.ru/index.php/topic,26526.0.html
Любой дурак может писать код. Настоящий профессионал - это тот, кто способен постоянно создавать продукт высокого качества, укладываясь при этом в бюджет.
J. Ganssle
Контактная информация:
Нашел транзистор. Понюхал.
Сообщения: 186
Зарегистрирован: Пн авг 18, 2008 13:13:29

Сообщение andrej »

пасиб.
Закрыто

Вернуться в «Микроконтроллеры и ПЛИС»