;
;         "lan_i2c.txt"  файл обработчика шины I2C
;          с частью касательно особенностей DS1307
;
;------------------------------------------------------
;заготовка программного модуля для обработки кристаллов и снтерфейсом I2C
; асинхронный режим обмена, вплоть до полного останова в процессе работы.
;
; ------------ константы ------------ 
;
; wr_1307   equ 0b11010000 ; команда "запись в DS1307"
; rd_1307   equ 0b11010001 ; команда "чтение из DS1307"
; SDA       equ 0 ; позиционный номер линии SDA
; SCL       equ 1 ; позиционный номер линии SCL
; SQVOUT    equ 2 ; позиционный номер линии SQVOUT
; port_i2c  equ P3 ; переприсвоение порта
;
; ------------ регистры ------------ 
;
;  .DSEG
; adr2i:   .ds 1 ; буфер младшей части начального/целевого адреса
; tm2i:    .ds 1 ; счетчик задержки 1/4 стробимпульса
; cnt2i:   .ds 1 ; счетчик бит ввода/вывода
; cnte2i:  .ds 1 ; счетчик ошибок обмена/ожидания ответа
; data2i:  .ds 1 ; буфер ввода/вывода данных ??
;
; ------------ флаги ------------ 
;
;  .BSEG
; err2i: .dbit 1 ; флаг ошибки обмена
;          ; в области флагов ошибок
; fask:  .dbit 1 ; интерпритатор статуса сигнала ACK
;          ; в области общих флагов
;
; ----- собственно утилиты -----
;
  .CSEG
;-------------------------------------------------
; 1/4 длительности строб-импульса приема/передачи
tm4i:
  mov tm2i,#8
  djnz tm2i,$
  ret
;
;-------------------------------------------------
;start2 - п/п генерации старт-условия для шины и2с
;вызов acall start2 , используемый регистр tm2i, передаваемых
;параметров нет, по умолчанию исходно dout_P3=0xFF
;   по выходу SDA=SCL=0 
start2: 
  acall tm4i
  clr port_i2c.SDA
  acall tm4i
  acall tm4i
  clr port_i2c.SCL
  acall tm4i
  ret
;
;-------------------------------------------------
;stop2 - п/п генерации стоп-условия для шины и2с
;вызов acall stop2 , используемый регистр tm2i, передаваемых
;параметров нет, при входе dout_P3=0bnnnnnn??
;   по выходу SDA=SCL=1
stop2:
  anl port_i2c,#0b11111100
  acall tm4i
  setb port_i2c.SCL
  acall tm4i
  acall tm4i
  setb port_i2c.SDA
  acall tm4i
  ret
;
;-------------------------------------------------
;"повторный старт" (Sr-условие) протокола I2C
;(желательно разместить в блоке п/п работы с I2C, чтобы избежать "длинные"
;вызовы типа LCALL для субблоков strob)
restar:
  setb port_i2c.SDA ; страховка
  acall tm4i
 lwait:
  mov c,port_i2c.SDA
  jnc lwait ; ждем подтверждение ведомого
  acall tm4i
  setb port_i2c.SCL
  acall tm4i
  acall tm4i
  clr port_i2c.SDA
  acall tm4i
  clr port_i2c.SCL
  acall tm4i
  ret
;
;-------------------------------------------------
;  ---- strob SCL ----
strob2i:
   acall tm4i
   setb port_i2c.SCL
   acall tm4i
   acall tm4i
   clr port_i2c.SCL
   acall tm4i
  ret
;
;-------------------------------------------------
;rxb2 - программа для приема байта по протоколу и2с
;вызов = acall rxb2
; по выходу принятый байт размещается в А
; статус ACK=0 генерируется в случае, если перед вызовом rxb2 был установлен
; fask=1 (последний в текущем пакете rxb2 устанавливает статус ACK=1 /при fask=0/)
; по выходу SDA=1,SCL=0
rxb2:
   mov cnt2i,#8 ; загрузить счетчик бит приемника
   setb port_i2c.SDA ; ориентировать Р3.SDA как вход (SDA=1)
   nop
   nop
