搜索
bottom↓
回复: 4

BascomAVR自带的i2cslave_pcf8574.bas例程中,模拟i2c能扩展成接收多个字节吗?

[复制链接]

出0入0汤圆

发表于 2007-8-30 14:01:38 | 显示全部楼层 |阅读模式
下面是代码:

库文件放在下一贴

'-----------------------------------------------------------------------------------------

'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

阿莫论坛20周年了!感谢大家的支持与爱护!!

知道什么是神吗?其实神本来也是人,只不过神做了人做不到的事情 所以才成了神。 (头文字D, 杜汶泽)

出0入0汤圆

 楼主| 发表于 2007-8-30 14:03:40 | 显示全部楼层
库文件源代码:

基本上使用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.



[_i2c_slave]

;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



[end]

出0入0汤圆

 楼主| 发表于 2007-8-30 14:07:05 | 显示全部楼层
说明文件,压缩包里

点击此处下载armok01168771.zip

出0入0汤圆

 楼主| 发表于 2007-8-31 10:46:17 | 显示全部楼层
自己顶一下吧

出0入0汤圆

发表于 2013-7-11 17:34:00 | 显示全部楼层
ninjia 发表于 2007-8-30 00:07
说明文件,压缩包里

点击此处下载armok01168771.zip

有没有i2c_twi-slave.lbx? 小弟急用!!!
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片。注意:要连续压缩2次才能满足要求!!】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-7-24 01:25

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表