Задача
Записать байт во внешнюю память 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 |
Алгоритм
- Сформировать условие СТАРТ: спад SDA при высоком SCL.
- Передать адрес микросхемы с признаком записи, затем адрес ячейки и данные.
- Завершить условием СТОП и выдержать время внутренней записи.
- Для чтения повторить старт с признаком чтения и принять байт.
Листинг на ассемблере
Код проверен ассемблером и собирается без ошибок. Скачать: 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.