loopr2:
    acall tm4i ; задержка в 1/4 строб-импульса
    setb port_i2c.SCL ; начало строб-импульса
		acall tm4i ; задержка в 1/4 строб-импульса
		mov c,port_i2c.SDA
		rlc a
		acall tm4i ; задержка в 1/4 строб-импульса
		clr port_i2c.SCL ; конец строб-импульса SDA остается равной 1
		acall tm4i ; задержка в 1/4 строб-импульса
		djnz cnt2i,loopr2
	 jbc fask,off0
noack:
    acall tm4i ; задержка в 1/4 строб-импульса
    acall strob2i
		acall tm4i ; задержка в 1/4 строб-импульса
	 ret
off0:
    clr port_i2c.SDA ; установить SDA=0
    acall tm4i ; задержка в 1/4 строб-импульса
    acall strob2i
		acall tm4i ; задержка в 1/4 строб-импульса
		acall tm4i ; задержка в 1/4 строб-импульса
		setb port_i2c.SDA ; установить SDA=1
    nop
    nop
   ret
;
;-------------------------------------------------
; txb2 - программа для передачи байта по протоколу и2с
; вызов = acall txb2
;перед вызовом ---  разместить в А пересылаемый байт
; по выходу fask=1 в случае ошибки обмена типа "ведомый не отвечает"
;по выходу SDA=1,SCL=0
txb2:
   clr fask ; очистка fask
   mov cnte2i,#0x5F ; загрузка счетчика интервала ошибок
   mov cnt2i,#8 ; загрузить счетчик бит передатчика
   nop
   nop
loopt2:
    rlc a
    mov port_i2c.SDA,c ; текущий бит данных в SDA
    acall strob2i ; тело строба передачи
    djnz cnt2i,loopt2 ; повторять от LOOPT2 до исчерпания с-ка бит
askont:
   setb port_i2c.SDA ; ориентировать Р3.SDA как вход (SDA=1)
lpask1:
    acall tm4i ; задержка в 1/4 строб-импульса
    mov c,port_i2c.SDA ; проверка на ответ ведомого (SDA=0)
    jnc eask ; продолжать при SDA=0
    djnz cnte2i,lpask1 ; продолжать от lpask1 до исчерпания с-ка повторов
 extbof:
     setb fask ; установить флаг ошибки обмена
  txbof:
	    ret ; по выходу SDA=1,SCL=0
 eask:
   mov cnte2i,#0x5F ; перезагрузить счетчик ошибок
   acall strob2i ; тело 9-го строба передачи (поддержки сигнала AСK)
lpask2:
  mov c,port_i2c.SDA ; проверка на ответ ведомого (SDA=1)
  jc txbof ; при нормальном завершении продолжить от TXBOFF
  djnz cnte2i,lpask2
  sjmp extbof ; при ошибке ответа ведомого продолжить от ETXBOF
;
;-------------------------------------------------
; --- типовой пример чтения с произвольной точки ---
;чтение байта данных из 1307 согласно текущей задаче
;по выходу принятый байт данных в data2i
;(эта программа читает 1 байт, адрес которого должен быть
; определен в регистре adr2i (в разумных для DS1307 пределах))
rdsdt:
   acall start2
   mov a,#wr_1307
   acall txb2
   jbc fask,erclk ; обработка ошибки I2C
   mov a,adr2i ; задаем целевой(начальный)адрес ячейки ИС накопителя
               ; содержимым из adr2i
   acall txb2 ; начальный адрес задан
   jbc fask,erclk ; обработка ошибки I2C
   acall restar
   mov a,#rd_1307
   acall tr1307
   clr fask ; установить ask=1
	      ; (если это единственный и последний принятый байт)
	 acall rxb2
;	 mov data2i,a ; дублируем данные в буфер-накопитель
	 acall stop2
	 ret
erclk:
    setb err2i ; флаг ошибки интерфейса I2C
    acall stop2
    ret
