; программа для макетки на Мега 16
;  отладка LCD  WH2004 D TMI CT
;  отладка АЦП ( ADC0 )  на PA0 и ШИМ OC1 на PD5
;
; 19 ноября 2011 года  версия 1.10
; тактирование МК: встроенный генератор 8 МГц
; = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
.nolist
.include "m16def.inc"     ; AVR ATmega16
.list
; = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
; Конфигурационные биты  Которые надо установить ( обнулить )
; при работе с портом С надо отключить режим JTAG ( снять галочку ) !!!!
; = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =

; Режимы настроек периферии:
; Timer0 - прерывания включены - динамическая индикация
; Timer2 - прерывания включены по переполнению, предделитель 1:8 (счет времени)

; = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
; Описание констант и переменных
; = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
.equ Fclk         = 8000000 ; тактовая частота контроллера
.equ T0_InitVal   = 253     ; 253, то есть считает до 256  3 раза, F= 2 604,16 Гц
.equ T1_InitVal   = 250     ; 251, то есть считает до 256  6 раза,
.equ T0_PreScaler = 5       ; коэффициент предделителя T0 дисплей = 1/1024
.equ T1_PreScaler = 5       ; коэффициент предделителя T1         = 1/1024
.equ T2_PreScaler = 5       ; коэффициент предделителя T2 = 5     = 1/1024

; = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
;
.def Zero      = r1   ; Нуль
.def One       = r2   ; Единица
.def full      = r3   ; Константа 0xFF
.def Byte0     = r4   ; байт 0
.def AregL     = r7   ; результат измерения - младший байт
.def AregH     = r8   ; результат измерения - старший байт

.def Temp      = r16  ; вспомогательный регистр для загрузок
.def Temp2     = r17  ; вспомогательный регистр для загрузок

.def C_ADC     = r25  ; Счётчик считываний АЦП

.def Flags     = r19  ; регистр флагов
.def TempT     = r20
.def  C_Pozic  = r21  ; счётчик позиции для ЖКИ
.def iark      = r22  ; яркость
.def TempL     = r23  ; для обмена данными с ЖКИ
.def C_ADC     = r18  ; Счётчик считываний АЦП

;================================================================
; сегмент данных - вспомогательные ячейки
;================================================================
  .dseg           ; сегмент данных
.org SRAM_START
  .byte	2         ; резерв
Buf_LCD:          ; WH 2004D
Ctroka1: .byte 20
Ctroka3: .byte 20
Ctroka2: .byte 20
Ctroka4: .byte 20
     
Delay:	.byte	1 ; счётчик задержек по таймеру

;================================================================
; сегмент кода - программа  - векторы прерываний
;================================================================
  .cseg
  .org	0      ; старт 
  rjmp	Begin  ; При сбросе
  
  .org	OVF2addr   ; Переполнение таймера 2
  rjmp	IntTimer1  ; таймер отрабатывает учёт времени
 
  .org OC1Aaddr    ; Interrupt vector for timer1 output compare match A
  rjmp OC1A_isr    ; это для ШИМ ( PWM )
  
  .org OC1Baddr    ; Interrupt vector for timer1 output compare match B
  rjmp OC1B_isr

  .org	OVF1addr    ; Переполнение таймера 2 счётчик 1
  rjmp	IntTimer1_1 ; таймер отрабатывает звуковой сигнал

  .org	OVF0addr   ; Переполнение таймера 0
  rjmp	IntTimer0  ; таймер отрабатывает динамическую индикацию

.cseg
.org IOEND+1
.include "macrocy.inc"   ; макросы
.include "D_Indic1.asm"  ; процедуры динамической индикации
.include "LCD.asm"       ; процедуры вывода на ЖКИ

; = = = = = = = = = = = = = = = = = = = = = =  LCD Init

OC1A_isr:
  out OCR1AL, iark ; вывод значения в регистр сравнения,канал А
reti

OC1B_isr:
  out OCR1BL, iark ; вывод значения в регистр сравнения,канал B
reti

IntTimer1_1:
  sbis  PinB , 6   ; пропустить след команду если не нажата
  rcall Zvuk
  out   TCNT1H, Full          ; начальное значение счетчика T1
  outi  TCNT1L, T1_InitVal    ; начальное значение счетчика T1
  reti

; = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =

Begin:	; начало рабочего кода
;================================================================
  cli   ; запрет прерыаний
; инициализация стека
  ldi 	Temp, LOW(RAMEND)
  out	spl, Temp
  ldi 	Temp, HIGH(RAMEND)
  out	sph, Temp

