Ревич, Ю.В. Программирование микроконтроллеров AVR: от Arduino к ассемблеру

130 ; программа : < что-то делаем > rcall Delay < что-то делаем > rcall Delay < что-то делаем > Часть //. Программирование микроконтроллеров АVR на ассемблере Здесь метка Delay указывает на начало подпрограммы (и одновременно является ее именем), а команда ret осуществляет корректный выход из подпрограммы с воз­ вратом именно в то место кода, из которого ее вызывали. В реальности происходит следующее: команда вызова rcall сначала сохраняет текущее значение адреса в стеке (области в памяти SRAM, которая располагается в самом конце этой памяти и растет в сторону начала), потом в программный счетчик РС загружается адрес метки Delay. Далее выполняется код задержки, и по команде ret осуществляется обратная операция - сохраненный в стеке адрес, откуда прервали, помещается в программный счетчик, и выполнение продолжается со следующей команды вы­ зывавшего участка кода. Оговорка здесь только одна: для контроллеров с памятью более 8 кбайт вместо rcall полагается вызывать более длинную команду call , которая действует на весь диапазон такой памяти. На самом деле это необязательно, потому что руками на ассемблере вы все равно не напишете код, превышающий 8 кбайт, а если и напише­ те, то на ошибку вам укажет компилятор. Причем у контроллеров с памятью 8 кбайт и менее команда cal l (так же, как и аналогичная по адресуемой памяти команда jmp ) вовсе отсутствует, и там ее вы применить не сможете . Существенный нюанс здесь состоит в том, что команда rcall занимает 3 такта про­ цессорного времени, а команда ret - еще 4. Потому выполнение подпрограммы всегда длится на 7 тактов больше, чем если бы ее код оставили просто в том месте, где он выполняется . При этом мы тут еще не учитываем, что может захотеться со­ орудить настоящую процедуру-функцию, передав в нее какие-то параметры и по­ том получив результаты обратно (см. далее в этой главе), или просто сохранить в стеке некоторые регистры на время выполнения подпрограммы. Каждое такое сохранение и извлечение - это еще по такту процессорного времени на выполне­ ние каждой из команд push и рор, а таких пар может быть много. И если здесь мы сможем почти всегда избегать такой работы со стеком, пользуясь добротой фирмы Atmel, предоставившей нам 32 регистра общего назначения, то языки высокого уровня даже не стараются как-то оптимизировать вызовы функций в этом отноше­ нии. Отсюда понятно, почему Аrduinо-программы намного больше ассемблерных по размеру и выполняются намного дольше. Есть альтернативное средство, которое позволяет избежать замедления выполнения программы, и в то же время сократить ее текст, сделав ее более читаемой и понят­ ной. Это средство - макросы, и когда применять целесообразно именно их, а когда - подпрограммы, мы обсудим немного далее.

RkJQdWJsaXNoZXIy MTExODQxMg==