;
;-------------------------------------------------
; tr1307 - программа для передачи предварительно заданного адреса
;в заголовке блока приема одного байта по предварительно заданному
; адресу для DS1307 - вызов = acall tr1307
;перед вызовом ---  разместить в А пересылаемый байт
;в данном случае сигнал АСК=0 выдает ведущий -
; порверка флага FASK не проводится!
;по выходу SDA=1,SCL=0
tr1307:
    clr fask ; очистка FASK
    mov cnte2i,#0x5F ; загрузка счетчика интервала ошибок
    mov cnt2i,#8 ; загрузить счетчик бит
    anl port_i2c,#0b11111100
    nop
    nop
lopt2:
    rlc a
    mov port_i2c.SDA,c ; текущий бит данных в SDA
    acall strob2i ; тело строба передачи
    djnz cnt2i,lopt2 ; повторять от LOPT2 до исчерпания с-ка бит
	;---------------------------------------------------
	;этот фрагмент-особенность DS1307 в данном режиме !!!
	   clr port_i2c.SDA ; установить SDA=0
     acall tm4i ; задержка в 1/4 строб-импульса
     acall strob2i ; тело строба передачи
     acall tm4i ; задержка в 1/4 строб-импульса
     setb port_i2c.SDA ; установить SDA=1
     acall tm4i ; задержка в 1/4 строб-импульса
	;---------------------------------------------------
		ret
;
;-------------------------------------------------
;
; erw_1307 обработчик флага ошибки интерфейса DS1307/I2c
erw_1307:
       clr err2i
       nop ; записать собственно обработчик (индикация статуса)
       ret
;
;-------------------------------------------------
;
; rd_hdr чтение "заголовка" из DS1307
;   R2 - счетчик ячеек
;   R0- указатель адреса в блокноте
;
rd_hdr:
    push PSW
    setb RS0 ; sel RB1
  .using 1 ; директива компилятору "далее используется RB1"
      mov r0,#mlans
      mov r2,#15
       acall start2
       mov a,#wr_1307
       acall txb2
       jbc fask,erclk2 ; обработка ошибки I2C
       clr a
       acall txb2 ; начальный адрес задан
       jbc fask,erclk2 ; обработка ошибки I2C
      acall restar
      mov a,#rd_1307
      acall tr1307
 rd_loop:
      setb fask
      acall rxb2
      mov @r0,a
      inc r0
      djnz r2,rd_loop
     clr fask ; для последнего в пакете байта
     acall rxb2
     mov @r0,a
 rhdr:
    acall stop2
    pop PSW
  .using 0 ; директива компилятору "далее используется RB0"
    ret
erclk2:
    setb err2i ; флаг ошибки интерфейса I2C
   acall erw_1307 ; выполнить обработчик ошибок I2C DS1307
    sjmp rhdr
;
;-------------------------------------------------
;
; wr_hdr запись "заголовка" в DS1307
;   R2 - счетчик ячеек
;   R0- указатель адреса в блокноте
wr_hdr:
     push PSW
     setb RS0 ; sel RB1
   .using 1 ; директива компилятору "далее используется RB1"
       mov r0,#mlans
       mov r2,#16
        acall start2
        mov a,#wr_1307
        acall txb2
        jbc fask,erclk1 ; обработка ошибки I2C
        clr a
        acall txb2 ; начальный адрес задан
        jbc fask,erclk1 ; обработка ошибки I2C
 wr_loop:
       mov a,@r0
       acall txb2
       jbc fask,erclk1 ; обработка ошибки I2C
       inc r0
       djnz r2,wr_loop
 whdr:
     acall stop2
     pop PSW
   .using 0 ; директива компилятору "далее используется RB0"
     ret
erclk1:
    setb err2i ; флаг ошибки интерфейса I2C
    acall erw_1307 ; выполнить обработчик ошибок I2C DS1307
    sjmp whdr
;
;-------------------------------------------------
; reclok - перезагрузка RTC новым значением часы/минуты
; по введенному в datclock.txt
reclok:
  acall start2
   mov a,#wr_1307
   acall txb2
   jbc fask,er_clk_wr ; обработка ошибки I2C
   clr a ; задаем целевой(начальный)адрес ячейки ИС накопителя =0
   acall txb2 ; начальный адрес задан
   jbc fask,er_clk_wr ; обработка ошибки I2C
    clr a
    acall txb2 ; сброс секундомера
    jbc fask,er_clk_wr ; обработка ошибки I2C
    mov a,(mlans+rtc_min)
    acall txb2 ; запись данных минут
    jbc fask,er_clk_wr ; обработка ошибки I2C
    mov a,(mlans+rtc_hours)
    acall txb2 ; запись данных часов 24-часовый режим
    jbc fask,er_clk_wr ; обработка ошибки I2C
    acall stop2
	ret
