Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Скачиваний:
24
Добавлен:
20.06.2014
Размер:
920.58 Кб
Скачать

5 Тестирование программы

Тестирование системы заключается в проверке работы внешнего ОЗУ как наиболее сложной части системы. Тестирование осуществляется заполнением ОЗУ данными с определенным значением, затем проверкой и изменением данных на инверсное значение и повторной проверкой. Это позволяет проверить наличие «битых» ячеек, имеющих всегда нулевое или единичное значение, а также шину данных ОЗУ. Проверка шины адреса ОЗУ осуществляется при повторной проверке после изменения значения – если на одну ячейку ссылаются два адреса, то после изменения значения по первому адресу изменится и значение по второму адресу, и вторая проверка даст ошибку в этом месте. В качестве данных записывается некоторое значение, получаемое путем прибавления к начальному значению (нулю) числа 3, т.е. записывается 0,3,6,9,… и т.д.

Так как во внешнем ОЗУ используется только 14400 значений, проверка проводится только по 16384 первым значениям. Это позволяет использовать ОЗУ объемом 16К вместо установленных 32К.

Прием пакета осуществляется в прерывании, состояние которого задается байтом rsrdpos. Возможно несколько состояний – ожидание начала приема (прием байта 0xАА), продолжение – прием байта 00, далее прием двух байтов и их сравнение. Если принят байт, не соответствующий ожидаемому, происходит возврат в состояние ожидания байта 0xАА. В противном случае если оба принятых байта совпали – сбрасываются соответствующие биты порта B.

Проводилось частичное тестирование программы на эмуляторе. На эмуляторе проверялось время теста ОЗУ при командах перехода, замененных на nop – 58.5 мс.

Проведенный тест говорит о том, что время тестирования ОЗУ не превышает заданного значения – 61 мс, и что частота опроса АЦП совпадает с расчетной. Также проверена логика переключения каналов АЦП и записи в ОЗУ. Работа с портом RS232 не тестировалась в связи со сложностью его эмуляции, а также невозможностью эмуляции внешнего ОЗУ и как следствие – отсутствия передаваемых данных.

6 Алгоритм программного продукта

Алгоритм основной программы:

Рисунок 4

Алгоритм обработчика прерывания от модуля сравнения таймера

Рисунок 5

Алгоритм обработчика прерывания от АЦП

4

8

4

4

F0

4

4

4

4

4

4

3600

3489

Рисунок 6

Алгоритм обработчика прерывания от приемника UART

Рисунок 7

Алгоритм обработчика прерывания от освобождения буфера передатчика UART

Рисунок 8

7 Листинг программы

.include "m128def.inc"

.DSEG

;Делитель для выравнивания частоты отсчетов АЦП

timerdiv: .BYTE 1

; Переменные получения данных с АЦП

adcsigma: .BYTE 8 ; 4 двухбайтовых сумм для усреднения результата

adcnum: .BYTE 1 ; Счетчик полученных измерений

arrpos: .BYTE 2 ; Позиция в буфере результата

; Буфер для хранения четных данных

rezbuf: .BYTE 4

; Переменные отправки данных по RS232

rsstate: .BYTE 1 ; Состояние алгоритма передачи

rspos: .BYTE 2 ; Положение передаваемого байта в буфере

rscrc: .BYTE 1 ; Контрольная сумма

; Переменные получения блока по RS232

rsrdpos: .BYTE 1 ; Состояние алгоритма приема пакета

rsbyte: .BYTE 1 ; Принятый байт

; Переменные процедуры тестирования внешнего ОЗУ

chkcnt: .BYTE 1 ; Счетчик блоков до повторного теста

work: .BYTE 1 ; устанавливается в не ноль при необходимости тестирования

; Сегмент кода векторов прерываний - 35 векторов. Используются только

; команды jmp, так как они занимают ровно столько места, сколько выделено

; под каждый вектор, и нет нужды задавать в явном виде адреса векторов.

.CSEG

.org 0x0

jmp main ; 1

jmp toreti ; 2

jmp toreti ; 3

jmp toreti ; 4

jmp toreti ; 5

jmp toreti ; 6

