Юрий Ревич - Занимательная микроэлектроника
- Название:Занимательная микроэлектроника
- Автор:
- Жанр:
- Издательство:БХВ-Петербург
- Год:2007
- Город:Санкт-Петербург
- ISBN:978-5-9775-0080-7
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Юрий Ревич - Занимательная микроэлектроника краткое содержание
Для широкого круга радиолюбителей
Занимательная микроэлектроника - читать онлайн бесплатно ознакомительный отрывок
Интервал:
Закладка:
В первой строке служебный байт типа данных равен 02, и это означает, что данные в ней представляют сегмент памяти, с которого должна начинаться запись (в данном случае 0000). Заканчивается hex-файл всегда строкой «:00000001ff» — значение типа данных 01 означает конец записи, и данных больше не ожидается. А что означает FF?
Самым последним байтом в каждой строке идет контрольная сумма (дополнение до 2) для всех остальных байт строки, включая служебные. Алгоритм ее вычисления очень простой: нужно вычесть из числа 256 значения всех байтов строки (можно не обращая внимание на перенос), и взять младший байт результата. Соответственно, проверка целостности строки еще проще: нужно сложить значения всех байтов (включая контрольную сумму), и младший байт результата должен равняться нулю. Так, в первой строке число информационных байтов всего два (первое значение в строке), плюс служебный байт типа данных, равный также двум, итого контрольная сумма всегда равна 256 — 2–2 = 252 = $FC. В последней строке одни нули, кроме типа данных, равного 1, соответственно, контрольная сумма равна 256 — 1 = 255 = $FF.
Теперь попробуем немного расшифровать данные. Первое слово в первой информационной строке, как мы выяснили, равно $С03А. Если мы возьмем фирменное описание команд, то обнаружим, что значению старшей тетрады в КОП, равной $С (1100 в двоичной системе), соответствует команда rjmp, но ведь так и должно быть, мы же договорились, что любая программа начинается с безусловного перехода на метку RESET. Теперь очевидно, что остальные биты в этом значении ($03А) представляют абсолютный адрес в программе, где в ее тексте стояла метка reset. Попробуем его найти, для этого вспомним, что адреса отсчитываются по словам, а не по байтам, т. е. число $ЗА (58) надо умножить на 2 (получится 116 = $74), и искать в этой области. Разыщем строку с адресом $0070, отсчитаем три пары байт от начала данных, и найдем там фрагмент «F894», который в нормальной записи будет выглядеть, как $94F8, а это, как легко убедиться по справочнику, есть код команды cli, запрещающей прерывания (которая в начале программы лишняя, т. к. они все равно запрещены, но, видимо, поставлена на всякий случай). Следующая команда будет начинаться с байта $Е5, и первая тетрада в ней обозначает код команды ldi(1110 — проверьте!), а пятерка, очевидно, есть фрагмент адреса конца памяти ( RAMEND), который в силу довольно сложного формата записи получается на самом деле равным $025F (см. значение младшего байта, равное $2F). Такое значение соответствует значению ramend, определенному в inc-файлах для МК с 512 байтами встроенного ОЗУ [12] $025F = 607, т. е. всего адресов 608, из которых 96 ($5F) занимают регистры, итого получается 512 ($0200) незанятых байтовых ячеек, составляющих ОЗУ.
. Все, как и должно быть. Если мы обратим внимание опять на первую-вторую строки с данными, то увидим повторяющийся фрагмент «1895», который, как легко догадаться из материала предыдущего раздела, должен быть командой reti(если проверите по справочнику, то так оно и окажется).
Как видите, разобраться довольно сложно, но при некотором навыке и наличии под рукой таблицы двоичных кодов команд вполне возможно. Именно так работает программа, которая превращает код обратно в текст — дизассемблер (он входит в AVR Studio). А зачем это может понадобиться на практике? Дело в том, что в памяти программ часто хранят те константы, которые предположительно не будут изменяться в процессе эксплуатации, например, устанавливаемые по умолчанию значения какой-то величины. Но, разумеется, по истечении некоторого времени эти константы обязательно захочется изменить. И если у вас текст программы по каким-то причинам отсутствует (например, программа взята из публикации в журнале или скачана с радиолюбительского сайта), а загрузочный hex-файл имеется, то всегда можно «хакнуть» исходный код, и немного подправить его под свои нужды.
Команды перехода (передачи управления)
В языках высокого уровня была всего одна команда перехода на метку (GOTO), и то Дейкстра на нее «набросился». А в ассемблере AVR таких команд пруд пруди, целых 33 шутки! Зачем? На самом деле без доброй половины из них, если не больше, можно обойтись во всех жизненных случаях, т. к. они в значительной степени взаимозаменяемы. Разнообразие это, если угодно, дань памяти великому программисту — для повышения читаемости программ. Мы рассмотрим только ключевые команды из этого перечня.
С командами безусловного перехода rjmpи jmpмы уже познакомились достаточно подробно, так что сразу перейдем к вызову процедур rcallи call(официальный язык фирменных руководств Atmel предпочитает вместо процедуры упоминавшийся нами консервативный термин — подпрограмма, subroutine). Синтаксис у них точно такой же, как у команд безусловного перехода, и, по сути, это тот же самый переход по метке. И разница между этими двумя командами аналогичная: callработает в пределах 64 К адресов памяти (или до 8 М в соответствующем контроллере, поддерживающем такой объем адресного пространства), занимает 4 байта и выполняется за 4 цикла, a rcallгодится только для МК с объемом памяти не более 8 кбайт, но занимает 2 байта и выполняется за 3 цикла. Мы в дальнейшем будем пользоваться только командой rcall.
Отличаются они от команд безусловного перехода тем, что здесь в момент перехода к процедуре контроллер автоматически сохраняет в стеке адрес текущей команды для того, чтобы потом знать, куда вернуться (потому длительность выполнения этих команд на такт больше, чем для просто перехода). А как МК «узнает», когда именно нужно возвращаться? Для этого каждая процедура-подпрограмма оформляется специальным образом: не отличаясь поначалу ничем от любого другого участка программного кода, обозначенного меткой, в месте возврата она должна содержать специальную команду — ret(от return — «возврат»). По этой команде МК извлекает из стека сохраненное содержимое счетчика команд и продолжает выполнение прерванной основной программы.
Заметим, что стек — одно из самых употребительных понятий в программировании. Наличие программного стека позволяет, например, организовать привычное для языков высокого уровня разделение переменных на локальные и глобальные. Во всех последующих программах в этой книге мы будем пользоваться только глобальными переменными, и при нехватке регистров общего назначения для них мы будем использовать ячейки SRAM. (Привычку употреблять преимущественно глобальные переменные автор даже перенес в свой стиль программирования на Delphi, как вы увидите из главы 18 .) Однако в больших проектах локальные переменные зачастую бывает просто необходимы (например, когда одна и та же процедура вызывается в разных местах с исходными данными, хранящимися в различных регистрах). Механизм организации локальных переменных с помощью стека приведен в листинге 13.2 (он в точности такой же, как это происходит при компиляции в «настоящих» языках программирования).
Читать дальшеИнтервал:
Закладка: