I2C Generelt

Fra Kommunikation-IT Holstebro HTX
Skift til: navigering, søgning

Kommunikationen med I2C er baseret på at man kan kommunikere på 2 ledninger som beskrevet under I2C. Det gør man ved hjælp af Wire-modulet[1] der ligger som standard i Arduino-installationen.

Normal kommunikation

Alle I2C moduler har en adresse, der ligger mellem 8 og 119 (hexadecimalt 0x08 til 0x77), hvor man i alt hvad man kommunikerer til modulet skal starte med denne adresse og en angivelse af om man vil læse eller skrive. Dette kobles sammen i en byte, så man tit skal betragte det som adressen * 2 når man vil skrive og adressen * 2 + 1 når man vil læse - det kommer an på de interface-rutiner man anvender.

De fleste I2C moduler kan betragtes som et hukommelses-areal eller et array, hvor det første man sender til modulet er den adresse man vil starte på (det index i arrayet), og derefter sender / modtager man det antal bytes man har behov for.

Eksempel på et modul

For at illustrere hvordan man normalt kommunikerer er der her beskrevet et eksempel ud fra Arduino_DS1307_RTC, hvor der er to små eksempler, hvor det ene kan stille uret til PC'ens tid og det andet kan læse uret hvert sekund. Dette er baseret på et modul DS1307RTC, der udnytter Wire modulet.

Fra databladet for DS1307[2] kan man se hvordan hukommelsen i RTC'en er fordelt, som vist her:

Real Time Clock data area
Real Time Clock register tabel

Adressen for Real Time Clock modulet kan læses i databladet som 0x68, som ganget med 2 bliver til 0xD0.

Eksempel på skrivning

For at skrive urets indhold starter man med at skrive adressen på modulet og så startadressen 0x00, og derefter kommer de 7 registre. Dette pakkes ind i en beginTransmission og afslutter med en endTransmission, der kan angive om transmissionen er gået godt.

I arduinoen kan dette udtrykkes ved hjælp af følgende kode:

 Wire.beginTransmission(DS1307_CTRL_ID);  // RTC Address 0x68
 Wire.write((uint8_t)0x00); // reset register pointer  
 Wire.write(tm.Second) ;   
 Wire.write(tm.Minute);
 Wire.write(tm.Hour);      // sets 24 hour format
 Wire.write(tm.Wday);   
 Wire.write(tm.Day);
 Wire.write(tm.Month);
 Wire.write(tm.Year); 
 if (Wire.endTransmission() != 0) {
    return false;
 }

Som det kan ses i koden, så skrives der kun til de første 7 bytes i RTC. Den 8. byte har en speciel betydning hvor man kan indstille det ekstra output til at have forskellige funktioner, dette skal man læses i databladet[2] Ud over dette ligger der 56 byte RAM i RTC'en. De kan anvendes til at gemme oplysninger der gemmes med det batteri der sidder på RTC-modulet.

Hvis man måler på modulet ved en skrivning ved hjælp af en logik-analysator, der kan tolke I2C protokollen, så kan man se følgende:

Real Time Clock skrivning
Real Time Clock skrivning af klokken

Den første Byte er adressen 0x68 der ganget med 2 bliver til 0xD0. Næste byte er 0x00 som er register-adreseen inde i RTC-modulet, og derefter følger de 7 byte der skal skrives ind i RTC-modulet for at stille uret.

Uret stilles i dette eksempel til 18:32:53 søndag (0x00) d. 9/12-2014 ved at der skrives 0x53, 0x32, 0x18, 0x00, 0x09, 0x12 og 0x14.

Eksempel på læsning

For at læse urets indhold, så skal man starte med at skrive adressen på modulet og så startadressen 0x00. Dette pakkes ind i en beginTransmission og afslutter med en endTransmission, der kan angive om transmissionen er gået godt. Dette er blot for at angive hvor der skal læses fra.

Hvis angivelsen af hvor man vil læses henne er gået godt, så skal man lave den aktuelle læsning. Dette sker ved hjælp af requestFrom, som igen sender adressen, men denne gang med en læse-angivelse. Det er faktisk her den aktuelle læsning sker. Ved hjælp af available kan man se om det er gået godt, og hvis det er det, så kan man læse ved hjælp af read de 7 byte der er læst i modulet.

I arduinoen kan dette udtrykkes ved hjælp af følgende kode:

 Wire.beginTransmission(DS1307_CTRL_ID);
 Wire.write((uint8_t)0x00); 
 if (Wire.endTransmission() != 0) {
    return false;
 }

 // request the 7 data fields   (secs, min, hr, dow, date, mth, yr)
 Wire.requestFrom(DS1307_CTRL_ID, tmNbrFields);  // Read 7 bytes fra 0x68
 if (Wire.available() < tmNbrFields) return false;
 tm.Second = Wire.read();
 tm.Minute = Wire.read();
 tm.Hour   = Wire.read() & 0x3f;  // mask assumes 24hr clock
 tm.Wday   = Wire.read();
 tm.Day    = Wire.read();
 tm.Month  = Wire.read();
 tm.Year   = Wire.read();

Hvis man måler på modulet ved en læsning ved hjælp af en logik-analysator, der kan tolke I2C protokollen, så kan man se følgende:

Real Time Clock læsning
Real Time Clock læsning af klokken

Den første byte 0xD0 er igen adressen 0x68 ganget med 2. Herefter skrives 0x00, der angiver at der skal læses fra register-adresse 0x00 og fremad. Den 3. byte er igen 0x68 ganget med 2, men denne gang er der lagt 1 til der angiver læsning, så det bliver 0xD1, og herefter er det RTC-modulet der sender de næste 7 bytes tilbage til masteren, hvor den sender 0x09, 0x55, 0x17, 0x00, 0x09, 0x12 og 0x14, hvilket kan tolkes til 17:55:09 søndag d. 9/12-2014.

Referencer

  1. Arduinos dokumentation af Wire-modulet
  2. 2,0 2,1 Datablad for DS1307 Real Time Clock