;ATmega32	10 МГц
.include "m32def.inc"

.def	I2C_adr		=r31	;в этот регистр заносится slave-адрес устройства, с которым работаем по I2C
.def	I2C_data	=r30	;в этот регистр заносится данные для/от устройства
.def	temp		=r29	;временный регистр
.def	seconds_1	=r28	;единицы секунд
.def	seconds_10	=r27	;десятки секунд
.def	minutes_1	=r26	;единицы минут
.def	minutes_10	=r25	;десятки минут
.def	hours_1		=r24	;единицы часов
.def	hours_10	=r23	;десятки часов
.def	delay		=r22	;регистр задержки

;Коды работы модуля TWI
.equ	start		=0x08	;Условие START было успешно сформировано
.equ	r_start		=0x10	;Условие повторный START было успешно сформировано
.equ	mr_sla_ack	=0x40	;Был успешно передан slave-адрес + READ и принято   подтверждение (ACK)
.equ	mr_sla_nack	=0x48	;Был успешно передан slave-адрес + READ и принято НЕподтверждение (NACK)
.equ	mr_data_ack	=0x50	;Был успешно принят байт данных и передано   подтверждение (ACK)
.equ	mr_data_nack	=0x58	;Был успешно принят байт данных и передано НЕподтверждение (NACK)
.equ	mw_sla_ack	=0x18	;Был успешно передан slave-адрес + WRITE и принято   подтверждение (ACK)
.equ	mw_sla_nack	=0x20	;Был успешно передан slave-адрес + WRITE и принято НЕподтверждение (NACK)
.equ	mw_data_ack	=0x28	;Был успешно передан байт данных и принято   подтверждение (ACK)
.equ	mw_data_nack	=0x30	;Был успешно передан байт данных и принято НЕподтверждение (NACK)

;Адрес DS1307
.equ	DS1307_WR_adr	=0xD0	;write	1101 000 0
.equ	DS1307_RD_adr	=0xD1	;read	1101 000 1

;------------------------------------------------
;	ИНИЦИАЛИЗАЦИЯ КОНТРОЛЛЕРА		|
;------------------------------------------------
.org $0000
		rjmp	reset			;прерывание по сбросу (включению питания)
;------------------------------------------------
;	НАЧАЛЬНЫЕ УСТАНОВКИ			|
;------------------------------------------------
reset:		
;------------------------------------------------
;	УСТАНОВКА УКАЗАТЕЛЯ СТЕКА		|
;------------------------------------------------
		ldi	temp,low(ramend)
		out	spl,temp

		ldi	temp,high(ramend)
		out	sph,temp
;------------------------------------------------
;	НАСТРОЙКА ПОРТОВ			|
;------------------------------------------------
	;PORT C

		ldi	temp,0b11111100		;PC1 - вход+R - SDA
		out	ddrc,temp		;PC0 - вход+R - SCL

		ldi	temp,0b00000011		;PC1 - вход+R - SDA
		out	portc,temp		;PC0 - вход+R - SCL

;------------------------------------------------
;	НАСТРОЙКА ИНТЕРФЕЙСА TWI (I2C)		|
;------------------------------------------------

;	Настройка скорости передачи
;	Fscl=Fclk/(16+2*[TWBR]*4^[TWPS])
;	Fscl=10'000'000/(16+2*[92]*4^[0])=10'000'000/200 = 50 kHz

		ldi	temp,92
		out	twbr,temp

;------------------------------------------------
;	ИНИЦИАЛИЗАЦИЯ DS1307			|
;------------------------------------------------

	;Читаем значение бита CH (если CH=1 - генератор DS1307 остановлен)

	;1 - Необходимо установить Register Point = 0, т.е. будем читать регистр SECONDS
		
		rcall	twi_start		;START		

		ldi	I2C_adr,DS1307_WR_adr	;Передаем адрес DS1307 + Write
		rcall	twi_adr_w

		ldi	I2C_data,0x00		;Устанавливаем Register Point = 0
		rcall	twi_data_write

		rcall	twi_stop		;STOP	

	;2 - Теперь читаем SECONDS

		rcall	twi_start		;START		

		ldi	I2C_adr,DS1307_RD_adr	;Передаем адрес DS1307 + Read
		rcall	twi_adr_r

		rcall	twi_data_read_NACK	;Читаем значение регистра SECONDS

		rcall	twi_stop		;STOP		

		sbrs	I2C_data,7
		rjmp	main			;перход, если генератор DS1307 запущен

	;Запускаем генератор DS1307, если он был остановлен

	;1 - Необходимо установить Register Point = 0, т.е. будем писать в регистр SECONDS

		rcall	twi_start		;START

		ldi	I2C_adr,DS1307_WR_adr	;Передаем адрес DS1307 + Write
		rcall	twi_adr_w

		ldi	I2C_data,0x00		;Устанавливаем Register Point = 0
		rcall	twi_data_write

	;2 - Теперь пишемем SECONDS

		ldi	I2C_data,0b00000000	;CH=0 - запустили генератор DS1307
		rcall	twi_data_write

		rcall	twi_stop		;STOP

