;**** Реализация АЦП с двойным интегрированием с помощью T/C1***********
;*
;* Микроконтроллер AT90S8515 преобразует аналоговое входное напряжение
;* в шестнадцатеричное число.
;* Разрешение - 11 разрядов ($000..$7FF).
;* Флаг T определяет, какое напряжение измеряется: Ux0 (T=0) или Ux1 (T=1).
;*
;* Тактовая частота микроконтроллера AVR: 4 МГц (стандарт STK200)
;*  
;***************************************************************************
.nolist
.include "8515def.inc"
.list

.def  tmp1 = r16	; Рабочий регистр 1
.def  tmp2 = r17	; Рабочий регистр 2
.def  Prm1 = r18	; Передаваемый параметр 1
.def  tim1 = r19	; Счетчик цикла 1
.def  tim2 = r20	; Счетчик цикла 2
.def  Cnt  = r21	; Счетчик строк

.def	ErgL	= r22	; Рабочий регистр
.def	ErgH	= r23	; Рабочий регистр 
.def	WorkL	= r24	; Рабочий регистр 
.def	WorkH	= r25	; Рабочий регистр 

.equ  RS   = 6	; Register Select = разряд 6 порта C (A14)
.equ  Ena  = 7	; Enable Impuls = разряд 7 порта C (A15)
.equ  RW   = 6	; R/W = разряд 6 порта D (/WR)
.equ  RD   = 7	; /RD = разряд 7 порта D
.equ  BF   = 7	; Флаг занятости = разряд 7 порта A

.equ	Tx	= $1000	; 4096 тактов таймера для Tx=65,536 мс
.equ	Max	= $2000	; Макс. продолжительность интегрирования Uref-
.equ    a	= PB0	; Разряд 0 порта B, линия a на этапе S1
.equ    b	= PB1	; Разряд 1 порта B, линия b на этапе S1

Reset:
rjmp Initial	; Переход к части инициализации

.org 13	; Конец точки входа в прерывание
InitLCD:
rcall wait5ms
rcall wait5ms
rcall wait5ms	; Задержка на 15 мс после подачи питания
ldi   prm1,$30	; $30: установка функции, 8 разрядов
rcall SendCom	; Отправка команды на ЖК-модуль
rcall wait5ms	; Задержка на 5 мс
ldi   prm1,$30	; $30: установка функции, 8 разрядов
rcall SendCom	; Повторяем команду
rcall wait5ms	; Задержка на 5 мс
ldi   prm1,$30	; $30: установка функции, 8 разрядов
rcall SendCom	; Повторяем команду
rcall wait5ms	; Задержка на 5 мс
rcall WaitBusy	; Ожидаем готовности ЖК-модуля к приему
ldi   prm1,$38	; $38: функция = 8 разрядов, 2 строки, 5x8
rcall SendCom	; Отправляем команду
rcall wait150us	; Задержка на 150 мкс
rcall WaitBusy	; Ожидаем готовности ЖК-модуля к приему
ldi   prm1,$08	; $08: отключение табло, курсора, мерцания
rcall SendCom	; Передаем команду
rcall wait150us	; Задержка на 150 мкс
rcall WaitBusy	; Ожидаем готовности ЖК-модуля к приему
ldi   prm1,$01	; $01: очистка табло
rcall SendCom	; Передаем команду
rcall wait5ms	; Задержка на 5 мс
rcall WaitBusy	; Ожидаем готовности ЖК-модуля к приему
ldi   prm1,$06	; $06: режим инкремента адреса, без сдвига
rcall SendCom	; Передаем команду
rcall wait150us	; Задержка на 150 мкс
ret

SendCom:	; Передача в ЖК-модуль команды
cbi   PortC,RS	; Register Select = команда
rcall Ausgabe
ret

SendDat:	; Передача в ЖК-модуль байта данных
sbi   PortC,RS	; Register Select = байт данных
rcall Ausgabe
ret

Ausgabe:	; Длина данных = 8 бит
out   PortA,prm1	; Выдача команды/данных на порт A
sbi   PortC,Ena	; Подаем импульс разрешения
nop
nop	; Длительность импульса – минимум 450 нс
cbi   PortC,Ena	; Снимаем импульс разрешения
ret

