BascomAVR自带的i2cslave_pcf8574.bas例程中,模拟i2c能扩展成接收多个字节吗?
下面是代码:库文件放在下一贴
'-----------------------------------------------------------------------------------------
'name : i2c_pcf8574.bas
'copyright : (c) 1995-2005, MCS Electronics
'purpose : shows how you could use the I2C slave library to create a PCF8574
'micro : AT90S2313
'suited for demo : NO, ADDON NEEDED
'commercial addon needed: yes
'-----------------------------------------------------------------------------------------
'$regfile = "2313def.dat" ' specify the used micro
$regfile = "attiny13.dat" ' specify the used micro
$crystal = 3684000 ' used crystal frequency
'$baud = 19200 ' use baud rate
$hwstack = 32 ' default use 32 for the hardware stack
$swstack = 32 ' default use 32for the SW stack
$framesize = 40 ' default use 40 for the frame space
'This program shows how you could use the I2C slave library to create a PCF8574
'The PCF8574 is an IO extender chip that has 8 pins.
'The pins can be set to a logic level by writing the address followed by a value
'In order to read from the pins you need to make them '1' first
'This program uses a AT90S2313, PORTB is used as the PCF8574 PORT
'The slave library needs INT0 and TIMER0 in order to work.
'SCL is PORTD.4 (T0)
'SDA is PORTD.2 (INT0)
'Use 10K pull up resistors for both SCL and SDA
'The Slave library will only work for chips that have T0 and INT0 connected to the same PORT.
'These chips are : 2313,2323, 2333,2343,4433,tiny22, tiny12,tiny15, M8
'The other chips have build in hardware I2C(slave) support.
'specify the slave address. This is &H40 for the PCF8574
'You always need to specify the address used for write. In this case &H40 ,
'The config i2cslave command will enable the global interrupt enable flag !
Config I2cslave = &B00000001 ' same as &H40
'Config I2cslave = &H40 , Int = Int0 , Timer = Timer0
'A byte named _i2c_slave_address_received is generated by the compiler.
'This byte will hold the received address.
'A byte named _i2c_slave_address is generated by the compiler.
'This byte must be assigned with the slave address of your choice
'the following constants will be created that are used by the slave library:
' _i2c_pinmask = &H14
' _i2c_slave_port = Portd
' _i2c_slave_pin = Pind
' _i2c_slave_ddr = Ddrd
' _i2c_slave_scl = 4
' _i2c_slave_sda = 2
'These values are adjusted automatic depending on the selected chip.
'You do not need to worry about it, only provided as additional info
'by default the PCF8574 port is set to input
Config Portb = Input
Portb = 255 'all pins high by default
'DIM a byte that is not needed but shows how you can store/write the I2C DATA
Dim Bfake As Byte
'empty loop
Do
' you could put your other program code here
'In any case, do not use END since it will disable interrupts
Loop
'here you can write your other program code
'But do not forget, do not use END. Use STOP when needed
'!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
' The following labels are called from the slave library
'!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
'When the master wants to read a byte, the following label is allways called
'You must put the data you want to send to the master in variable _a1 which is register R16
I2c_master_needs_data:
'when your code is short, you need to put in a waitms statement
'Take in mind that during this routine, a wait state is active and the master will wait
'After the return, the waitstate is ended
Config Portb = Input ' make it an input
_a1 = Pinb ' Get input from portB and assign it
Return
'When the master writes a byte, the following label is always called
'It is your task to retrieve variable _A1 and do something with it
'_A1 is register R16 that could be destroyed/altered by BASIC statements
'For that reason it is important that you first save this variable
I2c_master_has_data:
'when your code is short, you need to put in a waitms statement
'Take in mind that during this routine, a wait state is active and the master will wait
'After the return, the waitstate is ended
Bfake = _a1 ' this is not needed but it shows how you can store _A1 in a byte
'after you have stored the received data into bFake, you can alter R16
Config Portb = Output ' make it an output since it could be an input
Portb = _a1 'assign _A1 (R16)
Return
'!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
'You could simply extend this sample so it will use 3 pins of PORT D for the address selection
'For example portD.1 , portd.2 and portD.3 could be used for the address selection
'Then after the CONFIG I2CSLAVE = &H40 statement, you can put code like:
'Dim switches as Byte ' dim byte
'switches = PIND ' get dip switch value
'switches = switches and &H1110 ' we only need the lower nibble without the LS bit
'_i2c_slave_address = &H40 + switches ' set the proper address 库文件源代码:
基本上使用ASM写的,看不明白,晕~~~~~~~~~~~~
Copyright = Mcs Electronics
Www = Http : / / Www.mcselec.com
Email = Avr@mcselec.com
Comment = I2c Soft Slave Library
Libversion = 1.11.6.8
Date = 2 April 2002
Statement = No Source Code From The Library May Be Distributed In Any Form
Statement = Of Course This Does Not Applies For The Compiled Code When You Have A Bascom -avr License
Statement = It Is Not Allowed To Use The Asm In Any Other Development Tool Other Than Bascom !
Statement = Based On Atmel An 302. An302 Contained Some Bugs.
History = No Known Bugs.
;This modules contains all the I2C slave code
;Init is done in the BASIC program
;***************************************************************************
;*
;* FUNCTION
;* i2c_init
;*
;* DESCRIPTION
;* Initialization of interrupts and port used by the I2C interface
;* and waits for the first start condition.
;*
;* USAGE
;* Jump to this code directly after a reset.
;*
;* RETURN
;* none
;*
;***************************************************************************
_i2c_slave_init:
;**** PORT Initialization ****
* Cbi _i2c_slave_ddr , _i2c_slave_sda
; Initialize INT0 for open colector operation (SDA in/out)
* Cbi _i2c_slave_ddr , _i2c_slave_scl
; Initialize(T0) for open colector operation (SCL in/out)
* Cbi _i2c_slave_port , _i2c_slave_sda
* Cbi _i2c_slave_port , _i2c_slave_scl
;**** Interrupt Initialization ****
* Basic : Config Int0 = Falling
; Set INT0 to generate an interrupt on falling edge
; Enable INT0
* Basic : Enable Int0
; Set clock to count on falling edge of T0
* Basic : Config Timer0 = Counter , Edge = Falling
Sei ; enable interrupts
Ret
;Int0 interrupt
_i2c_slave_int0:
push r24 ; save reg
* In R24 , Sreg ; Get Sreg
push r24 ; save used register
push r25
push r16
push r17
; Get I2C Slave Address *
I2c_get_adr:
ldi R17,1 ; initialize address register
Wlo_ga0:
* Sbic _i2c_slave_pin , _i2c_slave_scl ; Wait For Scl Low
rjmp wlo_ga0
rjmp first_ga
Do_ga : ; Do
Wlo_ga:
* Sbic _i2c_slave_pin , _i2c_slave_scl ; Wait For Scl Low
rjmp wlo_ga
First_ga:
sec ;set carry
Whi_ga:
* Sbis _i2c_slave_pin , _i2c_slave_scl ; Wait For Scl High
rjmp whi_ga
* Sbis _i2c_slave_pin , _i2c_slave_sda ; If Sda Low
clc ;clear carry
rol R17 ;shift carry into address register
brcc do_ga ; while register not full
Wlo_ca:
* Sbic _i2c_slave_pin , _i2c_slave_scl ; Wait For Scl Low
rjmp wlo_ca
mov r24,R17 ; get copy of slave address
* Sts {_i2c_slave_address_received} , R24 ; Store For The User
* Lds R25 , {_i2c_slave_address} ; Load The Specified Slave Address
Andi r24,254 ; remove read/write bit
Cp r24,r25 ; compare with slave address
breq i2c_adr_ack ; does it match?
rjmp i2c_adr_miss ; no, goto address miss handle
;**** Acknowledge Address ****
I2c_adr_ack:
* Sbi _i2c_slave_ddr , _i2c_slave_sda ; Assert Acknowledge On Sda
Whi_aa:
* Sbis _i2c_slave_pin , _i2c_slave_scl ; Wait For Scl High
rjmp whi_aa
;**** Check Transfer Direction ****
lsr R17 ; if master write
brcc i2c_master_write ; goto master write handle
;* Transmit Data (master read) *
I2c_master_read:
* Sbi _i2c_slave_ddr , _i2c_slave_scl ; Start Wait State
@genus(100)
Call I2c_master_needs_data ; Call User Program To Get A Byte
sec ; shift MSB out and "floating empty flag" in
rol R16
* Cbi _i2c_slave_ddr , _i2c_slave_scl ; End Wait State
Wlo_mr:
* Sbic _i2c_slave_pin , _i2c_slave_scl ; Wait For Scl Low
rjmp wlo_mr
;**** Transmitt data ****
brcc fb_low_mr ; if current data bit high
* Cbi _i2c_slave_ddr , _i2c_slave_sda ; Release Sda
rjmp fb_mr ; goto read loop
Fb_low_mr:
* Sbi _i2c_slave_ddr , _i2c_slave_sda ; Force Sda
Fb_mr:
lsl R16 ; if data register not empty
Loop_mr:
Whi_mr:
* Sbis _i2c_slave_pin , _i2c_slave_scl ; Wait For Scl High
rjmp whi_mr
Wlo_mr2:
* Sbic _i2c_slave_pin , _i2c_slave_scl ; Wait For Scl Low
rjmp wlo_mr2
brcc b_low_mr ; if current data bit high
* Cbi _i2c_slave_ddr , _i2c_slave_sda ; Release Sda
lsl R16 ; if data register not empty
brne loop_mr ; loop
rjmp done_mr ; done
B_low_mr:
* Sbi _i2c_slave_ddr , _i2c_slave_sda ; Force Sda
lsl R16 ; if data register not empty
brne loop_mr ; loop
Done_mr:
Whi_mr2:
* Sbis _i2c_slave_pin , _i2c_slave_scl ; Wait For Scl High
rjmp whi_mr2
Wlo_mr3:
* Sbic _i2c_slave_pin , _i2c_slave_scl ; Wait For Scl Low
rjmp wlo_mr3
* Cbi _i2c_slave_ddr , _i2c_slave_sda ; Release Sda
;**** Read Acknowledge from Master ****
Whi_ra:
* Sbis _i2c_slave_pin , _i2c_slave_scl ; Wait For Scl High
rjmp whi_ra
sec ; read acknowledge
* Sbis _i2c_slave_pin , _i2c_slave_sda
clc
brcc i2c_master_read ; if ack transfer (next) data
Wlo_ra:
* Sbic _i2c_slave_pin , _i2c_slave_scl ; Wait For Scl Low
rjmp wlo_ra
rjmp i2c_wait_cond ; goto wait condition (rep. start or stop)
;*******************************
;* Receive Data (master write) *
;*******************************
I2c_master_write:
Wlo_mw0:
* Sbic _i2c_slave_pin , _i2c_slave_scl ; Wait For Scl Low
rjmp wlo_mw0
* Cbi _i2c_slave_ddr , _i2c_slave_sda ; Remove Acknowledge From Sda
Whi_mw:
* Sbis _i2c_slave_pin , _i2c_slave_scl ; Wait For Scl High
rjmp whi_mw
* In R24 , _i2c_slave_pin ; Sample Sda(first Bit) And Scl
* Andi R24 , _i2c_pinmask ; Mask Out Sda And Scl
Do_mw:
* In R25 , _i2c_slave_pin ; New Sample
* Andi R25 , _i2c_pinmask ; Mask Out Sda And Scl
cp r25,r24
breq do_mw ; while no change
* Sbrs R25 , _i2c_slave_scl ; If Scl Changed To Low
rjmp receive_data ; goto receive data
* Sbrs R25 , _i2c_slave_sda ; If Sda Changed To Low
rjmp i2c_get_adr ; goto repeated start
rjmp i2c_slave_stop ; goto transfer stop
Receive_data:
ldi R16,2 ; set R16 MSB to zero
* Sbrc R24 , _i2c_slave_sda ; If Sda Sample Is One
ldi R16,3 ; set R16 MSB to one
Do_rd:
Wlo_rd:
* Sbic _i2c_slave_pin , _i2c_slave_scl ; Wait For Scl Low
rjmp wlo_rd
sec ;set carry
Whi_rd:
* Sbis _i2c_slave_pin , _i2c_slave_scl ; Wait For Scl High
rjmp whi_rd
* Sbis _i2c_slave_pin , _i2c_slave_sda ; If Sda Low
clc ;clear carry
rol R16 ;shift carry into data register
brcc do_rd ; while register not full
;**** Acknowledge Data ****
I2c_dat_ack:
Wlo_da:
* Sbic _i2c_slave_pin , _i2c_slave_scl ; Wait For Scl Low
rjmp wlo_da
* Sbi _i2c_slave_ddr , _i2c_slave_sda ; Assert Acknowledge On Sda
Whi_da:
* Sbis _i2c_slave_pin , _i2c_slave_scl ; Wait For Scl High
rjmp whi_da
;**** Store Data (handle incoming data) ****
* Sbi _i2c_slave_ddr , _i2c_slave_scl ;(start Wait State)
@genus(100)
Call I2c_master_has_data ; Call User Program To Inform We Received A Byte
* Cbi _i2c_slave_ddr , _i2c_slave_scl ;(end Wait State)
rjmp i2c_master_write ; Start on next transfer
;timer0 interrupts
_i2c_slave_timer0:
;* This interrupt handles a "address miss". If the slave device is
;* not addressed by a master, it will not acknowledge the address.
;*
;* Instead of waiting for a new start condition in a "busy loop"
;* the slave set up the counter to count 8 falling edges on SCL and
;* returns from the current interrupt. This "skipping" of data
;* do not occupies any processor time. When 8 egdes are counted, a
;* timer overflow interrupt handling routine (this one) will check
;* the next condition that accure. If its a stop condition
;* the transfer ends, if its a repeated start condition a jump
;* to the i2c_wakeup interrupt will read the new address. If a new
;* transfer is initiated the "skipping" process is repeated.
;*
* Push R24 ; Save Reg
* In R24 , Sreg ; Get Sreg
push r24 ; save used register
push r25
push r16
push r17
I2c_adr_miss:
;**** Drop Acknowledge ****
Whi_dac:
* Sbis _i2c_slave_pin , _i2c_slave_scl ; Wait For Scl High
rjmp whi_dac
Wlo_dac:
* Sbic _i2c_slave_pin , _i2c_slave_scl ; Wait For Scl Low
rjmp wlo_dac
* Basic : Disable Timer0
* Basic : Enable Int0
;************************
;* Wait for a Condition *
;************************
I2c_wait_cond:
Whi_wc:
* Sbis _i2c_slave_pin , _i2c_slave_scl ; Wait For Scl High
rjmp whi_wc
* In R24 , _i2c_slave_pin ; Sample Sda(first Bit) And Scl
* Andi R24 , _i2c_pinmask ; Mask Out Sda And Scl
Do_wc:
* In R25 , _i2c_slave_pin ; New Sample
* Andi R25 , _i2c_pinmask ; Mask Out Sda And Scl
cp r25,r24
breq do_wc ; while no change
* Sbrs R25 , _i2c_slave_scl ; If Scl Changed To Low
rjmp i2c_skip_byte ; goto skip byte
* Sbrs R25 , _i2c_slave_sda ; If Sda Changed To Low
rjmp i2c_get_adr ; goto repeated start
;*************************
;* Handle Stop Condition *
;*************************
I2c_slave_stop:
; Set INT0 to generate an interrupt on low level,
* Basic : Config Int0 = Low Level
; then set INT0 to generate an interrupt on falling edge.
* Basic : Config Int0 = Falling
;This will clear the EXT_INT0 request flag.
I2c_exit:
pop r17 ; restore used registers
pop r16
pop r25
pop r24
* Out Sreg , R24
pop r24
Reti ; return from int
;****************
;* Skip byte(s) *
;****************
I2c_skip_byte:
ldi r24,-7
* Out Tcnt0 , R24
* Basic : Enable Timer0
; enable timer 0 overflow interrupt
* Basic : Disable Int0
rjmp i2c_exit ; return from int
说明文件,压缩包里
点击此处下载armok01168771.zip 自己顶一下吧 ninjia 发表于 2007-8-30 00:07 static/image/common/back.gif
说明文件,压缩包里
点击此处下载armok01168771.zip
有没有i2c_twi-slave.lbx? 小弟急用!!!{:titter:}
页:
[1]