;------------------------------------------------
;	ОСНОВНАЯ ПРОГРАММА			|
;------------------------------------------------

main:	rcall	read_time	;эта подпрограмма читает время

;	здесь выводишь время на экран 
;	или еще что-нибудь делаешь с регистрами seconds_1, seconds_10, minutes_1, minutes_10, hours_1, hours_10 и т.д.

	rcall	write_time	;эта подпрограмма устанавливает время

	rjmp	main

;------------------------------------------------
;	ПОДПРОГРАММА ЧТЕНИЯ ВРЕМЕНИ		|
;------------------------------------------------

;для примера прочитаем только секунды, минуты и часы

read_time:
	;1 - Необходимо установить Register Point = 0, т.е. начнем читать время с секунд
	;при каждом чтении/записи значений регистров DS1307 Register Point автоматически инкрементируется 

		rcall	twi_start		;START

		ldi	I2C_adr,DS1307_WR_adr	;Передаем адрес DS1307 + Write
		rcall	twi_adr_w

		ldi	I2C_data,0x00			
		rcall	twi_data_write		;Устанавливаем Register Point = 0

		rcall	twi_stop		;STOP
		
	;2 - Читаем секунды (Register Point = 0)

		rcall	twi_start		;START			

		ldi	I2C_adr,DS1307_RD_adr	;Передаем адрес DS1307 + Read
		rcall	twi_adr_r				

		rcall	twi_data_read_ACK	;Читаем значение регистра SECONDS
			
		mov	seconds_1,I2C_data
		andi	seconds_1,0b00001111	;Теперь в регистре seconds_1 единицы секунд (0..9)

		swap	I2C_data

		mov	seconds_10,I2C_data
		andi	seconds_10,0b00000111	;Теперь в регистре seconds_10 десятки секунд (0..5)

	;3 - Читаем минуты (Register Point = 1)

		rcall	twi_data_read_ACK	;Читаем значение регистра MINUTES

		mov	minutes_1,I2C_data
		andi	minutes_1,0b00001111	;Теперь в регистре minutes_1 единицы минут (0..9)

		swap	I2C_data

		mov	minutes_10,I2C_data
		andi	minutes_10,0b00000111	;Теперь в регистре minutes_10 единицы минут (0..5)

	;4 - Читаем часы (Register Point = 2)

		rcall	twi_data_read_NACK	;Читаем значение регистра HOURS
						;ВАЖНО! 
						;Если больше ничего читать не будем - используем "twi_data_read_NACK" вместо "twi_data_read_ACK"

		mov	hours_1,I2C_data
		andi	hours_1,0b00001111	;Теперь в регистре hours_1 единицы часов (0..9)
	
		swap	I2C_data

		mov	hours_h_10,I2C_data
		andi	hours_h_10,0b00000011	;Теперь в регистре hours_10 десятки часов (0..2)

		rcall	twi_stop		;STOP

		ret

;------------------------------------------------
;	ПОДПРОГРАММА УСТАНОВКИ ВРЕМЕНИ		|
;------------------------------------------------

;для примера устанавливаем только секунды, минуты и часы

write_time:
	;1 - Необходимо установить Register Point = 0, т.е. начнем записывать время с секунд
	;при каждом чтении/записи значений регистров DS1307 Register Point автоматически инкрементируется 

		rcall	twi_start		;START

		ldi	I2C_adr,DS1307_WR_adr	;Передаем адрес DS1307 + Write
		rcall	twi_adr_w

		ldi	I2C_data,0x00			
		rcall	twi_data_write		;Устанавливаем Register Point = 0

	;2 - Устанавливаем секунды (Register Point = 0)

		mov	I2C_data,seconds_10
		swap	I2C_data		;"Собрали" из десятков и единиц секунд регистр SECONDS
		or	I2C_data,seconds_1

		rcall	twi_data_write

	;3 - Устанавливаем минуты (Register Point = 1)

		mov	I2C_data,minutes_10
		swap	I2C_data		;"Собрали" из десятков и единиц минут регистр MINUTES
		or	I2C_data,minute_1

		rcall	twi_data_write

	;4 - Устанавливаем часы (Register Point = 2)

		mov	I2C_data,hours_10
		swap	I2C_data		;"Собрали" из десятков и единиц часов регистр HOURS
		or	I2C_data,hours_1

		rcall	twi_data_write

		rcall	twi_stop		;STOP

		ret

