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

Разработка программного обеспечения контроллера

Важным моментом является настройка битов конфигурации контроллера, так называемые Fuse. Выбрана следующая конфигурация:

Extended fuse = 0x03 – Режим совместимости с AtMega103 отключен, WDT отключен

High Fuse Byte = 0x99 – Внутрисхемный отладчик, CKOPT, сохранение данных EEPROM при стирании, переход к загрузчику - отключены, JTAG, последовательная запись данных – включены.

Low Fuse Byte = 0xEE – BOR отключено, время запуска после сброса – по умолчанию, тактовый генератор работает от внешнего высокочастотного кварца с диапазоном 3-8 МГц.

Программу можно разбить на ряд процессов, протекающих параллельно и связанных только в нескольких ключевых точках:

  1. Измерение

  2. Передача данных (момент начала передачи привязан к готовности данных)

  3. Прием пакета и сброс флагов ошибки

  4. Тест системы (должен производиться только в то время, когда ОЗУ свободно)

Рассмотрим реализацию измерения.

Данный процесс является основным, он запускает передачу данных в нужный момент, а также запускает процесс самотестирования.

Требуется 10 раз в секунду получить данные для всех 5 каналов, причем каждый канал нужно измерить 8 раза и усреднить по этим отсчетам данные. Для этого настраивается таймер на генерацию 10*5*8 = 400 отсчетов в секунду.

По каждому отсчету таймера запускается АЦП.

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

Такой алгоритм запуска АЦП выбран для того чтобы ввести паузу между переключением внутреннего мультиплексора и измерением, необходимую для перезаряда внутренних емкостей аналоговых линий микроконтроллера.

Для получения ровно 400 отсчетов в секунду нужно разделить тактовую частоту контроллера 7372800 Гц на 400:

7372800 / 400 = 18432,

Нужно запрограммировать таймер таким образом, чтобы он генерировал прерывания каждые 18432 тактов. Можно заметить, что 16384 = 288*64, поэтому можно использовать 16-ти битный Timer0 с делителем на 64. Число 288 заносится в регистр сравнения таймера. Используются прерывания от модуля сравнения таймера, и в каждом прерывании к значению регистра сравнения прибавляется 288. Это позволяет получить точное число отсчетов в секунду, даже если прерывания не будут обрабатываться сразу после наступления события, например из-за занятости контроллера процедурой обработки другого прерывания.

При получении очередного отсчета АЦП производятся следующие действия:

- Вычисляется номер двухбайтовой ячейки в массиве adcsigma

- Считывается результат преобразования АЦП и прибавляется к выбранной ячейке

- Увеличивается номер канала (и одновременно – ячейки). Если следующий номер – 4, то происходит возврат к номеру 0. Номер канала хранится непосредственно в регистре управления мультиплексором АЦП.

- Увеличивается количество отсчетов adcnum. Если получено меньше 8 отсчетов, то процедура завершается

- Если получено 8 отсчета, то они обрабатываются следующим образом:

- Определяется позиция в массиве выходных данных на основе счетчика выходных данных arrpos.

- Каждая из 5 двухбайтовых ячеек массива adcsigma считывается, делится на 16 (на 4 – из-за усреднения, и на 4 – чтобы результат лежал в диапазоне 0..255), и записывается в массив выходных данных.

- Массив adcsigma обнуляется.

- Позиция в массиве arrpos увеличивается на 1.Если новая позиция =2400, arrpos сбрасывается.

- При значении arrpos=2399. запускается передача массива данных в порт.

Основной массив данных включает в себя 12009 байт информации. Со скоростью 38400, при параметрах передачи 8N1 передача всего пакета займет 312,7 миллисекунд. Передача одного байта занимает 0.02604мс. Рассчитаем момент начала передачи таким образом, чтобы к моменту получения последних 8 отсчетов передавать оставалось 10 байт информации (с небольшим перекрытием):

