I2C for 8051

Posted in June 26th, 2007

Target: 8051

Content of .asm file

; ***************************************************************
; This collection of routines allows an 80x51 microcontroller
; to read and write the I2C devices
; FOSC = 24MHz.
; ***************************************************************

_R         EQU        0

SDA        EQU        P3.1
SCL        EQU        P3.7


        RSEG RCODE


PUBLIC    I2C_Start
; void I2C_Start (void);
; Send START, defined as high-to-low SDA with SCL high
; Input:  None
; Output: None
; Registers destroyed: A, PSW, R1

I2C_Start:
        setb    SDA
        mov     A, #5          ; wait Tr + Tsu:dat, prevent "STOP"
        mov     R1, #7
        setb    SCL            ; release bus
        djnz    R1, $          ; wait Tr + Tsu:sta (> 5.7us)

        clr     SDA            ; high-to-low SDA with SCL high
        mov     R1, A
        djnz    R1, $          ; wait Tf + Thd:sta (> 4.3us)

        clr     SCL            ; SCL low, enable data change
        djnz    ACC, $         ; wait Tf + Tlow (> 5us)
        ret


PUBLIC    I2C_Stop
; void I2C_Stop (void);
; Send STOP, defined as low-to-high SDA with SCL high
; Input:  None
; Output: None
; Registers destroyed: R1
; SCL expected low on entry. Return with SCL, SDA high

I2C_Stop:
        clr     SDA
        nop                    ; wait Tf + Tsu:dat, prevent "START"
        mov     R1, #7
        setb    SCL            ; prepare for "STOP"
        djnz    R1, $          ; wait Tr + Tsu:sto (> 5.7us)

        setb    SDA            ; low-to-high SDA with SCL high
        ret


PUBLIC    I2C_OUTB
; bit I2C_OUTB (data BYTE b);
; Shift out a byte to the device, most significant bit first.
;     Read ACK or NAK from the device.
; Input:  R4 - Byte to be shifted out
; Output: Carry flag - Clear if there is not acknowledge
; Registers destroyed: A, PSW, R1, R4
; SCL expected low on entry. Return with SCL low

I2C_OUTB:
        setb    C              ; CY = 1, get ACK bit
        mov     A, R4          ; byte to be shifted in A
        sjmp    I2C_Shift


PUBLIC    I2C_INB
; BYTE I2C_INB (data BYTE SendACK);
; Shift in a byte from the device, most significant bit first.
;     Send ACK or NAK to the device.
; Input:  R4 - 0 - Send NAK to device
;              else - Send ACK to device
; Output: R4 - Received data byte from device
; Registers destroyed: A, PSW, R1
; SCL expected low on entry. Return with SCL low

I2C_INB:
        mov     A, R4
        add     A, #0FFh       ; move ACK bit into CY
        cpl     C
        mov     A, #0FFh       ; SDA high
I2C_Shift:
        mov     R1, #9         ; bit counter, 8 bits + ACK
L_Next_Bit:
        rlc     A              ; move bit7 into CY
        mov     SDA, C         ; output bit
        mov     R4, #2
        djnz    R4, $          ; wait Tr + Tsu:dat + more (3us)

        setb    SCL            ; raise clock
        mov     R4, #4
        djnz    R4, $          ; wait Tr + Thigh (5us)

        mov     C, SDA         ; input bit
        clr     SCL            ; drop clock
        djnz    R1, L_Next_Bit ; now wait Tf + Tlow (> 5us)

        cpl     C              ; ACK bit
        mov     R4, A
        ret


        END



Example of .c routines for interfacing DS1307, block Read/Write functions

bit RTCWriteBlock (data BYTE Addr, data BYTE data *p, data BYTE Count)
{
    bit    Result;

    Result = FALSE;

    I2C_Start ();
    if (I2C_OUTB (0xD0))                            // write
    {
        if (I2C_OUTB (Addr))                        // addr
        {
            Result = TRUE;
            for (; Count; Count--)
            {
                if (!I2C_OUTB (*p++))
                {
                    Result = FALSE;
                    break;
                }
            }
        }
    }
    I2C_Stop ();

    return Result;
}


bit RTCReadBlock (data BYTE Addr, data BYTE data *p, data BYTE Count)
{
    bit    Result;

    Result = FALSE;

    I2C_Start ();
    if (I2C_OUTB (0xD0))                            // write
    {
        if (I2C_OUTB (Addr))                        // addr
        {
            Result = TRUE;
            if (Count)
            {
                I2C_Start ();
                if (Result = I2C_OUTB (0xD1))        // read
                {
                    while (Count)
                    {
                        Count--;
                        *p++ = I2C_INB (Count);
                    }
                }
            }
        }
    }
    I2C_Stop ();

    return Result;
}

One Response to "I2C for 8051"

Follow-up responses to this entry through the RSS feed, Leave a Reply or Trackback from your own site.
candy gift baskets said,
in September 9th, 2008 at 8:24 am

candy gift baskets…

The term is used colloquially for any kind of Linkback. (Blogger now has backlinks - very similar to the trackback feature in Movable…

Leave a Reply

 Username (*required)

 Email Address (*private)

 Website (*optional)