Урок по mikropascal для AVR. I2C

I2C - послідовна шина даних для зв'язку інтегральних схем. I2C використовує 2 двонаправлені лінії зв'язку SDA і SCL, підтягнуті до напруги живлення.

Приклад роботи I2C інтерфейсу.

Інтерфейс I2C використовується у багатьох пристроях, вони мають низьку вартість і простоту розробки пристроїв на них, ми розглянемо 2 з них: 24AA02 (2к-EEPROM з I2C інтерфейсом) і DS1307 ( годинник/календар реального часу також підключається по I2C.

Отже, перейдемо до справи. Для роботи з I2C в mikropascal є вбудована бібліотека, правда називається вона TWI library. Бібліотека має 8 команд:

  • TWI_Init(clock : dword); - ініціалізація I2C. Параметр clock це частота роботи I2C в герцах, зазвичай використовується частота в 100 КГц або 100000 Гц.
  • TWI_Busy() : byte; - повертає стан зайнятості шини I2C. 1 - якщо зайнята, 0 - якщо не зайнята.
  • TWI_Start() : char; - якщо шина не зайнята, дає стартовий сигнал. Повертає 1 - якщо послідовність не завершена і 0 - якщо завершена.
  • TWI_Read(ack : byte) : byte; - зчитує 1 байт.
  • TWI_Write(data_ : byte); - відправляє 1 байт по шині I2C. Параметр data_ це байт який ми відправляємо на пристрій.
  • TWI_Stop(); - відправляє завершальний сигнал. Нічого не повертає.
  • TWI_Status() : byte; - повертає статус шини I2C.
  • TWI_Close(); - закриває з'єднання I2C. Нічого не повертає.

Думаю, з цим усе зрозуміло, тому переходимо до коду. Спершу приєднаємо до ATmega8 енергонезалежну пам'ять 24AA02. Напишемо програму, яка спочатку записує байт у пам'ять, потім зчитує його і відправляє на PORTB. Ось так виглядає наш код:

program _24aa02;

begin
     DDRB:=0xff;        /Порт Б на вивід
     twi_Init(100000);  /Ініціалізуємо I2C з частотою 100 КГц
     twi_Start();       /Старт I2C
     twi_write(0xa4);   /Відправляємо ячейку
     twi_write(1);      /Відправляємо сектор EEPROM
     twi_write(0xaa);   /Записуємо байт
     twi_stop();        /Стоп I2C
     delay_ms(50);
     
     twi_start();
     twi_write(0xa4);
     twi_write(1);
     twi_start();
     twi_write(0xa5);   /Відправляємо ячейку на один більше того, в який записали
     PORTB:=twi_read(0);/Зчитуємо в Порт Б значення байта
     twi_stop();
     
end.

Думаю, тут усе повинно бути зрозуміло, вкажу лише деякі характеристики 24AA02. У 24AA02 2кб енергонезалежна пам'ять розбита на 8 секторів по 256 ячеек, запис однієї ячейки займає 10мс.

Тепер ідемо в Proteus. Робимо таку схему:

Запускаємо симуляцію і бачимо таку картину:

Значення PORTB перейшло в 0xAA, як і повинно було бути. З пам'яттю розібралися, тепер робимо нещо складніше.

DS1307 годинник/календар реального часу підключається по I2C інтерфейсу, відлічує  секунди, хвилини, години, дні, число, місяць і рік. Ми будемо зчитувати секунди, хвилини і години та виводити їх на семисегментний індикатор.

program ds1307;
var
   sec,mint,hour:byte;
   i,temp:integer;
   secs,mins,hours:array[3] of char;
const
     d0:byte=192;
     d1:byte=249;
     d2:byte=164;
     d3:byte=176;
     d4:byte=153;
     d5:byte=146;
     d6:byte=130;
     d7:byte=248;
     d8:byte=128;
     d9:byte=144;
     dp:byte=127;
begin
     twi_init(100000);
     mint:=0;
     hour:=0;
     sec:=1;
     DDRB:=0xff;
     DDRD:=0x0f;

     twi_start();
     twi_write(0xd0);
     twi_write(0);
     twi_stop();

     twi_start();
     twi_write(0xd0);
     twi_write(1);
     twi_stop();

     twi_start();
     twi_write(0xd0);
     twi_write(2);
     twi_stop();

     while true do
     begin
         if PIND.6=0 then begin
             mint:=dec2bcd(mint);
             inc(mint);
             if mint>89 then mint:=0;
             twi_start();
             twi_write(0xd0);
             twi_write(1);
             twi_write(mint);
             twi_stop();
         end;
         if PIND.7=0 then begin
            hour:=dec2bcd(hour);
            inc(hour);
            if hour>35 then hour:=0;
            twi_start();
            twi_write(0xd0);
            twi_write(2);
            twi_write(hour);
            twi_stop();
         end;
         twi_start();
         twi_write(0xd0);
         twi_write(0);
         twi_start();
         twi_write(0xd1);
         sec:=twi_read(1);
         mint:=twi_read(1);
         hour:=twi_read(0);
         twi_stop();

         sec:=bcd2dec(sec);
         mint:=bcd2dec(mint);
         hour:=bcd2dec(hour);

         bytetostr(mint,mins);
         bytetostr(hour,hours);

         for temp:=1 to 25 do begin
         for i:=0 to 3 do begin
             if i>=2 then begin
             if i=2 then portd:=4;
             if i=3 then portd:=8;
             case mins[i-1] of
                  '1':portb:=d1;
                  '2':portb:=d2;
                  '3':portb:=d3;
                  '4':portb:=d4;
                  '5':portb:=d5;
                  '6':portb:=d6;
                  '7':portb:=d7;
                  '8':portb:=d8;
                  '9':portb:=d9;
                  '0':portb:=d0;
                  ' ':portb:=d0;
             end;
             end
             else begin
                  portd:=i+1;
                  case hours[i+1] of
                       '1':portb:=d1;
                       '2':portb:=d2;
                       '3':portb:=d3;
                       '4':portb:=d4;
                       '5':portb:=d5;
                       '6':portb:=d6;
                       '7':portb:=d7;
                       '8':portb:=d8;
                       '9':portb:=d9;
                       '0':portb:=d0;
                       ' ':portb:=d0;
                  end;
             end;
             delay_ms(10);
         end;
         end;
     end;

end.

Тепер Протеус:

Тепер, під урочисту музику, запускаємо нашу схему і сподіваємося, що вона працює.

І, о чудо, вона працює! Як ви вже здогадалися, 2 кнопки внизу призначені для регулювання часу, кварц частотою 32768 Гц.

Ну от, урок підійшов до кінця. Тепер ви вмієте працювати з I2C в mikropascal for AVR. Всі необхідні відомості по підключенню пристрою та адресах даних можна знайти в документації до потрібного вам пристрою. 

Прикріплені файли:

Top