这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 综合技术 » 基础知识 » I2C 如何用普通I/O口模拟I2C功能?

共4条 1/1 1 跳转至

I2C 如何用普通I/O口模拟I2C功能?

院士
2006-09-17 18:14:16     打赏
I2C 如何用普通I/O口模拟I2C功能?



关键词: 何用     普通     模拟     功能    

院士
2006-12-22 22:43:00     打赏
2楼
问 我的问题是,对于不带I2C口的AVR单片机,如何用普通I/O口模拟I2C功能?我现在知道AVR的每位I/O口在使用都是要定义输入输出方向的。那对于I2C总线的SDA线,它既要输入又要输出数据,那么是不是在输出数据前,要先在DDRX里面定义成输出,输入时再改回来?或者,在输入时,不改变DDRX中的输出定义,而是直接读PINX的状态了?还望DX们指教。 1: pls see atmel i2c demo;**** A P P L I C A T I O N   N O T E   A V R 3 0 0 ************************
;*
;* Title        : I2C (Single) Master Implementation
;* Version        : 1.0 (BETA)
;* Last updated        : 97.08.27
;* Target        : AT90Sxxxx (any AVR device)
;*
;* Support email    : AVR@atmel.com
;*
;* DESCRIPTION
;*     Basic routines for communicating with I2C slave devices. This
;*    "single" master implementation is limited to one bus master on the
;*    I2C bus. Most applications do not need the multimaster ability
;*    the I2C bus provides. A single master implementation uses, by far,
;*    less resources and is less XTAL frequency dependent.
;*
;*    Some features :
;*    * All interrupts are free, and CAN be used for other activities.
;*    * Supports normal and fast mode.
;*    * Supports both 7-bit and 10-bit addressing.
;*    * Supports the entire AVR microcontroller family.
;*
;*    Main I2C functions :
;*    'i2c_start' -        Issues a start condition and sends address
;*                and transfer direction.
;*    'i2c_rep_start' -    Issues a repeated start condition and sends
;*                address and transfer direction.
;*    'i2c_do_transfer' -    Sends or receives data depending on
;*                direction given in address/dir byte.
;*    'i2c_stop' -        Terminates the data transfer by issue a
;*                stop condition.
;*
;* USAGE
;*    Transfer formats is described in the AVR300 documentation.
;*    (An example is shown in the 'main' code).    
;*
;* NOTES
;*    The I2C routines CAN be called either from non-interrupt or
;*    interrupt routines, not both.
;*
;* STATISTICS
;*    Code Size    : 81 words (maximum)
;*    Register Usage    : 4 High, 0 Low
;*    Interrupt Usage    : None
;*    Other Usage    : Uses two I/O pins on port D
;*    XTAL Range    : N/A
;*
;***************************************************************************

;**** Includes ****

.include "1200def.inc"            ; change if an other device is used

;**** Global I2C Constants ****

.equ    SCLP    = 1            ; SCL Pin number (port D)
.equ    SDAP    = 0            ; SDA Pin number (port D)

.equ    b_dir    = 0            ; transfer direction bit in i2cadr

.equ    i2crd    = 1
.equ    i2cwr    = 0

;**** Global Register Variables ****

.def    i2cdelay= r16            ; Delay loop variable
.def    i2cdata    = r17            ; I2C data transfer register
.def    i2cadr    = r18            ; I2C address and direction register
.def    i2cstat    = r19            ; I2C bus status register

;**** Interrupt Vectors ****

    rjmp    RESET            ; Reset handle
;    ( rjmp    EXT_INT0 )        ; ( IRQ0 handle )
;    ( rjmp    TIM0_OVF )        ; ( Timer 0 overflow handle )
;    ( rjmp    ANA_COMP )        ; ( Analog comparator handle )


;***************************************************************************
;*
;* FUNCTION
;*    i2c_hp_delay
;*    i2c_qp_delay
;*
;* DESCRIPTION
;*    hp - half i2c clock period delay (normal: 5.0us / fast: 1.3us)
;*    qp - quarter i2c clock period delay (normal: 2.5us / fast: 0.6us)
;*
;*    SEE DOCUMENTATION !!!
;*
;* USAGE
;*    no parameters
;*
;* RETURN
;*    none
;*
;***************************************************************************

i2c_hp_delay:
    ldi    i2cdelay,2
i2c_hp_delay_loop:
    dec    i2cdelay
    brne    i2c_hp_delay_loop
    ret

i2c_qp_delay:
    ldi    i2cdelay,1    
i2c_qp_delay_loop:
    dec    i2cdelay
    brne    i2c_qp_delay_loop
    ret


;***************************************************************************
;*
;* FUNCTION
;*    i2c_rep_start
;*
;* DESCRIPTION
;*    Assert repeated start condition and sends slave address.
;*
;* USAGE
;*    i2cadr - Contains the slave address and transfer direction.
;*
;* RETURN
;*    Carry flag - Cleared if a slave responds to the address.
;*
;* NOTE
;*    IMPORTANT! : This funtion must be directly followed by i2c_start.
;*
;***************************************************************************

