Мир книг по микроэлектронике
Книги авторства Белова Александра
На главнуюРеквизиты автора Сайт МирМК FUSE калькулятор Сайт "Симферополь вчера и сегодня"

В печатный вариант книги текст этого раздела вошел в ошибочной интерпретации.
На этой страничке приведен полный исправленный вариант текста раздела.

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.9.
           
    ;******************************************************
;**                Чтение Температуры
;**                     второй вариант
;******************************************************
; Входные параметры в acc - номер канала
; Выходные параметры - в bufLAN 8 байтов считанного кода
           
1   rdtmp: push psw  
2     mov psw,#bank2 ; Выбор банка 2 памяти
           
3   rtm1: mov b,#8 ; Вычисление смещения
4     mul ab ; для адреса ПЗУ
5     mov r7,a ; Временно сохранить в r7
           
    ;-------------------- Начальный сброс
6     call resLAN ; Вызов процедуры сброса
7     cjne a,#0,rtm2 ; Если ошибка
           
    ;-------------------- Выбор ПЗУ
8     mov a,#55H ; Выдать команду
9     call wr8LAN  
10     mov b,r7 ; Восстановить смещение
11     mov r6,#8 ; Счетчик байтов
12     mov DPTR,#pzu1 ; Начальный адрес кодов ПЗУ
13   szu1: mov a,b ; Текущее смещение
14     movc a,@a+DPTR ; Извлечь очередной байт
15     call wr8LAN ; Выдать на линию
16     inc b ; Увеличить смещение на 1
17     djnz r6,szu1 ; Продолжить цикл, если не последний
           
    ;-------------------- Чтение ОЗУ
18     mov r0,#bufLAN ; Инициализация указателя буфера
19     mov r1,#9 ; Инициализация счетчика байтов
20     mov a,#0BEH ; Выдать команду
21     call wr8LAN  
22   szu2: call rd8LAN ; Чтение младшего байта
23     mov @r0,a ; Запись в буфер
24     inc r0 ; Увеличение указателя буфера
25     djnz r1,szu2  
           
    ;-------------------- Проверка контрольной суммы
26     call cmpCRC ; Вызов процедуры проверки КС
27     cjne a,#0,rtm2 ; Если ошибка
           
28     pop psw ; Завершение подпрограммы
29     ret    
           
30   rtm2: call prErr ; Если ошибка вывести ее на экран
31     jmp rtm1 ; Перейти в начало
           
           
32   pzu1: DB 28H,0B8H,56H,4BH,0,0,0,0C5H ; Коды ПЗУ датчиков
33   pzu2: DB 28H,06FH,5CH,4BH,0,0,0,39H  
           

Теперь посмотрим, как работает подпрограмма расчета контрольной суммы. Для начала вспомним алгоритм. Схематически алгоритм вычисления контрольной суммы приведен на рисун-ке 4.19. Этот алгоритм одинаков как для восьми ячеек ID кода, так и для девяти ячеек блокнотной памяти. Как мы можем увидеть из рисунка 4.19, алгоритм основывается на операции сдвига и трех операциях "Исключающего ИЛИ" (XOR). Нам придется организовать обе эти операции про-граммным путем. В системе команд микроконтроллера AT80C2051 имеются команды, позволяю-щие выполнить обе эти операции. Однако решение задачи "в лоб" не всегда рационально. Для за-дачи подсчета контрольной суммы существуют приемы, позволяющие максимально упростить программу. Для того, что бы понять сущность этих приемов, вспомним сначала некоторые свойст-ва двоичной функции "Исключающее ИЛИ". На рисунке 4.34 приведена таблица истинности для этой функции. Внимательно посмотрев на эту таблицу, вы можете легко заметить интересную особенность. Функция "Исключающее ИЛИ" может использоваться в качестве управляемого ин-вертора. Представим себе, что вход X1 - это вход данных, а вход X2 - управляющий. Тогда, если на управляющем входе X2 установлен нулевой уровень, то сигнал на выходе Y повторяет сигнал на входе X1. Если же на управляющий вход X2 подать логическую единицу, то сигнал на выходе Y всегда будет инверсным, по отношению к сигналу на входе X1. Это свойство широко использу-ется в вычислительной технике и в программировании. Используется он и в описываемой подпро-грамме проверки контрольной суммы. Ниже приводятся два варианта подпрограммы. Оба вариан-та абсолютно равнозначны и любой из них может использоваться в подпрограмме rdtmp, текст которой приведен в Листинге 4.9.

