1000000000308A000428000084011F308305073077
100010009F00A201А301A108031914282108A20727
100020000318A30AA1030B282208F8002308F900EB
0200300063006В
00000001FF
;PIC16F627
Давайте посмотрим, как компилятор транслировал нашу программу.
unsigned long main(unsigned int n)
Точка входа в функцию main () всегда располагается по адресу вектора сброса h’000’. Сначала обнуляется регистр PCLATH (h’0A’), поскольку все последующие команды размещаются в младших адресах памяти программ. Далее управление передается по адресу вектора прерывания h’004’. Поскольку в данном случае прерывания не используются, компилятор разместил по этому адресу код функции main (). Функция main () начинается с очистки регистра FSR (h’004’). Затем сбрасываются биты IRP, RP1 и RP0 регистра STATUS, обеспечивая работу с 0-м банком. Наконец, специально для модели PIC16F627 путем установки трех младших битов регистра управления компаратором CMCON (h’1F’) выключается модуль аналогового компаратора (см. Рис. 14.6 на стр. 497).
Наличие этой фазы инициализации является отличительной особенностью функции main (). Благодаря ей выполнение «полезного» кода после сброса будет начинаться с определенного состояния микроконтроллера. Обычно программа на языке Си состоит из множества функций, но только в функции main () производится настройка окружения программы.
unsigned long sum = 0;
Компилятор CCS резервирует два байта под объект типа long. В данном случае младший и старший байты переменной main.sum были размещены в регистрах h’22’ и h’23’ соответственно. Для обнуления этих двух РОН компилятор сгенерировал две команды clrf:
clrf h’22’; Обнуляем младший байт суммы
clrf h’23’; Обнуляем старший байт суммы
while (n > 0) {
Компилятор выделил регистр h’21’ под однобайтный объект main.n. По-хорошему его значение должно задаваться вызывающей функцией. Оператор while реализуется проверкой main.n на ноль и переходом к оператору возврата return в случае, если это условие истинно.
movf h’21’,f; Проверяем на ноль
btfsc STATUS,Z; ЕСЛИ не ноль, ТО пропускаем команду
goto h’014’; ИНАЧЕ переходим к адресу h’014’ (return)
sum = sum + n;
Это выражение реализовано в виде операции прибавления однобайтного числа к двухбайтному следующим образом:
movf h’21’,w; Считываем main.n
addwf h’22’,f; Складываем с младшим байтом суммы
btfsc STATUS,С; Пропускаем команду, ЕСЛИ нет переноса
incf h’23’,f; ИНАЧЕ инкрементируем старший байт суммы
Большинство программистов на Си в этом случае воспользовались бы альтернативным оператором
sum +=n;
результатом которого является переменная sum,
--n;
Теперь декрементируем однобайтное число в регистре h’21’:
decf h’21’,f; Декрементируем main.n
В более сложных выражениях результат может зависеть от того, где располагается оператор
number = --
то значение
number =
операция декрементирования выполняется после сложения.
В нашем примере положение оператора декремента не влияет на логику работы программы. Однако в последнем случае компилятор добавит дополнительную команду для перегрузки main.n в рабочий регистр перед его декрементированием, чтобы обеспечить возможность выполнения вычислений с использованием исходного значения main.n, которые могут иметь место.
}
Возврат к началу цикла while осуществляется переходом к командам проверки условия, которые размещаются, начиная с адреса h’00B’.
goto h’00B’
return sum;
В конце функции, возвращающей объект типа unsigned long, компилятор CCS заносит двухбайтное значение в регистры с фиксированными адресами h’78’:h’79’ (младший и старший байты). В нашем случае в эти регистры просто копируется содержимое регистров h’22’:h’23’, т. е. значение main.sum.