;------------------------------------------------
;	ПОДПРОГРАММА ФОРМИРОВАНИЯ START TWI	|
;------------------------------------------------

twi_start:	ldi	temp,(1<<twint)|(1<<twsta)|(1<<twen)
		out	twcr,temp

wait_start:	in 	temp,twcr		;Этим индицируется завершение передачи условия СТАРТ
		sbrs 	temp,twint		;Ожидание установки флага TWINT
		rjmp 	wait_start
	
;-----ЕСЛИ НАДО СЛЕДИТЬ ЗА ПРАВИЛЬНОСТЬЮ РАБОТЫ МОДУЛЯ TWI,
;	то РАЗКОММЕНТИРУЮ СЛЕДУЮЩИЕ 4 СТРОКИ

;		in 	temp,twsr		;Проверка кода состояния TWI.
;		andi 	temp,0b11111000		;Маскир. бит предделителя.

;		cpi	temp,start	
;		brne	twi_error 		;Если код состояния не равен СТАРТ, перходим на twi_error

		ret

;----------------------------------------------------------------
;	ПОДПРОГРАММА ПЕРЕДАЧИ АДРЕСА+READ И ПРИЕМ ACK(NACK)	|
;----------------------------------------------------------------

twi_adr_r:	mov 	temp,I2C_adr		;Загрузка ПОДЧИН_АДР + ЧТЕНИЕ в регистр TWDR.
		out 	twdr,temp			

		ldi	temp,(1<<twint)|(1<<twen)
		out	twcr,temp		;Сброс бита TWINT в TWCR для начала передачи адреса

wait_adr_r:	in 	temp,twcr		;Ожидание установки флага TWINT.							
		sbrs 	temp,twint		;Этим сигнализируется завершение передачи ПОДЧИН_АДР + ЧТЕНИЕ
		rjmp 	wait_adr_r		;и получение/неполучение подтверждения

;-----ЕСЛИ НАДО СЛЕДИТЬ ЗА ПРАВИЛЬНОСТЬЮ РАБОТЫ МОДУЛЯ TWI,
;	то РАЗКОММЕНТИРУЮ СЛЕДУЮЩИЕ 4 СТРОКИ

;		in 	temp,twsr		;Проверка значения регистра состояния.
;		andi 	temp,0b11111000		;Маскирование бит предделителя. 

;		cpi 	temp,mr_sla_ack		
;		brne 	twi_error		;Если состояние отличается от MR_SLA_ACK, перходим на twi_error

		ret

;----------------------------------------------------------------
;	ПОДПРОГРАММА ПЕРЕДАЧИ АДРЕСА+WRITE И ПРИЕМ ACK(NACK)	|
;----------------------------------------------------------------

twi_adr_w:	mov 	temp,I2C_adr		;Загрузка ПОДЧИН_АДР + ЗАПИСЬ в регистр TWDR.
		out 	twdr,temp			

		ldi	temp,(1<<twint)|(1<<twen)
		out	twcr,temp		;Сброс бита TWINT в TWCR для начала передачи адреса

wait_adr_w:	in 	temp,twcr		;Ожидание установки флага TWINT.							
		sbrs 	temp,twint		;Этим сигнализируется завершение передачи ПОДЧИН_АДР + ЧТЕНИЕ
		rjmp 	wait_adr_w		;и получение/неполучение подтверждения

;-----ЕСЛИ НАДО СЛЕДИТЬ ЗА ПРАВИЛЬНОСТЬЮ РАБОТЫ МОДУЛЯ TWI,
;	то РАЗКОММЕНТИРУЮ СЛЕДУЮЩИЕ 4 СТРОКИ

;		in 	temp,twsr		;Проверка значения регистра состояния.
;		andi 	temp,0b11111000		;Маскирование бит предделителя.

;		cpi 	temp,mw_sla_ack		
;		brne 	twi_error		;Если состояние отличается от MW_SLA_ACK, перходим на twi_error

		ret