X1 X2 Y
0 0 0
0 1 1
1 0 1
1 1 0

Рис 4.34. Таблица истинности логической функции XOR

Текст первого варианта подпрограммы cmpCRC приведен в Листинге 4.10. Этот вариант сна-чала вычисляет контрольную сумму первых восьми ячеек буфера bufLAN. Затем он сравнивает вычисленное значение с содержимым последней, девятой ячейкой буфера. Если обе величины окажутся равными, подпрограмма возвращает ноль в аккумуляторе. Если контрольная сумма не сойдется, подпрограмма возвращает код ошибки. Код ошибки, как уже говорилось, в данном слу-чае равен 3.
Для правильной работы подпрограммы нам потребуется зарезервировать еще одну ячейку в ОЗУ микроконтроллера. Эта ячейка будет использоваться подпрограммой для хранения промежу-точного результата при подсчете контрольной суммы. Две дополнительные строки, резервирую-щие такую ячейку, выглядит следующим образом:

    ORG 21H  
  bufCRC: DS 1 ; Буфер контрольной суммы
         

Адрес 21H выбран не случайно. Для правильной работы подпрограммы нам потребуется как прямой доступ к этой ячейке памяти, так и доступ к отдельным ее битам. Не все ячейки ОЗУ мик-роконтроллера AT89C2051 имеют такую возможность. Двойной доступ допускают ячейки с адре-са 20H по адрес 2FH (подробнее об этом смотри в [1]). Однако ячейка с адресом 20H уже занята. Ее младший бит используется в качестве флага fpit. Поэтому выбрана следующая по счету не-задействованная ячейка.

Для вычисления контрольной суммы восьми первых ячеек буфера мы должны представить со-держимое всех этих ячеек в виде единой последовательности из 64 битов. Затем мы должны по-битно "вдвигать" эти данные в буфер контрольной суммы bufCRC, одновременно производя три операции "Исключающего ИЛИ" в соответствующих разрядах (см. схему алгоритма на рис. 4.19). Таких циклов сдвига должно быть ровно 64 (по числу проверяемых битов). Если действовать строго по алгоритму, изображенному на рисунке 4.19, то мы должны на каждом шаге расчета контрольной суммы одновременно сдвигать содержимое буфера и на ходу производить операции XOR. Однако эту операцию удобно разделить на два отдельных действия. Сначала вычислить все операции XOR, поместив результат операций в те же самые разряды. А затем произвести сдвиг. В результате, для того, что бы реализовать один цикл вычисления контрольной суммы, мы должны выполнить четыре этапа. В графическом виде все этапы изображены на рисунке 4.35.


Рис 4.35. Этапы одного цикла вычисления контрольной суммы

  • На первом этапе нужно произвести сдвиг 64 младших битов в буфере bufLAN таким образом, что бы самый младший бит оказался в ячейке CY. Здесь буфер представляется в виде непре-рывного 72-битного регистра.
  • На втором этапе нужно произвести операцию XOR между полученным на предыдущем этапе битом и младшим разрядом буфера bufCRC. Тем самым будет реализована первая из опера-ций XOR алгоритма (самый правый по рисунку 4.19, сразу на входе алгоритма). Результат операции XOR удобно сохранить в CY.
  • На третьем этапе мы можем произвести сразу две оставшихся операции XOR одновременно. Вот тут нам и пригодится удивительное свойство оператора "Исключающее ИЛИ". Обе ос-тавшиеся операции XOR в схеме алгоритма получают на один из своих входов только что вы-численный нами бит, который пока находится в CY. Если значения этого бита равно нулю, то обе интересующие нас операции XOR должны превратится в повторители и пропустить через себя сигнал без изменения. Если с CY находится единица, то оба оператора XOR должны про-инвертировать входной сигнал. Для имитации работы в режиме повторителей можно просто не производить никаких действий, тогда значение разрядов не изменится. Если нам необходи-мо проинвертировать эти два разряда, то мы должны сначала сформировать константу, равную 00011000B. А затем произвести операцию "Исключающее ИЛИ" между содержимым буфера bufCRC и этой константой. В результате значение двух разрядов проинвертируется.
  • На последнем этапе нужно просто сдвинуть содержимое буфера на один разряд вправо. На этом один цикл расчета контрольной суммы будет завершен.