OutText:	; Вывод символа <cnt> на табло
lsl   ZL
rol   ZH	; Указатель Z – на 1 позицию влево
OT1:
lpm	; Загружаем код символа в r0
mov   prm1,r0	; Копируем код символа в prm1
rcall WaitBusy	; Ожидаем готовности ЖК-модуля к приему
rcall SendDat	; Передаем символ, автоинкремент адреса
adiw  ZL,1	; Инкрементируем указатель Z
dec   cnt	; Счетчик – 1
brne  OT1	; Выводим все символы на ЖК-табло
ret

WaitBusy:	; Ожидание готовности ЖК-модуля к приему
clr   tmp1
out   DDRA,tmp1	; Порт A = вход
cbi   PortC,RS	; Register Select = команда
sbi   PortD,RW	; Направление = чтение из ЖК-модуля
WB1:
sbi   PortC,Ena	; Подаем импульс разрешения
nop
nop	; После макс. 320 нс стабильности данных
in    tmp1,PinA	; считываем BF и значение счетчика адреса
cbi   PortC,Ena	; Снимаем импульс разрешения
nop
sbrc  tmp1,BF	; Пропускаем следующую команду, если ЖК-модуль готов (BF=0)
rjmp  WB1
cbi   PortD,RW	; Направление записи = в ЖК-модуль
ser   tmp1
out   DDRA,tmp1	; Порт A = выход
ret

HexAscii:	; Преобразование шестнадцатеричного в Ascii
cpi   prm1,$0A	; Больше 9 ?
brsh  HA1	; Переход, если > 9
subi  prm1,-$30	; Прибавляем $30
ret
HA1:
subi  prm1,-$37	; Прибавляем $37
ret

SetAdr:	; Установка адреса индикатора для Ux
brts  Ux1	; Переход, если флаг T = 1 (Ux1)
ldi   prm1,64+1	; Адрес = 2-й символ 2-й строки
sbr   prm1,1<<7	; Устанавливаем разряд 7 -> строка DD-RAM
rcall WaitBusy	; Ожидаем готовности ЖК-модуля к приему
rcall SendCom	; Устанавливаем указатель адреса в DD-RAM
ret
Ux1:	; Измеряемое значение Ux1
ldi   prm1,64+9	; Адрес = 10-й символ 2-й строки
sbr   prm1,1<<7	; Устанавливаем разряд 7 -> строка DD-RAM
rcall WaitBusy	; Ожидаем готовности ЖК-модуля к приему
rcall SendCom	; Устанавливаем указатель адреса в DD-RAM
ret

DispErg:	; Вывод результата на табло
mov   prm1,ErgH	; Старший байт результата
rcall HexAscii	; Шестнадцатеричное значение в младшем полубайте -> Ascii
rcall WaitBusy	; Ожидаем готовности ЖК-модуля к приему
rcall SendDat	; Передаем символ, автоинкремент адреса
mov   prm1,ErgL	; Младший байт результата
swap  prm1	; Меняем местами старш. и млад. полубайты
andi  prm1,$0F	; Обнуляем старший полубайт
rcall HexAscii	; Шестнадцатеричное значение в младшем полубайте -> Ascii
rcall WaitBusy	; Ожидаем готовности ЖК-модуля к приему
rcall SendDat	; Передаем символ, автоинкремент адреса
mov   prm1,ErgL	; Младший байт результата
andi  prm1,$0F	; Обнуляем старший полубайт
rcall HexAscii	; Шестнадцатеричное значение в младшем полубайте -> Ascii
rcall WaitBusy	; Ожидаем готовности ЖК-модуля к приему
rcall SendDat	; Передаем символ, автоинкремент адреса
ret

DispOFL:	; Выдача сообщения о переполнении
ldi   prm1,'O'	; 
rcall WaitBusy	; Ожидаем готовности ЖК-модуля к приему
rcall SendDat	; Передаем символ, автоинкремент адреса
ldi   prm1,'F'	; 
rcall WaitBusy	; Ожидаем готовности ЖК-модуля к приему
rcall SendDat	; Передаем символ, автоинкремент адреса
ldi   prm1,'L'	; "OFL" = "OverFLow" (переполнение)
rcall WaitBusy	; Ожидаем готовности ЖК-модуля к приему
rcall SendDat	; Передаем символ, автоинкремент адреса
ret