er_clk_wr:
   setb err2i ; флаг ошибки интерфейса I2C
   acall stop2
 acall erw_1307 ; выполнить обработчик ошибок I2C DS1307
  ret
;
;-------------------------------------------------
;
; wr_newcor запись константы досчета в ОЗУ DS1307
wr_newcor:
     acall start2
    mov a,#wr_1307
    acall txb2
    jbc fask,er_clk_wr ; обработка ошибки I2C
     mov a,#rtc_cor_l ; задаем целевой(начальный)адрес ячейки ИС накопителя
     acall txb2 ; начальный адрес задан
     jbc fask,er_clk_wr ; обработка ошибки I2C
     mov a,corsek
     acall txb2 ; младший байт данных передан
     jbc fask,er_clk_wr ; обработка ошибки I2C
     mov a,corsek+1
     acall txb2 ; старший байт данных передан
     jbc fask,er_clk_wr ; обработка ошибки I2C
    acall stop2
   ret
;
;-------------------------------------------------
;
; wrustbo запись данных бодунов в ОЗУ DS1307
wrustbo:
    acall start2
      mov a,#wr_1307
      acall txb2
      jbc fask,er_clk_wr ; обработка ошибки I2C
      mov a,#rtc_bdm1 ; задаем целевой(начальный)адрес ячейки ИС накопителя
      acall txb2 ; начальный адрес задан
      jbc fask,er_clk_wr ; обработка ошибки I2C
   mov a,bodun1
   acall txb2 ; данных передан
   jbc fask,er_clk_wr ; обработка ошибки I2C
   mov a,bodun1+1
   acall txb2 ; данных передан
   jbc fask,er_clk_wr ; обработка ошибки I2C
   mov a,bodun2
   acall txb2 ; данных передан
   jbc fask,er_clk_wr ; обработка ошибки I2C
   mov a,bodun2+1
   acall txb2 ; данных передан
   jbc fask,er_clk_wr ; обработка ошибки I2C
   mov a,bodunf
   acall txb2 ; данных передан
   jbc fask,er_clk_wr ; обработка ошибки I2C
     acall stop2
    ret
;
;-------------------------------------------------
;
; wrustbl запись модифицированного по отключению бодуна
; bodunf в ОЗУ DS1307
wrustbl:
   acall start2
  mov a,#wr_1307
  acall txb2
  jbc fask,er_clk_wr ; обработка ошибки I2C
  mov a,#rtc_bodus ; задаем целевой(начальный)адрес ячейки ИС накопителя
  acall txb2 ; начальный адрес задан
  jbc fask,er_clk_wr ; обработка ошибки I2C
  mov a,bodunf
  acall txb2 ; данных передан
  jbc fask,er_clk_wr ; обработка ошибки I2C
   acall stop2
    ret
;
;-------------------------------------------------
; запись дисплея уставки таймера в ОЗУ RTC
tm_wrt:
    acall start2
  mov a,#wr_1307
  acall txb2
  jbc fask,erclk3 ; обработка ошибки I2C
  mov a,#rtc_setu0 ; задаем целевой(начальный)адрес ячейки ИС накопителя
  acall txb2 ; начальный адрес задан
  jbc fask,erclk3 ; обработка ошибки I2C
  mov a,setibu0
  acall txb2 ; данных передан
  jbc fask,erclk3 ; обработка ошибки I2C
  mov a,setibu1
  acall txb2 ; данных передан
  jbc fask,erclk3 ; обработка ошибки I2C
  mov a,setibu2
  acall txb2 ; данных передан
  jbc fask,erclk3 ; обработка ошибки I2C
   acall stop2
    ret
