LPCXpresso Урок 13. Debug. Погружаемся в отладку на примере UART.

Я в курсе для новичков предлагаю вам уже избавленный от ошибок код, но что делать, когда пишешь код сам. Отладчик это мощное средство, давайте же изучим его ещё немного лучше. До сих пор мы только наблюдали в нем за ходом выполнения программы, в этом же уроке мы будем им управлять.

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

Схема

Для данного урока нам надо соединить выводы RXD и TXD платы LPCXpresso, либо непосредственно между собой, либо через выключатель (который изначально нужен нам в положение «эхо»):

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

Перспективы

Среда разработки LPCXpresso имеет так называемые «перспективы». Назначение их в отображение в среде подготовленного набора окон. Так в «Develop perspective», в которой мы работали до сих пор, у нас были доступны окна исходного кода, дерево проектов, консоль, а во время отладки ещё окно Debug со стеком вызовов. Этого нам было достаточно для изучения проектов, но этого мало для удобной и полноценной отладки.
Давайте переключимся в «Debug perspective», для этого в правой верхней части окна нажмём соответствующую кнопку:

Среда изменит свою компоновку:

Кроме уже знакомых нам окон появилось ещё несколько:
  • Variables — окно отображения значений переменных, доступных в текущей области (упомянем ниже);
  • Breakpoints — окно отображения/управления точками останова (интуитивно понятно);
  • Core Registers — окно регистров ядра (иногда вам могут пригодится регистры Cycle и CycleDelta);
  • Expression — отображение значений выражений (упомянем ниже);
  • Peripherals — выбор периферии для отображения (упомянем ниже);
  • Disassembly — окно дизассемблера (при желании можете посмотреть как скомпилирован тот или иной участок, так же используется при отладке в Instruction Stepping Mode);
  • Memory — окно «мониторинга» памяти и отображения периферии (упомянем ниже).
Переключаться между перспективами можно в любое время. Переключение возможно там же из меню Windows -> Open Perspective.

Углубляемся в отладку

Я предлагаю вым установить точку останова на первой строке бесконечного цикла:
c = UARTGetChar();

И запустить выполнение. Попав на эту строку, мы продолжим выполнение в пошаговом режиме (без входа в функции, что бы сильно не блуждать). При выполнении функции мы, благодаря наличию соединения RXD с TXD, получим в переменную c отправленный нами же символ '>'. Пройдем по циклу и снова остановимся на вызове этой функции. Если мы попробуем просто выполнить эту функцию повторно, то мы зависнем в ней на ожидании приёма данных, ведь больше ничего мы не отправляли и принять соответственно не можем. Как нам быть? Ведь проверить работу программы надо.
Давайте установим курсор (каретку редактирования кода) на следующей строке:
switch(C) {

Из вызванного правой кнопкой мыши контекстного меню выберем пункт «Move To Line».

И с радостью замечаем, что курсор выполнения кода перешел на указанную нами строку. Только что мы пропустили вызов «потенциально опасной для нас» функции. Мы можем продолжить выполнение с вновь выбранной точки.
Но. Функция должна была нам вернуть принятые по UART данные, а мы, обойдя её вызов, оставили значение переменной c без изменений. Естественно это нас не устраивает. По-этому переходим к окну Variables. В нем отображена наша переменная c с её текущим значением '>'. Давайте изменим его на '+', для этого просто делаем левый клик на значении и вводим новое значение. Вводить надо с одинарными кавычками, так как мы должны задать код интересующего нас символа.

Продолжаем выполнение и наблюдаем как на плате зажигается светодиод, в подтверждение того, что выполненные нами действия были расценены как мы того хотели.

Наблюдение за значениями выражений

Окно Variables отображает нам значения только «локальных» переменных, доступных в текущем участке кода. А что делать если мы хотим видеть значение какой-нибудь «глобальной» переменной. Для этих целей можно выделить интересующую нас переменную и из контекстного меню (правый клик мышкой) выбрать пункт Add Watch Expression…. В появившемся окне мы можем отредактировать имя переменной (если что-то не выделили или вообще ничего не выделяли). В моём случае я выбрал всё ту же переменную c:

Но почему же пункт содержит Expression (выражение), а не Variable (переменная)? Дело в том, что мы можем добавить не просто имя переменной, а целые выражения с участием, как переменных, так и константы и вызовы функций. Для примера измените значение переменной c в '5' (с одинарными кавычками), поместив тем самым в переменную c код символа 5. В окне ввода выражения введите c – '0' тем самым составив выражение, возвращающее численное значение помещённого в переменную c символа цифры (что есть символ, а что есть число лучше прочтите в учебнике по Си):

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

Переферия

Последнее, про что я хотел бы рассказать в этом уроке, это окна Peripherals и Memory. В окне Peripherals перечислена имеющаяся у контроллера периферия, с отображением её адресов. У вас имеется возможность установки флажка рядом с интересующей вас периферией. После чего в окне Memory появится развернутое отображение выбранного вами пункта:

Это довольно мощное средство, позволяющее вам управлять периферией контроллера «на лету» и даже без написания соответствующего кода. Но одновременно оно является и «опасным» средством, способным нарушить нормальное функционирование контроллера. Связано это с наличием «побочного эффекта» у некоторых регистров. Так чтение из регистра RBR у UART извлекает прочитанный байт из буфера приёма, и вы его не сможете получить в коде программы. Некоторые флаги ошибок/достоверности так же сбрасываются после чтения регистра, в итоге ваша программа может зависнуть в ожидание события, которое уже извлек отладчик.
Поэтому вы должны осознавать, что вы изменяете и с какой целью.

Вместо завершения

При обнаружении ошибки в программы во время тестирования вам не обязательно её сразу исправлять и снова прошивать контроллер. Порой можно воспользоваться средствами отладчика и просто обойти проблемный участок.
Или же наоборот, вы хотите проверить реакцию вашей программы на недействительные данные с датчика, а датчик как назло работает корректно. Вам достаточно просто подтасовать данные и проанализировать реакцию вашего кода.
Отладчик – мощное средство. При использовании его «с умом» вы сильно облегчите себе процесс написания программ и повысите качество разрабатываемых вами устройств.
Пользуйтесь отладчиком.
  • +2
  • 22 сентября 2011, 09:08
  • angel5a
  • 1
Файлы в топике: blinky_uart.zip

Комментарии (5)

RSS свернуть / развернуть
… а что это за брэйкпоинт (аппаратный, программный)? и сколько их можно понаставить в отладке?
0
Ну контроллер поддерживает до 2-х аппаратных бряков. По идеи аппаратным предпочтение и отдается, т.к. если ставить 3+ бряка, то контроллер начинает тормозить и идет активный обмен по шине. Хотя не понятно почему, для програмного то просто команду переписать надо…
В прочем мне как-то и 2-х хватало.
0
Да, если ставить бряк с условием, то выполнение тоже неплохо тормозится, но все равно быстрее чем самомтоятильно просматривать значения переменнх :)
Возможно про бряки с условиями стоило тоже написать.
0
… а во время отладки, максимальное число перезаписи flash памяти не уменьшается?
0
Проверку на износ не проводил. Даже перезамуск делаю через стоп-дебаг, вместо предусмотренного рестарта (который не перепрошивает контроллер).
0
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.