AFON // радиотехник affonya@mail.ru
← Проекты на PIC

Проект 38. Программный I²C и память 24C02

Шина I²C реализована программно на двух обычных выводах: условия старта и стопа, передача байта, подтверждение. Записываем байт во внешнюю память и читаем обратно.

Задача

Записать байт во внешнюю память 24C02 и прочитать его обратно.

Микроконтроллер: PIC16F84A, кварц 4 МГц. Среда: MPLAB X + MPASM (или любой совместимый ассемблер). Как настроить среду и прошить контроллер — в статье программирование PIC.

Что понадобится

  • PIC16F84A
  • кварц 4 МГц + 2×22 пФ
  • микросхема 24C02
  • два резистора 4,7 кОм (подтяжки)
  • светодиоды индикации

Схема подключения

ВыводПодключение
RB0 / SDAвывод данных памяти, подтяжка 4,7 кОм на +5 В
RB1 / SCLвывод тактирования, подтяжка 4,7 кОм на +5 В
A0…A2 памятина GND — адрес микросхемы 0

Алгоритм

  1. Сформировать условие СТАРТ: спад SDA при высоком SCL.
  2. Передать адрес микросхемы с признаком записи, затем адрес ячейки и данные.
  3. Завершить условием СТОП и выдержать время внутренней записи.
  4. Для чтения повторить старт с признаком чтения и принять байт.

Листинг на ассемблере

Код проверен ассемблером и собирается без ошибок. Скачать: p38.asm · p38.hex (готовая прошивка).

;=======================================================
; Проект 38. Программный I2C: память 24C02
; PIC16F84A, 4 МГц. SDA — RB0, SCL — RB1
; Подтяжки 4,7 кОм на +5 В обязательны
; Записываем байт по адресу 0x10 и читаем его обратно
;=======================================================
        LIST    p=16F84A
        #include <p16f84a.inc>
        __CONFIG _XT_OSC & _WDT_OFF & _PWRTE_ON & _CP_OFF

#define SDA_PIN PORTB,0
#define SCL_PIN PORTB,1

        cblock  0x0C
        d1, bitcnt, obyte, ibyte
        endc

        ORG     0x000
        goto    Start

Start
        bsf     STATUS,RP0
        movlw   b'00000011'     ; SDA и SCL — входы (линии отпущены)
        movwf   TRISB
        bcf     STATUS,RP0
        bcf     SDA_PIN         ; в защёлке всегда ноль
        bcf     SCL_PIN

        ;--- запись байта 0xA5 по адресу 0x10 ---
        call    I2CStart
        movlw   0xA0            ; адрес микросхемы, режим записи
        call    I2CWrite
        movlw   0x10            ; адрес ячейки
        call    I2CWrite
        movlw   0xA5            ; данные
        call    I2CWrite
        call    I2CStop
        call    Delay10ms       ; цикл внутренней записи памяти

        ;--- чтение того же байта ---
        call    I2CStart
        movlw   0xA0
        call    I2CWrite
        movlw   0x10
        call    I2CWrite
        call    I2CStart        ; повторный старт
        movlw   0xA1            ; адрес микросхемы, режим чтения
        call    I2CWrite
        call    I2CRead
        movwf   ibyte
        call    I2CStop

Main
        movf    ibyte,w         ; прочитанное значение на светодиоды
        movwf   PORTB
        goto    Main

;--- условие СТАРТ: SDA вниз при высоком SCL ---
I2CStart
        call    SdaHigh
        call    SclHigh
        call    Delay5us
        call    SdaLow
        call    Delay5us
        call    SclLow
        return

;--- условие СТОП: SDA вверх при высоком SCL ---
I2CStop
        call    SdaLow
        call    SclHigh
        call    Delay5us
        call    SdaHigh
        call    Delay5us
        return

;--- передача байта из W, старший бит вперёд ---
I2CWrite
        movwf   obyte
        movlw   .8
        movwf   bitcnt
WBit
        btfss   obyte,7
        goto    W0
        call    SdaHigh
        goto    WClk
W0
        call    SdaLow
WClk
        call    SclHigh
        call    Delay5us
        call    SclLow
        rlf     obyte,f
        decfsz  bitcnt,f
        goto    WBit
        call    SdaHigh         ; отпускаем линию под ACK
        call    SclHigh
        call    Delay5us
        call    SclLow
        return

;--- приём байта в W ---
I2CRead
        call    SdaHigh
        movlw   .8
        movwf   bitcnt
        clrf    ibyte
RBit
        call    SclHigh
        call    Delay5us
        bcf     STATUS,C
        btfsc   SDA_PIN
        bsf     STATUS,C
        rlf     ibyte,f
        call    SclLow
        decfsz  bitcnt,f
        goto    RBit
        call    SdaHigh         ; NACK — читаем один байт
        call    SclHigh
        call    Delay5us
        call    SclLow
        movf    ibyte,w
        return

;--- управление линиями через направление вывода ---
SdaLow
        bsf     STATUS,RP0
        bcf     TRISB,0
        bcf     STATUS,RP0
        return
SdaHigh
        bsf     STATUS,RP0
        bsf     TRISB,0
        bcf     STATUS,RP0
        return
SclLow
        bsf     STATUS,RP0
        bcf     TRISB,1
        bcf     STATUS,RP0
        return
SclHigh
        bsf     STATUS,RP0
        bsf     TRISB,1
        bcf     STATUS,RP0
        return

Delay5us
        nop
        nop
        nop
        nop
        return

Delay10ms
        movlw   .20
        movwf   d1
DlyA    movlw   .165
        movwf   bitcnt
DlyB    nop
        decfsz  bitcnt,f
        goto    DlyB
        decfsz  d1,f
        goto    DlyA
        return

        END

Пояснения

  • Линиями управляют переключением направления вывода, а не уровнем: в защёлке ноль, а высокий уровень создаёт подтягивающий резистор. Это требование открытого стока.
  • Повторный СТАРТ при чтении обязателен: он меняет направление обмена, не отпуская шину.
  • После записи микросхеме нужно до 5 мс на внутренний цикл — обращение раньше времени вернёт ошибку.

Что дальше

Разобравшись с этим проектом, переходите к следующему в разделе проекты на PIC. Справочник по архитектуре и периферии контроллеров — на странице микроконтроллеры PIC.