312,7 – 0.02604*10 = за 312,45 миллисекунды до завершения последнего измерения. Момент времени можно задавать при выбранном алгоритме только с точностью 0.01 секунды. Выберем момент запуска равным 240-0,312 секунды, то есть 2397 отсчет. На момент получения 2400 отсчета будет передаваться

313/ 0.02604 = 11982 байт.

Передача завершится через

(12009-11982) * 0.02604 = 27 миллисекунды после завершения измерения.

Такой сложный алгоритм запуска передачи выбран для того, чтобы провести тест внешней памяти в тот момент, когда данные в ней не используются. После завершения передачи до момента, когда алгоритм получения данных будет записывать данные во внешнее ОЗУ, останется около 61 миллисекунды на тест ОЗУ – все данные на этот момент будут переданы, а результаты нового измерения ещё будут накапливаться во внутреннем ОЗУ, в буфере adcsigma и rezbuf.

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

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

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

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

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

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

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

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

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

.include "m128def.inc"

.DSEG

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

timerdiv: .BYTE 1

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

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

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

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

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

rezbuf: .BYTE 5

; Переменные отправки данных по 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 - Передается второй байт, надо передать 0xE1, прибавить к CRC и перейти к следующему состоянию

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

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

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

; 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,0xE1

rjmp addcrcincstate

snbis3:

ldi r16,0x2E

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,0x2E

sub r1,r16

brne outsnb

ldi r16,0xDE

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/400 секунды

TimerOcr:

push r16

push r17

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

; Для этого ещё используем счетчик тактов прерывания

lds r16,timerdiv

inc r16

sts timerdiv,r16

ldi r17,0x38 ;

sub r16,r17

ldi r17,0x120 ; Прибавляемая константа

brne normalotr

; Сбрасываем счетчик

sts timerdiv,r16 ; r16 равен нулю

ldi r17,0xF5 ; Прибавляемая константа на 8 отсчетов больше

normalotr:

in r16,OCR0

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,0x05

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,0x05

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,0x05

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

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

; Умножаем номер элемента на 5, сдвигами и сложениями

mov r0,r16

mov r1,r17 ; Одно значение

rol r16

rol r17

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

add r0,r16

adc r1,r17 ; одно + удвоенное значение, т.е. *3

rol r16

rol r17

add r0,r16

adc r1,r17 ;

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

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

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

adc r31,r1

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

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

ldi r16,0x05

ldi r28,Low(rezbuf)

ldi r29,High(rezbuf)

cyclecopy1:

ld r2,Y+

st Z+,r2

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

dec r16

brne cyclecopy1

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

tocalcandwrite:

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

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

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

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

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

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

ldi r28,Low(adcsigma)

ldi r29,High(adcsigma)

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

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

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,10 ; Повторяем 10 раз

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

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

; 1200 = 0x960

ldi r29,0x04

sub r29,r16

brne notclearpos

ldi r29,0xB0

sub r29,r17

brne notclearpos

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

ldi r16,0

ldi r17,0

notclearpos:

sts arrpos,r16

sts arrpos+1,r17

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

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

; 1157 = 0x485

ldi r29,0x04

sub r29,r16

brne nilabel

ldi r29,0x85

sub r29,r17

brne nilabel

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

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,0x7F

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/400 секундных интервалов

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

out TCCR0,r16

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

out ASSR,r16

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

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

Список используемой литературы.

  1. Булычев А…Л…Галкин В. И.,Прохоренко В. А. Аналоговые интегральные схемы.

Справочник.- 2-е издание, переработанное и дополненное.- Минск: Беларусь,1993.

  1. Якубовский С.В. и др. Цифровые и аналоговые интегральные микросхемы.

Справочник.- М: Радио и связь.1989.

  1. Бродин В.Б.,Шагурин И.И. Микроконтроллеры. Архитектура, программирование,

Интерфейс.- М.:ЭКОМ,1999.

  1. Сайт фирмы Atmel- www.atmel.com.

  2. Сайт фирмы Texas Instruments- www.ti.com.

  3. Сайт фирмы Maxim Dallas Semiconductor- www.maxim-ic.com.

  4. Сайт фирмы Intel- www.intel.com.

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