jmp toreti ; 7

jmp toreti ; 8

jmp toreti ; 9

jmp toreti ; 10

jmp toreti ; 11

jmp toreti ; 12

jmp toreti ; 13

jmp toreti ; 14

jmp toreti ; 15

jmp TimerOcr ; 16

jmp toreti ; 17

jmp toreti ; 18

jmp GetNextByte ; 19

jmp SendNextByte; 20

jmp toreti ; 21

jmp ADCgetrez ; 22

jmp toreti ; 23

jmp toreti ; 24

jmp toreti ; 25

jmp toreti ; 26

jmp toreti ; 27

jmp toreti ; 28

jmp toreti ; 29

jmp toreti ; 30

jmp toreti ; 31

jmp toreti ; 32

jmp toreti ; 33

jmp toreti ; 34

jmp toreti ; 35

; Мой сегмент кода

.CSEG

; "Пустая" процедура прерывания для неинициализированных векторов

toreti:

reti

;================================================

; Процедура, вызываемая при получении очередного байта

; Состояния приемника - rsrdpos

; 0 - получаем очередной байт, проверяем на 0xAA

; 1 - получаем очередной байт, проверяем на 00

; 2 - получаем и сохраняем

; 3 - получаем, проверяем с сохраненным. Если совпадает - меняем состояния флагов

; При сбое в любом состоянии (кроме 2 - в нём сбиваться нечему) возвращаемся к нулевому состоянию

GetNextByte:

push r16

push r17

push r18

lds r16,UDR0 ; Получаем принятый байт

lds r17,rsrdpos

; Выбираем куда переходить

ldi r18,1

sub r18,r17

breq rdst1

ldi r18,2

sub r18,r17

breq rdst2

ldi r18,3

sub r18,r17

breq rdst3

; Сюда - при нулевом либо ошибочном состоянии

ldi r17,0xAA

sub r16,r17

breq setst1

resetreader:

; Сбрасываем состояние

ldi r17,0

sts rsrdpos,r17

rjmp exitgnb

setst1:

ldi r17,1

sts rsrdpos,r17

rjmp exitgnb

rdst1:

ldi r17,0x00

sub r16,r17

brne resetreader

ldi r17,2

sts rsrdpos,r17

rjmp exitgnb

rdst2:

sts rsbyte,r17

ldi r17,3

sts rsrdpos,r17

rjmp exitgnb

rdst3:

lds r17,rsbyte

sub r17,r16

brne resetreader

; Применяем байт

in r17,PORTB

com r16

ori r16,0xC0

and r17,r16

out PORTB,r17

rjmp resetreader ; Возвращаемся к ожиданию байта

exitgnb:

pop r18

pop r17

pop r16

reti

;================================================

; Процедура, вызываемая при опустошении буфера передачи

; Вход - SendNextByte

; Внутренности процедуры - чтобы хватало длины отноительного перехода

snbis6:

lds r16,rscrc

out UDR0,r16

cbi UCSR0A,5 ; Запрещаем прерывание от освобождения буфера передачи

ldi r16,0

sts rsstate,r16 ; Сбрасываем в ноль

rjmp outsnb

snbis20:

snbis40:

ldi r16,0

out UDR0,r16

rjmp snbincstate

snbis21:

ldi r16,0xAA

out UDR0,r16

rjmp snbincstate

snbis22:

ldi r16,0xAA

out UDR0,r16

cbi UCSR0A,5 ; Запрещаем прерывание от освобождения буфера передачи

ldi r16,0

sts rsstate,r16 ; Сбрасываем в ноль

rjmp outsnb

snbis41:

ldi r16,0xFF

out UDR0,r16

rjmp snbincstate

snbis42:

ldi r16,0xFF

out UDR0,r16

cbi UCSR0A,5 ; Запрещаем прерывание от освобождения буфера передачи

ldi r16,0

sts rsstate,r16 ; Сбрасываем в ноль

rjmp outsnb

SendNextByte:

push r0

push r16

push r17

push r28

push r29

; Обработка - в зависимости от состояния

; Состояния могут быть:

; любой байт, не состоящий в списке - ничего не делаем, прерывания запрещаются. В это состояние процедура даже попадать не должна

; 1 - Передается первый байт, надо передать 0x00 и перейти к следующему состоянию

; 2 - Передается второй байт, надо передать 0x41, прибавить к CRC и перейти к следующему состоянию

; 3 - Передается третий байт, надо передать 0x38, прибавить к CRC и перейти к следующему состоянию

; 4 - Передается четвертый байт, надо передать байт флагов переполнения, прибавить к CRC и перейти к следующему состоянию

; 5 - Передается основной пакет. Надо передавать очередной байт, прибавлять к CRC пока не будет передано 14400 байтов. Затем перейти к следующему состоянию и разрешить проверку ОЗУ.

; 6 - Надо передать CRC и запретить прерывания - больше передавать нечего

; Передача пакета "тест успешен"

; 20 - Передаем 00, переходим к следующему

; 21 - Передаем AA

; 22 - Передаем AA и останавливаем передачу

; Передача пакета "тест не пройден"

; 40 - Передаем 00, переходим к следующему

; 41 - Передаем FF

; 42 - Передаем FF и останавливаем передачу

lds r0,rsstate

ldi r16,1

sub r16,r0

breq snbis1

ldi r16,2

sub r16,r0

breq snbis2

ldi r16,3

sub r16,r0

breq snbis3

ldi r16,4

sub r16,r0

breq snbis4

ldi r16,5

sub r16,r0

breq snbis5

ldi r16,6

sub r16,r0

breq snbis6

ldi r16,20

sub r16,r0

breq snbis20

ldi r16,21

sub r16,r0

breq snbis21

ldi r16,22

sub r16,r0

breq snbis22

ldi r16,40

sub r16,r0

breq snbis40

ldi r16,41

sub r16,r0

breq snbis41

ldi r16,42

sub r16,r0

breq snbis42

; Данного варианта нет в списке - запрещаем прерывания

cbi UCSR0A,5 ; Запрещаем прерывание от освобождения буфера передачи

ldi r16,0

sts rsstate,r16 ; На всякий случай сбрасываем в ноль

rjmp outsnb

snbis1:

ldi r16,0

out UDR0,r16

rjmp snbincstate

snbis2:

ldi r16,0x41

rjmp addcrcincstate

snbis3:

ldi r16,0x38

rjmp addcrcincstate

snbis4:

in r16,PORTB

andi r16,0x3F

rjmp addcrcincstate

snbis5:

; Тут получаем очередной байт из буфера

lds r0,rspos

lds r1,rspos+1

ldi r28,0 ; Прибавляем начальный адрес в памяти

ldi r29,0x80

add r28,r0

adc r29,r1

ld r16,Y ; Считываем

; Запускаем на передачу, добавляем к CRC

out UDR0,r16

lds r0,rscrc

add r0,r16

sts rscrc,r0

; Прибавляем 1 к счетчику байтов

ldi r16,1

ldi r17,0

add r16,r0

adc r17,r1

sts rspos,r0

sts rspos+1,r1

; Проверяем, не завершена ли передача пакета?

ldi r16,0x38

sub r1,r16

brne outsnb

ldi r16,0x40

sub r0,r16

brne outsnb

; Всё передано - проверяем, не запустить ли тест системы

lds r16,chkcnt

inc r16

sts chkcnt,r16

subi r16,0x0A

brne snbincstate ; Переходим к передаче CRC

; Выставляем флаг разрешения теста ОЗУ

ldi r16,0xFF

sts work,r16

; переходим к передаче CRC

rjmp snbincstate

; Выдаем в порт r16 и добавляем его к CRC

addcrcincstate:

out UDR0,r16

lds r0,rscrc

add r0,r16

sts rscrc,r0

; Переходим к следующему состоянию

snbincstate:

lds r0,rsstate

inc r0

sts rsstate,r0

outsnb:

pop r29

pop r28

pop r17

pop r16

pop r0

reti

;================================================

; Процедура, вызываемая каждые 1/480 секунды

TimerOcr:

push r16

push r17

; Корректируем значение регистра сравнения