;
;-------------------------------------------------
; чтение ОЗУ RTC в дисплей уставки таймера
tm_rd:
   acall start2
   mov a,#wr_1307
   acall txb2
   jbc fask,erclk3 ; обработка ошибки I2C
   mov a,#rtc_setu0 ; задаем целевой(начальный)адрес ячейки ИС накопителя
               ; содержимым из adr2i
   acall txb2 ; начальный адрес задан
   jbc fask,erclk3 ; обработка ошибки I2C
   acall restar
   mov a,#rd_1307
   acall tr1307
   setb fask
   acall rxb2
   mov setibu0,a
   setb fask
   acall rxb2
   mov setibu1,a
   clr fask ; установить ask=1
	      ; (если это единственный и/или последний принятый байт)
	 acall rxb2
	 mov setibu2,a
	  acall stop2
	   ret
erclk3:
    setb err2i ; флаг ошибки интерфейса I2C
    acall stop2
    acall erw_1307 ; выполнить обработчик ошибок I2C DS1307
    ret
;
;-------------------------------------------------
; запись из буфера новых данных календаря (mlans) в ОЗУ RTC
 wre_kald:
      acall start2
      mov a,#wr_1307
      acall txb2
      jbc fask,erclk3 ; обработка ошибки I2C
      mov a,#rtc_day ; задаем целевой(начальный)адрес ячейки ИС накопителя
      acall txb2 ; начальный адрес задан
      jbc fask,erclk3 ; обработка ошибки I2C
       mov a,(mlans+rtc_day)
       acall txb2 ;
       jbc fask,erclk3 ; обработка ошибки I2C
       mov a,(mlans+rtc_date)
       acall txb2 ;
       jbc fask,erclk3 ; обработка ошибки I2C
       mov a,(mlans+rtc_mons)
       acall txb2 ;
       jbc fask,erclk3 ; обработка ошибки I2C
       mov a,(mlans+rtc_year)
       acall txb2 ;
       jbc fask,erclk3 ; обработка ошибки I2C
     acall stop2
	    ret
;
;-------------------------------------------------
;
; rtc_cold_init модуль запуска при холодном включении
rtc_cold_init:
   mov r0,#mlans
;   mov @r0,#0x80 ; останов часов, сброс секундомера /0
   mov @r0,#0 ; пуск часов, сброс секундомера /0
   inc r0
   mov @r0,#0 ; сброс счетчика минут /1
   inc r0
   mov @r0,#0 ; сброс счетчика часов, режим 24-х часового счета /2
   inc r0
   mov @r0,#1 ; 1=понедельник, 2=вторник... 7=воскресенье
	          ; установка дня недели /3
	 inc r0
   mov @r0,#1 ; установка числа =01 /4
   inc r0
   mov @r0,#1 ; 1=январь, 2=февраль... 12=декабрь
	          ; установка месяца /5
	 inc r0
   mov @r0,#0x14 ; вторая пара текущего года (2014)
	          ; установка текущего года /6
	 inc r0
   mov @r0,#0x80 ; на выходе SQVOUT фиксированная 1
	          ; установка статуса выхода SQVOUT /7
	 inc r0
   mov @r0,#0 ; bodun1=0
	          ; минуты бодуна1=0 /8
	 inc r0
   mov @r0,#0 ; bodun1+1=0
	          ; часы бодуна1=0 /9
	 inc r0
   mov @r0,#0 ; bodun2=0
	          ; минуты бодуна2=0 /A
	 inc r0
   mov @r0,#0 ; bodun2+1=0
	          ; часы бодуна2=0 /B
	 inc r0
   mov @r0,#0 ; режим бодунов ( bodunf ) загружен /C
   inc r0
   mov @r0,#low(mark2) ; младший байт константы досчета главных часов
            ; "по умолчанию" загружен /D
   inc r0
   mov @r0,#high(mark2) ; старший байт константы досчета главных часов
            ; "по умолчанию" загружен /E
   inc r0
   mov @r0,#1 ; флаг rtce активирован в блокноте RTC /F
   ; состояние остальной части ОЗУ неопределено
   acall wr_hdr
   ret
;
;-------------------------------------------------
;