Assert param stm32 что это
Текущее время: Пн фев 05, 2024 03:03:03 |
Часовой пояс: UTC + 3 часа
Запрошенной темы не существует.
Часовой пояс: UTC + 3 часа
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group
Русская поддержка phpBB
Extended by Karma MOD © 2007—2012 m157y
Extended by Topic Tags MOD © 2012 m157y
Работоспособность сайта проверена в браузерах:
IE8.0, Opera 9.0, Netscape Navigator 7.0, Mozilla Firefox 5.0
Адаптирован для работы при разрешениях экрана от 1280х1024 и выше.
При меньших разрешениях возможно появление горизонтальной прокрутки.
По всем вопросам обращайтесь к Коту: kot@radiokot.ru
©2005-2024
Assert param stm32 что это
Авг 5, 2014 | 0 comments
assert_param stm32
При отладке программы очень удобно для вывода сообщений об той или иной ситуации, иметь универсальную функцию, которая позволяла бы выводить сообщение об ошибке, номер строки и файл в котором эта ошибка возникла. Для этого, в библиотеке периферии от ST, используется assert_param.
Перед тем как использовать данную функцию необходимо указать, что мы ее используем:
#define USE_FULL_ASSERT
И создать функцию обработчик:
void assert_failed(uint8_t* file, uint32_t line)
assert_param(TESTING(test)); #define TESTING(PAR) (((PAR) == 10) || \ ((PAR) == 11) || \ ((PAR) == 12)) uint8_t tmp = 13; assert_param(TESTING(tmp)); assert_param(tmp == 13);
На самом деле assert_param представляет собой:
assert_param(expr) ((expr) ? (void)0 : assert_failed((uint8_t *)__FILE__, __LINE__))
Или в более простой записи:
if(expr) продолжаем программу else assert_failed
expr — это выражение, которое передается в assert_param(expr) — assert_param(x > 10).
Assert. Что это?
Assert — это специальная конструкция, позволяющая проверять предположения о значениях произвольных данных в произвольном месте программы. Эта конструкция может автоматически сигнализировать при обнаружении некорректных данных, что обычно приводит к аварийному завершению программы с указанием места обнаружения некорректных данных. Странная, на первый взгляд, конструкция — может завалить программу в самый неподходящий момент. Какой же в ней смысл? Давайте подумаем, что произойдет, если во время исполнения программы в какой-то момент времени некоторые данные программы стали некорректными и мы не «завалили» сразу же программу, а продолжили ее работу, как ни в чем не бывало. Программа может еще долго работать после этого без каких-либо видимых ошибок. А может в любой момент времени в будущем «завалиться» сама по известной только ей причине. Или накачать вам полный винчестер контента с гей-порносайтов. Это называется неопределенное поведение (undefined behavior) и, вопреки расхожему мнению, оно свойственно не только языкам программирования с произвольным доступом к памяти (aka C, C++). Т.к. assert завершает программу сразу же после обнаружения некорректных данных, он позволяет быстро локализировать и исправить баги в программе, которые привели к некорректным данным. Это его основное назначение. Assert’ы доступны во многих языках программирования, включая java, c#, c и python.
Какие виды assert’ов бывают?
Assert’ы позволяют отлавливать ошибки в программах на этапе компиляции либо во время исполнения. Проверки на этапе компиляции не так важны — в большинстве случаев их можно заменить аналогичными проверками во время исполнения программы. Иными словами, assert’ы на этапе компиляции являются ничем иным, как синтаксическим сахаром. Поэтому в дальнейшем под assert’ами будем подразумевать лишь проверки во время исполнения программы.
- Проверка входящих аргументов в начале функции.
// Считает факториал числа n. // Число n должно лежать в пределах от 0 до 10 включительно. int factorial(int n) < // Факториал отрицательного числа не считается assert(n >= 0); // Если n превысит 10, то это может привести либо к целочисленному // переполнению результата, либо к переполнению стэка. assert(n return factorial(n - 1) * n; > // мы 'забыли' об ограничениях функции factorial() и пытаемся вычислить // факториалы чисел от 0 до 99. // // проверка внутри factorial() любезно напомнит нам о своих ограничениях, // так что мы сможем быстро выявить и исправить этот баг. // // если бы эта проверка отсутствовала, то баг мог бы долго оставаться // незамеченным, периодически давая о себе знать переполнениями стэка и // некорректным поведением программы. for (int i = 0; i
Важно понимать, что входящие аргументы функции могут быть неявными. Например, при вызове метода класса в функцию неявно передается указатель на объект данного класса (aka this и self). Также функция может обращаться к данным, объявленным в глобальной области видимости, либо к данным из области видимости лексического замыкания. Эти аргументы тоже желательно проверять с помощью assert’ов при входе в функцию.
Если некорректные данные обнаружены на этом этапе, то код данной функции может содержать баги. Пример:
int factorial(int n) < int result = 1; for (int i = 2; i // С первого взгляда эта проверка никогда не сработает - факториал должен // быть всегда положительным числом. Но как только n превысит допустимый // предел, произойдет целочисленное переполнение. В этом случае // a[i] может принять отрицательное либо нулевое значение. // // После срабатывания этой проверки мы быстро локализуем баг и поймем, // что либо нужно ограничивать значение n, либо использовать целочисленную // арифметику с бесконечной точностью. assert(result > 0); return result; >
- Проверка данных, с которыми работает функция, внутри кода функции.
int factorial(int n) < int result = 1; while (n >1) < // Знакомая нам проверка на целочисленное переполнение. // // При ее срабатывании мы быстро определим, что эта функция должна уметь // корректно обрабатывать слишком большие n, ведущие к переполнению. // // Эта проверка лучше, чем проверка из предыдущего пункта (перед выходом // из функции), т.к. она срабатывает перед первым переполнением result, // тогда как проверка из предыдущего пункта может пропустить случай, когда // в результате переполнения (или серии переполнений) итоговое значение // result остается положительным. assert(result return result; >
Когда и где стоит использовать assert’ы?
Ответ прост — используйте assert’ы всегда и везде, где они хоть чуточку могут показаться полезными. Ведь они существенно упрощают локализацию багов в коде. Даже проверка результатов выполнения очевидного кода может оказаться полезной при последующем рефакторинге, после которого код может стать не настолько очевидным и в него может запросто закрасться баг. Не бойтесь, что большое количество assert’ов ухудшит ясность кода и замедлит выполнение вашей программы. Assert’ы визуально выделяются из общего кода и несут важную информацию о предположениях, на основе которых работает данный код. Правильно расставленные assert’ы способны заменить большинство комментариев в коде. Большинство языков программирования поддерживают отключение assert’ов либо на этапе компиляции, либо во время выполнения программы, так что они оказывают минимальное влияние на производительность программы. Обычно assert’ы оставляют включенными во время разработки и тестирования программ, но отключают в релиз-версиях программ. Если программа написана в лучших традициях ООП, либо с помощью enterprise методологии, то assert’ы вообще можно не отключать — производительность вряд ли изменится.
Когда можно обойтись без assert’ов?
Понятно, что дублирование assert’ов через каждую строчку кода не сильно улучшит эффективность отлова багов. Не существует единого мнения насчет оптимального количества assert’ов, также как и насчет оптимального количество комментариев в программе. Когда я только узнал про существование assert’ов, мои программы стали содержать 100500 assert’ов, многие из которых многократно дублировали друг друга. С течением времени количество assert’ов в моем коде стало уменьшаться. Следующие правила позволили многократно уменьшить количество assert’ов в моих программах без существенного ухудшения в эффективности отлова багов:
Можно избегать дублирующих проверок входящих аргументов путем размещения их лишь в функциях, непосредственно работающих с данным аргументом. Т.е. если функция foo() не работает с аргументом, а лишь передает его в функцию bar(), то можно опустить проверку этого аргумента в функции foo(), т.к. она продублирована проверкой аргумента в функции bar().
Можно опускать assert’ы на недопустимые значения, которые гарантированно приводят к краху программы в непосредственной близости от данных assert’ов, т.е. если по краху программы можно быстро определить местонахождение бага. К таким assert’ам можно отнести проверки указателя на NULL перед его разыменованием и проверки на нулевое значение делителя перед делением. Еще раз повторюсь — такие проверки можно опускать лишь тогда, когда среда исполнения гарантирует крах программы в данных случаях.
Вполне возможно, что существуют и другие способы, позволяющие уменьшить количество assert’ов без ухудшения эффективности отлова багов. Если вы в курсе этих способов, делитесь ими в комментариях к данному посту.
Когда нельзя использовать assert’ы?
Т.к. assert’ы могут быть удалены на этапе компиляции либо во время исполнения программы, они не должны менять поведение программы. Если в результате удаления assert’а поведение программы может измениться, то это явный признак неправильного использования assert’а. Таким образом, внутри assert’а нельзя вызывать функции, изменяющие состояние программы либо внешнего окружения программы. Например, следующий код неправильно использует assert’ы:
// Захватывает данный мютекс. // // Возвращает 0, если невозможно захватить данный мютекс из-за следующих причин: // - мютекс уже был захвачен. // - mtx указывает на некорректный объект мютекса. // Возвращает 1, если мютекс успешно захвачен. int acquire_mutex(mutex *mtx); // Освобождает данный мютекс. // // Возвращает 0, если невозможно освободить данный мютекс из-за следующих // причин: // - мютекс не был захвачен. // - mtx указывает на некорректный объект мютекса. // Возвращает 1, если мютекс успешно захвачен. int release_mutes(mutex *mtx); // Убеждаемся, что мютекс захвачен. assert(acquire_mutex(mtx)); // Работаем с данными, "защищенными" мютексом. process_data(data_protected_by_mtx); // Убеждаемся, что мютекс освобожден. assert(release_mutes(mtx));
Очевидно, что данные могут оказаться незащищенными при отключенных assert’ах.
Чтобы исправить эту ошибку, нужно сохранять результат выполнения функции во временной переменной, после чего использовать эту переменную внутри assert’а:
int is_success; is_success = acquire_mutex(mtx); assert(is_success); // Теперь данные защищены мютексом даже при отключенных assert'ах. process_data(data_protected_by_mtx); is_success = release_mutex(mtx); assert(is_success);
Т.к. основное назначение assert’ов — отлов багов (aka ошибки программирования), то они не могут заменить обработку ожидаемых ошибок, которые не являются ошибками программирования. Например:
// Пытается записать buf_size байт данных, на которые указывает buf, // в указанное сетевое соединение connection. // // Возвращает 0 в случае ошибки записи, возникшей не по нашей вине. Например, // произошел разрыв сетевого соединения во время записи. // Возвращает 1 в случае успешной записи данных. int write(connection *connection, const void *buf, size_t buf_size); int is_success = write(connection, buf, buf_size); // "Убеждаемся", что данные корректно записаны. assert(is_success);
Если write() возвращает 0, то это вовсе не означает, что в нашей программе есть баг. Если assert’ы в программе будут отключены, то ошибка записи может остаться незамеченной, что впоследствие может привести к печальным результатам. Поэтому assert() тут не подходит. Тут лучше подходит обычная обработка ошибки. Например:
while (!write(connection, buf, buf_size)) < // Пытаемся создать новое соединение и записать данные туда еще раз. close_connection(connection); connection = create_connection(); >
Я программирую на javascript. В нем нет assert’ов. Что мне делать?
В некоторых языках программирования отсутствует явная поддержка assert’ов. При желании они легко могут быть там реализованы, следуя следующему «паттерну проектирования»:
function assert(condition) < if (!condition) < throw "Assertion failed! See stack trace for details"; >> assert(2 + 2 === 4); assert(2 + 2 === 5);
Вообще, assert’ы обычно реализованы в различных фреймворках и библиотеках, предназначенных для автоматизированного тестирования. Иногда они там называются expect’ами. Между автоматизированным тестированием и применением assert’ов есть много общего — обе техники предназначены для быстрого выявления и исправления багов в программах. Но, несмотря на общие черты, автоматизированное тестирование и assert’ы являются не взаимоисключающими, а, скорее всего, взаимодополняющими друг друга. Грамотно расставленные assert’ы упрощают автоматизированное тестирование кода, т.к. тестирующая программа может опустить проверки, дублирующие assert’ы в коде программы. Такие проверки обычно составляют существенную долю всех проверок в тестирующей программе.
- assert
- тестирование
- программирование
- Тестирование IT-систем
- Программирование
Быстрый старт c микроконтроллерами STM32F10x. Использование библиотеки STM32 Standard Peripheral Library
В этой публикации я попытаюсь акцентировать внимание на основных моментах для быстрого начала работы с микроконтроллерами STM32F10x на основе библиотеки стандартной периферии от компании-производителя STMicroelectronics.
В качестве среды разработки в статье будет использоваться Eclipse CDT. Поскольку основное внимание будет сосредоточено вокруг программного кода, то вы можете спокойно проделать все манипуляции в Code::Blocks.
Общая структура проекта для ARM микроконтроллеров описана в моей статье «Программирование AVR и ARM микроконтроллеров в Eclipse. Часть 2».
Здесь я коротко напомню, что для сборки проекта для ARM — микроконтроллеров (STM32F10x в частности) понадобится скрипт компоновщика и C-Startup файл.
Скрипт компоновщика представляет собой файл с инструкциями по размещению кода программы и данных в памяти микроконтроллера. Он может скомандовать загрузить код вашей программы в Flash -память программ или SRAM -память данных.
Для микроконтроллеров с различным объемом памяти программ и данных необходимы разные скрипты компоновки. Их можно достать у производителя микроконтроллеров — компании STMicroelectronics.
Распакуйте из архива ARM_Toolchain/Lib/stm32f10x_stdperiph_lib.zip библиотеку STM32F10x standard peripheral library.
В ней имеются примеры проектов для различных сред разработки ( IAR EWB, Keil uVision, Atollic True Studio и т.д). Наиболее близким для нас является Atollic True Studio, поскольку представляет собой модификацию Eclipse.
Зайдите в каталог Project/StdPeriph_Template/TrueSTUDIO, там есть несколько подкаталогов, названия которых соответствуют названиям отладочных плат STM3210x-EVAL.
Узнайте, в какой из этих плат используется микроконтроллер той же линейки, что и ваш. Скопируйте файл stm32_flash.ld из соответствующего каталога в свой проект.
Возможно также создать универсальный скрипт, в котором будут изменяться только объем памяти программ и данных в соответствии с используемым микроконтроллером.
Стартовый код (C-Startup) для микроконтроллеров STM32 может быть написан на С или Assembler.
Хотя библиотеку STM32F10x Standard Peripheral Library (далее по тексту используется сокращение STM32F10x SPL) часто критикуют за наличие ошибок, все же для начала программирования под STM32 использование этой библиотеки предоставляет самый простой способ быстро приступить к работе.
Но всегда хочется, чтобы была какая-то альтернатива. На самом деле их множество, например, программировать на языке ассемблера .
Это самый тяжелый и бессмысленный путь. Второй способ — использовать библиотеку CMSIS, которая предоставляет синтаксис обращения к структурам языка С для доступа к различной периферии микроконтроллера. Самым простым и логичным способом (на мой взгляд) является использование библиотек.
Если вы категорически настроены против STM32F10x SPL, то специально для вас имеется еще одна альтернатива — библиотека libopencm3. В ней основное количество примеров сосредоточено вокруг основной серии микроконтроллеров STM32F10x , но появление примеров для других серий ( STM32F2xx/4xx) является только вопросом времени. Вы всегда можете присоединиться к проекту libopencm3 и ускорить этот процесс.
Стандарт CMSIS также является не обязательным для применения в ваших программах.
Можно обойтись и без него, потратив некоторые усилия и время для реализации HAL ( Hardware Abstraction Layer ) уровня на языке программирования С.
Такой способ может оказаться в некоторых случаях единственным доступным способом. Например, ваша организация использует заказные микросхемы на основе разработанных компанией ARM вычислительных ядер и специфической для отрасли периферией.
Или вам необходимо реализовать программное обеспечение на языке С для микроконтроллеров с ядром ARM9, для которого производители ориентируются на использование готовых операционных систем (Linux, QNX, Windows CE), поэтому библиотек для программирования на языке С в чистом виде или в сочетании с более легковесной RTOS производители могут не предоставлять.
К счастью производители микроконтроллеров на основе ядра Cortex-M3 предоставляют в распоряжение разработчиков большое количество библиотек кода. Это касается и микроконтроллеров STM32.
Продолжим рассмотрение библиотеки STM32F10x SPL. Рассматривать ее будем на примере stm32f10xQuickstart.
Вы можете открыть этот пример или же создать свой проект «с нуля», чтобы лучше осознать весь процесс происходящего.
Для второго случая я перечислю список необходимых шагов :
- Создать в Eclipse новый пустой проект
- Скопировать в проект скрипт компоновки и стартовый файл
- Создать новый или скопировать шаблонный Makefile
- При использовании в качестве шаблона Makefile из моего примера необходимо создать внутри проекта каталоги src, inc, bin, obj , внутри каталогов bin и obj создать подкаталоги Debug и Release.
- Скопировать необходимые исходные и заголовочные файлы из библиотек CMSIS и STM32F10x SPL.
- Внести необходимые изменения в секции настроек пользователя шаблонного Makefile, если он используется.
- Создать в окне Eclipse “make target ” новые цели “Debug”, “cleanDebug”, “Release”, “cleanRelease”, “Program”.
- Запустить на выполнение цель «Debug» и проследить за ее выполнением в окне «Console».
Для лучшего понимания материала я разбил статью на несколько независимых параграфов, в каждом из которых описывается только какой-то один аспект работы с библиотекой STM32F10x SPL.
Конфигурирование STM32F10x SPL с помощью макроопределений
Для конфигурирования библиотеки используются предопределенные значения макросов, которые мы сейчас и рассмотрим.
Их можно задать внутри заголовочных файлов с помощью директивы препроцессора #define или же передать значения макроопределений через ключ -D компилятора GCC.
В своем примере я использую второй способ.
В Makefile переменная DEFINE содержит макросы, необходимые для компиляции библиотеки STM32F10x SPL.
Макроопределение STM32F10X_MD задает принадлежность используемого микроконтроллера к линейке Medium-density.
Сюда входят микроконтроллеры с объемом Flash-памяти от 64 до 128кБ .
В следующей таблице перечислены названия макросов для разных серий микроконтроллеров :
Наименование серии | Макрос | Описание |
Low density Value line | STM32F10X_LD_VL | микроконтроллеры серии STM32F100xx с объемом Flash-памяти 16 — 32кБ |
Low density | STM32F10X_LD | микроконтроллеры серии STM32F101xx, STM32F102xx, STM32F103xx с объемом Flash-памяти 16 — 32кБ |
Medium density Value line | STM32F10X_MD_VL | микроконтроллеры серии STM32F100xx с объемом Flash — памяти 64 — 128кБ |
Medium-density | STM32F10X_MD | микроконтроллеры серии STM32F101xx, STM32F102xx, STM32F103xx с объемом Flash- памяти 64 — 128кБ |
High density Value line | STM32F10X_HD_VL | микроконтроллеры серии STM32F100xx с объемом Flash — памяти 256 — 512кБ |
High density | STM32F10X_HD | микроконтроллеры серии STM32F101xx, STM32F103xx с объемом Flash- памяти 256 — 512кБ |
XL-density | STM32F10X_XL | микроконтроллеры серии STM32F101xx, STM32F103xx с объемом Flash- памяти 512 — 1024кБ |
Connectivity line | STM32F10X_CL | микроконтроллеры серии STM32F105xx и STM32F107xx |
Для задания тактовой частоты микроконтроллера необходимо раскомментировать в файле system_stm32f10x.c макрос с необходимым значение тактовой частоты.