;****** Инициализация служебных регистров **********************;

  clr Zero        ; Константа 0x00
  mov One , Zero
  inc One         ; Константа 0x01
  mov Full, Zero
  com Full        ; Константа 0xFF
  
; инициализация портов
; настраиваем порт A
  outi DDRA,  (1<<DDA5)+(1<<DDA6)+(1<<DDA7) ; выходы для управления LCD
  out PortA , Zero       ; убираем подтяжки
	
; настраиваем порт B на ввод от кнопок порт после сброса содержат 00
  out DDRB, Zero
  out PortB , Zero       ; убираем подтяжки
 
; настраиваем порт C на вывод данных для LCD
  out DDRC , Full        ; порт C все контакты на вывод
  out PortC , Zero       ; гасим всё

; настраиваем порт D	
  outi DDRD,  (1<<DDD1)+(1<<DDD4)+(1<<DDD5)+(1<<DDD6)+(1<<DDD7) ; выходы
  outi PortD, (1<<PD2)+(1<<PD3)             ; входы с подтяжкой к VCC

; инициализация АЦП
  outi ADCSRA, (1<<ADEN)|(1<<ADPS2)|(1<<ADPS1) 
; ADEN=1 - это 0х80  ; ADPS2..0=110;  это 0x06 - делим на 64 и получаем 125 кГц итого 0x86
  outi ADMUX, (1<<ADLAR)             ; у нас вывод 0 . +(1<<MUX1)
; 0x20 ; ADLAR=1; MUX4..0=ADC0  для ADC0 MUX = 0
; бит 5 0x20 для выравнивания результата влево ; если бит 7 0x07 - это вывод ADC7
 
; инициализация таймеров
  outi  TCNT0, T0_InitVal    ; начальное значение счетчика T0
  outi  TCCR0, T0_PreScaler  ; значение предъделителя и запускаем таймер 

  out   TCNT1H, Full          ; начальное значение счетчика T1
  outi  TCNT1L, T1_InitVal    ; начальное значение счетчика T1
  outi  TCCR1B, T1_PreScaler  ; предъделитель счётчика 1 таймера 2
  outi  TCCR2 , T2_PreScaler  ; стартуем таймер 2
	
;             (1<<OCIE1B)        ; Enable Timer1 OVF interrupt
  outi TIMSK, (1<<TOIE0)+(1<<TOIE1)+(1<<TOIE2)
   ; маска разрешения прерываний от таймера 0 и 2 и счётчика 1 
  sei             ; разрешаем прерывания
	
  clr iark        ; регистр яркости
  clr Byte0       ; очищаем байт 0
  
; = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =

; инициация ЖКИ -  строки убраны чтоб не загромождать

; Главный цикл работы Мерим напряжение на входе АЦП и выводим по-битно на LCD
; ждём нажатия кнопки на PD7
GCikl:

  rcall Merit_U
  ldi TempL , 62    ; знак ">"
  rcall LCD_W_DAT   ; вывод байта на LCD
  
  ldi C_Pozic, 8
Cdv:
  clr TempL
  rol Byte0        ; выдвинули в "С" старший бит
  rol TempL        ; и затолкали его в TempL
  ORI TempL, 0x30
  rcall LCD_W_DAT   ; вывод байта на LCD
  dec C_Pozic
  brne Cdv
  ldi TempL , 32    ; пробел
  rcall LCD_W_DAT   ; вывод байта на LCD
  
  rcall Zdu_Kn7

  rjmp GCikl        ; основной цикл

; = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
Vzat_U:             ; Взять напряжение с PC0
  sbi  ADCSRA, ADSC ; запуск преобразования
Zdem:
  sbic ADCSRA, ADSC ; проверяем бит ADSC
  rjmp Zdem         ; бит ADSC стоит
  nop               ; бит ADSC сброшен
  in   Temp, ADCH
  ret
    
; = = = = = = = = = = = = = = = = = = = = = = = = = = =
Merit_U: 
  ldi C_ADC, 64    ; Делаем 64 измерения и усредняем
ADC_64:
  rcall Vzat_U
  add AregL, Temp
  adc AregH, Zero  ; учли перенос
  dec C_ADC
  brne ADC_64

  clr C_ADC
div64:              ; деление на 64 для усреднения результата
  lsr AregH         ; сдвинули старший байт
  ror AregL         ; сдвинули младший байт
  inc C_ADC
  cpi C_ADC, 6
  brne div64
  
  mov iark , AregL
  mov Byte0, AregL ; выводим значение U для индикации
  mov TempL, AregL ; выводим значение U для индикации
  
;  out OCR1AL, AregL ; вывод значения в регистр сравнения, канал А
 ret

