|
|
В печатный вариант книги текст
этого раздела вошел в ошибочной интерпретации. 4.16. Программа подсчета контрольной суммы В предыдущем разделе мы рассмотрели упрощенный вариант считывания информации с дат-чиков температуры, без проверки контрольной суммы. Для простого домашнего термометра этот вариант вполне подходит. Но в условиях значительного удаления датчика от микроконтроллера и особенно в случае повышенного уровня помех, упрощенный вариант программы будет работать неустойчиво. Поэтому, в данном разделе я хотел бы рассмотреть вопрос: как программным путем рассчитать, а затем сверить контрольную сумму. Для того, что бы рассчитать контрольную сумму нам уже не достаточно будет двух байтов. Нам придется считывать из термодатчика все девять регистров блокнотной памяти. Значения этих регистров мы будем размещать все в том же буфере bufLAN. Для этого нужно увеличить размер буфера до 9 байт (см. команду инициализации буфера в разделе 4.13). Новая версия подпрограммы rdtmp приведена на Листинге 4.9. Текст подпро-граммы практически полностью повторяет текст первого ее варианта, приведенного на Листинге 4.7. Отличие только в последних строках. Вместо строк, где читаются два байта блокнотной памя-ти (строки 34, 57, Листинг 4.7) в новом варианте подпрограммы применен цикл считывания бай-тов (строки 18…25, Листинг 4.11). Тело цикла занимает строки 22…25. В строках 18, 19 произ-водится инициализация этого цикла. Регистр r0 используется в качестве указателя буфера, а ре-гистр r1 - в качестве параметра цикла. В строках 20, 21 на шину выдается команда "Чтение блок-нотной памяти". В первой строке цикла производится чтение очередного байта (строка 22). В строке 23 прочитанный байт записывается в буфер bufLAN. В строке 28 значение указателя буфе-ра увеличивается на единицу. Оператор djnz (строка 25) обеспечивает повторение цикла для всех девяти байтов. После того, как все девять байтов прочитаны и записаны в
буфер, вызывается подпрограмма расчета контрольной суммы cmpCRC (строка
26). Эта подпрограмма будет описана чуть позже. Подпрограмма cmpCRC рассчитывает
и сверяет значение контрольной суммы, используя инфор-мацию из буфера
bufLAN. По результатам работы подпрограмма возвращает код ошибки в акку-муляторе.
Если контрольная сумма не сошлась, код в аккумуляторе будет равен трем
(ошибка но-мер 3). Если ошибки не обнаружено, то в аккумуляторе будет
ноль. Ошибка контрольной суммы обрабатывается точно таким же образом,
как и остальные виды ошибок. На экране высвечивается "Error3",
а программа начинает процесс считывания температуры с начала.
Теперь посмотрим, как работает подпрограмма расчета контрольной
суммы. Для начала вспомним алгоритм. Схематически алгоритм вычисления
контрольной суммы приведен на рисун-ке 4.19. Этот алгоритм одинаков как
для восьми ячеек ID кода, так и для девяти ячеек блокнотной памяти. Как
мы можем увидеть из рисунка 4.19, алгоритм основывается на операции сдвига
и трех операциях "Исключающего ИЛИ" (XOR). Нам придется организовать
обе эти операции про-граммным путем. В системе команд микроконтроллера
AT80C2051 имеются команды, позволяю-щие выполнить обе эти операции. Однако
решение задачи "в лоб" не всегда рационально. Для за-дачи подсчета
контрольной суммы существуют приемы, позволяющие максимально упростить
программу. Для того, что бы понять сущность этих приемов, вспомним сначала
некоторые свойст-ва двоичной функции "Исключающее ИЛИ". На рисунке
4.34 приведена таблица истинности для этой функции. Внимательно посмотрев
на эту таблицу, вы можете легко заметить интересную особенность. Функция
"Исключающее ИЛИ" может использоваться в качестве управляемого
ин-вертора. Представим себе, что вход X1 - это вход данных, а вход X2
- управляющий. Тогда, если на управляющем входе X2 установлен нулевой
уровень, то сигнал на выходе Y повторяет сигнал на входе X1. Если же на
управляющий вход X2 подать логическую единицу, то сигнал на выходе Y всегда
будет инверсным, по отношению к сигналу на входе X1. Это свойство широко
использу-ется в вычислительной технике и в программировании. Используется
он и в описываемой подпро-грамме проверки контрольной суммы. Ниже приводятся
два варианта подпрограммы. Оба вариан-та абсолютно равнозначны и любой
из них может использоваться в подпрограмме rdtmp, текст которой приведен
в Листинге 4.9.
Рис 4.34. Таблица истинности логической функции XOR Текст первого варианта подпрограммы cmpCRC приведен в Листинге 4.10.
Этот вариант сна-чала вычисляет контрольную сумму первых восьми ячеек
буфера bufLAN. Затем он сравнивает вычисленное значение с содержимым последней,
девятой ячейкой буфера. Если обе величины окажутся равными, подпрограмма
возвращает ноль в аккумуляторе. Если контрольная сумма не сойдется, подпрограмма
возвращает код ошибки. Код ошибки, как уже говорилось, в данном слу-чае
равен 3.
Адрес 21H выбран не случайно. Для правильной работы подпрограммы нам потребуется как прямой доступ к этой ячейке памяти, так и доступ к отдельным ее битам. Не все ячейки ОЗУ мик-роконтроллера AT89C2051 имеют такую возможность. Двойной доступ допускают ячейки с адре-са 20H по адрес 2FH (подробнее об этом смотри в [1]). Однако ячейка с адресом 20H уже занята. Ее младший бит используется в качестве флага fpit. Поэтому выбрана следующая по счету не-задействованная ячейка. Для вычисления контрольной суммы восьми первых ячеек буфера мы должны представить со-держимое всех этих ячеек в виде единой последовательности из 64 битов. Затем мы должны по-битно "вдвигать" эти данные в буфер контрольной суммы bufCRC, одновременно производя три операции "Исключающего ИЛИ" в соответствующих разрядах (см. схему алгоритма на рис. 4.19). Таких циклов сдвига должно быть ровно 64 (по числу проверяемых битов). Если действовать строго по алгоритму, изображенному на рисунке 4.19, то мы должны на каждом шаге расчета контрольной суммы одновременно сдвигать содержимое буфера и на ходу производить операции XOR. Однако эту операцию удобно разделить на два отдельных действия. Сначала вычислить все операции XOR, поместив результат операций в те же самые разряды. А затем произвести сдвиг. В результате, для того, что бы реализовать один цикл вычисления контрольной суммы, мы должны выполнить четыре этапа. В графическом виде все этапы изображены на рисунке 4.35.
Если произвести 64 описанных выше цикла, то в конце операции в буфере bufCRC сформиру-ется значение контрольной суммы. Текст подпрограммы cmpCRC, реализующей описанный выше алгоритм, приведен в Листинге 4.10. Начинается подпрограмма с обнуления буфера bufCRC (строка 1). Обнулить буфер перед началом вычислений нужно обязательно. Это тоже требование алгоритма. Далее, в строках 3…11, начинается цикл подсчета контрольной суммы. В качестве па-раметра цикла используется регистр r2. В строке 2 ему присваивается начальное значение - 64. Тело цикла занимает строки 3…11. В начале цикла (строка 3) вызывается специальная подпро-грамма, которая производит сдвиг первых восьми ячеек (64 бит) буфера bufLAN. Специальная подпрограмма используется потому, что сдвигать нам надо не одну, а сразу восемь ячеек. Описа-ние подпрограммы сдвига будет приведено чуть позже. В результате работы этой подпрограммы информация в буфере bufLAN сдвигается на один бит вправо, а самый младший бит оказывается в ячейке CY. На этом завершается первый этап (см. рис 4.35). Затем программа приступает ко второму этапу. На этом этапе она должна выполнить функцию XOR между двумя битами информации. В системе команд микроконтроллера AT89C2051 отсут-ствует операция "Исключающее ИЛИ" для отдельных битов. Поэтому она заменяется нескольки-ми командами, приводящими к аналогичному результату. Тут мы опять вспомним, что операция "Исключающее ИЛИ" - это управляемый инвертор. Управляемая инверсия реализуется в строках 4 и 5 программы. В качестве бита управления служит содержимое ячейки CY. В качестве инверти-руемого бита младший бит буфера bufCRC. В строке 4 оценивается значение ячейки CY. Если это значение равно нулю, то происходит переход по метке cpr2 и инверсии не производится. Если признак переноса равен единице, то младший бит буфера bufCRC инвертируется (строка 5). Дальше программа переходит к третьему этапу. Для этого извлекается содержимое
буфера bufCRC и помещается в аккумулятор (строка 6). Далее производится
проверка значения младшего разряда буфера bufCRC (строка 7). Если младший
разряд равен единице, то нужно произвести операцию "Исключающее ИЛИ"
аккумулятора с константой 00011000B. Если младший бит буфе-ра bufCRC равен
нулю, то никаких больше действий на этом этапе выполнять не нужно. Операция
"Исключающее ИЛИ" между содержимым аккумулятора и константой
00011000B выполняется в строке 8. Листинг 4.10.
Последний этап - это сдвиг содержимого аккумулятора. Исходный код после
предыдущего этапа уже находится в аккумуляторе. Сдвиг выполняется оператором
rr в строке 9 программы. После сдвига аккумулятор будет содержать промежуточное
значение контрольной суммы. Это значение помещается назад, в буфер bufCRC
(строка 10). Теперь рассмотрим подробнее работу подпрограммы, которая производит сдвиг
64 разрядов буфера bufLAN. Она вызывается по ссылке rr64. Расположение
всех 64 разрядов в буфере и на-правление сдвига информации изображены
на рисунке 4.36. Для того, что бы осуществить такой сдвиг, содержимое
каждой из восьми ячеек буфера bufLAN поочередно вызывается в аккумуля-тор.
В аккумуляторе содержимое очередной ячейки сдвигается вправо, при помощи
команды rrc (сдвиг вправо через признак переноса). Затем результат сдвига
записывается обратно в ту же ячейку, откуда был прочитан. Ячейка признака
переноса CY используется для передачи сдвигае-мого бита из одной обрабатываемой
ячейки в другую. При этом бит, из младшего разряда преды-дущей ячейки
попадает в старший разряд последующей. Для того, что бы обеспечить правильную
передачу битов от одной сдвигаемой ячейки в другую, нужно начинать обработку
ячеек с самой последней ячейки последовательности (bufLAN+7). После завершения
всей процедуры сдвига в CY оказывается самый младший бит всей последовательности
(P0).
Следующие две строки содержат команды, которые помещают в CY содержимое
бита P0 (см. рис. 4.35). Эта операция нужна для соблюдения условия цикличности
(сдвиг по кругу). Для извле-чения содержимого разряда P0 в аккумулятор
помещается содержимое самой первой ячейки бу-фера с адресом bufLAN (строка
21). Затем младший бит аккумулятора отправляется в CY. Это действие
выполняется при помощи операции сдвига rrc (строка 22). После этого
сразу начинает-ся цикл сдвига. Описанную только что программу можно немного сократить.
Для этого можно использовать одно любопытное свойство алгоритма расчета
контрольной суммы. Если вычислить контрольную сумму не восьми, а всех
девяти ячеек буфера, то результат вычисления будет равен нулю. Но это
только в том случае, если все девять байтов были считаны без ошибок.
В случае любой ошибки результат будет отличен от нуля. Немного изменив
программу, можно реализовать и этот новый способ проверки контрольной
суммы. При этом мы экономим на операции сравнения. Новый, бо-лее оптимальный
вариант подпрограммы cmpCRC приведен в Листинге 4.11. В результате такой
оптимизации текст программы уменьшился на три строчки, а результирующий
код подпрограммы становится короче на целых 5 байт. Листинг 4.11.
|