i2c_rep_start:
    sbi    DDRD,SCLP        ; force SCL low
    cbi    DDRD,SDAP        ; release SDA
    rcall    i2c_hp_delay        ; half period delay
    cbi    DDRD,SCLP        ; release SCL
    rcall    i2c_qp_delay        ; quarter period delay


;***************************************************************************
;*
;* FUNCTION
;*    i2c_start
;*
;* DESCRIPTION
;*    Generates start condition and sends slave address.
;*
;* USAGE
;*    i2cadr - Contains the slave address and transfer direction.
;*
;* RETURN
;*    Carry flag - Cleared if a slave responds to the address.
;*
;* NOTE
;*    IMPORTANT! : This funtion must be directly followed by i2c_write.
;*
;***************************************************************************

i2c_start:                
    mov    i2cdata,i2cadr        ; copy address to transmitt register
    sbi    DDRD,SDAP        ; force SDA low
    rcall    i2c_qp_delay        ; quarter period delay


;***************************************************************************
;*
;* FUNCTION
;*    i2c_write
;*
;* DESCRIPTION
;*    Writes data (one byte) to the I2C bus. Also used for sending
;*    the address.
;*
;* USAGE
;*    i2cdata - Contains data to be transmitted.
;*
;* RETURN
;*    Carry flag - Set if the slave respond transfer.
;*
;* NOTE
;*    IMPORTANT! : This funtion must be directly followed by i2c_get_ack.
;*
;***************************************************************************

i2c_write:
    sec                ; set carry flag
    rol    i2cdata            ; shift in carry and out bit one
    rjmp    i2c_write_first
i2c_write_bit:
    lsl    i2cdata            ; if transmit register empty
i2c_write_first:
    breq    i2c_get_ack        ;    goto get acknowledge
    sbi    DDRD,SCLP        ; force SCL low

    brcc    i2c_write_low        ; if bit high
    nop                ;    (equalize number of cycles)
    cbi    DDRD,SDAP        ;    release SDA
    rjmp    i2c_write_high
i2c_write_low:                ; else
    sbi    DDRD,SDAP        ;    force SDA low
    rjmp    i2c_write_high        ;    (equalize number of cycles)
i2c_write_high:
    rcall    i2c_hp_delay        ; half period delay
    cbi    DDRD,SCLP        ; release SCL
    rcall    i2c_hp_delay        ; half period delay

    rjmp    i2c_write_bit


;***************************************************************************
;*
;* FUNCTION
;*    i2c_get_ack
;*
;* DESCRIPTION
;*    Get slave acknowledge response.
;*
;* USAGE
;*    (used only by i2c_write in this version)
;*
;* RETURN
;*    Carry flag - Cleared if a slave responds to a request.
;*
;***************************************************************************

i2c_get_ack:
    sbi    DDRD,SCLP        ; force SCL low
    cbi    DDRD,SDAP        ; release SDA
    rcall    i2c_hp_delay        ; half period delay
    cbi    DDRD,SCLP        ; release SCL

i2c_get_ack_wait:
    sbis    PIND,SCLP        ; wait SCL high
                    ;(In case wait states are inserted)
    rjmp    i2c_get_ack_wait

    clc                ; clear carry flag
    sbic    PIND,SDAP        ; if SDA is high
    sec                ;    set carry flag
    rcall    i2c_hp_delay        ; half period delay
    ret


;***************************************************************************
;*
;* FUNCTION
;*    i2c_do_transfer
;*
;* DESCRIPTION
;*    Executes a transfer on bus. This is only a combination of i2c_read
;*    and i2c_write for convenience.
;*
;* USAGE
;*    i2cadr - Must have the same direction as when i2c_start was called.
;*    see i2c_read and i2c_write for more information.
;*
;* RETURN
;*    (depends on type of transfer, read or write)
;*
;* NOTE
;*    IMPORTANT! : This funtion must be directly followed by i2c_read.
;*
;***************************************************************************

i2c_do_transfer:
    sbrs    i2cadr,b_dir        ; if dir = write
    rjmp    i2c_write        ;    goto write data


;***************************************************************************
;*
;* FUNCTION
;*    i2c_read
;*
;* DESCRIPTION
;*    Reads data (one byte) from the I2C bus.
;*
;* USAGE
;*    Carry flag -     If set no acknowledge is given to the slave
;*            indicating last read operation before a STOP.
;*            If cleared acknowledge is given to the slave
;*            indicating more data.
;*
;* RETURN
;*    i2cdata - Contains received data.
;*
;* NOTE
;*    IMPORTANT! : This funtion must be directly followed by i2c_put_ack.
;*
;***************************************************************************