Если произвести 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.
           
    ;################################################
;##         Проверка контрольной суммы         ##
;##                Вариант 1                   ##
;################################################
           
1   cmpCRC: mov bufCRC,#0 ; Обнуление буфера КС
2     mov r2,#64 ; Инициализация счетчика сдвигов
3   cpr1: call rr64 ; Сдвиг 64 разрядов в буфере
4     jnc cpr2 ; Проверка очередного бита
5     cpl bufCRC.0 ; Если он равен единице, инвертируем
6   cpr2: mov a,bufCRC ; Читаем содержимое буфера КС
7     jnb bufCRC.0,cpr3 ; Проверка младшего бита
8     xrl a,#00011000B ; Если он равен единице делаем XOR
9   cpr3: rr a ; Сдвиг
10     mov bufCRC,a ; Помещаем назад в буфер
11     djnz r2,cpr1 ; Оператор цикла
12     clr c ; Сброс признака переноса
13     mov a,bufLAN+8 ; Извлечение КС из буфера bufLAN
14     subb a,bufCRC ; Вычитание из него рассчитанной КС
15     jz cpr4 ; Проверка результата
16     mov a,#3 ; Если не ноль - ошибка номер три
17   cpr4:      
18     ret    
           
    ; ------------ Сдвиг 8 ячеек буфера на один бит вправо
           
19   rr56: mov r0,#bufLAN+7 ; Инициализация указателя буфера
20     mov r1,#8 ; Инициализация счетчика байтов
21     mov a,bufLAN ; Извлечение первого байта
22     rrc a ; засылка в CY младшего бита
23   rr1: mov a,@r0 ; Извлечение очередного числа
24     rrc a ; Сдвиг
25     mov @r0,a ; Запись назад
26     dec r0 ; Итерация счетчика байтов
27     djnz r1,rr1 ; Оператор цикла
28     ret    
           

Последний этап - это сдвиг содержимого аккумулятора. Исходный код после предыдущего этапа уже находится в аккумуляторе. Сдвиг выполняется оператором rr в строке 9 программы. После сдвига аккумулятор будет содержать промежуточное значение контрольной суммы. Это значение помещается назад, в буфер bufCRC (строка 10).
После того, как все четыре этапа закончены, нужно повторить их еще и еще раз. Всего должно быть 64 цикла. Оператор djnz (строка 11) возвращает управление в начало цикла (метка cpr1) до тех пор, пока не будут обработаны все 64 бита информации.
По завершении процесса вычисления контрольной суммы ее окончательное значение будет на-ходиться в буфере bufCRC. Не смотря на то, что в процессе подсчета контрольной суммы содер-жимое буфера bufLAN постоянно сдвигалось, после окончания всех 64 циклов сдвига оно восста-новится (сдвиг происходит по кругу). В результате там снова будут находиться те же самые ис-ходные значения, которые были считаны из микросхемы термодатчика.

Теперь рассмотрим подробнее работу подпрограммы, которая производит сдвиг 64 разрядов буфера bufLAN. Она вызывается по ссылке rr64. Расположение всех 64 разрядов в буфере и на-правление сдвига информации изображены на рисунке 4.36. Для того, что бы осуществить такой сдвиг, содержимое каждой из восьми ячеек буфера bufLAN поочередно вызывается в аккумуля-тор. В аккумуляторе содержимое очередной ячейки сдвигается вправо, при помощи команды rrc (сдвиг вправо через признак переноса). Затем результат сдвига записывается обратно в ту же ячейку, откуда был прочитан. Ячейка признака переноса CY используется для передачи сдвигае-мого бита из одной обрабатываемой ячейки в другую. При этом бит, из младшего разряда преды-дущей ячейки попадает в старший разряд последующей. Для того, что бы обеспечить правильную передачу битов от одной сдвигаемой ячейки в другую, нужно начинать обработку ячеек с самой последней ячейки последовательности (bufLAN+7). После завершения всей процедуры сдвига в CY оказывается самый младший бит всей последовательности (P0).
Текст подпрограммы rr64 занимает строки 19…28 (см. Листинг 4.10). Для последовательного перебора всех восьми ячеек буфера в подпрограмме организован цикл. В качестве счетчика цикла используется регистр r1. В строке 20 ему присваивается начальное значение. В качестве указателя текущей ячейки используется регистр r0. В строке 19 в него записывается адрес ячейки, с которой будет начинаться обработка.