Wait50us:	; Такт системной синхронизации = 4 МГц
ldi   tim1,65	; Загрузка счетчика
Wait51:
dec   tim1
brne  Wait51
ret

Wait150us:	; Такт системной синхронизации = 4 МГц
rcall wait50us
rcall wait50us
rcall wait50us
ret

Wait5ms:	; Такт системной синхронизации = 4 МГц
ldi   tim2,100	; Загрузка счетчика
Wait501:
rcall wait50us
dec   tim2
brne  Wait501
ret

Wait38ms:	; Такт системной синхронизации = 4 МГц
ldi   tim2,0	; Загрузка счетчика
Wait381:
rcall wait150us
dec   tim2
brne  Wait381
ret

Wait5s:	; Такт системной синхронизации = 4 МГц
ldi   cnt,130	; Загрузка счетчика
Wait5s1:
rcall wait38ms
dec   cnt
brne  Wait5s1
ret

Initial:	; Инициализация регистров ввода/вывода
ldi   WorkH,High(RamEnd)
out   sph,WorkH
ldi   WorkH,Low(RamEnd)
out   spl,WorkH	; Инициализация стека
ldi   tmp1,$3F	; Разряды 7..6 = 0, остальные = 1
out   PortD,tmp1	; /RD,/WR = 0, ост. разряды порта D = 1
out   PortC,tmp1	; Ena, RS = 0, ост. разряды порта C = 1
ldi   tmp1,$C0	; Разряд 7 = 1, разряд 6 = 1
out   DDRD,tmp1	; Разряды 7..6 - выходы, остальные - входы
out   DDRC,tmp1	; Разряды 7..6 - выходы, остальные - входы
ser   tmp1	; Инициализация tmp1
out   DDRA,tmp1	; Порт A - выход
ldi   WorkH,$02	; b (разряд 1) - в 1, остальные – в 0
out   PortB,WorkH	; Выбираем Uref-
ldi   WorkH,$03	; Разряды 0..1,4..7 - в 1, остальные – в 0
out   DDRB,WorkH	; b (PB1) и a (PB0) - выход
ldi   WorkH,$00	; Захват по ниспадающему фронту на входе ICP
out   ACSR,WorkH	; Регистр управления компаратора
rcall InitLCD	; Инициализируем 8-разрядный ЖК-модуль
ldi   prm1,$0C	; Табло – вкл., курсор, мерцание – откл.
rcall WaitBusy	; Ожидаем готовности ЖК-модуля к приему
rcall SendCom	; Передаем команду
ldi   prm1,$01	; Гасим табло, курсор – в начало
rcall WaitBusy	; Ожидаем готовности ЖК-модуля к приему
rcall SendCom	; Передаем команду
ldi   ZH,high(Text1)
ldi   ZL,low(Text1)	; Указатель Z указывает на начало текста
ldi   cnt,16	; Текст – из 16-ти символов
rcall OutText	; Выводим Text1
ldi   prm1,64	; Адрес = начало второй строки
sbr   Prm1,1<<7	; Устанавливаем разряд 7 -> строка DD-RAM
rcall WaitBusy	; Ожидаем готовности ЖК-модуля к приему
rcall SendCom	; Устанавливаем указатель адреса в DD-RAM
ldi   ZH,high(Text2)
ldi   ZL,low(Text2)	; Указатель Z указывает на начало текста
ldi   cnt,16	; Текст – из 16-ти символов
rcall OutText	; Выводим Text2

