<<<

Подпрограммы для работы с шиной I2C с использованием микроконтроллеров Microchip PIC.

  В приведенных ниже примерах вывод SCL I2C устройства подключен к выводу RB2 pic-контроллера, вывод SDA - к RB3.
  Процедуры написаны на ассемблере и могут быть встроены в код С-компиллятора (как это сделано в примерах - для C2C). Проверялась работа процедур с частотой кварца 4МГц. При более высоких частотах возможно потребуется вводить временные задержки для корректного обмена по шине I2C.

/*--------- начало примера-----------
 Требуется 2 байта ОЗУ - i2c_byte - в него помещается байт,
 который необходимо вывести на шину, в нем оказывается байт, 
 считанный с шины; tmp - счетчик, используемый в цикле. */

char i2c_byte; /* рабочий регистр */
char tmp;      /* счетчик */

void i2c_start() {
 asm {
  bcf STATUS, RP0  
  bsf PORTB, 2     ; SCL - 1
  bsf PORTB, 3     ; SDA - 1
  bcf PORTB, 3     ; SDA - 0
  bcf PORTB, 2     ; SCL - 0
 }
}

void i2c_stop() {  
 asm {
  bcf STATUS, RP0
  bcf PORTB, 3     ; SDA - 0
  bsf PORTB, 2     ; SCL - 1
  bsf PORTB, 3     ; SDA - 1
 }
} 

void i2c_write() {
 asm {
            movlw 0x08
            movwf _tmp
            bsf STATUS, RP0
            bcf TRISB, 3          ; SDA - вывод
            bcf STATUS, RP0
            bcf PORTB, 2          ; SCL - 0
  send_bit  bsf PORTB, 3          ; выводим 1 на SDA
            btfss _i2c_byte, 7    ; бит данных - 1 ?
            bcf PORTB, 3          ; нет - выводим 0 на SDA 
            bsf PORTB, 2          ; SCL - 1
            rlf _i2c_byte, F      ; сдвигаем влево байт данных
            bcf PORTB, 2          ; SCL - 0
            decfsz _tmp, F        ; конец цикла ?
            goto send_bit         ; нет - переход
                       

            bsf PORTB, 3          ; осв. SDA
            bsf PORTB, 2          ; SCL - 1, получаем ACK-бит и игнорируем его (!)
            bcf PORTB, 2          ; SCL - 0
 }
}

void i2c_read() {
 asm {
            movlw 0x08
            movwf _tmp
            bsf STATUS, RP0
            bsf TRISB, 3          ; SDA - на ввод
            bcf STATUS, RP0
            bcf PORTB, 2          ; SCL - на 0
  read_bit  rlf _i2c_byte, F      ; сдвигаем байт влево
            bsf PORTB, 2          ; SCL - up
            bsf _i2c_byte, 0      ; устанавливаем бит в 1
            btfss PORTB, 3        ; SDA - 1?
            bcf _i2c_byte, 0      ; нет - устанавливаем бит в 0
            bcf PORTB, 2          ; SCL - 0
            decfsz _tmp, F        ; конец цикла ?
            goto read_bit         ; нет - переход
            bsf STATUS, RP0
            bcf TRISB, 3          ; SDA - на вывод
            bcf STATUS, RP0
 }
}
/*------------- окончание примера ------------ */
Примеры использования процедур

  Рассмотрим применение этих процедур на примере микросхемы памяти 24LC256. Микросхема содержит 32К памяти, выпускается фирмой Microchip.
  Подробнее о микросхеме...
*/------------начало примера----------------

 вывод содержимого памяти на COM-порт */
 
void outAllData() {
for (i = 0; i < 32767; i++) {
    i2c_start();
    i2c_byte = 0xA0;          // control байт с битом WR
    i2c_write();
    asm {
            movfw _i+1
            movwf _i2c_byte   ; старший байт адреса памяти
    }
    i2c_write();
    asm {     
            movfw _i
            movwf _i2c_byte   ;  младший байт адреса памяти
    }
    i2c_write();  
    i2c_start();
    i2c_byte = 0xA1;          // control байт с битом RD
    i2c_write();
    i2c_read();
    i2c_stop();
    putchar(i2c_byte);
   }
}

/* запись в 24LC256 числа 1Fh по адресам от 00h по FFh */

   for (temp = 0; temp <= 0xFF; temp++) {
    i2c_start();
    i2c_byte = 0xA0;         //control байт с битом WR
    i2c_write();
    i2c_byte = 0;            // старший байт адреса памяти
    i2c_write();
    i2c_byte = temp;         // младший байт адреса памяти
    i2c_write();  
    i2c_byte = 0x1F;         // записываемые данные
    i2c_write();              
    i2c_stop();
   }

/*------------окончание примера---------------*/