Рис 4.36. Схема сдвига битов в буфере bufLAN

Следующие две строки содержат команды, которые помещают в CY содержимое бита P0 (см. рис. 4.35). Эта операция нужна для соблюдения условия цикличности (сдвиг по кругу). Для извле-чения содержимого разряда P0 в аккумулятор помещается содержимое самой первой ячейки бу-фера с адресом bufLAN (строка 21). Затем младший бит аккумулятора отправляется в CY. Это действие выполняется при помощи операции сдвига rrc (строка 22). После этого сразу начинает-ся цикл сдвига.
Тело цикла составляет строки 23…27. В строке 23 очередной байт извлекается из буфера. В строке 24 происходит его сдвиг на один бит вправо. В строке 25 результат помещается обратно в ячейку, откуда он был взят. В строке 26 содержимое указателя буфера уменьшается на единицу. Оператор цикла в строке 27 обеспечивает повторение цикла сдвига для всех восьми ячеек буфера. В строке 28 подпрограмма rr64 завершается.

Описанную только что программу можно немного сократить. Для этого можно использовать одно любопытное свойство алгоритма расчета контрольной суммы. Если вычислить контрольную сумму не восьми, а всех девяти ячеек буфера, то результат вычисления будет равен нулю. Но это только в том случае, если все девять байтов были считаны без ошибок. В случае любой ошибки результат будет отличен от нуля. Немного изменив программу, можно реализовать и этот новый способ проверки контрольной суммы. При этом мы экономим на операции сравнения. Новый, бо-лее оптимальный вариант подпрограммы cmpCRC приведен в Листинге 4.11. В результате такой оптимизации текст программы уменьшился на три строчки, а результирующий код подпрограммы становится короче на целых 5 байт.

Листинг 4.11.
           
    ;################################################
;##        Проверка контрольной суммы          ##
;##                Вариант 2                   ##
;################################################
           
1   cmpCRC: mov BufCRC,#0 ; Обнуление буфера КС
2     mov r2,#72 ; Инициализация счетчика сдвигов
3   cpr1: call rr72 ; Сдвиг 72 разрядов в буфере
4     jnc cpr2 ; Проверка очередного бита
5     cpl bufCRC.0 ; Если он равен единице, инвертируем
6   cpr2: mov a,bufCRC ; Читаем содержимое буфера КС
7     jnb bufCRC.0,cpr3 ; Проверка младшего бита
8     xrl a,#00011000B ; Если он равен единице делаем XOR
9   cpr3: rr a ; Сдвиг
10     mov bufCRC,a ; Помещаем назад в буфер
11     djnz r2,cpr1 ; Оператор цикла
12     jz cpr4 ; Проверка результата
13     mov a,#3 ; Если не ноль - ошибка номер три
14   cpr4:      
15     ret    
           
    ; ------------ Сдвиг 9 ячеек буфера на один бит вправо
           
16   rr72: mov r0,#bufLAN+8 ; Инициализация указателя буфера
17     mov r1,#9 ; Инициализация счетчика байтов
18     mov a,bufLAN ; Извлечение первого байта
19     rrc a ; засылка в CY младшего бита
20   rr1: mov a,@r0 ; Извлечение очередного числа
21     rrc a ; Сдвиг
22     mov @r0,a ; Запись назад
23     dec r0 ; Итерация счетчика байтов
24     djnz r1,rr1 ; Оператор цикла
25     ret