I2C of ook wel IIC.
Met je mini processor kan je een blok I2C IC's bedienen.
I2C is een manier van communiceren door Phillips bedacht.
Je stuurt een adres en opdracht naar alle IC's en het IC van dat adres stuurt het antwoord of voert de opdracht uit.
Hierdoor moet je de datasheet van een bepaald IC vaak moeten hebben.
Je hebt voor een I2C protocol (of ook wel IIC), 4 draden nodig, een plus een min en 2 stuur draden.
De plus en min zijn er voor om de IC's die je via I2C gaat
benaderen, van spanning te voorzien.
De spanning kan 3.3V of 5V zijn. Via een tussen brug kan je data van een 3.3V bus naar een 5V bus v.v. sturen. De data snelheid is tussen de 100 en de 400 kHz. Door de bus laag of hoog te maken wordt de data over gegeven.
Er zijn 4 potentionele modes:
master zend
master ontvangt
slave zend
slave ontvangt
De 2 draden met signaal zijn de SDA (serial data) en de SDL (serial clock). Mocht het geheel ondanks alles niet werken, verwissel die draden eens wellicht heb je de SDA op de SDL aangesloten en andersom.
Omdat berichten verschillende lengtes hebben is er een code die aangeeft dat het bericht aan het einde is.
Start condition: SDA: HIGH -> LOW als SCL is HIGH
Stop condition: SDA: LOW -> HIGH als SCL is HIGH
Dat houdt in dat alleen bij start of stop de SDA status veranderd als de SCL HIGH is. In alle andere gevallen veranderd de SDA alleen als de SCL LOW is.
Het adres van een apparaat is 7 of 10 bit en uniek op de I2C bus. Elk apparaat kan intern ook adressen hebben om te kunnen functioneren. Die interne adressen worden pas na het apparaat adres via de I2C
bus door gegeven .
Het is het verstandig om elke draad (SDA en SCL) via een weerstand met de plus te verbinden.(Soms is die weerstand niet nodig) Een beetje afhankelijk van de lengte van de draden en het aantal IC's kan je de waarde van de weerstanden aanpassen.
Ik begin meestal met 4K7 oftewel 4700 Ohm 1/8 watt.
Op de tekening zien we 3 IC typen. A B en C. Elk IC type stelt een zelfde groep van 3 IC's voor.
Meer achtergond info vind je
hier
De meeste I2C IC's hebben 3 pennetjes waar een nul of een één op kan staan. Soms zijn er minder en soms meer aan te passen adressen mogelijk. (In dit geval dus x y z) Als een pootje (die x, y of z) aan de min (0) of aan de plus (1) verbinden worden verander je het adres van het IC. Dat kunnen 8 adresseer mogelijkheden zijn.
Om elk IC type te kunnen benaderen heeft elk IC een hardware nummer. Die kan je dus niet veranderen. Op de tekening A B en C maar bij IC's is dat b.v. 20 70 90.
De MCP23017 heeft hardware adres 2x. De x is het zelf te maken adres van de drie lijnen.(0 t/m 7)
Je kan dus de adressen 20 t/m 27 gebruiken om 8x een MCP23017 aan te sturen wat 8x 16 in/out poorten zijn.
Een ander IC wat ik gebruik is de A/D omzetter PCF8591 welke hardware adres 9x heeft.
Dus adres 90 t/m 98 kan je gebruiken.
IC type heeft de zelfde eigenschappen.(3 verschillden IC's maar meerdere van dezelfde IC's per groep) Je moet dus in je adressering het blok, het individuele IC, en de functie opnemen.
Als je in IC A, nr 2, functie 'pootje 1 lezen' wil zetten moet je dat dus bij elke opdracht aangeven.
Het makkelijkste is met de opdracht #define van Arduino. Je kan dan getallen omzetten in namen. //schrijf 12- voeruit - schrijf 01 - voer uit//
is lastiger te lezen dan // schrijf IC blok A IC 1 - voer uit - lees 1 - voeruit.//
Klinkt leuk maar er wordt wel van je verwacht dat je weet wat het IC kan doen.
Als je een IC hebt moet je wel weten hoe je eventuele opdrachten moet programeren.
De MCP 23017 heeft 2 registers van 8 bits die je ook kan benaderen als 1 register van 16 bits.
00000000 00000000 of 0000000000000000
Wil je weten of een pootje van een IC hoog of laag is:
ICtype en ICnummer ingeven
stuur naar IC
opdracht en locatie aangeven
stuur naar IC
lezen of schrijven
stuur naar IC
voeropdracht uit
stuur naar IC
Je begint te begrijpen dat er veel mogelijkheden zijn. En die mogelijkheden moet je wel kunnen adresseren.
Zo heeft de MCP23017 de volgende adresser mogelijkheden:
naam | adres | functie |
IODIRA | 00 | 0=input 1= output (wil je data lezen of schrijven) |
IODIRB | 01 | 0=input 1= output |
IOPOLA | 02 | 0= normal 1= inverse (een 1 wordt een nul etc) |
IOPOLB | 03 | 0= normal 1= inverse |
GPINTENA | 04 | 0= uit 1= aan (interupt A als iets veranderd) |
GPINTENB | 05 | 0= uit 1= aan (interupt B als iets veranderd) |
DEFVALA | 06 | Vaste waarde bij verandering bij interupts. A |
DEFVALB | 07 | Vaste waarde bij verandering bij interupts. B |
| 08 | |
| 09 | |
Zo gaat die lijst door t/m 15. Als je dus iets wil instellen in de setup van dat IC moet je dus
voor het 2e IC het adres 0x21 (0x21 betekend HEX 21) gebruiken en dan op b.v. IOPOLB te veranderen, 0x02 te sturen of als de #define IOPOLB= 0x02 gedefinieerd heb, Wire.send(IOPOLB) gebruiken.
Je kan een IC dus 'handmatig' zonder library gebruiken maar dan moet je goed weten wat je moet doen. De librarys maken het leven soms
makkelijk en soms erg lastig. Na een update hoeft een library niet goed te werken.
Arduino zend 7 bits uit voor het adres en je hebt soms 8 bits nodig. Er moet dus met bits geschoven worden.
1001 Moet altijd voor IC herkenning en dan 3 bits hardware adres en als laatste om te lezen een 0 en te schrijven een 1
Het adres wordt dan 1001xxx1 om te lezen
of 1001xxx0 om te schrijven.
Het vreemde is dat volgens de info van de Arduino dit automatisch zou moeten gebeuren bij het verzenden van de data door
de Arduino. Bij mij blijkt echter dat als ik gewoon adres 90 gebruik het proces niet goed te verlopen.
Er zijn 3 bytes nodig om alles goed te laten verlopen:
1e byte adres
2e byte de configuratie (zie datasheet.
3e byte de te schrijven of te lezen data.
De 2e en 3e byte mogen 8 bits zijn.
Adafruit heeft een mooie lijst met veel I2C adressen die ik niet allemaal opgenomen heb op mijn site maar wel degene die ik belangrijk vind.
Speciale gevallen:
PCA9685 kan gebruikt worden door elk adres tussen 0x40 to 0x7F (https://adafru.it/dUG)
0x00 - 0x07 and 0x78 - 0x7F zijn gereserveerde I2C adressen.
IC | hardware adres | soort IC |
Algemene oproep adres | 0x00 | |
C bus compatibility | 0x01 | |
I2C vergelijkbare bus variant | 0x02 | |
Toekomstig gebruik | 0x03 | |
Hs master | 0x04 t/m 0x07 | |
Mag3110 | 0x0E | 3 assige magnetometer |
VEML6075 | 0x10 | UV sensor |
VEML7700 | 0x10 | Ambient Licht sensor |
SI 4713 | 0x11 (of 0x63) | FM zender met RDS /td> |
VCNL 40x0 | 0x13 | proximity sensor |
MCP 9808 | 0x18 ( t/m 0x1F) | temperatuur sensor |
LIS 3DH | 0x18 (of 0x19) | 3 assige versnellings meter |
MCP 9808 | 0x19 | temperatuur sensor |
LIS 3DH | 0x19 (of 0x18) | 3 assige versnellings meter |
LSM 303 | 0x19 | versnellings- en magneto-meter |
MCP 9808 | 0x0A | temp sensor |
MCP 23008 | 0x20 (t/m 0x27) | GPIO expander |
MCP23017 | 0x20 (t/m 0x27) | 16x digitaal in/out expander |
LCM1602 | 0x27 | lcddisplay |
DS3502 | 0x28 (t/m 0x2B) | Digitale 10K Potentiometer |
TCS 34725 | 0x29 | kleuren sensor |
PCF8574A | 0x38 | 8 bits in/out |
PFC8574P | 0x38 | 8 bits expander |
PCA9586 | 0x40 | 16 bits PWM out |
PCF8574 | 0x40 | 8 bits expander |
GY80 | 0x53 | MEMS Accelerometer Gyroscope Magnetometer |
DS1307/DS3231 | 0x68 | Real time clock |
GY-65 of BMP085 | 0x77 | Atmosfeer druk temperatuur sensor |
PCF8591 | 0x90 | 8 bits 4x Analoog in 1x Analoog out |
Ook kan het knap lastig zijn om achter het I2C adres van een component te komen als dat niet vermeld is.
Daar kan je met de Arduino een I2C adreszoeker voor gebruiken:
// --------------------------------------
// i2c_scanner
//
// Version 1
// This program (or code that looks like it)
// can be found in many places.
// For example on the Arduino.cc forum.
// The original author is not know.
// Version 2, Juni 2012, Using Arduino 1.0.1
// Adapted to be as simple as possible by Arduino.cc user Krodal
// Version 3, Feb 26 2013
// V3 by louarnold
// Version 4, March 3, 2013, Using Arduino 1.0.3
// by Arduino.cc user Krodal.
// Changes by louarnold removed.
// Scanning addresses changed from 0...127 to 1...119,
// according to the i2c scanner by Nick Gammon
// http://www.gammon.com.au/forum/?id=10896
// Version 5, March 28, 2013
// As version 4, but address scans now to 127.
// A sensor seems to use address 120.
// Version 6, November 27, 2015.
// Added waiting for the Leonardo serial communication.
//
//
// This sketch tests the standard 7-bit addresses
// Devices with higher bit address might not be seen properly.
//
#include <Wire.h>
void setup()
{
Wire.begin();
Serial.begin(9600);
while (!Serial); // Leonardo: wait for serial monitor
Serial.println("\nI2C Scanner");
}
void loop()
{
byte error, address;
int nDevices;
Serial.println("Scanning...");
nDevices = 0;
for(address = 1; address < 127; address++ )
{
// The i2c_scanner uses the return value of
// the Write.endTransmisstion to see if
// a device did acknowledge to the address.
Wire.beginTransmission(address);
error = Wire.endTransmission();
//Serial.println("");
//Serial.print("adres: ");
//Serial.print(address);
if (error == 0)
{
Serial.print("I2C device gevonden op adres 0x");
if (address<16)
Serial.print("0");
Serial.print(address,HEX);
Serial.println(" !");
nDevices++;
}
else if (error==4)
{
Serial.print("Onbekende fout op addres 0x");
if (address<16)
Serial.print("0");
Serial.println(address,HEX);
}
}
if (nDevices == 0)
Serial.println("Geen I2C devices gevonden\n");
else
Serial.println("klaar\n");
delay(5000); // wait 5 seconds for next scan
}
bronnen:
Adafruit I2C adressen
diyi0t.com i2c-tutorial-for-arduino-and-esp8266