i2c_read:
    rol    i2cstat            ; store acknowledge
                    ; (used by i2c_put_ack)
    ldi    i2cdata,0x01        ; data = 0x01
i2c_read_bit:                ; do
    sbi    DDRD,SCLP        ;     force SCL low
    rcall    i2c_hp_delay        ;    half period delay

    cbi    DDRD,SCLP        ;    release SCL
    rcall    i2c_hp_delay        ;    half period delay

    clc                ;    clear carry flag
    sbic    PIND,SDAP        ;    if SDA is high
    sec                ;        set carry flag

    rol    i2cdata            ;     store data bit
    brcc    i2c_read_bit        ; while receive register not full


;***************************************************************************
;*
;* FUNCTION
;*    i2c_put_ack
;*
;* DESCRIPTION
;*    Put acknowledge.
;*
;* USAGE
;*    (used only by i2c_read in this version)
;*
;* RETURN
;*    none
;*
;***************************************************************************

i2c_put_ack:
    sbi    DDRD,SCLP        ; force SCL low

    ror    i2cstat            ; get status bit
    brcc    i2c_put_ack_low        ; if bit low goto assert low
    cbi    DDRD,SDAP        ;    release SDA
    rjmp    i2c_put_ack_high
i2c_put_ack_low:            ; else
    sbi    DDRD,SDAP        ;    force SDA low
i2c_put_ack_high:

    rcall    i2c_hp_delay        ; half period delay
    cbi    DDRD,SCLP        ; release SCL
i2c_put_ack_wait:
    sbis    PIND,SCLP        ; wait SCL high
    rjmp    i2c_put_ack_wait
    rcall    i2c_hp_delay        ; half period delay
    ret


;***************************************************************************
;*
;* FUNCTION
;*    i2c_stop
;*
;* DESCRIPTION
;*    Assert stop condition.
;*
;* USAGE
;*    No parameters.
;*
;* RETURN
;*    None.
;*
;***************************************************************************

i2c_stop:
    sbi    DDRD,SCLP        ; force SCL low
    sbi    DDRD,SDAP        ; force SDA low
    rcall    i2c_hp_delay        ; half period delay
    cbi    DDRD,SCLP        ; release SCL
    rcall    i2c_qp_delay        ; quarter period delay
    cbi    DDRD,SDAP        ; release SDA
    rcall    i2c_hp_delay        ; half period delay
    ret


;***************************************************************************
;*
;* FUNCTION
;*    i2c_init
;*
;* DESCRIPTION
;*    Initialization of the I2C bus interface.
;*
;* USAGE
;*    Call this function once to initialize the I2C bus. No parameters
;*    are required.
;*
;* RETURN
;*    None
;*
;* NOTE
;*    PORTD and DDRD pins not used by the I2C bus interface will be
;*    set to Hi-Z (!).
;*
;* COMMENT
;*    This function CAN be combined with other PORTD initializations.
;*
;***************************************************************************

i2c_init:
    clr    i2cstat            ; clear I2C status register (used
                    ; as a temporary register)
    out    PORTD,i2cstat        ; set I2C pins to open colector
    out    DDRD,i2cstat
    ret


;***************************************************************************
;*
;* PROGRAM
;*    main - Test of I2C master implementation
;*
;* DESCRIPTION
;*    Initializes I2C interface and shows an example of using it.
;*
;***************************************************************************

RESET:
main:    rcall    i2c_init        ; initialize I2C interface

;**** Write data => Adr(00) = 0x55 ****

    ldi    i2cadr,$A0+i2cwr    ; Set device address and write
    rcall    i2c_start        ; Send start condition and address

    ldi    i2cdata,$00        ; Write word address (0x00)
    rcall    i2c_do_transfer        ; Execute transfer

    ldi    i2cdata,$55        ; Set write data to 01010101b
    rcall    i2c_do_transfer        ; Execute transfer

    rcall    i2c_stop        ; Send stop condition

;**** Read data => i2cdata = Adr(00) ****

    ldi    i2cadr,$A0+i2cwr    ; Set device address and write
    rcall    i2c_start        ; Send start condition and address

    ldi    i2cdata,$00        ; Write word address
    rcall    i2c_do_transfer        ; Execute transfer

    ldi    i2cadr,$A0+i2crd    ; Set device address and read
    rcall    i2c_rep_start        ; Send repeated start condition and address

    sec                ; Set no acknowledge (read is followed by a stop condition)
    rcall    i2c_do_transfer        ; Execute transfer (read)

    rcall    i2c_stop        ; Send stop condition - releases bus

    rjmp    main            ; Loop forewer

;**** End of File ****

2: 谢谢david1234!收到,谢谢拉。

高工
2023-03-11 17:02:34     打赏
3楼

学习


高工
2023-03-11 21:04:26     打赏
4楼

谢谢分享


共4条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]