in r16,OCR0

ldi r17,0xF0

add r16,r17

out OCR0,r16

; Запускаем АЦП

sbi ADCSR,6

;

pop r17

pop r16

reti

;================================================

; Процедура, вызываемая при завершении измерения АЦП

ADCgetrez:

push r0

push r1

push r2

push r3

push r16

push r17

push r20

push r28

push r29

push r30

push r31

; Получаем результат и прибавляем его к соответствующей сумме

;

; Рассчитываем адрес в массиве сумм

in r16,ADMUX

andi r16,0x07

add r16,r16

ldi r30,Low(adcsigma)

ldi r31,High(adcsigma)

ldi r17,0

add r30,r16

adc r31,r17

; Считываем предыдущую сумму

ld r0,Z

ldd r1,Z+1

; Прибавляем результат АЦП

in r16,ADCL

in r17,ADCH

add r0,r16

adc r1,r17

; Сравниваем с порогами - 0 и 1023.

mov r2,r16

or r2,r17

breq toalarm ; Если ноль - переполнение

; Прибавляем единицу

clr r2

clr r3

inc r2

add r2,r16

adc r3,r17

ldi r16,0x04 ; Если прибавили единицу и получилось 1024 (0x400) - тоже переполнение

sub r16,r17

brne tonoalarm

toalarm:

; Фиксируем переполнение данного канала

in r16,ADMUX

andi r16,0x07

ldi r17,1

; Рассчитываем, какой бит установить, для этого сдвигаем единицу

; влево столько раз, каков номер канала

calcbitcycle:

or r16,r16

breq tosetled

rol r17

dec r16

rjmp calcbitcycle

tosetled:

; Устанавливаем соответствующий бит регистра PORTB

in r16,PORTB

or r16,r17

out PORTB,r16

tonoalarm:

; Записываем новую сумму

st Z,r0

std Z+1,r1

; Переходим к следующему каналу

in r16,ADMUX

inc r16

out ADMUX,r16

mov r17,r16

andi r17,0x07

subi r17,0x04 ; Количество каналов

breq tocheck8

jmp nilabel

tocheck8:

; Все четыре канала получены - возвращаемся к нулевому каналу

andi r16,0xF0

out ADMUX,r16

; Прибавляем счетчик измерений

lds r16,adcnum

inc r16

andi r16,3 ; От этого зависит число усреднений

sts adcnum,r16

; Проверяем - если 0, то нужно усреднять и сохранять. Все 4 получены.

breq tousedata

jmp nilabel

tousedata:

; Да - обрабатываем результаты

;

; Рассчитываем адрес в массиве данных

lds r16,arrpos

lds r17,arrpos+1

; Выбираем, записываем во внешнее ОЗУ или в промежуточный буфер

sbrc r16,0

rjmp realwrite

; Сброшен - т.е. четный номер. Записываем в промежуточный буфер

ldi r30,Low(rezbuf)

ldi r31,High(rezbuf)

rjmp tocalcandwrite

realwrite:

andi r16,0xFE

; Умножаем номер элемента на 4 при помощи сдвигов влево

rol r16

rol r17

andi r16,0xfe ; Сбрасываем младший бит. r16/r17 теперь умножены на два

rol r16

rol r17

andi r16,0xfe ; Сбрасываем младший бит. r16/r17 теперь умножены на четыре

mov r0,r16 ; получаем r*4

mov r1,r17

;

lds r30,0 ; Массив находится во внешнем ОЗУ

lds r31,0x80 ; Всегда по фиксированному адресу

add r30,r0 ; Прибавляем

adc r31,r1

; Теперь Z ссылается на первую ячейку, в которую надо записать результат

; Записываем промежуточный буфер

ldi r16,0x04

ldi r28,Low(rezbuf)

ldi r29,High(rezbuf)

cyclecopy1:

ld r2,Y+

st Z+,r2

; Повторяем r16 раз

dec r16

brne cyclecopy1

; На выходе - адрес в Z уже указывает на нужное место в ОЗУ

tocalcandwrite:

; Для каждой двухбайтовой ячейки массива adcsigma производим следующие действия:

; - Считываем оба байта

; - Делим на 4 - находим среднее значение

; - Делим на 4 - чтобы результат был от 0 до 255

; - Сохраняем в массив результатов только один байт

; Деление на 4*4=16 - это сдвиг на 4 бита вправо.

ldi r28,Low(adcsigma)

ldi r29,High(adcsigma)

ldi r16,0x80 ; Для перевода в дополнительный код

ldi r20,4 ; Повторяем 4 раза

cycle1:

ld r2,Y+

ld r3,Y+

ror r3

ror r2

ror r3

ror r2

ror r3

ror r2

ror r3

ror r2

; Теперь в r2 получились данные, в которых "0" соответствует числу 0x80, а "+U" - 255.

; Нужно перевести результат в дополнительный код вычитанием из числа 0x80

sub r2,r16

st Z+,r2

; Повторяем r4 раз

dec r20

brne cycle1

; Скопировали. Стираем массив adcsigma

ldi r28,Low(adcsigma)

ldi r29,High(adcsigma)

ldi r20,4 ; Повторяем 8 раз

clr r2

cycle2:

st Y+,r2

dec r20

brne cycle2

; === Переходим к следующему отсчету

lds r16,arrpos

lds r17,arrpos+1

ldi r28,1

ldi r29,0

add r16,r28

adc r17,r29

; Сравниваем с 3600 - если уже равно, надо сбрасывать счетчик в ноль

; 3600 = 0xE10

ldi r29,0x0E

sub r29,r16

brne notclearpos

ldi r29,0x10

sub r29,r17

brne notclearpos

; Сбрасываем указатель в ноль

ldi r16,0

ldi r17,0

notclearpos:

sts arrpos,r16

sts arrpos+1,r17

; Отсчет увеличили

; === Тут проверяем, не запустить ли передачу данных?

; 3489 = 0xDA1

ldi r29,0x0D

sub r29,r16

brne nilabel

ldi r29,0xA1

sub r29,r17

brne nilabel

; Да. Запускаем передачу - получен 3489-й отсчет

ldi r16,0x00

sts rscrc,r16 ; Сбрасываем контрольную сумму

; Заносим нулевую позицию в буфере

sts rspos,r16

sts rspos+1,r16

ldi r16,0x01

sts rsstate,r16 ; Переходим в состояние "1" процедуры отправки пакета в порт

sbi UCSR0A,5 ; Разрешаем прерывание от освобождения буфера передачи

ldi r16,0x55

out UDR0,r16 ; Начинаем передавать первый байт пакета. После того как байт начнет передаваться, произойдет прерывание от опустошения буфера

; Передача начата. Дальнейшее сделает процедура обработки буфера передачи

nilabel:

pop r31

pop r30

pop r29

pop r28

pop r20

pop r17

pop r16

pop r3

pop r2

pop r1

pop r0

reti

;================================================

; Основная программа

main:

; Конфигурируем стек

ldi r16,0

out SPL,r16

ldi r16,0x10

out SPH,r16

; Конфигурируем порты

ldi r16,0

out DDRA,r16

out DDRC,r16

out DDRE,r16

sts DDRF+0x20,r16

ldi r16,0x0F

out DDRB,r16

ldi r16,0x40

out DDRD,r16

ldi r16,0

out PORTB,r16

out PORTD,r16

; Конфигурируем ОЗУ - будем использовать диапазон 0x8000-0xFFFF

in r16,MCUCR

ori r16,0x80

out MCUCR,r16

ldi r16,0x00 ; ОЗУ работает с минимальными задержками по всем адресам

sts XMCRA+0x20,r16

ldi r16,0x80 ; Полный диапазон адресов, Bus keeper включен

sts XMCRB+0x20,r16

; Конфигурируем UART, скорость 38400, прерывания на прием сразу разрешены

ldi r16,0x20

out UCSR0A,r16 ; Удвоения скорости нет

ldi r16,0x98

out UCSR0B,r16 ; Разрешены прерывания от приема байта, включен приемник и передатчик, 8 бит данных

ldi r16,0x06

