Реализация I2C slave-device на примере at89c2051

8-битные микроконтроллеры и микропроцессоры от Intel и их клоны, а также компьютеры на них построенные

Moderator: Shaos

jdigreze
God
Posts: 1388
Joined: 02 Jan 2006 02:28
Location: Abakan

Реализация I2C slave-device на примере at89c2051

Post by jdigreze »

Примерно год назад делал небольшой проект, в котором требовалось собирать информацию с множества датчиков по RS232 и I2C. Когда источников RS232 один или два, то можно подобрать соответствующий микроконтроллер, с нужным количеством последовательных портов, но источников было несколько, а искать многопортовое решение не было времени. Потому, я сдел "ход конём" и повесил несколько процессоров at89c2051 для сбора информации. Далее оставалось организовать сбор всех потоков в одну кучу. Здесь решающим фактором было использование уже имеющейся шины I2C, по которой происходил сбор информации с других датчиков без какого-либо преобразования. Оставалось написать код, который бы отслеживал состояние линий I2C, и адекватно принимал и отправлял нужную информацию.
В результате "долгих" раздумий и экспериментов получил вот такой код, на основе которого были сделаны прошивки для всех at89c2051:

Code: Select all

;================================================================
; программа эмуляции датчика температуры ds1621(4) на at89c2051
;================================================================
; константы и определения
;================================================================
sda			equ	p1.0
scl			equ	p1.1

led			equ	p3.7

first_sda		equ	020h
flags1		equ	first_sda+1
var1			equ	flags1+1
address		equ	var1+1
ds_temp_l		equ	address+1
ds_temp_h		equ	ds_temp_l+1
command		equ	ds_temp_h+1

ds_readtemp		equ	0aah
ds_startconv	equ	0eeh
ds_stopconv		equ	022h
ds_config		equ	0ach

i2c_start		bit	flags1.0
i2c_its_me		bit	flags1.1
was_command		bit	flags1.2

;================================================================
; точка входа по reset
;================================================================
			org 0000h
			jmp	start

			org 0100h
;================================================================
; подпрограммы
;================================================================
;инкремент "температуры"
inc_temp:
			mov	a,	ds_temp_l
			inc	a
			mov	ds_temp_l,	a
			jnc	_inc_temp_d1
			mov	a,	ds_temp_h
			inc	a
			mov	ds_temp_h,	a
_inc_temp_d1:
			ret 
;================================================================
wait_action:
			setb	sda
			setb	scl

			jnb	scl,	$

			mov	a,	P1
			anl	a,	#001h
			mov	first_sda,	a
_wait_end_strobe:
			mov	a,	P1
			anl	a,	#001h
			cjne	a,	first_sda,	_wait_exit
			jb	scl,	_wait_end_strobe
_wait_exit:
			ret

;========================================================================
write_byte:
			mov	b,	#008h				;счетчик бит
_write_byte_l1:
			jb	acc.7,_write_byte_d1		;если младший бит = 1, то перейдем на посылку "1"
			clr	sda					;иначе пошлем "0"
			jmp	_write_byte_d2			;перейдем на формирование строба
_write_byte_d1:
			setb	sda					;пошлем "1"
_write_byte_d2:
			jnb	scl,	$				;ждем начала строба

			rl	a					;сдвинем старший бит в младший

			jb	scl,	$				;ждем окончания строба

			djnz	b,	_write_byte_l1		;если не все передали, то вернемся к началу

			setb	sda

			jnb	scl,	$				;ждем начала строба
			mov	a,	P1				;читаем подтверждение
			jb	scl,	$				;ждем окончания строба

			ret						;вернемся назад

;========================================================================
byte_readed:
			jnb	i2c_start,	_not_start

			clr	i2c_start
			mov	b,	a
			clr	acc.0
			cjne	a,	address,	_br_exit

			clr	sda
			jnb	scl,	$

			setb	i2c_its_me
			clr	was_command

			jb	scl,	$
			setb	sda

			jnb	b.0,	_br_exit

			mov	a,	command
			cjne	a,	#ds_config,	_not_config

			mov	a,	var1
			jmp	write_byte

_not_config:
			cjne	a,	#ds_readtemp,	_br_exit

			mov	a,	dS_temp_h
			call	write_byte
			jb	acc.0,	_br_exit
			mov	a,	ds_temp_l
			jmp	write_byte

_not_start:
			jnb	i2c_its_me,	_br_exit

			clr	sda
			jnb	scl,	$
			jb	scl,	$
			setb	sda

			jb	was_command,	_was_command

			mov	command,	a
			setb	was_command
			cjne	a,	#ds_startconv,	_br_exit
			jmp	inc_temp

_was_command:
			mov	b,	a
			mov	a,	command
			cjne	a,	#ds_config,	_br_exit

			mov	var1,	b

_br_exit:
			ret

;========================================================================
; основной цикл
;========================================================================
start:
			mov	p0,	#0ffh
			mov	p1,	#0ffh
			mov	p2,	#0ffh
			mov	p3,	#0ffh

			mov	a,	p3
			anl	a,	#01ch
			rr	a
			orl	a,	#090h

			mov	address,	a

			clr	i2c_start
			clr	i2c_its_me

			clr	a
			mov	ds_temp_h,	a
			mov	ds_temp_l,	a

restart_read:
			mov	b,	#008h
			clr	a
main_loop:
			rl	a
			mov	r0,	a

			call	wait_action
			cjne	a,	first_sda,	_is_condition

			orl	a,	r0

			djnz	b,	main_loop

			call	byte_readed
			jmp	restart_read

_is_condition:
			clr	i2c_start
			clr	i2c_its_me

			orl	a,	#000h
			jnz	restart_read	;was stop condition

			jb	scl,	$
			setb	i2c_start
			jmp	restart_read

;================================================================
; конец
;================================================================
			end