Messung:
ldi  WorkH,high(-Tx)	; Старший байт времени интегрирования Tx - 
out  TCNT1H,WorkH	;   в счетный регистр
ldi  WorkL,low(-Tx)	; Младший байт времени интегрирования Tx - 
out  TCNT1L,WorkL	;   в счетный регистр
Schritt1:	; Установка нулевой точки интегрирования
sbi  PortB,b	; b = 1
sbic PinB,PB2	; Пропускаем следующую команду, если Ui < 0
rjmp S12	; Переход, если Ui > 0
cbi  PortB,a	; a = 0 -> выбираем Uref- 
S11:
sbis PinB,PB2	; Пропускаем следующую команду, если Ui > 0
rjmp S11
rjmp Schritt2	; Достигаем нулевой точки
S12:
sbi  PortB,a	; a = 1 -> выбираем Uref+
S13:
sbic PinB,PB2	; Пропускаем следующую команду, если Ui < 0
rjmp S13
Schritt2:	; Начало Tx при интегрировании Ux
in   WorkH,PortB
bld  WorkH,a	; T-Flag -> a (Ux0 или Ux1)
cbr  WorkH,1<<b	; b = 0
out  PortB,WorkH	; Переключаем Ux0 или Ux1 
ldi  WorkH,$03	; ICNC1=0, ICES1=1, CTC1=0
out  TCCR1B,WorkH	;Запускаем T/C1, такт сист. синхр. /64
S21:
in   WorkL,TCNT1L	; Альтернатива для OCR1A-Int.
in   WorkH,TCNT1H	; Считываем содержимое счетчика
subi WorkL,$FF	; Ожидаем, когда счетчик перейдет 
sbci WorkH,$FF	;   в состояние $FFFF
brlo S21	; Переход, если еще не достигнуто
in   WorkH,PortB	; Готовим подклчюение Uref-
cbr  WorkH,1<<a	; a = 0,
sbr  WorkH,1<<b	;   b = 1 -> выбрано Uref-
S22:
in   WorkL,TIFR	; Извлекаем флаги T/C1
sbrs WorkL,TOV1	; Пропускаем следующую команду, если переполнение в $0000
rjmp S22	; Переход, если Tx еще не завершено
Schritt3:	; Определение TR при интегрировании Uref-
out  PortB,WorkH	; Подано Uref-
sbr  WorkL,1<<TOV1 | 1<<ICF1	; ICF1,TOV1 = 1
out  TIFR,WorkL	; Сбрасываем ICF1 и TOV1
WaitCapt:	; Ожидание захвата
in   WorkL,TIFR	; Извлекаем флаги T/C1
sbrs WorkL,ICF1	; Пропускаем следующую команду, если имеет место захват
rjmp CheckOFL	; Переполнение счетчика?
MessEnde:
in   ErgL,ICR1L	; Результат – из регистра захвата
in   ErgH,ICR1H	;   
WaitTime:	; Ожидание окончания измерения
in   WorkL,TCNT1L	; 
in   WorkH,TCNT1H	; Считываем содержимое счетчика
subi WorkL,low(Max)	; Достигнуто ли 
sbci WorkH,high(Max)	;   максимальное состояние счетчика?
brlo WaitTime	; Переход, если еще нет
lsr  ErgH
ror  ErgL
lsr  ErgH
ror  ErgL	; Делим результат на 4
Display:
rcall SetAdr	; Установка адреса индикатора для Ux
sbrc  ErgH,3	; Если разряд 11 = 0, то нет переполнения
rjmp  OFlow	; Переход, если переполнение
rcall DispErg	; Выводим результат на табло
rjmp  Next
OFlow:
rcall DispOFL	; Выводим сообщение о переполнении
rjmp  Next

CheckOFL:
in    WorkL,TCNT1L	; 
in    WorkH,TCNT1H	; Считываем содержимое счетчика
subi  WorkL,low(Max)	; Превышено ли
sbci  WorkH,high(Max)	;   максимальное состояние счетчика?
brlo  WaitCapt	; Переход, если еще нет
rcall SetAdr	; Установка адреса индикатора для Ux
rjmp  OFlow	; Возникло переполнение

Next:
ldi  WorkH,$00	; ICNC1=0, ICES1=1, CTC1=0
out  TCCR1B,WorkH	; Останавливаем T/C1
brts N1	; Переход, если флаг T=1
set	; Устанавливаем флаг T -> Ux1
rjmp Messung	; Следующее измерение
N1:
clt	; Сбрасываем флаг T -> Ux0
rjmp Messung	; Следующее измерение


.org  $400
Text1:
.db   "Ux0:    Ux1:    "
Text2:
.db   "$---    $---    "