;----------------------------------------------------------------
;	ПОДПРОГРАММА ПРИЕМА ДАННЫХ И ПЕРЕДАЧИ ACK		|
;----------------------------------------------------------------

twi_data_read_ACK:
		ldi 	temp,(1<<twint)|(1<<twen)|(1<<twea)	;Сброс флага TWINT в TWCR для начала прередачи данных 
		out 	twcr,temp

wait_data_r_ACK:
		in	temp,twcr		;Ожидание установки флага TWINT. Этим индицируется,
		sbrs	temp,twint		;что данные были переданы
		rjmp 	wait_data_r_ACK		
		
		in 	I2C_data,twdr		;Загрузка данных из TWDRС.

;-----ЕСЛИ НАДО СЛЕДИТЬ ЗА ПРАВИЛЬНОСТЬЮ РАБОТЫ МОДУЛЯ TWI,
;	то РАЗКОММЕНТИРУЮ СЛЕДУЮЩИЕ 4 СТРОКИ

;		in 	temp,twsr		;Проверка значения регистра состояния TWI.
;		andi	temp,0b11111000		;Маскирование бит предделителя.

;		cpi 	temp,mr_data_ack	
;		brne 	twi_error		;Если состояние отличается от MR_DATA_ACK, перходим на twi_error

		ret

;----------------------------------------------------------------
;	ПОДПРОГРАММА ПРИЕМА ДАННЫХ И ПЕРЕДАЧИ NACK		|
;----------------------------------------------------------------

twi_data_read_NACK:
		ldi 	temp,(1<<twint)|(1<<twen)|(0<<twea)	;Сброс флага TWINT в TWCR для начала прередачи данных 
		out 	twcr,temp
wait_data_r_NACK:
		in	temp,twcr		;Ожидание установки флага TWINT. Этим индицируется,
		sbrs	temp,twint		;что данные были переданы
		rjmp 	wait_data_r_NACK	
		
		in 	I2C_data,twdr		;Загрузка данных из TWDRС.

;-----ЕСЛИ НАДО СЛЕДИТЬ ЗА ПРАВИЛЬНОСТЬЮ РАБОТЫ МОДУЛЯ TWI,
;	то РАЗКОММЕНТИРУЮ СЛЕДУЮЩИЕ 4 СТРОКИ

;		in 	temp,twsr		;Проверка значения регистра состояния TWI.
;		andi	temp,0b11111000		;Маскирование бит предделителя.

;		cpi 	temp,mr_data_nack	
;		brne 	twi_error		;Если состояние отличается от MR_DATA_NACK, перходим на twi_error

		ret

;----------------------------------------------------------------
;	ПОДПРОГРАММА ПЕРЕДАЧИ ДАННЫХ И ПРИЕМ ACK(NACK)		|
;----------------------------------------------------------------

twi_data_write:
		out	twdr,I2C_data

		ldi 	temp,(1<<twint)|(1<<twen);|(1<<twea)	;Сброс флага TWINT в TWCR для начала приема данных
		out 	twcr,temp

wait_data_w:	in	temp,twcr		;Ожидание установки флага TWINT. Этим индицируется,
		sbrs	temp,twint		;что данные были переданы и принято/не принято
		rjmp 	wait_data_w		;подтверждение 

;-----ЕСЛИ НАДО СЛЕДИТЬ ЗА ПРАВИЛЬНОСТЬЮ РАБОТЫ МОДУЛЯ TWI,
;	то РАЗКОММЕНТИРУЮ СЛЕДУЮЩИЕ 4 СТРОКИ		

;		in 	temp,twsr		;Проверка значения регистра состояния TWI.
;		andi	temp,0b11111000		;Маскирование бит предделителя.

;		cpi 	temp,mw_data_ack	
;		brne 	twi_error		;Если состояние отличается от MW_DATA_NACK, перходим на twi_error

		ret

;----------------------------------------------------------------
;	ПОДПРОГРАММА ФОРМИРОВАНИЯ STOP TWI			|
;----------------------------------------------------------------
		
twi_error:	;здесь можешь анализировать ошибки работы модуля TWI и принимать соответствующие меры
		;пока никаких действий не производится, просто выдается STOP

twi_stop:	ldi	temp,(1<<twint)|(1<<twen)|(1<<twsto)	;Передача условия СТОП
		out	twcr,temp

delay7_5mks:	ldi	delay1,25		;задержка Tbuf 4,7 мкс MIN - между STOP и START
del7_5:		dec 	delay1
		brne	del7_5

		ret