sts UCSR0C+0x20,r16 ; Асинхронный режим, 1 стопбит, 8 бит данных

ldi r16,0x00

sts UBRR0H+0x20,r16

ldi r16,11

out UBRR0L,r16 ; Скорость - 38400. Константа взята из datasheet на контроллер

; Конфигурируем таймер0 на генерацию 1/480 секундных интервалов

ldi r16,0x04 ; Входы и выходы таймера не используются, делитель на 64

out TCCR0,r16

ldi r16,0x00 ; Синхронизация от внутренней частоты

out ASSR,r16

ldi r16,0xF0 ; 240 - делитель для получения нужного периода

out OCR0,r16

in r16,TIMSK

ori r16,0x02

out TIMSK,r16

; Конфигурируем АЦП

ldi r16,0xC0 ; Внутренний 2.56В источник опорного напряжения, правое выравниваение результата, канал 0

out ADMUX,r16

ldi r16,0x8E ; АЦП разрешен, делитель на 64, прерывания от АЦП разрешены, измерение выключено

out ADCSR,r16

; Устанавливаем начальные значения переменных

ldi r16,0xFF

sts work,r16 ; Начинаем с теста ОЗУ

ldi r16,0

sts adcsigma,r16

sts adcsigma+1,r16

sts adcsigma+2,r16

sts adcsigma+3,r16

sts adcsigma+4,r16

sts adcsigma+5,r16

sts adcsigma+6,r16

sts adcsigma+7,r16

sts adcsigma+8,r16

sts adcsigma+9,r16

sts adcsigma+10,r16

sts adcsigma+11,r16

sts adcsigma+12,r16

sts adcsigma+13,r16 ; Сумм нету

sts adcnum,r16 ;

sts arrpos,r16 ; Позиция - нулевая

sts arrpos+1,r16 ;

sts rsstate,r16 ; Ничего не передается

sts timerdiv,r16

; Основной цикл программы

sei ; Разрешаем прерывания

maincycle:

ldi r16,work

or r16,r16

breq maincycle

; Сбрасываем флаг

ldi r16,0

sts work,r16

; Здесь - процедура теста ОЗУ

ldi r30,0

ldi r31,0x80

ldi r16,0

ldi r17,3

; Заполнение

wr1clk:

st Z+,r16

add r16,r17

sbrs r31,6

rjmp wr1clk

; Проверка прямого значения и заполнение инверсным

ldi r30,0

ldi r31,0x80

ldi r16,0

ldi r17,3

wr2clk:

ld r18,Z

com r18

st Z+,r18

sub r18,r16

nop ; brne chkerr

add r16,r17

sbrs r31,6

rjmp wr2clk

; Проверка инверсного значения

ldi r30,0

ldi r31,0x80

ldi r16,0

ldi r17,3

wr3clk:

ld r18,Z+

com r18

sub r18,r16

nop ; brne chkerr

add r16,r17

sbrs r31,6

rjmp wr3clk

; Проверка прошла успешно

; Отключаем светодиод "ошибка"

in r16,PORTD

andi r16,0xBF

out PORTD,r16

; Переходим к состоянию "передача блока удачной проверки"

ldi r16,20

jmp startpkg

chkerr:

; Проверка завершилась ошибкой

; Включаем светодиод "ошибка"

in r16,PORTD

ori r16,0x40

out PORTD,r16

; Переходим к состоянию "передача блока ошибки проверки"

ldi r16,40

startpkg: ; Запуск передачи блока

cli ; Запрещаем прерывания - дальше идет блок, работающий с теми же данными, что и процедуры прерывания

sts rsstate,r16 ; Переходим в состояние "1" процедуры отправки пакета в порт

sbi UCSR0A,5 ; Разрешаем прерывание от освобождения буфера передачи

ldi r16,0xA5

out UDR0,r16 ; Начинаем передавать первый байт пакета. После того как байт начнет передаваться, произойдет прерывание от опустошения буфера

sei ; Разрешаем прерывания

ldi r16,0 ;

sts chkcnt,r16 ; Блоки считаем с нуля - повторный тест через 10 блоков

jmp maincycle

Соседние файлы в папке Материалы